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