Line data Source code
1 : import 'dart:async'; 2 : 3 : import 'package:hive/hive.dart'; 4 : import 'package:path/path.dart' as path_helper; 5 : import 'package:recase/recase.dart'; 6 : import 'package:riverpod/riverpod.dart'; 7 : 8 : class HiveLocalStorage { 9 1 : HiveLocalStorage({ 10 : required this.hive, 11 : this.baseDirFn, 12 : List<int>? encryptionKey, 13 : bool? clear, 14 : }) : encryptionCipher = 15 1 : encryptionKey != null ? HiveAesCipher(encryptionKey) : null, 16 : clear = clear ?? false; 17 : 18 : final HiveInterface hive; 19 : final HiveAesCipher? encryptionCipher; 20 : final FutureOr<String> Function()? baseDirFn; 21 : final bool clear; 22 : 23 : bool isInitialized = false; 24 : 25 1 : Future<void> initialize() async { 26 1 : if (isInitialized) return; 27 : 28 1 : if (baseDirFn == null) { 29 1 : throw UnsupportedError(''' 30 : A base directory path MUST be supplied to 31 : the hiveLocalStorageProvider via the `baseDirFn` 32 : callback. 33 : 34 : In Flutter, `baseDirFn` will be supplied automatically if 35 : the `path_provider` package is in `pubspec.yaml` AND 36 : Flutter Data is properly configured: 37 : 38 : Did you supply the override? 39 : 40 : Widget build(context) { 41 : return ProviderContainer( 42 : overrides: [ 43 : configureRepositoryLocalStorage() 44 : ], 45 : child: MaterialApp( 46 : '''); 47 : } 48 : 49 4 : final path = path_helper.join(await baseDirFn!(), 'flutter_data'); 50 2 : hive.init(path); 51 : 52 1 : isInitialized = true; 53 : } 54 : 55 1 : Future<Box<B>> openBox<B>(String name) async { 56 : // start using snake_case name only if box 57 : // does not exist in order not to break present boxes 58 3 : if (!await hive.boxExists(name)) { 59 : // since the snakeCase function strips leading _'s 60 : // we capture them restore them afterwards 61 2 : final matches = RegExp(r'^(_+)[a-z]').allMatches(name); 62 2 : name = ReCase(name).snakeCase; 63 1 : if (matches.isNotEmpty) { 64 3 : name = matches.first.group(1)! + name; 65 : } 66 : } 67 4 : return await hive.openBox<B>(name, encryptionCipher: encryptionCipher); 68 : } 69 : 70 1 : Future<void> deleteBox(String name) async { 71 : // if hard clear, remove box 72 : try { 73 3 : if (await hive.boxExists(name)) { 74 3 : await hive.deleteBoxFromDisk(name); 75 : } 76 : // now try with the new snake_case name 77 2 : name = ReCase(name).snakeCase; 78 3 : if (await hive.boxExists(name)) { 79 3 : await hive.deleteBoxFromDisk(name); 80 : } 81 : } catch (e) { 82 : // weird fs bug? where even after checking for file.exists() 83 : // in Hive, it throws a No such file or directory error 84 0 : if (e.toString().contains('No such file or directory')) { 85 : // we can safely ignore? 86 : } else { 87 : rethrow; 88 : } 89 : } 90 : } 91 : } 92 : 93 4 : final hiveLocalStorageProvider = Provider<HiveLocalStorage>((ref) => 94 4 : HiveLocalStorage(hive: ref.read(hiveProvider), baseDirFn: () => '')); 95 : 96 3 : final hiveProvider = Provider<HiveInterface>((_) => Hive);