diff --git a/lib/features/caching/utils/caching_constants.dart b/lib/features/caching/utils/caching_constants.dart index 2b662890d..a1e97fd6b 100644 --- a/lib/features/caching/utils/caching_constants.dart +++ b/lib/features/caching/utils/caching_constants.dart @@ -23,4 +23,5 @@ class CachingConstants { static const String emailContentFolderName = 'email_content'; static const int maxNumberNewEmailsForOffline = 10; + static const int maxNumberOpenedEmailsForOffline = 30; } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index 005c16c48..a072a4b72 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -46,6 +46,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_id import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identity_interactors_bindings.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_worker_queue.dart'; +import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart'; import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; import 'package:tmail_ui_user/features/upload/data/datasource/attachment_upload_datasource.dart'; import 'package:tmail_ui_user/features/upload/data/datasource_impl/attachment_upload_datasource_impl.dart'; @@ -97,6 +98,7 @@ class ComposerBindings extends BaseBindings { Get.lazyPut(() => EmailHiveCacheDataSourceImpl( Get.find(), Get.find(), + Get.find(), Get.find(), Get.find(), Get.find())); diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index 4b59b302d..9a731fdb4 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -79,4 +79,6 @@ abstract class EmailDataSource { Future getDetailedEmailById(Session session, AccountId accountId, EmailId emailId); Future storeEmail(Session session, AccountId accountId, Email email); + + Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail); } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/email_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_datasource_impl.dart index 9f88f3e72..6d4cb554f 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -166,4 +166,9 @@ class EmailDataSourceImpl extends EmailDataSource { Future storeEmail(Session session, AccountId accountId, Email email) { throw UnimplementedError(); } + + @override + Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail) { + throw UnimplementedError(); + } } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart index 6f81579e7..56cfba190 100644 --- a/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart @@ -27,6 +27,7 @@ import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_reques import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_worker_queue.dart'; +import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart'; import 'package:tmail_ui_user/features/offline_mode/worker/hive_task.dart'; import 'package:tmail_ui_user/features/thread/data/extensions/email_extension.dart'; import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; @@ -36,6 +37,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { final DetailedEmailCacheManager _detailedEmailCacheManager; final DetailedEmailCacheWorkerQueue _cacheWorkerQueue; + final OpenedEmailCacheWorkerQueue _openedEmailCacheWorkerQueue; final EmailCacheManager _emailCacheManager; final FileUtils _fileUtils; final ExceptionThrower _exceptionThrower; @@ -43,6 +45,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { EmailHiveCacheDataSourceImpl( this._detailedEmailCacheManager, this._cacheWorkerQueue, + this._openedEmailCacheWorkerQueue, this._emailCacheManager, this._fileUtils, this._exceptionThrower @@ -149,4 +152,27 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { return await _emailCacheManager.storeEmail(accountId, session.username, email.toEmailCache()); }).catchError(_exceptionThrower.throwException); } + + @override + Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail) { + return Future.sync(() async { + final task = HiveTask( + runnable: () async { + final fileSaved = await _fileUtils.saveToFile( + nameFile: detailedEmail.emailId.asString, + content: detailedEmail.htmlEmailContent ?? '', + folderPath: detailedEmail.folderPath, + extensionFile: ExtensionType.text.value + ); + log('EmailHiveCacheDataSourceImpl::storeOpenedEmailToCache():fileSavedPath: ${fileSaved.path}'); + final detailedEmailSaved = detailedEmail.fromEmailContentPath(fileSaved.path); + + await _detailedEmailCacheManager.storeOpenedEmail( + accountId, + session.username, + detailedEmailSaved); + }); + return await _openedEmailCacheWorkerQueue.addTask(task); + }).catchError(_exceptionThrower.throwException); + } } \ No newline at end of file diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index efe85c026..0f060630c 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -201,6 +201,6 @@ class EmailRepositoryImpl extends EmailRepository { @override Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail) { - throw UnimplementedError(); + return emailDataSource[DataSourceType.hiveCache]!.storeOpenedEmailToCache(session, accountId, detailedEmail); } } \ No newline at end of file diff --git a/lib/features/email/presentation/email_bindings.dart b/lib/features/email/presentation/email_bindings.dart index c07017128..fea4e2f57 100644 --- a/lib/features/email/presentation/email_bindings.dart +++ b/lib/features/email/presentation/email_bindings.dart @@ -44,6 +44,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_id import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identity_interactors_bindings.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_worker_queue.dart'; +import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart'; import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; @@ -98,6 +99,7 @@ class EmailBindings extends BaseBindings { Get.lazyPut(() => EmailHiveCacheDataSourceImpl( Get.find(), Get.find(), + Get.find(), Get.find(), Get.find(), Get.find())); diff --git a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart index 205176229..07de54022 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -96,6 +96,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_worker_queue.dart'; +import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart'; import 'package:tmail_ui_user/features/quotas/presentation/quotas_controller_bindings.dart'; import 'package:tmail_ui_user/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart'; import 'package:tmail_ui_user/features/search/email/presentation/search_email_bindings.dart'; @@ -234,6 +235,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => EmailHiveCacheDataSourceImpl( Get.find(), Get.find(), + Get.find(), Get.find(), Get.find(), Get.find())); diff --git a/lib/features/offline_mode/manager/detailed_email_cache_manager.dart b/lib/features/offline_mode/manager/detailed_email_cache_manager.dart index f80c15bd4..ad2c7ef16 100644 --- a/lib/features/offline_mode/manager/detailed_email_cache_manager.dart +++ b/lib/features/offline_mode/manager/detailed_email_cache_manager.dart @@ -1,19 +1,24 @@ import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/file_utils.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:model/extensions/email_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/clients/detailed_email_hive_cache_client.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/extensions/detailed_email_extension.dart'; +import 'package:tmail_ui_user/features/email/domain/model/detailed_email.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 DetailedEmailCacheManager { final DetailedEmailHiveCacheClient _cacheClient; + final FileUtils _fileUtils; - DetailedEmailCacheManager(this._cacheClient); + DetailedEmailCacheManager(this._cacheClient, this._fileUtils); Future handleStoreDetailedEmail( AccountId accountId, @@ -58,4 +63,56 @@ class DetailedEmailCacheManager { log('DetailedEmailCacheManager::getAllDetailedEmails():SIZE: ${detailedEmailCacheList.length}'); return detailedEmailCacheList; } + + Future storeOpenedEmail( + AccountId accountId, + UserName userName, + DetailedEmail detailedEmail + ) async { + final listDetailedEmails = await getAllDetailedEmails(accountId, userName); + + final checkDuplicateDetailedEmail = await _handleDuplicateOpenedEmail(accountId, detailedEmail); + + if (checkDuplicateDetailedEmail) { + return Future.value(); + } + + if (listDetailedEmails.length >= CachingConstants.maxNumberOpenedEmailsForOffline) { + final latestEmail = listDetailedEmails.last; + log('DetailedEmailCacheManager::handleStoreDetailedEmail():latestEmail: $latestEmail'); + await removeDetailedEmail(accountId, userName, latestEmail.emailId); + } + await insertDetailedEmail(accountId, userName, detailedEmail.toHiveCache()); + } + + Future _handleDuplicateOpenedEmail(AccountId accountId, DetailedEmail detailedEmail) async { + final emailContentPath = await _getEmailContentPath(detailedEmail); + final detailedEmailCacheExists = await _getDetailedEmailCache(accountId); + + if (emailContentPath != null && detailedEmailCacheExists) { + return true; + } else { + return false; + } + } + + Future _getEmailContentPath(DetailedEmail detailedEmail) async { + final fileSaved = await _fileUtils.getFromFile( + nameFile: detailedEmail.emailId.asString, + folderPath: detailedEmail.folderPath, + extensionFile: ExtensionType.text.value + ); + log('DetailedEmailCacheManager::_getDetailedEmailCache():_getEmailContentPath: $fileSaved'); + return fileSaved; + } + + Future _getDetailedEmailCache(AccountId accountId) async { + final detailedEmailCache = await _cacheClient.getItem(accountId.asString); + log('DetailedEmailCacheManager::_getDetailedEmailCache():_getDetailedEmailCache: $detailedEmailCache'); + if (detailedEmailCache != null) { + return true; + } else { + return false; + } + } } \ No newline at end of file diff --git a/lib/features/offline_mode/manager/opened_email_cache_worker_queue.dart b/lib/features/offline_mode/manager/opened_email_cache_worker_queue.dart new file mode 100644 index 000000000..e25a2663b --- /dev/null +++ b/lib/features/offline_mode/manager/opened_email_cache_worker_queue.dart @@ -0,0 +1,7 @@ +import 'package:tmail_ui_user/features/offline_mode/worker/hive_worker_queue.dart'; + +class OpenedEmailCacheWorkerQueue extends WorkerQueue { + + @override + String get workerName => 'OpenedEmailCache'; +} \ No newline at end of file diff --git a/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart b/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart index eb8441e31..ce6e22eaf 100644 --- a/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart +++ b/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart @@ -25,6 +25,7 @@ import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart'; import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_isolate_worker.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_worker_queue.dart'; +import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart'; import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart'; import 'package:tmail_ui_user/features/push_notification/data/datasource_impl/fcm_datasource_impl.dart'; import 'package:tmail_ui_user/features/push_notification/data/datasource_impl/cache_fcm_datasource_impl.dart'; @@ -103,6 +104,7 @@ class FcmInteractorBindings extends InteractorsBindings { Get.lazyPut(() => EmailHiveCacheDataSourceImpl( Get.find(), Get.find(), + Get.find(), Get.find(), Get.find(), Get.find())); diff --git a/lib/main/bindings/local/local_bindings.dart b/lib/main/bindings/local/local_bindings.dart index 40a920d8b..2bcdff9a3 100644 --- a/lib/main/bindings/local/local_bindings.dart +++ b/lib/main/bindings/local/local_bindings.dart @@ -1,4 +1,5 @@ +import 'package:core/utils/file_utils.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tmail_ui_user/features/caching/clients/account_cache_client.dart'; @@ -69,7 +70,7 @@ class LocalBindings extends Bindings { Get.put(FCMCacheManager(Get.find(),Get.find())); Get.put(HiveCacheVersionClient(Get.find(), Get.find())); Get.put(DetailedEmailHiveCacheClient()); - Get.put(DetailedEmailCacheManager(Get.find())); + Get.put(DetailedEmailCacheManager(Get.find(), Get.find())); Get.put(CachingManager( Get.find(), Get.find(),