From 63f375a29cdf975f0390cfb5c16df22ac07fbb7c Mon Sep 17 00:00:00 2001 From: HuyNguyen Date: Thu, 11 May 2023 17:27:42 +0700 Subject: [PATCH] TF-1808: Hanlde store email when opening email (cherry picked from commit 2c895379f83b34e9bafb7545b21d790d01d444af) --- core/lib/utils/file_utils.dart | 16 +++- core/test/utils/file_utils_test.dart | 2 +- .../opened_email_hive_cache_client.dart | 9 ++ .../caching/utils/caching_constants.dart | 1 + .../presentation/composer_bindings.dart | 2 + .../data/datasource/email_datasource.dart | 2 +- .../email_datasource_impl.dart | 2 +- .../email_hive_cache_datasource_impl.dart | 27 ++++-- .../repository/email_repository_impl.dart | 4 +- .../domain/repository/email_repository.dart | 2 +- .../store_opened_email_to_cache_state.dart | 11 ++- ...tore_opened_email_to_cache_interactor.dart | 8 +- .../controller/single_email_controller.dart | 25 +++++ .../email/presentation/email_bindings.dart | 23 +++-- .../bindings/mailbox_dashboard_bindings.dart | 2 + .../manager/detailed_email_cache_manager.dart | 59 +----------- .../manager/opened_email_cache_manager.dart | 94 +++++++++++++++++++ .../opened_email_cache_worker_queue.dart | 2 +- .../bindings/fcm_interactor_bindings.dart | 2 + lib/main/bindings/local/local_bindings.dart | 8 +- model/lib/email/presentation_email.dart | 8 +- model/lib/extensions/email_extension.dart | 1 + 22 files changed, 215 insertions(+), 95 deletions(-) create mode 100644 lib/features/caching/clients/opened_email_hive_cache_client.dart create mode 100644 lib/features/offline_mode/manager/opened_email_cache_manager.dart diff --git a/core/lib/utils/file_utils.dart b/core/lib/utils/file_utils.dart index 438b5cf68..90674bde6 100644 --- a/core/lib/utils/file_utils.dart +++ b/core/lib/utils/file_utils.dart @@ -55,7 +55,7 @@ class FileUtils { return await file.writeAsString(content, mode: FileMode.append); } - Future getFromFile({ + Future getContentFromFile({ required String nameFile, String? folderPath, String? extensionFile @@ -73,6 +73,20 @@ class FileUtils { return emailContent; } + + Future isFileExisted({ + required String nameFile, + String? folderPath, + String? extensionFile + }) async { + final internalStorageDirPath = await _getInternalStorageDirPath( + nameFile: nameFile, + folderPath: folderPath, + extensionFile: extensionFile + ); + + return File(internalStorageDirPath).exists(); + } } enum ExtensionType { diff --git a/core/test/utils/file_utils_test.dart b/core/test/utils/file_utils_test.dart index ca19a5403..6596881b2 100644 --- a/core/test/utils/file_utils_test.dart +++ b/core/test/utils/file_utils_test.dart @@ -30,7 +30,7 @@ void main() { /// Create a temporary file that will be deleted after `getFromFile` is done final file = await FileUtils().saveToFile(nameFile: fileName, content: fileContent); - final htmlString = await FileUtils().getFromFile(nameFile: fileName); + final htmlString = await FileUtils().getContentFromFile(nameFile: fileName); expect(htmlString.isNotEmpty, equals(true)); diff --git a/lib/features/caching/clients/opened_email_hive_cache_client.dart b/lib/features/caching/clients/opened_email_hive_cache_client.dart new file mode 100644 index 000000000..b63d24692 --- /dev/null +++ b/lib/features/caching/clients/opened_email_hive_cache_client.dart @@ -0,0 +1,9 @@ +import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; +import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; +import 'package:tmail_ui_user/features/offline_mode/model/detailed_email_hive_cache.dart'; + +class OpenedEmailHiveCacheClient extends HiveCacheClient { + + @override + String get tableName => CachingConstants.openedEmailCacheBoxName; +} \ No newline at end of file diff --git a/lib/features/caching/utils/caching_constants.dart b/lib/features/caching/utils/caching_constants.dart index a1e97fd6b..c717cddbd 100644 --- a/lib/features/caching/utils/caching_constants.dart +++ b/lib/features/caching/utils/caching_constants.dart @@ -21,6 +21,7 @@ class CachingConstants { static const String fcmCacheBoxName = 'fcm_cache_box'; static const String detailedEmailCacheBoxName = 'detailed_email_cache_box'; static const String emailContentFolderName = 'email_content'; + static const String openedEmailCacheBoxName = 'opened_email_cache_box'; static const int maxNumberNewEmailsForOffline = 10; static const int maxNumberOpenedEmailsForOffline = 30; diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index a072a4b72..cea0bf49d 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_manager.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'; @@ -97,6 +98,7 @@ class ComposerBindings extends BaseBindings { Get.lazyPut(() => StateDataSourceImpl(Get.find(), Get.find())); Get.lazyPut(() => EmailHiveCacheDataSourceImpl( 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 9a731fdb4..7b346cacc 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -80,5 +80,5 @@ abstract class EmailDataSource { Future storeEmail(Session session, AccountId accountId, Email email); - Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail); + Future storeOpenedEmail(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 6d4cb554f..82a66cb8e 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -168,7 +168,7 @@ class EmailDataSourceImpl extends EmailDataSource { } @override - Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail) { + Future storeOpenedEmail(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 56cfba190..842b165a4 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_manager.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'; @@ -36,6 +37,7 @@ import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class EmailHiveCacheDataSourceImpl extends EmailDataSource { final DetailedEmailCacheManager _detailedEmailCacheManager; + final OpenedEmailCacheManager _openedEmailCacheManager; final DetailedEmailCacheWorkerQueue _cacheWorkerQueue; final OpenedEmailCacheWorkerQueue _openedEmailCacheWorkerQueue; final EmailCacheManager _emailCacheManager; @@ -44,6 +46,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { EmailHiveCacheDataSourceImpl( this._detailedEmailCacheManager, + this._openedEmailCacheManager, this._cacheWorkerQueue, this._openedEmailCacheWorkerQueue, this._emailCacheManager, @@ -119,8 +122,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { final fileSaved = await _fileUtils.saveToFile( nameFile: detailedEmail.emailId.asString, content: detailedEmail.htmlEmailContent ?? '', - folderPath: detailedEmail.folderPath, - extensionFile: ExtensionType.text.value + folderPath: detailedEmail.folderPath ); log('EmailHiveCacheDataSourceImpl::storeDetailedEmailToCache():fileSavedPath: ${fileSaved.path}'); final detailedEmailSaved = detailedEmail.fromEmailContentPath(fileSaved.path); @@ -154,25 +156,34 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { } @override - Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail) { + Future storeOpenedEmail(Session session, AccountId accountId, DetailedEmail detailedEmail) { return Future.sync(() async { final task = HiveTask( runnable: () async { + + final detailedEmailExisted = await _openedEmailCacheManager.isOpenedDetailEmailCached(accountId, session.username,detailedEmail); + log('EmailHiveCacheDataSourceImpl::storeOpenedEmail():detailedEmailExisted: $detailedEmailExisted'); + + if (detailedEmailExisted) { + return Future.value(); + } + final fileSaved = await _fileUtils.saveToFile( nameFile: detailedEmail.emailId.asString, content: detailedEmail.htmlEmailContent ?? '', - folderPath: detailedEmail.folderPath, - extensionFile: ExtensionType.text.value + folderPath: detailedEmail.folderPath ); - log('EmailHiveCacheDataSourceImpl::storeOpenedEmailToCache():fileSavedPath: ${fileSaved.path}'); + + log('EmailHiveCacheDataSourceImpl::storeOpenedEmail():fileSavedPath: ${fileSaved.path}'); + final detailedEmailSaved = detailedEmail.fromEmailContentPath(fileSaved.path); - await _detailedEmailCacheManager.storeOpenedEmail( + await _openedEmailCacheManager.storeOpenedEmail( accountId, session.username, detailedEmailSaved); }); - return await _openedEmailCacheWorkerQueue.addTask(task); + return _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 0f060630c..432bf3c91 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -200,7 +200,7 @@ class EmailRepositoryImpl extends EmailRepository { } @override - Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail) { - return emailDataSource[DataSourceType.hiveCache]!.storeOpenedEmailToCache(session, accountId, detailedEmail); + Future storeOpenedEmail(Session session, AccountId accountId, DetailedEmail detailedEmail) { + return emailDataSource[DataSourceType.hiveCache]!.storeOpenedEmail(session, accountId, detailedEmail); } } \ No newline at end of file diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 48711459b..f32ac77bd 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -94,5 +94,5 @@ abstract class EmailRepository { Future storeEmailToCache(Session session, AccountId accountId, Email email); - Future storeOpenedEmailToCache(Session session, AccountId accountId, DetailedEmail detailedEmail); + Future storeOpenedEmail(Session session, AccountId accountId, DetailedEmail detailedEmail); } \ No newline at end of file diff --git a/lib/features/email/domain/state/store_opened_email_to_cache_state.dart b/lib/features/email/domain/state/store_opened_email_to_cache_state.dart index fd611352e..fc42b34e4 100644 --- a/lib/features/email/domain/state/store_opened_email_to_cache_state.dart +++ b/lib/features/email/domain/state/store_opened_email_to_cache_state.dart @@ -1,12 +1,13 @@ -import 'package:core/core.dart'; +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; -class StoreOpenedEmailToCacheLoading extends UIState {} +class StoreOpenedEmailLoading extends UIState {} -class StoreOpenedEmailToCacheSuccess extends UIState {} +class StoreOpenedEmailSuccess extends UIState {} -class StoreOpenedEmailToCacheFailure extends FeatureFailure { +class StoreOpenedEmailFailure extends FeatureFailure { - StoreOpenedEmailToCacheFailure(dynamic exception) : super(exception: exception); + StoreOpenedEmailFailure(dynamic exception) : super(exception: exception); @override List get props => [exception]; diff --git a/lib/features/email/domain/usecases/store_opened_email_to_cache_interactor.dart b/lib/features/email/domain/usecases/store_opened_email_to_cache_interactor.dart index 070129202..3a0b29e8a 100644 --- a/lib/features/email/domain/usecases/store_opened_email_to_cache_interactor.dart +++ b/lib/features/email/domain/usecases/store_opened_email_to_cache_interactor.dart @@ -18,11 +18,11 @@ class StoreOpenedEmailToCacheInteractor { DetailedEmail detailedEmail ) async* { try { - yield Right(StoreOpenedEmailToCacheLoading()); - await _emailRepository.storeOpenedEmailToCache(session, accountId, detailedEmail); - yield Right(StoreOpenedEmailToCacheSuccess()); + yield Right(StoreOpenedEmailLoading()); + await _emailRepository.storeOpenedEmail(session, accountId, detailedEmail); + yield Right(StoreOpenedEmailSuccess()); } catch (e) { - yield Left(StoreOpenedEmailToCacheFailure(e)); + yield Left(StoreOpenedEmailFailure(e)); } } } \ No newline at end of file diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 930b00489..5e00df918 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -26,6 +26,8 @@ import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; +import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_to_cache_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/email_supervisor_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; @@ -91,6 +93,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { final MarkAsStarEmailInteractor _markAsStarEmailInteractor; final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; + final StoreOpenedEmailToCacheInteractor _storeOpenedEmailToCacheInteractor; CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor; SendReceiptToSenderInteractor? _sendReceiptToSenderInteractor; @@ -125,6 +128,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { this._markAsStarEmailInteractor, this._downloadAttachmentForWebInteractor, this._getAllIdentitiesInteractor, + this._storeOpenedEmailToCacheInteractor ); @override @@ -370,6 +374,21 @@ class SingleEmailController extends BaseController with AppLoaderMixin { initialEmailContents = success.emailContents; attachments.value = success.attachments; + if (!BuildUtils.isWeb) { + final detailedEmail = DetailedEmail( + emailId: currentEmail!.id!, + attachments: attachments, + headers: currentEmail?.emailHeader, + htmlEmailContent: emailContents.asHtmlString + ); + + _storeOpenedEmailToCache( + mailboxDashBoardController.sessionCurrent, + mailboxDashBoardController.accountId.value, + detailedEmail + ); + } + final isShowMessageReadReceipt = success.emailCurrent ?.hasReadReceipt(mailboxDashBoardController.mapMailboxById) == true; if (isShowMessageReadReceipt) { @@ -1193,4 +1212,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } return false; } + + void _storeOpenedEmailToCache(Session? session, AccountId? accountId, DetailedEmail detailedEmail) async { + if (session != null && accountId != null) { + consumeState(_storeOpenedEmailToCacheInteractor.execute(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 fea4e2f57..69e45bcc2 100644 --- a/lib/features/email/presentation/email_bindings.dart +++ b/lib/features/email/presentation/email_bindings.dart @@ -20,6 +20,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/get_stored_email_st import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_to_cache_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/email_supervisor_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart'; import 'package:tmail_ui_user/features/login/data/datasource/account_datasource.dart'; @@ -44,6 +45,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_manager.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'; @@ -55,15 +57,16 @@ class EmailBindings extends BaseBindings { void bindingsController() { Get.put(EmailSupervisorController()); Get.put(SingleEmailController( - 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() )); } @@ -98,6 +101,7 @@ class EmailBindings extends BaseBindings { Get.lazyPut(() => StateDataSourceImpl(Get.find(), Get.find())); Get.lazyPut(() => EmailHiveCacheDataSourceImpl( Get.find(), + Get.find(), Get.find(), Get.find(), Get.find(), @@ -134,6 +138,7 @@ class EmailBindings extends BaseBindings { Get.find(), Get.find())); Get.lazyPut(() => GetStoredEmailStateInteractor(Get.find())); + Get.lazyPut(() => StoreOpenedEmailToCacheInteractor(Get.find())); IdentityInteractorsBindings().dependencies(); } 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 07de54022..78f0183ef 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_manager.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'; @@ -234,6 +235,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find())); Get.lazyPut(() => EmailHiveCacheDataSourceImpl( 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 ad2c7ef16..f80c15bd4 100644 --- a/lib/features/offline_mode/manager/detailed_email_cache_manager.dart +++ b/lib/features/offline_mode/manager/detailed_email_cache_manager.dart @@ -1,24 +1,19 @@ 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, this._fileUtils); + DetailedEmailCacheManager(this._cacheClient); Future handleStoreDetailedEmail( AccountId accountId, @@ -63,56 +58,4 @@ 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_manager.dart b/lib/features/offline_mode/manager/opened_email_cache_manager.dart new file mode 100644 index 000000000..3f1288caf --- /dev/null +++ b/lib/features/offline_mode/manager/opened_email_cache_manager.dart @@ -0,0 +1,94 @@ +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/opened_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 OpenedEmailCacheManager { + + final OpenedEmailHiveCacheClient _cacheClient; + final FileUtils _fileUtils; + + OpenedEmailCacheManager(this._cacheClient, this._fileUtils); + + Future insertDetailedEmail( + AccountId accountId, + UserName userName, + DetailedEmailHiveCache detailedEmailCache + ) { + final keyCache = TupleKey(detailedEmailCache.emailId, accountId.asString, userName.value).encodeKey; + log('OpenedEmailCacheManager::insertDetailedEmail(): $keyCache'); + return _cacheClient.insertItem(keyCache, detailedEmailCache); + } + + Future removeDetailedEmail( + AccountId accountId, + UserName userName, + String emailId + ) { + final keyCache = TupleKey(emailId, accountId.asString, userName.value).encodeKey; + log('OpenedEmailCacheManager::removeDetailedEmail(): $keyCache'); + return _cacheClient.deleteItem(keyCache); + } + + Future> getAllDetailedEmails(AccountId accountId, UserName userName) async { + final detailedEmailCacheList = await _cacheClient.getListByTupleKey(accountId.asString, userName.value); + detailedEmailCacheList.sortByLatestTime(); + log('OpenedEmailCacheManager::getAllDetailedEmails():SIZE: ${detailedEmailCacheList.length}'); + return detailedEmailCacheList; + } + + Future storeOpenedEmail( + AccountId accountId, + UserName userName, + DetailedEmail detailedEmail + ) async { + final listDetailedEmails = await getAllDetailedEmails(accountId, userName); + + if (listDetailedEmails.length >= CachingConstants.maxNumberOpenedEmailsForOffline) { + final latestEmail = listDetailedEmails.last; + log('OpenedEmailCacheManager::handleStoreDetailedEmail():latestEmail: $latestEmail'); + await removeDetailedEmail(accountId, userName, latestEmail.emailId); + } + await insertDetailedEmail(accountId, userName, detailedEmail.toHiveCache()); + } + + Future isOpenedDetailEmailCached( + AccountId accountId, + UserName userName, + DetailedEmail detailedEmail + ) async { + final emailContentPathExists = await _isFileExisted(detailedEmail); + final detailedEmailCacheExists = await _isDetailEmailExistedInCache(accountId, userName, detailedEmail); + + return emailContentPathExists == true && detailedEmailCacheExists; + } + + Future _isFileExisted(DetailedEmail detailedEmail) async { + final fileSaved = await _fileUtils.isFileExisted( + nameFile: detailedEmail.emailId.asString, + folderPath: detailedEmail.folderPath, + ); + log('OpenedEmailCacheManager::_getDetailedEmailCache():_getEmailContentPath: $fileSaved'); + return fileSaved; + } + + Future _isDetailEmailExistedInCache( + AccountId accountId, + UserName userName, + DetailedEmail detailedEmail + ) async { + final keyCache = TupleKey(detailedEmail.emailId.asString, accountId.asString, userName.value).encodeKey; + final detailedEmailCache = await _cacheClient.getItem(keyCache); + log('OpenedEmailCacheManager::_getDetailedEmailCache():_getDetailedEmailCache: $detailedEmailCache'); + return detailedEmailCache != null; + } +} \ 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 index e25a2663b..997e769b8 100644 --- a/lib/features/offline_mode/manager/opened_email_cache_worker_queue.dart +++ b/lib/features/offline_mode/manager/opened_email_cache_worker_queue.dart @@ -3,5 +3,5 @@ import 'package:tmail_ui_user/features/offline_mode/worker/hive_worker_queue.dar class OpenedEmailCacheWorkerQueue extends WorkerQueue { @override - String get workerName => 'OpenedEmailCache'; + String get workerName => 'OpenedEmailCacheQueue'; } \ 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 ce6e22eaf..664f63e41 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_manager.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'; @@ -103,6 +104,7 @@ class FcmInteractorBindings extends InteractorsBindings { Get.find())); Get.lazyPut(() => EmailHiveCacheDataSourceImpl( 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 2bcdff9a3..a54636dca 100644 --- a/lib/main/bindings/local/local_bindings.dart +++ b/lib/main/bindings/local/local_bindings.dart @@ -11,6 +11,7 @@ import 'package:tmail_ui_user/features/caching/clients/encryption_key_cache_clie import 'package:tmail_ui_user/features/caching/clients/fcm_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/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'; @@ -30,6 +31,8 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/share_prefer import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.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_manager.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/local/fcm_cache_manager.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'; @@ -70,7 +73,9 @@ 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.find())); + Get.put(DetailedEmailCacheManager(Get.find())); + Get.put(OpenedEmailHiveCacheClient()); + Get.put(OpenedEmailCacheManager(Get.find(), Get.find())); Get.put(CachingManager( Get.find(), Get.find(), @@ -90,5 +95,6 @@ class LocalBindings extends Bindings { void _bindingWorkerQueue() { Get.put(DetailedEmailCacheWorkerQueue()); + Get.put(OpenedEmailCacheWorkerQueue()); } } \ No newline at end of file diff --git a/model/lib/email/presentation_email.dart b/model/lib/email/presentation_email.dart index afbf074fb..3cf8a3f55 100644 --- a/model/lib/email/presentation_email.dart +++ b/model/lib/email/presentation_email.dart @@ -5,6 +5,7 @@ import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_header.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/extensions/email_address_extension.dart'; @@ -31,6 +32,7 @@ class PresentationEmail with EquatableMixin { final SelectMode selectMode; final Uri? routeWeb; final PresentationMailbox? mailboxContain; + final List? emailHeader; PresentationEmail({ this.id, @@ -50,7 +52,8 @@ class PresentationEmail with EquatableMixin { this.mailboxNames, this.selectMode = SelectMode.INACTIVE, this.routeWeb, - this.mailboxContain + this.mailboxContain, + this.emailHeader }); String getSenderName() { @@ -117,6 +120,7 @@ class PresentationEmail with EquatableMixin { mailboxNames, selectMode, routeWeb, - mailboxContain + mailboxContain, + emailHeader ]; } \ No newline at end of file diff --git a/model/lib/extensions/email_extension.dart b/model/lib/extensions/email_extension.dart index a91cc8408..75ba2d0ec 100644 --- a/model/lib/extensions/email_extension.dart +++ b/model/lib/extensions/email_extension.dart @@ -72,6 +72,7 @@ extension EmailExtension on Email { replyTo: replyTo, mailboxIds: mailboxIds, selectMode: selectMode, + emailHeader: headers?.toList() ); }