import 'dart:typed_data'; import 'package:core/presentation/extensions/map_extensions.dart'; import 'package:core/utils/app_logger.dart'; import 'package:hive/hive.dart'; import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; abstract class HiveCacheClient { String get tableName; bool get encryption => false; Future _getEncryptionKey() => HiveCacheConfig.getEncryptionKey(); Future> openBox() async { if (Hive.isBoxOpen(tableName)) { return Hive.box(tableName); } else { return Hive.openBox(tableName); } } Future> openBoxEncryption() async { final encryptionKey = await _getEncryptionKey(); if (Hive.isBoxOpen(tableName)) { return Hive.box(tableName); } else { return Hive.openBox( tableName, encryptionCipher: encryptionKey != null ? HiveAesCipher(encryptionKey) : null); } } Future insertItem(String key, T newObject) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.put(key, newObject); }).catchError((error) { throw error; }); } Future insertMultipleItem(Map mapObject) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.putAll(mapObject); }).catchError((error) { throw error; }); } Future getItem(String key, {bool needToReopen = false}) { return Future.sync(() async { if (needToReopen) { await closeBox(); } final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.get(key); }).catchError((error) { throw error; }); } Future> getAll() { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.values.toList(); }).catchError((error) { throw error; }); } Future> getListByNestedKey(String nestedKey) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); final listItem = boxItem.toMap() .where((key, value) => _matchedNestedKey(key, nestedKey)) .values .toList(); log('HiveCacheClient::getListByNestedKey:listItem: ${listItem.length}'); return listItem; }).catchError((error) { throw error; }); } Future> getValuesByListKey(List listKeys) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.toMap() .where((key, value) => listKeys.contains(key)) .values .toList(); }).catchError((error) { throw error; }); } bool _matchedNestedKey(String key, String nestedKey) { final decodedKey = CacheUtils.decodeKey(key); final decodedNestedKey = CacheUtils.decodeKey(nestedKey); return decodedKey.contains(decodedNestedKey); } Future updateItem(String key, T newObject) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.put(key, newObject); }).catchError((error) { throw error; }); } Future updateMultipleItem(Map mapObject) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.putAll(mapObject); }).catchError((error) { throw error; }); } Future deleteItem(String key) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.delete(key); }).catchError((error) { throw error; }); } Future deleteMultipleItem(List listKey) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.deleteAll(listKey); }).catchError((error) { throw error; }); } Future isExistItem(String key) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.containsKey(key); }).catchError((error) { throw error; }); } Future isExistTable() { return Future.sync(() async { return Hive.boxExists(tableName); }).catchError((error) { throw error; }); } Future deleteBox() { return Hive.deleteBoxFromDisk(tableName); } Future clearAllData() { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); return boxItem.clear(); }).catchError((error) { throw error; }); } Future clearAllDataContainKey(String nestedKey) { return Future.sync(() async { final boxItem = encryption ? await openBoxEncryption() : await openBox(); final listKeys = boxItem.toMap().where((key, value) => _matchedNestedKey(key, nestedKey)).keys; log('HiveCacheClient::clearAllDataContainKey:listKeys: ${listKeys.length}'); return boxItem.deleteAll(listKeys); }).catchError((error) { throw error; }); } Future closeBox() async { if (Hive.isBoxOpen(tableName)) { await Hive.box(tableName).close(); } return Future.value(); } }