diff --git a/lib/features/base/upgradeable/upgrade_hive_database_steps_v17.dart b/lib/features/base/upgradeable/upgrade_hive_database_steps_v17.dart index 588ee5530..a7221e2c5 100644 --- a/lib/features/base/upgradeable/upgrade_hive_database_steps_v17.dart +++ b/lib/features/base/upgradeable/upgrade_hive_database_steps_v17.dart @@ -1,6 +1,7 @@ import 'package:tmail_ui_user/features/base/upgradeable/upgrade_database_steps.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; +import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart'; class UpgradeHiveDatabaseStepsV17 extends UpgradeDatabaseSteps { @@ -11,7 +12,9 @@ class UpgradeHiveDatabaseStepsV17 extends UpgradeDatabaseSteps { @override Future onUpgrade(int oldVersion, int newVersion) async { if (oldVersion > 0 && oldVersion < newVersion && newVersion == 17) { - await _cachingManager.clearAll(); + await HiveCacheConfig.instance.setUp(isolated: false); + await _cachingManager.migrateHiveToIsolatedHive(); + await _cachingManager.closeHive(isolated: false); } } } \ No newline at end of file diff --git a/lib/features/caching/caching_manager.dart b/lib/features/caching/caching_manager.dart index 34583d654..93436cf8d 100644 --- a/lib/features/caching/caching_manager.dart +++ b/lib/features/caching/caching_manager.dart @@ -5,81 +5,89 @@ import 'package:fcm/model/type_name.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/extensions/account_id_extensions.dart'; -import 'package:tmail_ui_user/features/caching/clients/account_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/email_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/fcm_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/firebase_registration_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/hive_cache_version_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/mailbox_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/new_email_hive_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/opened_email_hive_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/recent_login_url_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/recent_login_username_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/recent_search_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/session_hive_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart'; import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart'; +import 'package:tmail_ui_user/features/caching/manager/session_cache_manger.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; +import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart'; +import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart'; +import 'package:tmail_ui_user/features/cleanup/data/local/recent_search_cache_manager.dart'; +import 'package:tmail_ui_user/features/login/data/local/account_cache_manager.dart'; +import 'package:tmail_ui_user/features/login/data/local/authentication_info_cache_manager.dart'; +import 'package:tmail_ui_user/features/login/data/local/encryption_key_cache_manager.dart'; +import 'package:tmail_ui_user/features/login/data/local/oidc_configuration_cache_manager.dart'; +import 'package:tmail_ui_user/features/login/data/local/token_oidc_cache_manager.dart'; +import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart'; +import 'package:tmail_ui_user/features/mailbox/data/local/state_cache_manager.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_spam_report_manager.dart'; +import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_manager.dart'; +import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart'; import 'package:tmail_ui_user/features/push_notification/data/keychain/keychain_sharing_manager.dart'; +import 'package:tmail_ui_user/features/push_notification/data/local/fcm_cache_manager.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/extensions/type_name_extension.dart'; +import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; class CachingManager { - final MailboxCacheClient _mailboxCacheClient; - final StateCacheClient _stateCacheClient; - final EmailCacheClient _emailCacheClient; - final RecentSearchCacheClient _recentSearchCacheClient; - final RecentLoginUrlCacheClient _recentLoginUrlCacheClient; - final RecentLoginUsernameCacheClient _recentLoginUsernameCacheClient; - final AccountCacheClient _accountCacheClient; - final FcmCacheClient _fcmCacheClient; - final FirebaseRegistrationCacheClient _firebaseRegistrationCacheClient; + final MailboxCacheManager _mailboxCacheManager; + final StateCacheManager _stateCacheManager; + final EmailCacheManager _emailCacheManager; + final RecentSearchCacheManager _recentSearchCacheManager; + final RecentLoginUrlCacheManager _recentLoginUrlCacheManager; + final RecentLoginUsernameCacheManager _recentLoginUsernameCacheManager; + final AccountCacheManager _accountCacheManager; + final FCMCacheManager _fcmCacheManager; final HiveCacheVersionClient _hiveCacheVersionClient; - final NewEmailHiveCacheClient _newEmailHiveCacheClient; - final OpenedEmailHiveCacheClient _openedEmailHiveCacheClient; + final NewEmailCacheManager _newEmailCacheManager; + final OpenedEmailCacheManager _openedEmailCacheManager; final FileUtils _fileUtils; final SendingEmailCacheManager _sendingEmailCacheManager; - final SessionHiveCacheClient _sessionHiveCacheClient; + final SessionCacheManager _sessionCacheManager; final LocalSpamReportManager _localSpamReportManager; final KeychainSharingManager _keychainSharingManager; + final TokenOidcCacheManager _tokenOidcCacheManager; + final OidcConfigurationCacheManager _oidcConfigurationCacheManager; + final EncryptionKeyCacheManager _encryptionKeyCacheManager; + final AuthenticationInfoCacheManager _authenticationInfoCacheManager; CachingManager( - this._mailboxCacheClient, - this._stateCacheClient, - this._emailCacheClient, - this._recentSearchCacheClient, - this._recentLoginUrlCacheClient, - this._recentLoginUsernameCacheClient, - this._accountCacheClient, - this._fcmCacheClient, - this._firebaseRegistrationCacheClient, + this._mailboxCacheManager, + this._stateCacheManager, + this._emailCacheManager, + this._recentSearchCacheManager, + this._recentLoginUrlCacheManager, + this._recentLoginUsernameCacheManager, + this._accountCacheManager, + this._fcmCacheManager, this._hiveCacheVersionClient, - this._newEmailHiveCacheClient, - this._openedEmailHiveCacheClient, + this._newEmailCacheManager, + this._openedEmailCacheManager, this._fileUtils, this._sendingEmailCacheManager, - this._sessionHiveCacheClient, + this._sessionCacheManager, this._localSpamReportManager, this._keychainSharingManager, + this._tokenOidcCacheManager, + this._oidcConfigurationCacheManager, + this._encryptionKeyCacheManager, + this._authenticationInfoCacheManager, ); Future clearAll() async { await Future.wait([ - _stateCacheClient.clearAllData(), - _mailboxCacheClient.clearAllData(), - _emailCacheClient.clearAllData(), - _fcmCacheClient.clearAllData(), - _firebaseRegistrationCacheClient.clearAllData(), - _accountCacheClient.clearAllData(), + _stateCacheManager.clear(), + _mailboxCacheManager.clear(), + _emailCacheManager.clear(), + _fcmCacheManager.clear(), + _accountCacheManager.clear(), _localSpamReportManager.clear(), if (PlatformInfo.isMobile) ...[ - _sessionHiveCacheClient.clearAllData(), - _newEmailHiveCacheClient.clearAllData(), - _openedEmailHiveCacheClient.clearAllData(), + _sessionCacheManager.clear(), + _newEmailCacheManager.clear(), + _openedEmailCacheManager.clear(), _sendingEmailCacheManager.clearAllSendingEmails(), ], if (PlatformInfo.isIOS) @@ -94,16 +102,16 @@ class CachingManager { final stateKey = StateType.email.getTupleKeyStored(accountId, userName); return Future.wait([ - _emailCacheClient.clearAllDataContainKey(emailKey), - _stateCacheClient.deleteItem(stateKey), + _emailCacheManager.deleteByKey(emailKey), + _stateCacheManager.deleteByKey(stateKey), if (PlatformInfo.isMobile) clearFCMEmailStateCache(accountId: accountId, userName: userName), ]); } else { final stateKey = StateType.email.getTupleKeyStoredWithoutAccount(); return Future.wait([ - _emailCacheClient.clearAllData(), - _stateCacheClient.deleteItem(stateKey), + _emailCacheManager.clear(), + _stateCacheManager.deleteByKey(stateKey), if (PlatformInfo.isMobile) clearFCMEmailStateCache(), ]); } @@ -114,14 +122,14 @@ class CachingManager { if (accountId != null && userName != null) { final emailKey = TupleKey(accountId.asString, userName.value).encodeKey; return Future.wait([ - _newEmailHiveCacheClient.clearAllDataContainKey(emailKey), - _openedEmailHiveCacheClient.clearAllDataContainKey(emailKey), + _newEmailCacheManager.deleteByKey(emailKey), + _openedEmailCacheManager.deleteByKey(emailKey), clearAllFileInStorage(), ]); } else { return Future.wait([ - _newEmailHiveCacheClient.clearAllData(), - _openedEmailHiveCacheClient.clearAllData(), + _newEmailCacheManager.clear(), + _openedEmailCacheManager.clear(), clearAllFileInStorage(), ]); } @@ -138,8 +146,10 @@ class CachingManager { Future clearMailboxCache() { return Future.wait([ - _stateCacheClient.deleteItem(StateType.mailbox.getTupleKeyStoredWithoutAccount()), - _mailboxCacheClient.clearAllData(), + _stateCacheManager.deleteByKey( + StateType.mailbox.getTupleKeyStoredWithoutAccount(), + ), + _mailboxCacheManager.clear(), ], eagerError: true); } @@ -152,9 +162,8 @@ class CachingManager { return _hiveCacheVersionClient.getLatestVersion(); } - Future closeHive() async { - return await HiveCacheConfig.instance.closeHive(); - } + Future closeHive({bool isolated = true}) => + HiveCacheConfig.instance.closeHive(isolated: isolated); Future clearAllFileInStorage() async { await _fileUtils.removeFolder(CachingConstants.openedEmailContentFolderName); @@ -163,26 +172,50 @@ class CachingManager { Future clearFCMEmailStateCache({AccountId? accountId, UserName? userName}) async { if (accountId != null && userName != null) { - await _fcmCacheClient.deleteItem( + await _fcmCacheManager.deleteByKey( TypeName.emailDelivery.getTupleKeyStored(accountId, userName)); - await _fcmCacheClient.deleteItem( + await _fcmCacheManager.deleteByKey( TypeName.emailType.getTupleKeyStored(accountId, userName)); } else { - await _fcmCacheClient.deleteItem( + await _fcmCacheManager.deleteByKey( TypeName.emailDelivery.getTupleKeyStoredWithoutAccount()); - await _fcmCacheClient.deleteItem( + await _fcmCacheManager.deleteByKey( TypeName.emailType.getTupleKeyStoredWithoutAccount()); } } Future clearLoginRecentData() async { await Future.wait([ - _recentLoginUrlCacheClient.clearAllData(), - _recentLoginUsernameCacheClient.clearAllData(), + _recentLoginUrlCacheManager.clear(), + _recentLoginUsernameCacheManager.clear(), ]); } Future clearRecentSearchData() async { - await _recentSearchCacheClient.clearAllData(); + await _recentSearchCacheManager.clear(); + } + + Future migrateHiveToIsolatedHive() async { + await Future.wait([ + _tokenOidcCacheManager.migrateHiveToIsolatedHive(), + _accountCacheManager.migrateHiveToIsolatedHive(), + _stateCacheManager.migrateHiveToIsolatedHive(), + _mailboxCacheManager.migrateHiveToIsolatedHive(), + _emailCacheManager.migrateHiveToIsolatedHive(), + _fcmCacheManager.migrateHiveToIsolatedHive(), + _oidcConfigurationCacheManager.migrateHiveToIsolatedHive(), + _encryptionKeyCacheManager.migrateHiveToIsolatedHive(), + _authenticationInfoCacheManager.migrateHiveToIsolatedHive(), + _recentLoginUrlCacheManager.migrateHiveToIsolatedHive(), + _recentLoginUsernameCacheManager.migrateHiveToIsolatedHive(), + _recentSearchCacheManager.migrateHiveToIsolatedHive(), + if (PlatformInfo.isMobile) + ...[ + _sessionCacheManager.migrateHiveToIsolatedHive(), + _sendingEmailCacheManager.migrateHiveToIsolatedHive(), + _newEmailCacheManager.migrateHiveToIsolatedHive(), + _openedEmailCacheManager.migrateHiveToIsolatedHive(), + ] + ]); } } diff --git a/lib/features/caching/config/hive_cache_client.dart b/lib/features/caching/config/hive_cache_client.dart index 568d67c13..34fc93f39 100644 --- a/lib/features/caching/config/hive_cache_client.dart +++ b/lib/features/caching/config/hive_cache_client.dart @@ -14,84 +14,170 @@ abstract class HiveCacheClient { Future _getEncryptionKey() => HiveCacheConfig.instance.getEncryptionKey(); - Future> openBox() async { + Future> openIsolatedBox() async { if (IsolatedHive.isBoxOpen(tableName)) { return IsolatedHive.box(tableName); } else { - return IsolatedHive.openBox(tableName); - } - } - - Future> openBoxEncryption() async { - final encryptionKey = await _getEncryptionKey(); - if (IsolatedHive.isBoxOpen(tableName)) { - return IsolatedHive.box(tableName); - } else { - return IsolatedHive.openBox(tableName, + if (encryption) { + final encryptionKey = await _getEncryptionKey(); + return IsolatedHive.openBox( + tableName, encryptionCipher: - encryptionKey != null ? HiveAesCipher(encryptionKey) : null); + encryptionKey != null ? HiveAesCipher(encryptionKey) : null, + ); + } else { + return IsolatedHive.openBox(tableName); + } } } - Future insertItem(String key, T newObject) { - log('$runtimeType::insertItem:encryption: $encryption - key = $key'); + Future> openBox() async { + if (Hive.isBoxOpen(tableName)) { + return Hive.box(tableName); + } else { + if (encryption) { + final encryptionKey = await _getEncryptionKey(); + return Hive.openBox( + tableName, + encryptionCipher: + encryptionKey != null ? HiveAesCipher(encryptionKey) : null, + ); + } else { + return Hive.openBox(tableName); + } + } + } + + Future insertItem( + String key, + T newObject, { + bool isolated = true, + }) { + log('$runtimeType::insertItem:encryption: $encryption - key = $key - isolated'); return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - return boxItem.put(key, newObject); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.put(key, newObject); + } else { + final boxItem = await openBox(); + return boxItem.put(key, newObject); + } }).catchError((error) { throw error; }); } - Future insertMultipleItem(Map mapObject) { + Future insertMultipleItem( + Map mapObject, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - return boxItem.putAll(mapObject); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.putAll(mapObject); + } else { + final boxItem = await openBox(); + return boxItem.putAll(mapObject); + } }).catchError((error) { throw error; }); } - Future getItem(String key) { + Future getItem( + String key, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption - ? await openBoxEncryption() - : await openBox(); - return boxItem.get(key); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.get(key); + } else { + final boxItem = await openBox(); + return boxItem.get(key); + } }).catchError((error) { throw error; }); } - Future> getAll() { + Future> getAll({bool isolated = true}) { return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - final items = await boxItem.values; + Iterable items; + + if (isolated) { + final boxItem = await openIsolatedBox(); + items = await boxItem.values; + } else { + final boxItem = await openBox(); + items = boxItem.values; + } + log('$runtimeType::getAll: Length of items is ${items.length}'); return items.toList(); }).catchError((error) { throw error; }); } - Future> getListByNestedKey(String nestedKey) { + Future> getMapItems({bool isolated = true}) { return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - final mapItems = await boxItem.toMap(); + late Map mapItems; + + if (isolated) { + final boxItem = await openIsolatedBox(); + mapItems = await boxItem.toMap(); + } else { + final boxItem = await openBox(); + mapItems = boxItem.toMap(); + } + log('$runtimeType::getMapItems: Length of mapItems is ${mapItems.length}'); + return mapItems.map((key, value) => MapEntry(key.toString(), value)); + }).catchError((error) { + throw error; + }); + } + + Future> getListByNestedKey( + String nestedKey, { + bool isolated = true, + }) { + return Future.sync(() async { + late Map mapItems; + + if (isolated) { + final boxItem = await openIsolatedBox(); + mapItems = await boxItem.toMap(); + } else { + final boxItem = await openBox(); + mapItems = boxItem.toMap(); + } + final listItem = mapItems .where((key, value) => _matchedNestedKey(key, nestedKey)) .values .toList(); - log('$runtimeType::getListByNestedKey:listItem: ${listItem.length}'); + log('$runtimeType::getListByNestedKey: Length of listItem is ${listItem.length}'); return listItem; }).catchError((error) { throw error; }); } - Future> getValuesByListKey(List listKeys) { + Future> getValuesByListKey( + List listKeys, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - final mapItems = await boxItem.toMap(); + late Map mapItems; + + if (isolated) { + final boxItem = await openIsolatedBox(); + mapItems = await boxItem.toMap(); + } else { + final boxItem = await openBox(); + mapItems = boxItem.toMap(); + } + return mapItems .where((key, value) => listKeys.contains(key)) .values @@ -107,88 +193,149 @@ abstract class HiveCacheClient { return decodedKey.contains(decodedNestedKey); } - Future updateItem(String key, T newObject) { + Future updateItem( + String key, + T newObject, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - return boxItem.put(key, newObject); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.put(key, newObject); + } else { + final boxItem = await openBox(); + return boxItem.put(key, newObject); + } }).catchError((error) { throw error; }); } - Future updateMultipleItem(Map mapObject) { + Future updateMultipleItem( + Map mapObject, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - return boxItem.putAll(mapObject); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.putAll(mapObject); + } else { + final boxItem = await openBox(); + return boxItem.putAll(mapObject); + } }).catchError((error) { throw error; }); } - Future deleteItem(String key) { + Future deleteItem( + String key, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption ? await openBoxEncryption() : await openBox(); - return boxItem.delete(key); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.delete(key); + } else { + final boxItem = await openBox(); + return boxItem.delete(key); + } }).catchError((error) { throw error; }); } - Future deleteMultipleItem(List listKey) { + Future deleteMultipleItem( + List listKey, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption - ? await openBoxEncryption() - : await openBox(); - return boxItem.deleteAll(listKey); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.deleteAll(listKey); + } else { + final boxItem = await openBox(); + return boxItem.deleteAll(listKey); + } }).catchError((error) { throw error; }); } - Future isExistItem(String key) { + Future isExistItem( + String key, { + bool isolated = true, + }) { return Future.sync(() async { - final boxItem = encryption - ? await openBoxEncryption() - : await openBox(); - return boxItem.containsKey(key); + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.containsKey(key); + } else { + final boxItem = await openBox(); + return boxItem.containsKey(key); + } }).catchError((error) { throw error; }); } - Future deleteBox() { - return IsolatedHive.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 mapItems = await boxItem.toMap(); - final listKeys = mapItems - .where((key, value) => _matchedNestedKey(key, nestedKey)) - .keys; - log('$runtimeType::clearAllDataContainKey:listKeys: ${listKeys.length}'); - return boxItem.deleteAll(listKeys); - }).catchError((error) { - throw error; - }); - } - - Future closeBox() async { - if (IsolatedHive.isBoxOpen(tableName)) { - await IsolatedHive.box(tableName).close(); + Future deleteBox({bool isolated = true}) { + if (isolated) { + return IsolatedHive.deleteBoxFromDisk(tableName); + } else { + return Hive.deleteBoxFromDisk(tableName); } - return Future.value(); } -} \ No newline at end of file + + Future clearAllData({bool isolated = true}) { + return Future.sync(() async { + if (isolated) { + final boxItem = await openIsolatedBox(); + return boxItem.clear(); + } else { + final boxItem = await openBox(); + return boxItem.clear(); + } + }).catchError((error) { + throw error; + }); + } + + Future clearAllDataContainKey( + String nestedKey, { + bool isolated = true, + }) { + return Future.sync(() async { + if (isolated) { + final boxItem = await openIsolatedBox(); + final mapItems = await boxItem.toMap(); + final listKeys = mapItems + .where((key, value) => _matchedNestedKey(key, nestedKey)) + .keys; + log('$runtimeType::clearAllDataContainKey: Length of keys is ${listKeys.length}'); + return boxItem.deleteAll(listKeys); + } else { + final boxItem = await openBox(); + final listKeys = boxItem.toMap() + .where((key, value) => _matchedNestedKey(key, nestedKey)) + .keys; + log('$runtimeType::clearAllDataContainKey: Length of keys is ${listKeys.length}'); + return boxItem.deleteAll(listKeys); + } + }).catchError((error) { + throw error; + }); + } + + Future closeBox({bool isolated = true}) async { + if (isolated) { + if (IsolatedHive.isBoxOpen(tableName)) { + await IsolatedHive.box(tableName).close(); + } + } else { + if (Hive.isBoxOpen(tableName)) { + await Hive.box(tableName).close(); + } + } + } +} diff --git a/lib/features/caching/config/hive_cache_config.dart b/lib/features/caching/config/hive_cache_config.dart index c411708e0..ce988a31d 100644 --- a/lib/features/caching/config/hive_cache_config.dart +++ b/lib/features/caching/config/hive_cache_config.dart @@ -51,12 +51,15 @@ class HiveCacheConfig { static HiveCacheConfig get instance => _instance; - Future setUp({String? cachePath}) async { - await initializeDatabase(databasePath: cachePath); - _registerAdapter(); + Future setUp({String? cachePath, bool isolated = true}) async { + await initializeDatabase(databasePath: cachePath, isolated: isolated); + _registerAdapter(isolated: isolated); } - Future initializeDatabase({String? databasePath}) async { + Future initializeDatabase({ + String? databasePath, + bool isolated = true, + }) async { if (databasePath == null && PlatformInfo.isMobile) { Directory directory = await path_provider.getApplicationDocumentsDirectory(); databasePath = directory.path; @@ -64,10 +67,14 @@ class HiveCacheConfig { if (databasePath == null) return; - await IsolatedHive.init( - databasePath, - isolateNameServer: const FcmIsolateNameServer(), - ); + if (isolated) { + await IsolatedHive.init( + databasePath, + isolateNameServer: const FcmIsolateNameServer(), + ); + } else { + Hive.init(databasePath); + } } Future onUpgradeDatabase(CachingManager cachingManager) async { @@ -123,96 +130,130 @@ class HiveCacheConfig { } } - void _registerAdapter() { + void _registerAdapter({bool isolated = true}) { registerCacheAdapter( MailboxCacheAdapter(), - CachingConstants.MAILBOX_CACHE_IDENTIFY + CachingConstants.MAILBOX_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( MailboxRightsCacheAdapter(), - CachingConstants.MAILBOX_RIGHTS_CACHE_IDENTIFY + CachingConstants.MAILBOX_RIGHTS_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( StateCacheAdapter(), - CachingConstants.STATE_CACHE_IDENTIFY + CachingConstants.STATE_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( StateTypeAdapter(), - CachingConstants.STATE_TYPE_IDENTIFY + CachingConstants.STATE_TYPE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( EmailAddressHiveCacheAdapter(), - CachingConstants.EMAIL_ADDRESS_HIVE_CACHE_IDENTIFY + CachingConstants.EMAIL_ADDRESS_HIVE_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( EmailCacheAdapter(), - CachingConstants.EMAIL_CACHE_IDENTIFY + CachingConstants.EMAIL_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( RecentSearchCacheAdapter(), - CachingConstants.RECENT_SEARCH_HIVE_CACHE_IDENTIFY + CachingConstants.RECENT_SEARCH_HIVE_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( TokenOidcCacheAdapter(), - CachingConstants.TOKEN_OIDC_HIVE_CACHE_IDENTIFY + CachingConstants.TOKEN_OIDC_HIVE_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( AccountCacheAdapter(), - CachingConstants.ACCOUNT_HIVE_CACHE_IDENTIFY + CachingConstants.ACCOUNT_HIVE_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( EncryptionKeyCacheAdapter(), - CachingConstants.ENCRYPTION_KEY_HIVE_CACHE_IDENTIFY + CachingConstants.ENCRYPTION_KEY_HIVE_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( AuthenticationInfoCacheAdapter(), - CachingConstants.AUTHENTICATION_INFO_HIVE_CACHE_IDENTIFY + CachingConstants.AUTHENTICATION_INFO_HIVE_CACHE_IDENTIFY, + isolated: isolated, ); registerCacheAdapter( RecentLoginUrlCacheAdapter(), - CachingConstants.RECENT_LOGIN_URL_HIVE_CACHE_IDENTITY + CachingConstants.RECENT_LOGIN_URL_HIVE_CACHE_IDENTITY, + isolated: isolated, ); registerCacheAdapter( RecentLoginUsernameCacheAdapter(), - CachingConstants.RECENT_LOGIN_USERNAME_HIVE_CACHE_IDENTITY + CachingConstants.RECENT_LOGIN_USERNAME_HIVE_CACHE_IDENTITY, + isolated: isolated, ); registerCacheAdapter( FirebaseRegistrationCacheAdapter(), - CachingConstants.FIREBASE_REGISTRATION_HIVE_CACHE_IDENTITY + CachingConstants.FIREBASE_REGISTRATION_HIVE_CACHE_IDENTITY, + isolated: isolated, ); registerCacheAdapter( AttachmentHiveCacheAdapter(), - CachingConstants.ATTACHMENT_HIVE_CACHE_ID + CachingConstants.ATTACHMENT_HIVE_CACHE_ID, + isolated: isolated, ); registerCacheAdapter( EmailHeaderHiveCacheAdapter(), - CachingConstants.EMAIL_HEADER_HIVE_CACHE_ID + CachingConstants.EMAIL_HEADER_HIVE_CACHE_ID, + isolated: isolated, ); registerCacheAdapter( DetailedEmailHiveCacheAdapter(), - CachingConstants.DETAILED_EMAIL_HIVE_CACHE_ID + CachingConstants.DETAILED_EMAIL_HIVE_CACHE_ID, + isolated: isolated, ); registerCacheAdapter( SendingEmailHiveCacheAdapter(), - CachingConstants.SENDING_EMAIL_HIVE_CACHE_ID + CachingConstants.SENDING_EMAIL_HIVE_CACHE_ID, + isolated: isolated, ); registerCacheAdapter( SessionHiveObjAdapter(), - CachingConstants.SESSION_HIVE_CACHE_ID + CachingConstants.SESSION_HIVE_CACHE_ID, + isolated: isolated, ); registerCacheAdapter( OidcConfigurationCacheAdapter(), CachingConstants.OIDC_CONFIGURATION_CACHE_ID, + isolated: isolated, ); } - void registerCacheAdapter(TypeAdapter typeAdapter, int typeId) { - if (!IsolatedHive.isAdapterRegistered(typeId)) { - IsolatedHive.registerAdapter(typeAdapter); + void registerCacheAdapter( + TypeAdapter typeAdapter, + int typeId, { + bool isolated = true, + }) { + if (isolated) { + if (!IsolatedHive.isAdapterRegistered(typeId)) { + IsolatedHive.registerAdapter(typeAdapter); + } + } else { + if (!Hive.isAdapterRegistered(typeId)) { + Hive.registerAdapter(typeAdapter); + } } } - Future closeHive() async { - return await IsolatedHive.close(); + Future closeHive({bool isolated = true}) async { + if (isolated) { + await IsolatedHive.close(); + } else { + await Hive.close(); + } } } \ No newline at end of file diff --git a/lib/features/caching/interaction/cache_manager_interaction.dart b/lib/features/caching/interaction/cache_manager_interaction.dart new file mode 100644 index 000000000..6b981ec8f --- /dev/null +++ b/lib/features/caching/interaction/cache_manager_interaction.dart @@ -0,0 +1,4 @@ + +abstract class CacheManagerInteraction { + Future migrateHiveToIsolatedHive(); +} \ No newline at end of file diff --git a/lib/features/caching/manager/session_cache_manger.dart b/lib/features/caching/manager/session_cache_manger.dart new file mode 100644 index 000000000..cfe5ff416 --- /dev/null +++ b/lib/features/caching/manager/session_cache_manger.dart @@ -0,0 +1,39 @@ +import 'package:core/utils/app_logger.dart'; +import 'package:tmail_ui_user/features/caching/clients/session_hive_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; +import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; +import 'package:tmail_ui_user/features/home/data/model/session_hive_obj.dart'; + +class SessionCacheManager extends CacheManagerInteraction { + final SessionHiveCacheClient _cacheClient; + + SessionCacheManager(this._cacheClient); + + Future insertSession(SessionHiveObj sessionHiveObj) => + _cacheClient.insertItem(SessionHiveObj.keyValue, sessionHiveObj); + + Future getStoredSession() async { + final sessionHiveObj = await _cacheClient.getItem(SessionHiveObj.keyValue); + if (sessionHiveObj != null) { + return sessionHiveObj; + } else { + throw NotFoundSessionException(); + } + } + + Future clear() => _cacheClient.clearAllData(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _cacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _cacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_cacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_cacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } +} diff --git a/lib/features/cleanup/data/local/recent_login_url_cache_manager.dart b/lib/features/cleanup/data/local/recent_login_url_cache_manager.dart index e4684e303..f8e42132b 100644 --- a/lib/features/cleanup/data/local/recent_login_url_cache_manager.dart +++ b/lib/features/cleanup/data/local/recent_login_url_cache_manager.dart @@ -1,9 +1,13 @@ +import 'package:core/utils/app_logger.dart'; import 'package:tmail_ui_user/features/caching/clients/recent_login_url_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/cleanup/domain/model/recent_login_url_cleanup_rule.dart'; import 'package:tmail_ui_user/features/login/data/model/recent_login_url_cache.dart'; +import 'package:tmail_ui_user/features/login/domain/extensions/list_recent_login_url_extension.dart'; +import 'package:tmail_ui_user/features/login/domain/model/recent_login_url.dart'; -class RecentLoginUrlCacheManager { +class RecentLoginUrlCacheManager extends CacheManagerInteraction { final RecentLoginUrlCacheClient _recentLoginUrlCacheClient; @@ -21,4 +25,69 @@ class RecentLoginUrlCacheManager { await _recentLoginUrlCacheClient.deleteMultipleItem(newListKeyRecent); } } + + Future saveLoginUrl(RecentLoginUrlCache recentLoginUrlCache) async { + final isExist = await _recentLoginUrlCacheClient.isExistItem( + recentLoginUrlCache.url, + ); + + if (isExist) { + await _recentLoginUrlCacheClient.updateItem( + recentLoginUrlCache.url, + recentLoginUrlCache, + ); + } else { + await _recentLoginUrlCacheClient.insertItem( + recentLoginUrlCache.url, + recentLoginUrlCache, + ); + } + } + + Future> getAllRecentLoginUrlLatest({ + int? limit, + String? pattern, + }) async { + final listRecentUrlCache = await _recentLoginUrlCacheClient.getAll(); + final listRecentUrl = listRecentUrlCache + .where((recentCache) => _filterRecentUrlCache(recentCache, pattern)) + .map((recentCache) => recentCache.toRecentLoginUrl()) + .toList(); + listRecentUrl.sortByCreationDate(); + + final newLimit = limit ?? 5; + + final newListRecentSUrl = listRecentUrl.length > newLimit + ? listRecentUrl.sublist(0, newLimit) + : listRecentUrl; + + return newListRecentSUrl; + } + + bool _filterRecentUrlCache( + RecentLoginUrlCache recentLoginUrlCache, + String? pattern, + ) { + if (pattern == null || pattern.trim().isEmpty) { + return true; + } else { + return recentLoginUrlCache.matchUrl(pattern); + } + } + + Future clear() => _recentLoginUrlCacheClient.clearAllData(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _recentLoginUrlCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _recentLoginUrlCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_recentLoginUrlCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_recentLoginUrlCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/cleanup/data/local/recent_login_username_cache_manager.dart b/lib/features/cleanup/data/local/recent_login_username_cache_manager.dart index 447b06e8b..f385a6d88 100644 --- a/lib/features/cleanup/data/local/recent_login_username_cache_manager.dart +++ b/lib/features/cleanup/data/local/recent_login_username_cache_manager.dart @@ -1,9 +1,13 @@ +import 'package:core/utils/app_logger.dart'; import 'package:tmail_ui_user/features/caching/clients/recent_login_username_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/cleanup/domain/model/recent_login_username_cleanup_rule.dart'; import 'package:tmail_ui_user/features/login/data/model/recent_login_username_cache.dart'; +import 'package:tmail_ui_user/features/login/domain/extensions/list_recent_login_username_extension.dart'; +import 'package:tmail_ui_user/features/login/domain/model/recent_login_username.dart'; -class RecentLoginUsernameCacheManager { +class RecentLoginUsernameCacheManager extends CacheManagerInteraction { final RecentLoginUsernameCacheClient _recentLoginUsernameCacheClient; @@ -21,4 +25,71 @@ class RecentLoginUsernameCacheManager { await _recentLoginUsernameCacheClient.deleteMultipleItem(newListKeyRecent); } } + + Future> getAllRecentLoginUsernamesLatest({ + int? limit, + String? pattern, + }) async { + final listRecentUsernameCache = + await _recentLoginUsernameCacheClient.getAll(); + final listValidRecentUsername = listRecentUsernameCache + .where((recentCache) => + _filterRecentLoginUsernameCache(recentCache, pattern)) + .map((recentCache) => recentCache.toRecentLoginUsername()) + .toList(); + + listValidRecentUsername.sortByCreationDate(); + + final newLimit = limit ?? 5; + + return listValidRecentUsername.length > newLimit + ? listValidRecentUsername.sublist(0, newLimit) + : listValidRecentUsername; + } + + Future saveLoginUsername( + RecentLoginUsername recentLoginUsername, + ) async { + final isExist = await _recentLoginUsernameCacheClient.isExistItem( + recentLoginUsername.username, + ); + if (isExist) { + await _recentLoginUsernameCacheClient.updateItem( + recentLoginUsername.username, + recentLoginUsername.toRecentLoginUsernameCache(), + ); + } else { + await _recentLoginUsernameCacheClient.insertItem( + recentLoginUsername.username, + recentLoginUsername.toRecentLoginUsernameCache(), + ); + } + } + + bool _filterRecentLoginUsernameCache( + RecentLoginUsernameCache recentLoginUsernameCache, + String? pattern, + ) { + if (pattern == null || pattern.trim().isEmpty) { + return true; + } else { + return recentLoginUsernameCache.matchUsername(pattern); + } + } + + Future clear() => _recentLoginUsernameCacheClient.clearAllData(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _recentLoginUsernameCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _recentLoginUsernameCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_recentLoginUsernameCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_recentLoginUsernameCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/cleanup/data/local/recent_search_cache_manager.dart b/lib/features/cleanup/data/local/recent_search_cache_manager.dart index ed652ed1f..f017064c1 100644 --- a/lib/features/cleanup/data/local/recent_search_cache_manager.dart +++ b/lib/features/cleanup/data/local/recent_search_cache_manager.dart @@ -4,13 +4,14 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/clients/recent_search_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/cleanup/domain/model/recent_search_cleanup_rule.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/recent_search_cache.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/extensions/list_recent_search_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart'; -class RecentSearchCacheManager { +class RecentSearchCacheManager extends CacheManagerInteraction { static const int _defaultRecentSearchLimit = 10; @@ -98,4 +99,20 @@ class RecentSearchCacheManager { return recentSearchCache.match(pattern); } } + + Future clear() => _recentSearchCacheClient.clearAllData(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _recentSearchCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _recentSearchCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_recentSearchCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_recentSearchCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/home/data/datasource_impl/hive_session_datasource_impl.dart b/lib/features/home/data/datasource_impl/hive_session_datasource_impl.dart index fb97e5d76..1c6cb89c3 100644 --- a/lib/features/home/data/datasource_impl/hive_session_datasource_impl.dart +++ b/lib/features/home/data/datasource_impl/hive_session_datasource_impl.dart @@ -1,18 +1,16 @@ import 'package:jmap_dart_client/jmap/core/session/session.dart'; -import 'package:tmail_ui_user/features/caching/clients/session_hive_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/manager/session_cache_manger.dart'; import 'package:tmail_ui_user/features/home/data/datasource/session_datasource.dart'; -import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; import 'package:tmail_ui_user/features/home/data/extensions/session_hive_obj_extension.dart'; -import 'package:tmail_ui_user/features/home/data/model/session_hive_obj.dart'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class HiveSessionDataSourceImpl extends SessionDataSource { - final SessionHiveCacheClient _sessionHiveCacheClient; + final SessionCacheManager _sessionCacheManager; final ExceptionThrower _exceptionThrower; - HiveSessionDataSourceImpl(this._sessionHiveCacheClient, this._exceptionThrower); + HiveSessionDataSourceImpl(this._sessionCacheManager, this._exceptionThrower); @override Future getSession() { @@ -22,19 +20,15 @@ class HiveSessionDataSourceImpl extends SessionDataSource { @override Future storeSession(Session session) { return Future.sync(() async { - return _sessionHiveCacheClient.insertItem(SessionHiveObj.keyValue, session.toHiveObj()); + return _sessionCacheManager.insertSession(session.toHiveObj()); }).catchError(_exceptionThrower.throwException); } @override Future getStoredSession() { return Future.sync(() async { - final sessionHiveObj = await _sessionHiveCacheClient.getItem(SessionHiveObj.keyValue); - if (sessionHiveObj != null) { - return sessionHiveObj.toSession(); - } else { - throw NotFoundSessionException(); - } + final sessionHiveObj = await _sessionCacheManager.getStoredSession(); + return sessionHiveObj.toSession(); }).catchError(_exceptionThrower.throwException); } } \ No newline at end of file diff --git a/lib/features/login/data/datasource_impl/hive_login_datasource_impl.dart b/lib/features/login/data/datasource_impl/hive_login_datasource_impl.dart index 88085568f..654761011 100644 --- a/lib/features/login/data/datasource_impl/hive_login_datasource_impl.dart +++ b/lib/features/login/data/datasource_impl/hive_login_datasource_impl.dart @@ -1,118 +1,61 @@ -import 'package:tmail_ui_user/features/caching/clients/recent_login_url_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/recent_login_username_cache_client.dart'; +import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart'; +import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart'; import 'package:tmail_ui_user/features/login/data/datasource/login_datasource.dart'; import 'package:tmail_ui_user/features/login/data/model/recent_login_url_cache.dart'; -import 'package:tmail_ui_user/features/login/data/model/recent_login_username_cache.dart'; -import 'package:tmail_ui_user/features/login/domain/extensions/list_recent_login_url_extension.dart'; -import 'package:tmail_ui_user/features/login/domain/extensions/list_recent_login_username_extension.dart'; import 'package:tmail_ui_user/features/login/domain/model/recent_login_url.dart'; import 'package:tmail_ui_user/features/login/domain/model/recent_login_username.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class HiveLoginDataSourceImpl implements LoginDataSource { - final RecentLoginUrlCacheClient _recentLoginUrlCacheClient; - final RecentLoginUsernameCacheClient _recentLoginUsernameCacheClient; + final RecentLoginUrlCacheManager _recentLoginUrlCacheManager; + final RecentLoginUsernameCacheManager _recentLoginUsernameCacheManager; final ExceptionThrower _exceptionThrower; HiveLoginDataSourceImpl( - this._recentLoginUrlCacheClient, - this._recentLoginUsernameCacheClient, + this._recentLoginUrlCacheManager, + this._recentLoginUsernameCacheManager, this._exceptionThrower ); @override Future saveLoginUrl(RecentLoginUrl recentLoginUrl) { return Future.sync(() async { - if (await _recentLoginUrlCacheClient.isExistItem(recentLoginUrl.url)) { - return await _recentLoginUrlCacheClient.updateItem( - recentLoginUrl.url, - recentLoginUrl.toRecentLoginUrlCache() - ); - } else { - return await _recentLoginUrlCacheClient.insertItem( - recentLoginUrl.url, - recentLoginUrl.toRecentLoginUrlCache() - ); - } + return await _recentLoginUrlCacheManager.saveLoginUrl( + recentLoginUrl.toRecentLoginUrlCache(), + ); }).catchError(_exceptionThrower.throwException); } @override Future> getAllRecentLoginUrlLatest({int? limit, String? pattern}) { return Future.sync(() async { - final listRecentUrlCache = await _recentLoginUrlCacheClient.getAll(); - final listRecentUrl = listRecentUrlCache - .where((recentCache) => _filterRecentUrlCache(recentCache, pattern)) - .map((recentCache) => recentCache.toRecentLoginUrl()) - .toList(); - listRecentUrl.sortByCreationDate(); - - final newLimit = limit ?? 5; - - final newListRecentSUrl = listRecentUrl.length > newLimit - ? listRecentUrl.sublist(0, newLimit) - : listRecentUrl; - - return newListRecentSUrl; + return await _recentLoginUrlCacheManager.getAllRecentLoginUrlLatest( + limit: limit, + pattern: pattern, + ); }).catchError(_exceptionThrower.throwException); } - bool _filterRecentUrlCache(RecentLoginUrlCache recentLoginUrlCache, String? pattern) { - if (pattern == null || pattern.trim().isEmpty) { - return true; - } else { - return recentLoginUrlCache.matchUrl(pattern); - } - } - @override Future> getAllRecentLoginUsernamesLatest({int? limit, String? pattern}) { return Future.sync(() async { - final listRecentUsernameCache = await _recentLoginUsernameCacheClient.getAll(); - final listValidRecentUsername = listRecentUsernameCache - .where((recentCache) => _filterRecentLoginUsernameCache(recentCache, pattern)) - .map((recentCache) => recentCache.toRecentLoginUsername()) - .toList(); - - listValidRecentUsername.sortByCreationDate(); - - final newLimit = limit ?? 5; - - return listValidRecentUsername.length > newLimit - ? listValidRecentUsername.sublist(0, newLimit) - : listValidRecentUsername; + return await _recentLoginUsernameCacheManager.getAllRecentLoginUsernamesLatest( + limit: limit, + pattern: pattern, + ); }).catchError(_exceptionThrower.throwException); } @override Future saveLoginUsername(RecentLoginUsername recentLoginUsername) { return Future.sync(() async { - if (await _recentLoginUsernameCacheClient.isExistItem(recentLoginUsername.username)) { - return await _recentLoginUsernameCacheClient.updateItem( - recentLoginUsername.username, - recentLoginUsername.toRecentLoginUsernameCache() - ); - } else { - return await _recentLoginUsernameCacheClient.insertItem( - recentLoginUsername.username, - recentLoginUsername.toRecentLoginUsernameCache() - ); - } + return await _recentLoginUsernameCacheManager.saveLoginUsername( + recentLoginUsername, + ); }).catchError(_exceptionThrower.throwException); } - bool _filterRecentLoginUsernameCache( - RecentLoginUsernameCache recentLoginUsernameCache, - String? pattern - ) { - if (pattern == null || pattern.trim().isEmpty) { - return true; - } else { - return recentLoginUsernameCache.matchUsername(pattern); - } - } - @override Future dnsLookupToGetJmapUrl(String emailAddress) { throw UnimplementedError(); diff --git a/lib/features/login/data/local/account_cache_manager.dart b/lib/features/login/data/local/account_cache_manager.dart index fb0e11298..4a594deb5 100644 --- a/lib/features/login/data/local/account_cache_manager.dart +++ b/lib/features/login/data/local/account_cache_manager.dart @@ -2,12 +2,13 @@ import 'package:collection/collection.dart'; import 'package:core/utils/app_logger.dart'; import 'package:model/account/personal_account.dart'; import 'package:tmail_ui_user/features/caching/clients/account_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/login/data/extensions/account_cache_extensions.dart'; import 'package:tmail_ui_user/features/login/data/extensions/list_account_cache_extensions.dart'; import 'package:tmail_ui_user/features/login/data/extensions/personal_account_extension.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; -class AccountCacheManager { +class AccountCacheManager extends CacheManagerInteraction { final AccountCacheClient _accountCacheClient; AccountCacheManager(this._accountCacheClient); @@ -47,4 +48,20 @@ class AccountCacheManager { log('AccountCacheManager::deleteCurrentAccount(): $hashId'); return _accountCacheClient.deleteItem(hashId); } + + Future clear() => _accountCacheClient.clearAllData(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _accountCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _accountCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_accountCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_accountCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/login/data/local/authentication_info_cache_manager.dart b/lib/features/login/data/local/authentication_info_cache_manager.dart index a9089267f..a81f35df1 100644 --- a/lib/features/login/data/local/authentication_info_cache_manager.dart +++ b/lib/features/login/data/local/authentication_info_cache_manager.dart @@ -1,8 +1,10 @@ +import 'package:core/utils/app_logger.dart'; import 'package:tmail_ui_user/features/caching/clients/authentication_info_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/login/data/model/authentication_info_cache.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; -class AuthenticationInfoCacheManager { +class AuthenticationInfoCacheManager extends CacheManagerInteraction { final AuthenticationInfoCacheClient _authenticationInfoCacheClient; AuthenticationInfoCacheManager(this._authenticationInfoCacheClient); @@ -25,4 +27,18 @@ class AuthenticationInfoCacheManager { Future removeAuthenticationInfo() { return _authenticationInfoCacheClient.deleteItem(AuthenticationInfoCache.keyCacheValue); } + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _authenticationInfoCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _authenticationInfoCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_authenticationInfoCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_authenticationInfoCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/login/data/local/encryption_key_cache_manager.dart b/lib/features/login/data/local/encryption_key_cache_manager.dart index bb3720fc7..b85f675b1 100644 --- a/lib/features/login/data/local/encryption_key_cache_manager.dart +++ b/lib/features/login/data/local/encryption_key_cache_manager.dart @@ -1,7 +1,9 @@ +import 'package:core/utils/app_logger.dart'; import 'package:tmail_ui_user/features/caching/clients/encryption_key_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/login/data/model/encryption_key_cache.dart'; -class EncryptionKeyCacheManager { +class EncryptionKeyCacheManager extends CacheManagerInteraction { final EncryptionKeyCacheClient _encryptionKeyCacheClient; EncryptionKeyCacheManager(this._encryptionKeyCacheClient); @@ -15,4 +17,18 @@ class EncryptionKeyCacheManager { Future getEncryptionKeyStored() { return _encryptionKeyCacheClient.getItem(EncryptionKeyCache.keyCacheValue); } + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _encryptionKeyCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _encryptionKeyCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_encryptionKeyCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_encryptionKeyCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/login/data/local/oidc_configuration_cache_manager.dart b/lib/features/login/data/local/oidc_configuration_cache_manager.dart index bde2cd2d4..a94b263df 100644 --- a/lib/features/login/data/local/oidc_configuration_cache_manager.dart +++ b/lib/features/login/data/local/oidc_configuration_cache_manager.dart @@ -2,6 +2,7 @@ import 'package:core/utils/app_logger.dart'; import 'package:model/oidc/oidc_configuration.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tmail_ui_user/features/caching/clients/oidc_configuration_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; import 'package:tmail_ui_user/features/login/data/extensions/oidc_configutation_cache_extension.dart'; import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart'; @@ -9,7 +10,7 @@ import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart'; import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; -class OidcConfigurationCacheManager { +class OidcConfigurationCacheManager extends CacheManagerInteraction { final SharedPreferences _sharedPreferences; final OidcConfigurationCacheClient _oidcConfigurationCacheClient; @@ -51,4 +52,18 @@ class OidcConfigurationCacheManager { _sharedPreferences.remove(OIDCConstant.keyAuthorityOidc), ]); } + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _oidcConfigurationCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _oidcConfigurationCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_oidcConfigurationCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_oidcConfigurationCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/login/data/local/token_oidc_cache_manager.dart b/lib/features/login/data/local/token_oidc_cache_manager.dart index c124a5b83..04ef91114 100644 --- a/lib/features/login/data/local/token_oidc_cache_manager.dart +++ b/lib/features/login/data/local/token_oidc_cache_manager.dart @@ -1,11 +1,12 @@ import 'package:core/utils/app_logger.dart'; import 'package:model/oidc/token_oidc.dart'; import 'package:tmail_ui_user/features/caching/clients/token_oidc_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/login/data/extensions/token_oidc_cache_extension.dart'; import 'package:tmail_ui_user/features/login/data/extensions/token_oidc_extension.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; -class TokenOidcCacheManager { +class TokenOidcCacheManager extends CacheManagerInteraction { final TokenOidcCacheClient _tokenOidcCacheClient; TokenOidcCacheManager(this._tokenOidcCacheClient); @@ -34,4 +35,18 @@ class TokenOidcCacheManager { Future deleteTokenOidc() async { await _tokenOidcCacheClient.clearAllData(); } + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _tokenOidcCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _tokenOidcCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_tokenOidcCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_tokenOidcCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/login/presentation/login_bindings.dart b/lib/features/login/presentation/login_bindings.dart index 28eaa060d..b5f52702c 100644 --- a/lib/features/login/presentation/login_bindings.dart +++ b/lib/features/login/presentation/login_bindings.dart @@ -1,8 +1,8 @@ import 'package:core/data/model/source_type/data_source_type.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; -import 'package:tmail_ui_user/features/caching/clients/recent_login_url_cache_client.dart'; -import 'package:tmail_ui_user/features/caching/clients/recent_login_username_cache_client.dart'; +import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart'; +import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart'; import 'package:tmail_ui_user/features/login/data/datasource/login_datasource.dart'; import 'package:tmail_ui_user/features/login/data/datasource_impl/hive_login_datasource_impl.dart'; import 'package:tmail_ui_user/features/login/data/datasource_impl/login_datasource_impl.dart'; @@ -65,8 +65,8 @@ class LoginBindings extends BaseBindings { @override void bindingsDataSourceImpl() { Get.lazyPut(() => HiveLoginDataSourceImpl( - Get.find(), - Get.find(), + Get.find(), + Get.find(), Get.find() )); Get.lazyPut(() => LoginDataSourceImpl( diff --git a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart index 65eb4d641..0956ac80f 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart @@ -158,7 +158,7 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource { @override Future clearAllMailboxCache(AccountId accountId, UserName userName) { return Future.sync(() async { - return await _mailboxCacheManager.clearAll(accountId, userName); + return await _mailboxCacheManager.deleteByKey(accountId, userName); }).catchError(_exceptionThrower.throwException); } diff --git a/lib/features/mailbox/data/local/mailbox_cache_manager.dart b/lib/features/mailbox/data/local/mailbox_cache_manager.dart index 22100e977..faf7e6906 100644 --- a/lib/features/mailbox/data/local/mailbox_cache_manager.dart +++ b/lib/features/mailbox/data/local/mailbox_cache_manager.dart @@ -1,18 +1,20 @@ import 'package:collection/collection.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:model/extensions/mailbox_extension.dart'; import 'package:tmail_ui_user/features/caching/clients/mailbox_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/mailbox/data/extensions/list_mailbox_cache_extension.dart'; import 'package:tmail_ui_user/features/mailbox/data/extensions/list_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox/data/extensions/list_mailbox_id_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/spam_report_exception.dart'; -class MailboxCacheManager { +class MailboxCacheManager extends CacheManagerInteraction { final MailboxCacheClient _mailboxCacheClient; @@ -57,8 +59,24 @@ class MailboxCacheManager { } } - Future clearAll(AccountId accountId, UserName userName) async { + Future deleteByKey(AccountId accountId, UserName userName) async { final nestedKey = TupleKey(accountId.asString, userName.value).encodeKey; await _mailboxCacheClient.clearAllDataContainKey(nestedKey); } + + Future clear() => _mailboxCacheClient.clearAllData(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _mailboxCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _mailboxCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_mailboxCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_mailboxCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/mailbox/data/local/state_cache_manager.dart b/lib/features/mailbox/data/local/state_cache_manager.dart index 30e3ffa92..5c6ad1e0f 100644 --- a/lib/features/mailbox/data/local/state_cache_manager.dart +++ b/lib/features/mailbox/data/local/state_cache_manager.dart @@ -1,14 +1,16 @@ +import 'package:core/utils/app_logger.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/mailbox/data/extensions/state_cache_extension.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart'; -class StateCacheManager { +class StateCacheManager extends CacheManagerInteraction { final StateCacheClient _stateCacheClient; @@ -29,4 +31,22 @@ class StateCacheManager { final stateKey = TupleKey(stateType.name, accountId.asString, userName.value).encodeKey; return await _stateCacheClient.deleteItem(stateKey); } + + Future deleteByKey(String key) => _stateCacheClient.deleteItem(key); + + Future clear() => _stateCacheClient.clearAllData(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _stateCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _stateCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_stateCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_stateCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/offline_mode/manager/new_email_cache_manager.dart b/lib/features/offline_mode/manager/new_email_cache_manager.dart index 14855f6b2..39af123a1 100644 --- a/lib/features/offline_mode/manager/new_email_cache_manager.dart +++ b/lib/features/offline_mode/manager/new_email_cache_manager.dart @@ -6,13 +6,14 @@ import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/caching/clients/new_email_hive_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/email_cache_exceptions.dart'; import 'package:tmail_ui_user/features/offline_mode/extensions/list_detailed_email_hive_cache_extension.dart'; import 'package:tmail_ui_user/features/offline_mode/model/detailed_email_hive_cache.dart'; -class NewEmailCacheManager { +class NewEmailCacheManager extends CacheManagerInteraction { final NewEmailHiveCacheClient _cacheClient; final FileUtils _fileUtils; @@ -81,4 +82,23 @@ class NewEmailCacheManager { throw NotFoundStoredNewEmailException(); } } + + Future clear() => _cacheClient.clearAllData(); + + Future deleteByKey(String key) => + _cacheClient.clearAllDataContainKey(key); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _cacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _cacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_cacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_cacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/offline_mode/manager/opened_email_cache_manager.dart b/lib/features/offline_mode/manager/opened_email_cache_manager.dart index 6aee303a2..57c7ea14f 100644 --- a/lib/features/offline_mode/manager/opened_email_cache_manager.dart +++ b/lib/features/offline_mode/manager/opened_email_cache_manager.dart @@ -6,13 +6,14 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:model/extensions/email_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/clients/opened_email_hive_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/email_cache_exceptions.dart'; import 'package:tmail_ui_user/features/offline_mode/extensions/list_detailed_email_hive_cache_extension.dart'; import 'package:tmail_ui_user/features/offline_mode/model/detailed_email_hive_cache.dart'; -class OpenedEmailCacheManager { +class OpenedEmailCacheManager extends CacheManagerInteraction { final OpenedEmailHiveCacheClient _cacheClient; final FileUtils _fileUtils; @@ -85,4 +86,23 @@ class OpenedEmailCacheManager { Future _deleteFileExisted(String pathFile) async { await _fileUtils.deleteFile(pathFile); } + + Future clear() => _cacheClient.clearAllData(); + + Future deleteByKey(String key) => + _cacheClient.clearAllDataContainKey(key); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _cacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _cacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_cacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_cacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/offline_mode/manager/sending_email_cache_manager.dart b/lib/features/offline_mode/manager/sending_email_cache_manager.dart index fa7ea3a0b..9ea4e3931 100644 --- a/lib/features/offline_mode/manager/sending_email_cache_manager.dart +++ b/lib/features/offline_mode/manager/sending_email_cache_manager.dart @@ -1,14 +1,16 @@ +import 'package:core/utils/app_logger.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/clients/sending_email_hive_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/offline_mode/extensions/list_sending_email_hive_cache_extension.dart'; import 'package:tmail_ui_user/features/offline_mode/model/sending_email_hive_cache.dart'; import 'package:tmail_ui_user/features/sending_queue/data/exceptions/sending_queue_exceptions.dart'; -class SendingEmailCacheManager { +class SendingEmailCacheManager extends CacheManagerInteraction { final SendingEmailHiveCacheClient _hiveCacheClient; @@ -102,4 +104,18 @@ class SendingEmailCacheManager { } Future closeSendingEmailHiveCacheBox() => _hiveCacheClient.closeBox(); + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _hiveCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _hiveCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_hiveCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_hiveCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/push_notification/data/local/fcm_cache_manager.dart b/lib/features/push_notification/data/local/fcm_cache_manager.dart index f841cb83e..b73f9f8c9 100644 --- a/lib/features/push_notification/data/local/fcm_cache_manager.dart +++ b/lib/features/push_notification/data/local/fcm_cache_manager.dart @@ -1,3 +1,4 @@ +import 'package:core/utils/app_logger.dart'; import 'package:fcm/model/type_name.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; @@ -6,11 +7,12 @@ import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/clients/fcm_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/firebase_registration_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/push_notification/data/model/firebase_registration_cache.dart'; import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart'; -class FCMCacheManager { +class FCMCacheManager extends CacheManagerInteraction { final FcmCacheClient _fcmCacheClient; final FirebaseRegistrationCacheClient _firebaseRegistrationCacheClient; @@ -79,4 +81,47 @@ class FCMCacheManager { TypeName.emailType, ); } + + Future clear() async { + await Future.wait([ + _fcmCacheClient.clearAllData(), + _firebaseRegistrationCacheClient.clearAllData(), + ]); + } + + Future deleteByKey(String key) => _fcmCacheClient.deleteItem(key); + + @override + Future migrateHiveToIsolatedHive() async { + await Future.wait([ + _migrateFcmCacheHiveToIsolatedHive(), + _migrateFirebaseRegistrationHiveToIsolatedHive(), + ]); + } + + Future _migrateFcmCacheHiveToIsolatedHive() async { + try { + final legacyMapItems = await _fcmCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _fcmCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_fcmCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_fcmCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } + + Future _migrateFirebaseRegistrationHiveToIsolatedHive() async { + try { + final legacyMapItems = await _firebaseRegistrationCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _firebaseRegistrationCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_firebaseRegistrationCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_firebaseRegistrationCacheClient.tableName}" → IsolatedHive FAILED, Error: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/thread/data/local/email_cache_manager.dart b/lib/features/thread/data/local/email_cache_manager.dart index dfc352b12..20917ace0 100644 --- a/lib/features/thread/data/local/email_cache_manager.dart +++ b/lib/features/thread/data/local/email_cache_manager.dart @@ -1,3 +1,4 @@ +import 'package:core/utils/app_logger.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; @@ -6,6 +7,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/caching/clients/email_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/interaction/cache_manager_interaction.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/cleanup/domain/model/email_cleanup_rule.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/email_cache_exceptions.dart'; @@ -17,7 +19,7 @@ import 'package:tmail_ui_user/features/thread/data/extensions/list_email_id_exte import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; -class EmailCacheManager { +class EmailCacheManager extends CacheManagerInteraction { final EmailCacheClient _emailCacheClient; @@ -90,9 +92,10 @@ class EmailCacheManager { await _emailCacheClient.deleteMultipleItem(listEmailIdCacheExpire); } - Future clearAll() async { - return await _emailCacheClient.clearAllData(); - } + Future clear() => _emailCacheClient.clearAllData(); + + Future deleteByKey(String key) => + _emailCacheClient.clearAllDataContainKey(key); Future storeEmail(AccountId accountId, UserName userName, EmailCache emailCache) { final keyCache = TupleKey(emailCache.id, accountId.asString, userName.value).encodeKey; @@ -130,4 +133,18 @@ class EmailCacheManager { final emails = await _emailCacheClient.getValuesByListKey(keys); return emails; } + + @override + Future migrateHiveToIsolatedHive() async { + try { + final legacyMapItems = await _emailCacheClient.getMapItems( + isolated: false, + ); + log('$runtimeType::migrateHiveToIsolatedHive(): Length of legacyMapItems: ${legacyMapItems.length}'); + await _emailCacheClient.insertMultipleItem(legacyMapItems); + log('$runtimeType::migrateHiveToIsolatedHive(): ✅ Migrate Hive box "${_emailCacheClient.tableName}" → IsolatedHive DONE'); + } catch (e) { + logError('$runtimeType::migrateHiveToIsolatedHive(): ❌ Migrate Hive box "${_emailCacheClient.tableName}" → IsolatedHive FAILED, error: $e'); + } + } } \ No newline at end of file diff --git a/lib/main/bindings/local/local_bindings.dart b/lib/main/bindings/local/local_bindings.dart index c44ecf98a..03a32d844 100644 --- a/lib/main/bindings/local/local_bindings.dart +++ b/lib/main/bindings/local/local_bindings.dart @@ -22,6 +22,7 @@ import 'package:tmail_ui_user/features/caching/clients/sending_email_hive_cache_ import 'package:tmail_ui_user/features/caching/clients/session_hive_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/token_oidc_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/manager/session_cache_manger.dart'; import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart'; import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart'; import 'package:tmail_ui_user/features/cleanup/data/local/recent_search_cache_manager.dart'; @@ -89,25 +90,29 @@ class LocalBindings extends Bindings { Get.put(SendingEmailHiveCacheClient()); Get.put(SendingEmailCacheManager(Get.find())); Get.put(SessionHiveCacheClient()); + Get.put(SessionCacheManager(Get.find())); Get.put(LocalSpamReportManager(Get.find())); Get.put(CachingManager( - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), Get.find(), - Get.find(), - Get.find(), + Get.find(), + Get.find(), Get.find(), Get.find(), - Get.find(), + Get.find(), Get.find(), Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), )); } diff --git a/lib/main/bindings/session/session_bindings.dart b/lib/main/bindings/session/session_bindings.dart index 80035184e..00d379186 100644 --- a/lib/main/bindings/session/session_bindings.dart +++ b/lib/main/bindings/session/session_bindings.dart @@ -1,7 +1,7 @@ import 'package:core/data/model/source_type/data_source_type.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/interactors_bindings.dart'; -import 'package:tmail_ui_user/features/caching/clients/session_hive_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/manager/session_cache_manger.dart'; import 'package:tmail_ui_user/features/home/data/datasource/session_datasource.dart'; import 'package:tmail_ui_user/features/home/data/datasource_impl/hive_session_datasource_impl.dart'; import 'package:tmail_ui_user/features/home/data/datasource_impl/session_datasource_impl.dart'; @@ -25,7 +25,7 @@ class SessionBindings extends InteractorsBindings { Get.find(), Get.find())); Get.put(HiveSessionDataSourceImpl( - Get.find(), + Get.find(), Get.find())); } diff --git a/test/features/login/data/local/memory_account_cache_client.dart b/test/features/login/data/local/memory_account_cache_client.dart index 82a8a3bd0..f5f93c1de 100644 --- a/test/features/login/data/local/memory_account_cache_client.dart +++ b/test/features/login/data/local/memory_account_cache_client.dart @@ -6,35 +6,39 @@ class MemoryAccountCacheClient implements AccountCacheClient { final Map _cache = {}; @override - Future clearAllData() { + Future clearAllData({bool isolated = false}) { _cache.clear(); return Future.value(); } @override - Future clearAllDataContainKey(String nestedKey) { + Future clearAllDataContainKey( + String nestedKey, { + bool isolated = false, + }) { _cache.removeWhere((key, value) => key == nestedKey); return Future.value(); } @override - Future closeBox() { + Future closeBox({bool isolated = false}) { return Future.value(); } @override - Future deleteBox() { + Future deleteBox({bool isolated = false}) { return Future.value(); } @override - Future deleteItem(String key) { + Future deleteItem(String key, {bool isolated = false}) { _cache.remove(key); return Future.value(); } @override - Future deleteMultipleItem(List listKey) { + Future deleteMultipleItem(List listKey, + {bool isolated = false}) { _cache.removeWhere((key, value) => listKey.contains(key)); return Future.value(); } @@ -43,52 +47,60 @@ class MemoryAccountCacheClient implements AccountCacheClient { bool get encryption => false; @override - Future> getAll() { + Future> getAll({bool isolated = false}) { return Future.value(_cache.values.toList()); } @override - Future getItem(String key) { + Future getItem(String key, {bool isolated = false}) { return Future.value(_cache[key]); } @override - Future> getListByNestedKey(String nestedKey) { + Future> getListByNestedKey( + String nestedKey, { + bool isolated = false, + }) { return Future.value( _cache.values.where((account) => account.id == nestedKey).toList()); } @override - Future> getValuesByListKey(List listKeys) { + Future> getValuesByListKey( + List listKeys, { + bool isolated = false, + }) { return Future.value(_cache.values .where((account) => listKeys.contains(account.id)) .toList()); } @override - Future insertItem(String key, AccountCache newObject) { + Future insertItem( + String key, + AccountCache newObject, { + bool isolated = false, + }) { _cache[key] = newObject; return Future.value(); } @override - Future insertMultipleItem(Map mapObject) { + Future insertMultipleItem( + Map mapObject, { + bool isolated = false, + }) { _cache.addAll(mapObject); return Future.value(); } @override - Future isExistItem(String key) { + Future isExistItem(String key, {bool isolated = false}) { return Future.value(_cache.containsKey(key)); } @override - Future> openBox() { - throw UnimplementedError(); - } - - @override - Future> openBoxEncryption() { + Future> openBox() { throw UnimplementedError(); } @@ -96,14 +108,31 @@ class MemoryAccountCacheClient implements AccountCacheClient { String get tableName => 'AccountCache'; @override - Future updateItem(String key, AccountCache newObject) { + Future updateItem( + String key, + AccountCache newObject, { + bool isolated = false, + }) { _cache[key] = newObject; return Future.value(); } @override - Future updateMultipleItem(Map mapObject) { + Future updateMultipleItem( + Map mapObject, { + bool isolated = false, + }) { _cache.addAll(mapObject); return Future.value(); } + + @override + Future> openIsolatedBox() { + throw UnimplementedError(); + } + + @override + Future> getMapItems({bool isolated = true}) { + throw UnimplementedError(); + } }