From 71234778f65167aff2496a1ef71f122a9e656922 Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 24 Mar 2025 01:56:45 +0700 Subject: [PATCH 01/11] TF-3358 Rename `ComposerCache` to `LocalEmailDraft` --- .../state/save_local_email_draft_state.dart | 9 ++++ ...estore_email_inline_images_interactor.dart | 8 +-- ...=> save_local_email_draft_interactor.dart} | 22 ++++---- .../presentation/composer_bindings.dart | 48 ++++++++--------- .../presentation/composer_controller.dart | 22 ++++---- .../model/composer_arguments.dart | 4 +- ...dart => local_email_draft_datasource.dart} | 14 ++--- ...=> local_email_draft_datasource_impl.dart} | 21 ++++---- ...oser_cache.dart => local_email_draft.dart} | 26 +++++---- .../composer_cache_repository_impl.dart | 54 ------------------- .../local_email_draft_repository_impl.dart | 54 +++++++++++++++++++ ...dart => local_email_draft_repository.dart} | 14 ++--- .../state/get_composer_cache_state.dart | 14 ++--- .../state/remove_composer_cache_state.dart | 8 +-- .../state/save_composer_cache_state.dart | 9 ---- ...get_all_local_email_draft_interactor.dart} | 14 ++--- ...ove_all_local_email_draft_interactor.dart} | 14 ++--- ... remove_local_email_draft_interactor.dart} | 14 ++--- .../bindings/mailbox_dashboard_bindings.dart | 34 ++++++------ .../mailbox_dashboard_controller.dart | 40 +++++++------- .../open_and_close_composer_extension.dart | 2 +- .../reopen_composer_cache_extension.dart | 10 ++-- .../composer_controller_test.dart | 20 +++---- .../mailbox_dashboard_controller_test.dart | 26 ++++----- .../mailbox_dashboard_view_widget_test.dart | 26 ++++----- ...fore_time_in_search_email_filter_test.dart | 28 +++++----- 26 files changed, 280 insertions(+), 275 deletions(-) create mode 100644 lib/features/composer/domain/state/save_local_email_draft_state.dart rename lib/features/composer/domain/usecases/{save_composer_cache_on_web_interactor.dart => save_local_email_draft_interactor.dart} (75%) rename lib/features/mailbox_dashboard/data/datasource/{session_storage_composer_datasource.dart => local_email_draft_datasource.dart} (69%) rename lib/features/mailbox_dashboard/data/datasource_impl/{session_storage_composer_datasoure_impl.dart => local_email_draft_datasource_impl.dart} (83%) rename lib/features/mailbox_dashboard/data/model/{composer_cache.dart => local_email_draft.dart} (72%) delete mode 100644 lib/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart create mode 100644 lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart rename lib/features/mailbox_dashboard/domain/repository/{composer_cache_repository.dart => local_email_draft_repository.dart} (70%) delete mode 100644 lib/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart rename lib/features/mailbox_dashboard/domain/usecases/{get_composer_cache_on_web_interactor.dart => get_all_local_email_draft_interactor.dart} (59%) rename lib/features/mailbox_dashboard/domain/usecases/{remove_all_composer_cache_on_web_interactor.dart => remove_all_local_email_draft_interactor.dart} (60%) rename lib/features/mailbox_dashboard/domain/usecases/{remove_composer_cache_by_id_on_web_interactor.dart => remove_local_email_draft_interactor.dart} (63%) diff --git a/lib/features/composer/domain/state/save_local_email_draft_state.dart b/lib/features/composer/domain/state/save_local_email_draft_state.dart new file mode 100644 index 0000000000..b39e917465 --- /dev/null +++ b/lib/features/composer/domain/state/save_local_email_draft_state.dart @@ -0,0 +1,9 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; + +class SaveLocalEmailDraftSuccess extends UIState {} + +class SaveLocalEmailDraftFailure extends FeatureFailure { + + SaveLocalEmailDraftFailure(dynamic exception) : super(exception: exception); +} \ No newline at end of file diff --git a/lib/features/composer/domain/usecases/restore_email_inline_images_interactor.dart b/lib/features/composer/domain/usecases/restore_email_inline_images_interactor.dart index 0d10be8191..5f34aad7e2 100644 --- a/lib/features/composer/domain/usecases/restore_email_inline_images_interactor.dart +++ b/lib/features/composer/domain/usecases/restore_email_inline_images_interactor.dart @@ -3,12 +3,12 @@ import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:dartz/dartz.dart'; import 'package:tmail_ui_user/features/composer/domain/state/restore_email_inline_images_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; class RestoreEmailInlineImagesInteractor { - RestoreEmailInlineImagesInteractor(this._composerCacheRepository); + RestoreEmailInlineImagesInteractor(this._localEmailDraftRepository); - final ComposerCacheRepository _composerCacheRepository; + final LocalEmailDraftRepository _localEmailDraftRepository; Stream> execute({ required String htmlContent, @@ -18,7 +18,7 @@ class RestoreEmailInlineImagesInteractor { try { yield Right(RestoringEmailInlineImages()); - final emailContent = await _composerCacheRepository.restoreEmailInlineImages( + final emailContent = await _localEmailDraftRepository.restoreEmailInlineImages( htmlContent, transformConfiguration, mapUrlDownloadCID); diff --git a/lib/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart b/lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart similarity index 75% rename from lib/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart rename to lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart index 4f5c71d339..acd8a1e11c 100644 --- a/lib/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart +++ b/lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart @@ -4,17 +4,17 @@ import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/save_local_email_draft_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; -class SaveComposerCacheOnWebInteractor { - final ComposerCacheRepository _composerCacheRepository; +class SaveLocalEmailDraftInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; final ComposerRepository _composerRepository; - SaveComposerCacheOnWebInteractor( - this._composerCacheRepository, + SaveLocalEmailDraftInteractor( + this._localEmailDraftRepository, this._composerRepository, ); @@ -29,10 +29,10 @@ class SaveComposerCacheOnWebInteractor { withIdentityHeader: true, isDraft: true, ); - await _composerCacheRepository.saveComposerCacheOnWeb( + await _localEmailDraftRepository.saveLocalEmailDraft( accountId: accountId, userName: userName, - composerCache: ComposerCache( + composerCache: LocalEmailDraft( email: emailCreated, hasRequestReadReceipt: createEmailRequest.hasRequestReadReceipt, isMarkAsImportant: createEmailRequest.isMarkAsImportant, @@ -44,9 +44,9 @@ class SaveComposerCacheOnWebInteractor { draftEmailId: createEmailRequest.draftsEmailId, templateEmailId: createEmailRequest.templateEmailId, )); - return Right(SaveComposerCacheSuccess()); + return Right(SaveLocalEmailDraftSuccess()); } catch (exception) { - return Left(SaveComposerCacheFailure(exception)); + return Left(SaveLocalEmailDraftFailure(exception)); } } } diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index 27cc6b6ad9..aa34c6c295 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -15,7 +15,7 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_s import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/restore_email_inline_images_interactor.dart'; -import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/save_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart'; @@ -49,11 +49,11 @@ 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/mailbox/data/repository/mailbox_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/session_storage_composer_datasource.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/identities/identity_interactors_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/preferences/bindings/preferences_interactors_bindings.dart'; @@ -144,7 +144,7 @@ class ComposerBindings extends BaseBindings { Get.find(), Get.find(), ), tag: composerId); - Get.lazyPut(() => SessionStorageComposerDatasourceImpl( + Get.lazyPut(() => LocalEmailDraftDataSourceImpl( Get.find(), Get.find(), ), tag: composerId); @@ -184,8 +184,8 @@ class ComposerBindings extends BaseBindings { () => Get.find(tag: composerId), tag: composerId, ); - Get.lazyPut( - () => Get.find(tag: composerId), + Get.lazyPut( + () => Get.find(tag: composerId), tag: composerId, ); } @@ -200,7 +200,7 @@ class ComposerBindings extends BaseBindings { Get.find(), ), tag: composerId); Get.lazyPut( - () => ComposerCacheRepositoryImpl(Get.find(tag: composerId)), + () => LocalEmailDraftRepositoryImpl(Get.find(tag: composerId)), tag: composerId, ); Get.lazyPut( @@ -233,8 +233,8 @@ class ComposerBindings extends BaseBindings { () => Get.find(tag: composerId), tag: composerId, ); - Get.lazyPut( - () => Get.find(tag: composerId), + Get.lazyPut( + () => Get.find(tag: composerId), tag: composerId, ); Get.lazyPut( @@ -270,11 +270,11 @@ class ComposerBindings extends BaseBindings { tag: composerId, ); Get.lazyPut( - () => RemoveComposerCacheByIdOnWebInteractor(Get.find(tag: composerId)), + () => RemoveLocalEmailDraftInteractor(Get.find(tag: composerId)), tag: composerId, ); - Get.lazyPut(() => SaveComposerCacheOnWebInteractor( - Get.find(tag: composerId), + Get.lazyPut(() => SaveLocalEmailDraftInteractor( + Get.find(tag: composerId), Get.find(tag: composerId), ), tag: composerId); Get.lazyPut( @@ -294,7 +294,7 @@ class ComposerBindings extends BaseBindings { Get.find(tag: composerId), ), tag: composerId); Get.lazyPut( - () => RestoreEmailInlineImagesInteractor(Get.find(tag: composerId)), + () => RestoreEmailInlineImagesInteractor(Get.find(tag: composerId)), tag: composerId, ); Get.lazyPut( @@ -328,8 +328,8 @@ class ComposerBindings extends BaseBindings { Get.find(tag: composerId), Get.find(tag: composerId), Get.find(tag: composerId), - Get.find(tag: composerId), - Get.find(tag: composerId), + Get.find(tag: composerId), + Get.find(tag: composerId), Get.find(tag: composerId), Get.find(tag: composerId), Get.find(tag: composerId), @@ -364,7 +364,7 @@ class ComposerBindings extends BaseBindings { Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); - Get.delete(tag: composerId); + Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); @@ -374,16 +374,16 @@ class ComposerBindings extends BaseBindings { Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); - Get.delete(tag: composerId); + Get.delete(tag: composerId); Get.delete(tag: composerId); - Get.delete(tag: composerId); + Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); - Get.delete(tag: composerId); + Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); @@ -392,8 +392,8 @@ class ComposerBindings extends BaseBindings { Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); - Get.delete(tag: composerId); - Get.delete(tag: composerId); + Get.delete(tag: composerId); + Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); Get.delete(tag: composerId); diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 0a639e00ea..e0c7612afb 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -53,7 +53,7 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/get_all_autocomp import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/get_device_contact_suggestions_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/restore_email_inline_images_interactor.dart'; -import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/save_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/attachment_detection_extension.dart'; @@ -98,7 +98,7 @@ import 'package:tmail_ui_user/features/email/presentation/extensions/presentatio import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_paywall_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; @@ -160,8 +160,8 @@ class ComposerController extends BaseController final GetEmailContentInteractor _getEmailContentInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; final UploadController uploadController; - final RemoveComposerCacheByIdOnWebInteractor _removeComposerCacheByIdOnWebInteractor; - final SaveComposerCacheOnWebInteractor _saveComposerCacheOnWebInteractor; + final RemoveLocalEmailDraftInteractor _removeLocalEmailDraftInteractor; + final SaveLocalEmailDraftInteractor _saveLocalEmailDraftInteractor; final DownloadImageAsBase64Interactor _downloadImageAsBase64Interactor; final TransformHtmlEmailContentInteractor _transformHtmlEmailContentInteractor; final GetServerSettingInteractor _getServerSettingInteractor; @@ -268,8 +268,8 @@ class ComposerController extends BaseController this._getEmailContentInteractor, this._getAllIdentitiesInteractor, this.uploadController, - this._removeComposerCacheByIdOnWebInteractor, - this._saveComposerCacheOnWebInteractor, + this._removeLocalEmailDraftInteractor, + this._saveLocalEmailDraftInteractor, this._downloadImageAsBase64Interactor, this._transformHtmlEmailContentInteractor, this._getServerSettingInteractor, @@ -421,13 +421,13 @@ class ComposerController extends BaseController final username = mailboxDashBoardController.sessionCurrent?.username; final accountId = mailboxDashBoardController.accountId.value; if (composerId != null && username != null && accountId != null) { - await _removeComposerCacheByIdOnWebInteractor.execute( + await _removeLocalEmailDraftInteractor.execute( accountId, username, composerId!, ); } - await _saveComposerCacheOnWebAction(); + await _saveLocalEmailDraftAction(); } void _listenStreamEvent() { @@ -480,13 +480,13 @@ class ComposerController extends BaseController }); } - Future _saveComposerCacheOnWebAction() async { + Future _saveLocalEmailDraftAction() async { autoCreateEmailTag(); final createEmailRequest = await _generateCreateEmailRequestToSaveAsCache(); if (createEmailRequest == null) return; - await _saveComposerCacheOnWebInteractor.execute( + await _saveLocalEmailDraftInteractor.execute( createEmailRequest, mailboxDashBoardController.accountId.value!, mailboxDashBoardController.sessionCurrent!.username); @@ -2380,7 +2380,7 @@ class ComposerController extends BaseController if (mailboxDashBoardController.accountId.value != null && mailboxDashBoardController.sessionCurrent?.username != null ) { - await _saveComposerCacheOnWebAction(); + await _saveLocalEmailDraftAction(); } } diff --git a/lib/features/email/presentation/model/composer_arguments.dart b/lib/features/email/presentation/model/composer_arguments.dart index c6fd05eeb3..45a5847a77 100644 --- a/lib/features/email/presentation/model/composer_arguments.dart +++ b/lib/features/email/presentation/model/composer_arguments.dart @@ -6,7 +6,7 @@ import 'package:model/model.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart'; import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_action_type.dart'; import 'package:tmail_ui_user/main/routes/router_arguments.dart'; @@ -124,7 +124,7 @@ class ComposerArguments extends RouterArguments { savedEmailTemplateId: savedEmailTemplateId, ); - factory ComposerArguments.fromSessionStorageBrowser(ComposerCache composerCache) => + factory ComposerArguments.fromSessionStorageBrowser(LocalEmailDraft composerCache) => ComposerArguments( emailActionType: EmailActionType.reopenComposerBrowser, presentationEmail: composerCache.email?.toPresentationEmail(), diff --git a/lib/features/mailbox_dashboard/data/datasource/session_storage_composer_datasource.dart b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart similarity index 69% rename from lib/features/mailbox_dashboard/data/datasource/session_storage_composer_datasource.dart rename to lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart index 008a47ee5f..5e58a24290 100644 --- a/lib/features/mailbox_dashboard/data/datasource/session_storage_composer_datasource.dart +++ b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart @@ -1,25 +1,25 @@ import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; -abstract class SessionStorageComposerDatasource { - Future saveComposerCacheOnWeb({ +abstract class LocalEmailDraftDatasource { + Future saveLocalEmailDraft({ required AccountId accountId, required UserName userName, - required ComposerCache composerCache, + required LocalEmailDraft composerCache, }); - Future> getComposerCacheOnWeb( + Future> getLocalEmailDraft( AccountId accountId, UserName userName); - Future removeAllComposerCacheOnWeb( + Future removeAllLocalEmailDraft( AccountId accountId, UserName userName, ); - Future removeComposerCacheByIdOnWeb( + Future removeLocalEmailDraft( AccountId accountId, UserName userName, String composerId, diff --git a/lib/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart similarity index 83% rename from lib/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart rename to lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart index 824140b429..e1f836fd87 100644 --- a/lib/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart +++ b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart @@ -7,20 +7,19 @@ import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/session_storage_composer_datasource.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; import 'package:universal_html/html.dart' as html; -class SessionStorageComposerDatasourceImpl - extends SessionStorageComposerDatasource { - SessionStorageComposerDatasourceImpl(this._htmlTransform, this._exceptionThrower); +class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { + LocalEmailDraftDataSourceImpl(this._htmlTransform, this._exceptionThrower); final HtmlTransform _htmlTransform; final ExceptionThrower _exceptionThrower; @override - Future> getComposerCacheOnWeb( + Future> getLocalEmailDraft( AccountId accountId, UserName userName ) async { @@ -36,7 +35,7 @@ class SessionStorageComposerDatasourceImpl if (listEntries.isNotEmpty) { return listEntries - .map((entry) => ComposerCache.fromJson(jsonDecode(entry.value))) + .map((entry) => LocalEmailDraft.fromJson(jsonDecode(entry.value))) .toList(); } else { throw NotFoundInWebSessionException(); @@ -45,10 +44,10 @@ class SessionStorageComposerDatasourceImpl } @override - Future saveComposerCacheOnWeb({ + Future saveLocalEmailDraft({ required AccountId accountId, required UserName userName, - required ComposerCache composerCache, + required LocalEmailDraft composerCache, }) async { return Future.sync(() { final composerCacheKey = TupleKey( @@ -78,7 +77,7 @@ class SessionStorageComposerDatasourceImpl } @override - Future removeAllComposerCacheOnWeb(AccountId accountId, UserName userName) { + Future removeAllLocalEmailDraft(AccountId accountId, UserName userName) { return Future.sync(() { final keyWithIdentity = TupleKey( EmailActionType.reopenComposerBrowser.name, @@ -91,7 +90,7 @@ class SessionStorageComposerDatasourceImpl } @override - Future removeComposerCacheByIdOnWeb(AccountId accountId, UserName userName, String composerId) { + Future removeLocalEmailDraft(AccountId accountId, UserName userName, String composerId) { return Future.sync(() { final keyWithIdentity = TupleKey( EmailActionType.reopenComposerBrowser.name, diff --git a/lib/features/mailbox_dashboard/data/model/composer_cache.dart b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart similarity index 72% rename from lib/features/mailbox_dashboard/data/model/composer_cache.dart rename to lib/features/mailbox_dashboard/data/model/local_email_draft.dart index 428a4ee8f2..4f5b20ac12 100644 --- a/lib/features/mailbox_dashboard/data/model/composer_cache.dart +++ b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart @@ -5,17 +5,19 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:model/email/email_action_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; -part 'composer_cache.g.dart'; +part 'local_email_draft.g.dart'; @JsonSerializable( - explicitToJson: true, - includeIfNull: false, - converters: [ - EmailIdNullableConverter(), - ] + explicitToJson: true, + includeIfNull: false, + converters: [ + EmailIdNullableConverter(), + ] ) -class ComposerCache with EquatableMixin { +class LocalEmailDraft with EquatableMixin { + final String? id; + final DateTime? timeStamp; final Email? email; final bool? hasRequestReadReceipt; final bool? isMarkAsImportant; @@ -27,7 +29,9 @@ class ComposerCache with EquatableMixin { final EmailId? draftEmailId; final EmailId? templateEmailId; - ComposerCache({ + LocalEmailDraft({ + this.id, + this.timeStamp, this.email, this.hasRequestReadReceipt, this.isMarkAsImportant, @@ -40,12 +44,14 @@ class ComposerCache with EquatableMixin { this.templateEmailId, }); - factory ComposerCache.fromJson(Map json) => _$ComposerCacheFromJson(json); + factory LocalEmailDraft.fromJson(Map json) => _$LocalEmailDraftFromJson(json); - Map toJson() => _$ComposerCacheToJson(this); + Map toJson() => _$LocalEmailDraftToJson(this); @override List get props => [ + id, + timeStamp, email, hasRequestReadReceipt, isMarkAsImportant, diff --git a/lib/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart b/lib/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart deleted file mode 100644 index 80c2233b99..0000000000 --- a/lib/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; -import 'package:jmap_dart_client/jmap/account_id.dart'; -import 'package:jmap_dart_client/jmap/core/user_name.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/session_storage_composer_datasource.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; - -class ComposerCacheRepositoryImpl extends ComposerCacheRepository { - - final SessionStorageComposerDatasource composerCacheDataSource; - - ComposerCacheRepositoryImpl(this.composerCacheDataSource); - - @override - Future> getComposerCacheOnWeb( - AccountId accountId, - UserName userName - ) { - return composerCacheDataSource.getComposerCacheOnWeb(accountId, userName); - } - - @override - Future removeAllComposerCacheOnWeb(AccountId accountId, UserName userName) { - return composerCacheDataSource.removeAllComposerCacheOnWeb(accountId, userName); - } - - @override - Future removeComposerCacheByIdOnWeb(AccountId accountId, UserName userName, String composerId) { - return composerCacheDataSource.removeComposerCacheByIdOnWeb(accountId, userName, composerId); - } - - @override - Future saveComposerCacheOnWeb({ - required AccountId accountId, - required UserName userName, - required ComposerCache composerCache, - }) { - return composerCacheDataSource.saveComposerCacheOnWeb( - accountId: accountId, - userName: userName, - composerCache: composerCache); - } - - @override - Future restoreEmailInlineImages( - String htmlContent, - TransformConfiguration transformConfiguration, - Map mapUrlDownloadCID) { - return composerCacheDataSource.restoreEmailInlineImages( - htmlContent, - transformConfiguration, - mapUrlDownloadCID); - } -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart new file mode 100644 index 0000000000..1d5660323f --- /dev/null +++ b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart @@ -0,0 +1,54 @@ +import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/user_name.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; + +class LocalEmailDraftRepositoryImpl extends LocalEmailDraftRepository { + + final LocalEmailDraftDatasource _localEmailDraftDatasource; + + LocalEmailDraftRepositoryImpl(this._localEmailDraftDatasource); + + @override + Future> getLocalEmailDraft( + AccountId accountId, + UserName userName + ) { + return _localEmailDraftDatasource.getLocalEmailDraft(accountId, userName); + } + + @override + Future removeAllLocalEmailDraft(AccountId accountId, UserName userName) { + return _localEmailDraftDatasource.removeAllLocalEmailDraft(accountId, userName); + } + + @override + Future removeLocalEmailDraft(AccountId accountId, UserName userName, String composerId) { + return _localEmailDraftDatasource.removeLocalEmailDraft(accountId, userName, composerId); + } + + @override + Future saveLocalEmailDraft({ + required AccountId accountId, + required UserName userName, + required LocalEmailDraft composerCache, + }) { + return _localEmailDraftDatasource.saveLocalEmailDraft( + accountId: accountId, + userName: userName, + composerCache: composerCache); + } + + @override + Future restoreEmailInlineImages( + String htmlContent, + TransformConfiguration transformConfiguration, + Map mapUrlDownloadCID) { + return _localEmailDraftDatasource.restoreEmailInlineImages( + htmlContent, + transformConfiguration, + mapUrlDownloadCID); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart similarity index 70% rename from lib/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart rename to lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart index 929e3e7bb4..81376c12f0 100644 --- a/lib/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart +++ b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart @@ -1,25 +1,25 @@ import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; -abstract class ComposerCacheRepository { - Future saveComposerCacheOnWeb({ +abstract class LocalEmailDraftRepository { + Future saveLocalEmailDraft({ required AccountId accountId, required UserName userName, - required ComposerCache composerCache, + required LocalEmailDraft composerCache, }); - Future> getComposerCacheOnWeb( + Future> getLocalEmailDraft( AccountId accountId, UserName userName); - Future removeAllComposerCacheOnWeb( + Future removeAllLocalEmailDraft( AccountId accountId, UserName userName, ); - Future removeComposerCacheByIdOnWeb( + Future removeLocalEmailDraft( AccountId accountId, UserName userName, String composerId, diff --git a/lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart b/lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart index d80a71abf6..32f560cfb1 100644 --- a/lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart +++ b/lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart @@ -1,18 +1,18 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; -class GetComposerCacheSuccess extends UIState { +class GetLocalEmailDraftSuccess extends UIState { - final List listComposerCache; + final List listLocalEmailDraft; - GetComposerCacheSuccess(this.listComposerCache); + GetLocalEmailDraftSuccess(this.listLocalEmailDraft); @override - List get props => [listComposerCache]; + List get props => [listLocalEmailDraft]; } -class GetComposerCacheFailure extends FeatureFailure { +class GetLocalEmailDraftFailure extends FeatureFailure { - GetComposerCacheFailure(dynamic exception) : super(exception: exception); + GetLocalEmailDraftFailure(dynamic exception) : super(exception: exception); } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart b/lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart index 04460eda13..f12941d16d 100644 --- a/lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart +++ b/lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart @@ -1,15 +1,15 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; -class RemoveComposerCacheSuccess extends UIState { +class RemoveLocalEmailDraftSuccess extends UIState { - RemoveComposerCacheSuccess(); + RemoveLocalEmailDraftSuccess(); @override List get props => []; } -class RemoveComposerCacheFailure extends FeatureFailure { +class RemoveLocalEmailDraftFailure extends FeatureFailure { - RemoveComposerCacheFailure(dynamic exception) : super(exception: exception); + RemoveLocalEmailDraftFailure(dynamic exception) : super(exception: exception); } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart b/lib/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart deleted file mode 100644 index c4119537bc..0000000000 --- a/lib/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:core/presentation/state/failure.dart'; -import 'package:core/presentation/state/success.dart'; - -class SaveComposerCacheSuccess extends UIState {} - -class SaveComposerCacheFailure extends FeatureFailure { - - SaveComposerCacheFailure(dynamic exception) : super(exception: exception); -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart similarity index 59% rename from lib/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart rename to lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart index 4a96959d70..59f5361fab 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart @@ -3,23 +3,23 @@ import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart'; -class GetComposerCacheOnWebInteractor { - final ComposerCacheRepository composerCacheRepository; +class GetAllLocalEmailDraftInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; - GetComposerCacheOnWebInteractor(this.composerCacheRepository); + GetAllLocalEmailDraftInteractor(this._localEmailDraftRepository); Stream> execute(AccountId accountId, UserName userName) async* { try { - final listComposerCache = await composerCacheRepository.getComposerCacheOnWeb( + final listLocalEmailDraft = await _localEmailDraftRepository.getLocalEmailDraft( accountId, userName, ); - yield Right(GetComposerCacheSuccess(listComposerCache)); + yield Right(GetLocalEmailDraftSuccess(listLocalEmailDraft)); } catch (exception) { - yield Left(GetComposerCacheFailure(exception)); + yield Left(GetLocalEmailDraftFailure(exception)); } } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart similarity index 60% rename from lib/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart rename to lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart index 31bc522897..bda2a36089 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart @@ -3,20 +3,20 @@ import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart'; -class RemoveAllComposerCacheOnWebInteractor { - final ComposerCacheRepository composerCacheRepository; +class RemoveAllLocalEmailDraftInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; - RemoveAllComposerCacheOnWebInteractor(this.composerCacheRepository); + RemoveAllLocalEmailDraftInteractor(this._localEmailDraftRepository); Future> execute(AccountId accountId, UserName userName) async { try { - composerCacheRepository.removeAllComposerCacheOnWeb(accountId, userName); - return Right(RemoveComposerCacheSuccess()); + _localEmailDraftRepository.removeAllLocalEmailDraft(accountId, userName); + return Right(RemoveLocalEmailDraftSuccess()); } catch (exception) { - return Left(RemoveComposerCacheFailure(exception)); + return Left(RemoveLocalEmailDraftFailure(exception)); } } } diff --git a/lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart similarity index 63% rename from lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart rename to lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart index 08bdc06e5a..1b7abfa042 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart @@ -3,13 +3,13 @@ import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart'; -class RemoveComposerCacheByIdOnWebInteractor { - final ComposerCacheRepository composerCacheRepository; +class RemoveLocalEmailDraftInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; - RemoveComposerCacheByIdOnWebInteractor(this.composerCacheRepository); + RemoveLocalEmailDraftInteractor(this._localEmailDraftRepository); Future> execute( AccountId accountId, @@ -17,14 +17,14 @@ class RemoveComposerCacheByIdOnWebInteractor { String composerId, ) async { try { - composerCacheRepository.removeComposerCacheByIdOnWeb( + _localEmailDraftRepository.removeLocalEmailDraft( accountId, userName, composerId, ); - return Right(RemoveComposerCacheSuccess()); + return Right(RemoveLocalEmailDraftSuccess()); } catch (exception) { - return Left(RemoveComposerCacheFailure(exception)); + return Left(RemoveLocalEmailDraftFailure(exception)); } } } 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 3a6f8c8d26..0c39d585a1 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -60,34 +60,34 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_int import 'package:tmail_ui_user/features/mailbox/domain/usecases/mark_as_mailbox_read_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_bindings.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/app_grid_datasource.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/search_datasource.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/session_storage_composer_datasource.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/app_grid_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/hive_spam_report_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/local_app_grid_datasource_impl.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/local_spam_report_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/search_datasource_impl.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_sort_order_manager.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/network/linagora_ecosystem_api.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/app_grid_repository_impl.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/search_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/spam_report_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/app_grid_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/search_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/spam_report_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_app_dashboard_configuration_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_app_grid_linagra_ecosystem_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spam_mailbox_cached_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spam_report_state_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; @@ -186,7 +186,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find(), + Get.find(), Get.find(), Get.find(), Get.find(), @@ -206,8 +206,8 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find(), - Get.find(), + Get.find(), + Get.find(), Get.find(), Get.find(), Get.find(), @@ -225,7 +225,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); - Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut( @@ -274,7 +274,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => MailboxCacheDataSourceImpl( Get.find(), Get.find())); - Get.lazyPut(() => SessionStorageComposerDatasourceImpl( + Get.lazyPut(() => LocalEmailDraftDataSourceImpl( Get.find(), Get.find())); Get.lazyPut(() => LocalSpamReportDataSourceImpl( @@ -331,9 +331,9 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => RefreshChangesSearchEmailInteractor(Get.find())); Get.lazyPut(() => QuickSearchEmailInteractor(Get.find())); Get.lazyPut(() => MarkAsMailboxReadInteractor(Get.find())); - Get.lazyPut(() => GetComposerCacheOnWebInteractor(Get.find())); - Get.lazyPut(() => RemoveComposerCacheByIdOnWebInteractor(Get.find())); - Get.lazyPut(() => RemoveAllComposerCacheOnWebInteractor(Get.find())); + Get.lazyPut(() => GetAllLocalEmailDraftInteractor(Get.find())); + Get.lazyPut(() => RemoveLocalEmailDraftInteractor(Get.find())); + Get.lazyPut(() => RemoveAllLocalEmailDraftInteractor(Get.find())); Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find())); Get.lazyPut(() => MarkAsStarEmailInteractor(Get.find())); Get.lazyPut(() => MarkAsMultipleEmailReadInteractor( @@ -387,7 +387,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); - Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); @@ -423,7 +423,7 @@ class MailboxDashBoardBindings extends BaseBindings { }, Get.find(), )); - Get.lazyPut(() => ComposerCacheRepositoryImpl(Get.find())); + Get.lazyPut(() => LocalEmailDraftRepositoryImpl(Get.find())); Get.lazyPut(() => SpamReportRepositoryImpl( { DataSourceType.local: Get.find(), diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 660240fd41..03683263a6 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -102,12 +102,12 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_repor import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_stored_email_sort_order_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart'; @@ -228,7 +228,7 @@ class MailboxDashBoardController extends ReloadableController final MoveToMailboxInteractor _moveToMailboxInteractor; final DeleteEmailPermanentlyInteractor _deleteEmailPermanentlyInteractor; final MarkAsMailboxReadInteractor _markAsMailboxReadInteractor; - final GetComposerCacheOnWebInteractor _getEmailCacheOnWebInteractor; + final GetAllLocalEmailDraftInteractor _getAllLocalEmailDraftInteractor; final GetIdentityCacheOnWebInteractor _getIdentityCacheOnWebInteractor; final MarkAsEmailReadInteractor _markAsEmailReadInteractor; final MarkAsStarEmailInteractor _markAsStarEmailInteractor; @@ -248,8 +248,8 @@ class MailboxDashBoardController extends ReloadableController final UnsubscribeEmailInteractor _unsubscribeEmailInteractor; final RestoredDeletedMessageInteractor _restoreDeletedMessageInteractor; final GetRestoredDeletedMessageInterator _getRestoredDeletedMessageInteractor; - final RemoveComposerCacheByIdOnWebInteractor _removeComposerCacheByIdOnWebInteractor; - final RemoveAllComposerCacheOnWebInteractor _removeAllComposerCacheOnWebInteractor; + final RemoveLocalEmailDraftInteractor _removeLocalEmailDraftInteractor; + final RemoveAllLocalEmailDraftInteractor _removeAllLocalEmailDraftInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; final ClearMailboxInteractor clearMailboxInteractor; final StoreEmailSortOrderInteractor storeEmailSortOrderInteractor; @@ -329,7 +329,7 @@ class MailboxDashBoardController extends ReloadableController this._moveToMailboxInteractor, this._deleteEmailPermanentlyInteractor, this._markAsMailboxReadInteractor, - this._getEmailCacheOnWebInteractor, + this._getAllLocalEmailDraftInteractor, this._getIdentityCacheOnWebInteractor, this._markAsEmailReadInteractor, this._markAsStarEmailInteractor, @@ -349,8 +349,8 @@ class MailboxDashBoardController extends ReloadableController this._unsubscribeEmailInteractor, this._restoreDeletedMessageInteractor, this._getRestoredDeletedMessageInteractor, - this._removeAllComposerCacheOnWebInteractor, - this._removeComposerCacheByIdOnWebInteractor, + this._removeAllLocalEmailDraftInteractor, + this._removeLocalEmailDraftInteractor, this._getAllIdentitiesInteractor, this.clearMailboxInteractor, this.storeEmailSortOrderInteractor, @@ -386,11 +386,11 @@ class MailboxDashBoardController extends ReloadableController super.onReady(); } - void _handleComposerCache() async { + void _handleLocalEmailDraft() async { if (accountId.value == null || sessionCurrent == null) return; consumeState( - _getEmailCacheOnWebInteractor.execute( + _getAllLocalEmailDraftInteractor.execute( accountId.value!, sessionCurrent!.username)); } @@ -478,8 +478,8 @@ class MailboxDashBoardController extends ReloadableController _handleGetRestoredDeletedMessageSuccess(success); } else if (success is GetAllIdentitiesSuccess) { _handleGetAllIdentitiesSuccess(success); - } else if (success is GetComposerCacheSuccess) { - handleGetComposerCacheSuccess(success); + } else if (success is GetLocalEmailDraftSuccess) { + handleGetLocalEmailDraftSuccess(success); } else if (success is GetIdentityCacheOnWebSuccess) { goToSettings(); } else if (success is MarkAsStarEmailSuccess) { @@ -539,7 +539,7 @@ class MailboxDashBoardController extends ReloadableController _handleEmptyTrashFolderFailure(failure); } else if (failure is MoveMultipleEmailToMailboxFailure) { toastManager.showMessageFailure(failure); - } else if (failure is GetComposerCacheFailure) { + } else if (failure is GetLocalEmailDraftFailure) { _handleIdentityCache(); } else if (failure is GetServerSettingFailure) { isSenderImportantFlagEnabled.value = true; @@ -817,7 +817,7 @@ class MailboxDashBoardController extends ReloadableController _setUpComponentsFromSession(session); if (PlatformInfo.isWeb) { - _handleComposerCache(); + _handleLocalEmailDraft(); } if (PlatformInfo.isAndroid && !_notificationManager.isNotificationClickedOnTerminate) { @@ -1860,7 +1860,7 @@ class MailboxDashBoardController extends ReloadableController _getRouteParameters(); _setUpComponentsFromSession(session); if (PlatformInfo.isWeb) { - _handleComposerCache(); + _handleLocalEmailDraft(); } } @@ -3206,20 +3206,20 @@ class MailboxDashBoardController extends ReloadableController isRecoveringDeletedMessage.value = true; } - Future removeComposerCacheByIdOnWeb(String composerId) async { + Future removeLocalEmailDraft(String composerId) async { if (accountId.value == null || sessionCurrent == null) return; - await _removeComposerCacheByIdOnWebInteractor.execute( + await _removeLocalEmailDraftInteractor.execute( accountId.value!, sessionCurrent!.username, composerId, ); } - Future removeAllComposerCacheOnWeb() async { + Future removeAllLocalEmailDraft() async { if (accountId.value == null || sessionCurrent == null) return; - await _removeAllComposerCacheOnWebInteractor.execute( + await _removeAllLocalEmailDraftInteractor.execute( accountId.value!, sessionCurrent!.username, ); diff --git a/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart index 0bf967b5a0..3fd78493e4 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart @@ -114,7 +114,7 @@ extension OpenAndCloseComposerExtension on MailboxDashBoardController { _handleResultAfterCloseComposer(result); if (composerId != null) { - await removeComposerCacheByIdOnWeb(composerId); + await removeLocalEmailDraft(composerId); } } diff --git a/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart index c914b1abac..9a92658d99 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart @@ -4,15 +4,15 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_compos import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; -extension ReopenComposerCacheExtension on MailboxDashBoardController { +extension ReopenLocalEmailDraftExtension on MailboxDashBoardController { - void handleGetComposerCacheSuccess(GetComposerCacheSuccess success) { - removeAllComposerCacheOnWeb(); + void handleGetLocalEmailDraftSuccess(GetLocalEmailDraftSuccess success) { + removeAllLocalEmailDraft(); - final listComposerCacheSortByIndex = success.listComposerCache + final listLocalEmailDraftSortByIndex = success.listLocalEmailDraft ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); - final listArguments = listComposerCacheSortByIndex + final listArguments = listLocalEmailDraftSortByIndex .map((composerCache) => ComposerArguments.fromSessionStorageBrowser(composerCache)) .toList(); diff --git a/test/features/composer/presentation/composer_controller_test.dart b/test/features/composer/presentation/composer_controller_test.dart index 5f1355f506..edf1a2980f 100644 --- a/test/features/composer/presentation/composer_controller_test.dart +++ b/test/features/composer/presentation/composer_controller_test.dart @@ -33,7 +33,7 @@ import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart'; -import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/save_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart'; @@ -50,7 +50,7 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; @@ -168,8 +168,8 @@ class MockMailboxDashBoardController extends Mock implements MailboxDashBoardCon MockSpec(), MockSpec(), MockSpec(fallbackGenerators: fallbackGenerators), - MockSpec(), - MockSpec(), + MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -213,8 +213,8 @@ void main() { late MockGetEmailContentInteractor mockGetEmailContentInteractor; late MockGetAllIdentitiesInteractor mockGetAllIdentitiesInteractor; late MockUploadController mockUploadController; - late MockRemoveComposerCacheByIdOnWebInteractor mockRemoveComposerCacheByIdOnWebInteractor; - late MockSaveComposerCacheOnWebInteractor mockSaveComposerCacheOnWebInteractor; + late MockRemoveLocalEmailDraftInteractor mockRemoveLocalEmailDraftInteractor; + late MockSaveLocalEmailDraftInteractor mockSaveLocalEmailDraftInteractor; late MockDownloadImageAsBase64Interactor mockDownloadImageAsBase64Interactor; late MockTransformHtmlEmailContentInteractor mockTransformHtmlEmailContentInteractor; late MockGetServerSettingInteractor mockGetServerSettingInteractor; @@ -283,8 +283,8 @@ void main() { mockGetEmailContentInteractor = MockGetEmailContentInteractor(); mockGetAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); mockUploadController = MockUploadController(); - mockRemoveComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); - mockSaveComposerCacheOnWebInteractor = MockSaveComposerCacheOnWebInteractor(); + mockRemoveLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); + mockSaveLocalEmailDraftInteractor = MockSaveLocalEmailDraftInteractor(); mockDownloadImageAsBase64Interactor = MockDownloadImageAsBase64Interactor(); mockTransformHtmlEmailContentInteractor = MockTransformHtmlEmailContentInteractor(); mockGetServerSettingInteractor = MockGetServerSettingInteractor(); @@ -300,8 +300,8 @@ void main() { mockGetEmailContentInteractor, mockGetAllIdentitiesInteractor, mockUploadController, - mockRemoveComposerCacheByIdOnWebInteractor, - mockSaveComposerCacheOnWebInteractor, + mockRemoveLocalEmailDraftInteractor, + mockSaveLocalEmailDraftInteractor, mockDownloadImageAsBase64Interactor, mockTransformHtmlEmailContentInteractor, mockGetServerSettingInteractor, diff --git a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart index 9a4db5d7c4..b91efe658b 100644 --- a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart +++ b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart @@ -58,13 +58,13 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multipl import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart'; @@ -124,7 +124,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -184,8 +184,8 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), - MockSpec(), + MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -204,7 +204,7 @@ void main() { final deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); final markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); - final getEmailCacheOnWebInteractor = MockGetComposerCacheOnWebInteractor(); + final getEmailCacheOnWebInteractor = MockGetAllLocalEmailDraftInteractor(); final getIdentityCacheOnWebInteractor = MockGetIdentityCacheOnWebInteractor(); final markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); final markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); @@ -283,8 +283,8 @@ void main() { final verifyNameInteractor = MockVerifyNameInteractor(); final getAllMailboxInteractor = MockGetAllMailboxInteractor(); final refreshAllMailboxInteractor = MockRefreshAllMailboxInteractor(); - final removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor(); - final removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); + final removeAllLocalEmailDraftInteractor = MockRemoveAllLocalEmailDraftInteractor(); + final removeLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); final clearMailboxInteractor = MockClearMailboxInteractor(); final getAuthenticationInfoInteractor = MockGetAuthenticationInfoInteractor(); @@ -343,8 +343,8 @@ void main() { Get.put(updateAccountCacheInteractor); Get.put(getAllIdentitiesInteractor); Get.put(clearMailboxInteractor); - Get.put(removeAllComposerCacheOnWebInteractor); - Get.put(removeComposerCacheByIdOnWebInteractor); + Get.put(removeAllLocalEmailDraftInteractor); + Get.put(removeLocalEmailDraftInteractor); Get.put(composerManager); Get.put(getAuthenticationInfoInteractor); Get.put(getStoredOidcConfigurationInteractor); @@ -382,8 +382,8 @@ void main() { unsubscribeEmailInteractor, restoreDeletedMessageInteractor, getRestoredDeletedMessageInteractor, - removeAllComposerCacheOnWebInteractor, - removeComposerCacheByIdOnWebInteractor, + removeAllLocalEmailDraftInteractor, + removeLocalEmailDraftInteractor, getAllIdentitiesInteractor, clearMailboxInteractor, storeEmailSortOrderInteractor, diff --git a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart index d80af5984d..d08db51875 100644 --- a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart +++ b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart @@ -56,13 +56,13 @@ import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.d import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; @@ -125,7 +125,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -184,8 +184,8 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), - MockSpec(), + MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -203,7 +203,7 @@ void main() { final moveToMailboxInteractor = MockMoveToMailboxInteractor(); final deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); final markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); - final getEmailCacheOnWebInteractor = MockGetComposerCacheOnWebInteractor(); + final getEmailCacheOnWebInteractor = MockGetAllLocalEmailDraftInteractor(); final getIdentityCacheOnWebInteractor = MockGetIdentityCacheOnWebInteractor(); final markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); final markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); @@ -269,8 +269,8 @@ void main() { final verifyNameInteractor = MockVerifyNameInteractor(); final getAllMailboxInteractor = MockGetAllMailboxInteractor(); final refreshAllMailboxInteractor = MockRefreshAllMailboxInteractor(); - final removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor(); - final removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); + final removeAllLocalEmailDraftInteractor = MockRemoveAllLocalEmailDraftInteractor(); + final removeLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); final clearMailboxInteractor = MockClearMailboxInteractor(); final composerManager = MockComposerManager(); @@ -339,8 +339,8 @@ void main() { Get.put(updateAccountCacheInteractor); Get.put(getAllIdentitiesInteractor); Get.put(clearMailboxInteractor); - Get.put(removeAllComposerCacheOnWebInteractor); - Get.put(removeComposerCacheByIdOnWebInteractor); + Get.put(removeAllLocalEmailDraftInteractor); + Get.put(removeLocalEmailDraftInteractor); Get.put(composerManager); Get.put(getAuthenticationInfoInteractor); Get.put(getStoredOidcConfigurationInteractor); @@ -379,8 +379,8 @@ void main() { unsubscribeEmailInteractor, restoreDeletedMessageInteractor, getRestoredDeletedMessageInteractor, - removeAllComposerCacheOnWebInteractor, - removeComposerCacheByIdOnWebInteractor, + removeAllLocalEmailDraftInteractor, + removeLocalEmailDraftInteractor, getAllIdentitiesInteractor, clearMailboxInteractor, storeEmailSortOrderInteractor, diff --git a/test/features/search/verify_before_time_in_search_email_filter_test.dart b/test/features/search/verify_before_time_in_search_email_filter_test.dart index 04fc2524fc..2742e31b81 100644 --- a/test/features/search/verify_before_time_in_search_email_filter_test.dart +++ b/test/features/search/verify_before_time_in_search_email_filter_test.dart @@ -43,13 +43,13 @@ import 'package:tmail_ui_user/features/login/domain/usecases/get_token_oidc_inte import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cache_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/mark_as_mailbox_read_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_composer_cache_on_web_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; @@ -143,7 +143,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -160,8 +160,8 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), - MockSpec(), + MockSpec(), + MockSpec(), MockSpec(), MockSpec(fallbackGenerators: fallbackGenerators), MockSpec(), @@ -209,7 +209,7 @@ void main() { late MockMoveToMailboxInteractor moveToMailboxInteractor; late MockDeleteEmailPermanentlyInteractor deleteEmailPermanentlyInteractor; late MockMarkAsMailboxReadInteractor markAsMailboxReadInteractor; - late MockGetComposerCacheOnWebInteractor getEmailCacheOnWebInteractor; + late MockGetAllLocalEmailDraftInteractor getEmailCacheOnWebInteractor; late MockGetIdentityCacheOnWebInteractor getIdentityCacheOnWebInteractor; late MockMarkAsEmailReadInteractor markAsEmailReadInteractor; late MockMarkAsStarEmailInteractor markAsStarEmailInteractor; @@ -228,8 +228,8 @@ void main() { late MockUnsubscribeEmailInteractor unsubscribeEmailInteractor; late MockRestoredDeletedMessageInteractor restoreDeletedMessageInteractor; late MockGetRestoredDeletedMessageInterator getRestoredDeletedMessageInteractor; - late MockRemoveAllComposerCacheOnWebInteractor removeAllComposerCacheOnWebInteractor; - late MockRemoveComposerCacheByIdOnWebInteractor removeComposerCacheByIdOnWebInteractor; + late MockRemoveAllLocalEmailDraftInteractor removeAllLocalEmailDraftInteractor; + late MockRemoveLocalEmailDraftInteractor removeLocalEmailDraftInteractor; late MockGetAllIdentitiesInteractor getAllIdentitiesInteractor; late MockClearMailboxInteractor clearMailboxInteractor; late MockGetAuthenticationInfoInteractor getAuthenticationInfoInteractor; @@ -309,7 +309,7 @@ void main() { moveToMailboxInteractor = MockMoveToMailboxInteractor(); deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); - getEmailCacheOnWebInteractor = MockGetComposerCacheOnWebInteractor(); + getEmailCacheOnWebInteractor = MockGetAllLocalEmailDraftInteractor(); getIdentityCacheOnWebInteractor = MockGetIdentityCacheOnWebInteractor(); markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); @@ -328,8 +328,8 @@ void main() { unsubscribeEmailInteractor = MockUnsubscribeEmailInteractor(); restoreDeletedMessageInteractor = MockRestoredDeletedMessageInteractor(); getRestoredDeletedMessageInteractor = MockGetRestoredDeletedMessageInterator(); - removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor(); - removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); + removeAllLocalEmailDraftInteractor = MockRemoveAllLocalEmailDraftInteractor(); + removeLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); clearMailboxInteractor = MockClearMailboxInteractor(); getAuthenticationInfoInteractor = MockGetAuthenticationInfoInteractor(); @@ -381,8 +381,8 @@ void main() { unsubscribeEmailInteractor, restoreDeletedMessageInteractor, getRestoredDeletedMessageInteractor, - removeAllComposerCacheOnWebInteractor, - removeComposerCacheByIdOnWebInteractor, + removeAllLocalEmailDraftInteractor, + removeLocalEmailDraftInteractor, getAllIdentitiesInteractor, clearMailboxInteractor, mockStoreEmailSortOrderInteractor, From e471829da593467ce6cdddcef56eeca58febcbc8 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 25 Mar 2025 11:24:19 +0700 Subject: [PATCH 02/11] TF-3358 Save LocalEmailDraft to hive database --- .../clients/local_email_draft_client.dart | 9 ++ .../caching/config/hive_cache_config.dart | 5 + .../caching/utils/caching_constants.dart | 2 + .../save_local_email_draft_interactor.dart | 20 +--- .../presentation/composer_bindings.dart | 6 +- .../presentation/composer_controller.dart | 108 ++---------------- .../create_email_request_extension.dart | 28 +++++ .../handle_local_email_draft_extension.dart | 82 +++++++++++++ .../model/composer_arguments.dart | 20 ---- .../local_email_draft_datasource.dart | 8 +- .../local_email_draft_datasource_impl.dart | 61 ++++------ .../data/local/local_email_draft_manager.dart | 35 ++++++ .../local/local_email_draft_worker_queue.dart | 8 ++ .../data/model/local_email_draft.dart | 68 ++++++----- .../local_email_draft_repository_impl.dart | 15 +-- .../local_email_draft_exception.dart | 1 + .../local_email_draft_repository.dart | 8 +- ...t => get_all_local_email_draft_state.dart} | 10 +- .../get_all_local_email_draft_interactor.dart | 13 +-- .../bindings/mailbox_dashboard_bindings.dart | 4 + .../mailbox_dashboard_controller.dart | 10 +- .../local_email_draft_extension.dart | 25 ++++ .../reopen_composer_cache_extension.dart | 21 ---- .../reopen_local_email_draft_extension.dart | 17 +++ .../model/presentation_local_email_draft.dart | 38 ++++++ lib/main/bindings/local/local_bindings.dart | 6 + .../composer_controller_test.dart | 10 -- 27 files changed, 369 insertions(+), 269 deletions(-) create mode 100644 lib/features/caching/clients/local_email_draft_client.dart create mode 100644 lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart create mode 100644 lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart create mode 100644 lib/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart create mode 100644 lib/features/mailbox_dashboard/domain/exceptions/local_email_draft_exception.dart rename lib/features/mailbox_dashboard/domain/state/{get_composer_cache_state.dart => get_all_local_email_draft_state.dart} (51%) create mode 100644 lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart delete mode 100644 lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart create mode 100644 lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart create mode 100644 lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart diff --git a/lib/features/caching/clients/local_email_draft_client.dart b/lib/features/caching/clients/local_email_draft_client.dart new file mode 100644 index 0000000000..cd0c828540 --- /dev/null +++ b/lib/features/caching/clients/local_email_draft_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/mailbox_dashboard/data/model/local_email_draft.dart'; + +class LocalEmailDraftClient extends HiveCacheClient { + + @override + String get tableName => CachingConstants.localDraftEmailCacheBoxName; +} \ No newline at end of file diff --git a/lib/features/caching/config/hive_cache_config.dart b/lib/features/caching/config/hive_cache_config.dart index 2826b0af8f..31b1db42c6 100644 --- a/lib/features/caching/config/hive_cache_config.dart +++ b/lib/features/caching/config/hive_cache_config.dart @@ -36,6 +36,7 @@ import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_rights_cache.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'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/recent_search_cache.dart'; import 'package:tmail_ui_user/features/offline_mode/model/attachment_hive_cache.dart'; import 'package:tmail_ui_user/features/offline_mode/model/detailed_email_hive_cache.dart'; @@ -239,6 +240,10 @@ class HiveCacheConfig { CachingConstants.OIDC_CONFIGURATION_CACHE_ID, isolated: isolated, ); + registerCacheAdapter( + LocalEmailDraftAdapter(), + CachingConstants.LOCAL_EMAIL_DRAFT_CACHE_ID + ); } void registerCacheAdapter( diff --git a/lib/features/caching/utils/caching_constants.dart b/lib/features/caching/utils/caching_constants.dart index 4db4af99f5..96d1c2f934 100644 --- a/lib/features/caching/utils/caching_constants.dart +++ b/lib/features/caching/utils/caching_constants.dart @@ -20,6 +20,7 @@ class CachingConstants { static const int SENDING_EMAIL_HIVE_CACHE_ID = 18; static const int SESSION_HIVE_CACHE_ID = 19; static const int OIDC_CONFIGURATION_CACHE_ID = 20; + static const int LOCAL_EMAIL_DRAFT_CACHE_ID = 21; static const String fcmCacheBoxName = 'fcm_cache_box'; static const String newEmailCacheBoxName = 'new_email_cache_box'; @@ -28,6 +29,7 @@ class CachingConstants { static const String sessionCacheBoxName = 'session_cache_box'; static const String firebaseRegistrationCacheBoxName = 'firebase_registration_cache_box'; static const String oidcConfigurationCacheBoxName = 'oidc_configuration_cache_box'; + static const String localDraftEmailCacheBoxName = 'local_email_draft_cache_box'; static const String oidcConfigurationCacheKeyName = 'oidc_configuration_cache_key'; diff --git a/lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart b/lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart index acd8a1e11c..0a4533e0d2 100644 --- a/lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart +++ b/lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart @@ -5,8 +5,8 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_local_email_draft_state.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/create_email_request_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; class SaveLocalEmailDraftInteractor { @@ -30,20 +30,12 @@ class SaveLocalEmailDraftInteractor { isDraft: true, ); await _localEmailDraftRepository.saveLocalEmailDraft( - accountId: accountId, - userName: userName, - composerCache: LocalEmailDraft( + createEmailRequest.generateLocalEmailDraftFromEmail( email: emailCreated, - hasRequestReadReceipt: createEmailRequest.hasRequestReadReceipt, - isMarkAsImportant: createEmailRequest.isMarkAsImportant, - displayMode: createEmailRequest.displayMode, - composerIndex: createEmailRequest.composerIndex, - composerId: createEmailRequest.composerId, - draftHash: createEmailRequest.savedDraftHash, - actionType: createEmailRequest.savedActionType, - draftEmailId: createEmailRequest.draftsEmailId, - templateEmailId: createEmailRequest.templateEmailId, - )); + accountId: accountId, + userName: userName, + ), + ); return Right(SaveLocalEmailDraftSuccess()); } catch (exception) { return Left(SaveLocalEmailDraftFailure(exception)); diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index aa34c6c295..f0dfcb88b8 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -51,6 +51,8 @@ import 'package:tmail_ui_user/features/mailbox/data/repository/mailbox_repositor import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_manager.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; @@ -146,6 +148,8 @@ class ComposerBindings extends BaseBindings { ), tag: composerId); Get.lazyPut(() => LocalEmailDraftDataSourceImpl( Get.find(), + Get.find(), + Get.find(), Get.find(), ), tag: composerId); } @@ -328,8 +332,6 @@ class ComposerBindings extends BaseBindings { Get.find(tag: composerId), Get.find(tag: composerId), Get.find(tag: composerId), - Get.find(tag: composerId), - Get.find(tag: composerId), Get.find(tag: composerId), Get.find(tag: composerId), Get.find(tag: composerId), diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index e0c7612afb..345c0515c3 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -61,6 +61,7 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/auto_cre import 'package:tmail_ui_user/features/composer/presentation/extensions/get_draft_mailbox_id_for_composer_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/get_outbox_mailbox_id_for_composer_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/get_sent_mailbox_id_for_composer_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_local_email_draft_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_message_failure_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/list_identities_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/sanitize_signature_in_email_content_extension.dart'; @@ -98,7 +99,6 @@ import 'package:tmail_ui_user/features/email/presentation/extensions/presentatio import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_paywall_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; @@ -110,8 +110,8 @@ import 'package:tmail_ui_user/features/network_connection/presentation/network_c if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart'; import 'package:tmail_ui_user/features/server_settings/domain/usecases/get_server_setting_interactor.dart'; import 'package:tmail_ui_user/features/upload/domain/exceptions/pick_file_exception.dart'; -import 'package:tmail_ui_user/features/upload/domain/extensions/list_file_info_extension.dart'; import 'package:tmail_ui_user/features/upload/domain/extensions/file_info_extension.dart'; +import 'package:tmail_ui_user/features/upload/domain/extensions/list_file_info_extension.dart'; import 'package:tmail_ui_user/features/upload/domain/extensions/list_file_upload_extension.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart'; import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; @@ -160,8 +160,6 @@ class ComposerController extends BaseController final GetEmailContentInteractor _getEmailContentInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; final UploadController uploadController; - final RemoveLocalEmailDraftInteractor _removeLocalEmailDraftInteractor; - final SaveLocalEmailDraftInteractor _saveLocalEmailDraftInteractor; final DownloadImageAsBase64Interactor _downloadImageAsBase64Interactor; final TransformHtmlEmailContentInteractor _transformHtmlEmailContentInteractor; final GetServerSettingInteractor _getServerSettingInteractor; @@ -177,6 +175,7 @@ class ComposerController extends BaseController GetAutoCompleteInteractor? _getAutoCompleteInteractor; GetDeviceContactSuggestionsInteractor? _getDeviceContactSuggestionsInteractor; RestoreEmailInlineImagesInteractor? restoreEmailInlineImagesInteractor; + SaveLocalEmailDraftInteractor? saveLocalEmailDraftInteractor; List listToEmailAddress = []; List listCcEmailAddress = []; @@ -268,8 +267,6 @@ class ComposerController extends BaseController this._getEmailContentInteractor, this._getAllIdentitiesInteractor, this.uploadController, - this._removeLocalEmailDraftInteractor, - this._saveLocalEmailDraftInteractor, this._downloadImageAsBase64Interactor, this._transformHtmlEmailContentInteractor, this._getServerSettingInteractor, @@ -292,6 +289,7 @@ class ComposerController extends BaseController richTextWebController = getBinding(tag: composerId); restoreEmailInlineImagesInteractor = getBinding(tag: composerId); menuMoreOptionController = CustomPopupMenuController(); + saveLocalEmailDraftInteractor = getBinding(tag: composerId); } else { richTextMobileTabletController = getBinding(tag: composerId); } @@ -418,16 +416,7 @@ class ComposerController extends BaseController @override Future onUnloadBrowserListener(html.Event event) async { - final username = mailboxDashBoardController.sessionCurrent?.username; - final accountId = mailboxDashBoardController.accountId.value; - if (composerId != null && username != null && accountId != null) { - await _removeLocalEmailDraftInteractor.execute( - accountId, - username, - composerId!, - ); - } - await _saveLocalEmailDraftAction(); + await saveLocalEmailDraftAction(); } void _listenStreamEvent() { @@ -480,86 +469,15 @@ class ComposerController extends BaseController }); } - Future _saveLocalEmailDraftAction() async { - autoCreateEmailTag(); - - final createEmailRequest = await _generateCreateEmailRequestToSaveAsCache(); - if (createEmailRequest == null) return; - - await _saveLocalEmailDraftInteractor.execute( - createEmailRequest, - mailboxDashBoardController.accountId.value!, - mailboxDashBoardController.sessionCurrent!.username); - } - - Uri? _getUploadUriFromSession(Session session, AccountId accountId) { + Uri? getUploadUriFromSession(Session session, AccountId accountId) { try { return session.getUploadUri(accountId, jmapUrl: dynamicUrlInterceptors.jmapUrl); } catch (e) { - logError('ComposerController::_getUploadUriFromSession:Exception = $e'); + logError('ComposerController::getUploadUriFromSession:Exception = $e'); return null; } } - Future _generateCreateEmailRequestToSaveAsCache() async { - final arguments = composerArguments.value; - final session = mailboxDashBoardController.sessionCurrent; - final accountId = mailboxDashBoardController.accountId.value; - - if (arguments == null || session == null || accountId == null) { - log('ComposerController::_generateCreateEmailRequest: SESSION or ACCOUNT_ID or ARGUMENTS is NULL'); - return null; - } - - String emailContent = await getContentInEditor(); - if (currentEmailActionType == EmailActionType.compose) { - emailContent = await _composerRepository.removeCollapsedExpandedSignatureEffect( - emailContent: emailContent, - ); - } - final uploadUri = _getUploadUriFromSession(session, accountId); - - final composerIndex = composerId != null - ? mailboxDashBoardController.composerManager.getComposerIndex(composerId!) - : null; - - return CreateEmailRequest( - session: session, - accountId: accountId, - emailActionType: arguments.emailActionType, - ownEmailAddress: ownEmailAddress, - subject: subjectEmail.value ?? '', - emailContent: emailContent, - fromSender: arguments.presentationEmail?.from ?? {}, - toRecipients: listToEmailAddress.toSet(), - ccRecipients: listCcEmailAddress.toSet(), - bccRecipients: listBccEmailAddress.toSet(), - replyToRecipients: listReplyToEmailAddress.toSet(), - hasRequestReadReceipt: hasRequestReadReceipt.value, - isMarkAsImportant: isMarkAsImportant.value, - identity: identitySelected.value, - attachments: uploadController.attachmentsUploaded, - inlineAttachments: uploadController.mapInlineAttachments, - outboxMailboxId: getOutboxMailboxIdForComposer(), - sentMailboxId: getSentMailboxIdForComposer(), - draftsMailboxId: getDraftMailboxIdForComposer(), - draftsEmailId: getDraftEmailId(), - answerForwardEmailId: arguments.presentationEmail?.id, - unsubscribeEmailId: arguments.previousEmailId, - messageId: arguments.messageId, - references: arguments.references, - emailSendingQueue: arguments.sendingEmail, - displayMode: screenDisplayMode.value, - uploadUri: uploadUri, - composerIndex: composerIndex, - composerId: composerId, - savedDraftHash: arguments.savedDraftHash ?? _savedEmailDraftHash, - savedActionType: savedActionType ?? currentEmailActionType, - savedEmailDraftId: emailIdEditing, - templateEmailId: currentTemplateEmailId, - ); - } - void _scrollControllerEmailAddressListener() { if (toEmailAddressController.text.isNotEmpty) { keyToEmailTagEditor.currentState?.closeSuggestionBox(); @@ -951,7 +869,7 @@ class ComposerController extends BaseController required ComposerArguments arguments, required String emailContent, }) async { - final uploadUri = _getUploadUriFromSession(session, accountId); + final uploadUri = getUploadUriFromSession(session, accountId); final cancelToken = CancelToken(); final resultState = await _showSendingMessageDialog( session: session, @@ -1321,7 +1239,7 @@ class ComposerController extends BaseController } final emailContent = await getContentInEditor(); - final uploadUri = _getUploadUriFromSession(session, accountId); + final uploadUri = getUploadUriFromSession(session, accountId); final cancelToken = CancelToken(); final resultState = await _showSavingMessageToDraftsDialog( session: session, @@ -2146,7 +2064,7 @@ class ComposerController extends BaseController popBack(); final emailContent = await getContentInEditor(); - final uploadUri = _getUploadUriFromSession(session, accountId); + final uploadUri = getUploadUriFromSession(session, accountId); final draftEmailId = getDraftEmailId(); log('ComposerController::_handleSaveMessageToDraft: draftEmailId = $draftEmailId'); final cancelToken = CancelToken(); @@ -2377,11 +2295,7 @@ class ComposerController extends BaseController @override Future onBeforeReconnect() async { - if (mailboxDashBoardController.accountId.value != null && - mailboxDashBoardController.sessionCurrent?.username != null - ) { - await _saveLocalEmailDraftAction(); - } + await saveLocalEmailDraftAction(); } void _setUpMaxWidthInlineImage({ diff --git a/lib/features/composer/presentation/extensions/create_email_request_extension.dart b/lib/features/composer/presentation/extensions/create_email_request_extension.dart index 090546baeb..aaca7b02d5 100644 --- a/lib/features/composer/presentation/extensions/create_email_request_extension.dart +++ b/lib/features/composer/presentation/extensions/create_email_request_extension.dart @@ -1,5 +1,7 @@ import 'package:core/core.dart'; import 'package:http_parser/http_parser.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/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; @@ -9,13 +11,18 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/email/mail_priority_header.dart'; +import 'package:model/extensions/account_id_extensions.dart'; import 'package:model/extensions/email_address_extension.dart'; +import 'package:model/extensions/email_extension.dart'; +import 'package:model/extensions/email_id_extensions.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/identity_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/extensions/sending_email_extension.dart'; import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_arguments.dart'; import 'package:tmail_ui_user/main/localizations/localization_service.dart'; @@ -220,4 +227,25 @@ extension CreateEmailRequestExtension on CreateEmailRequest { createMailboxRequest() ); } + + LocalEmailDraft generateLocalEmailDraftFromEmail({ + required Email email, + required AccountId accountId, + required UserName userName, + }) { + return LocalEmailDraft( + id: TupleKey(composerId!, accountId.asString, userName.value).encodeKey, + composerId: composerId!, + savedTime: DateTime.now(), + email: email.asString(), + hasRequestReadReceipt: hasRequestReadReceipt, + isMarkAsImportant: isMarkAsImportant, + displayMode: displayMode.name, + composerIndex: composerIndex, + draftHash: savedDraftHash, + actionType: savedActionType?.name, + draftEmailId: draftsEmailId?.asString, + templateEmailId: templateEmailId?.asString, + ); + } } \ No newline at end of file diff --git a/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart new file mode 100644 index 0000000000..bb82dcdc8e --- /dev/null +++ b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart @@ -0,0 +1,82 @@ +import 'package:core/utils/app_logger.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/auto_create_tag_for_recipients_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/get_draft_mailbox_id_for_composer_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/get_outbox_mailbox_id_for_composer_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/get_sent_mailbox_id_for_composer_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; + +extension HandleLocalEmailDraftExtension on ComposerController { + Future generateCreateEmailRequest() async { + final arguments = composerArguments.value; + final session = mailboxDashBoardController.sessionCurrent; + final accountId = mailboxDashBoardController.accountId.value; + + if (arguments == null || session == null || accountId == null) { + log('HandleLocalEmailDraftExtension::generateCreateEmailRequest: SESSION or ACCOUNT_ID or ARGUMENTS is NULL'); + return null; + } + + final emailContent = await getContentInEditor(); + final uploadUri = getUploadUriFromSession(session, accountId); + + final composerIndex = composerId != null + ? mailboxDashBoardController.composerManager + .getComposerIndex(composerId!) + : null; + + return CreateEmailRequest( + session: session, + accountId: accountId, + emailActionType: arguments.emailActionType, + ownEmailAddress: ownEmailAddress, + subject: subjectEmail.value ?? '', + emailContent: emailContent, + fromSender: arguments.presentationEmail?.from ?? {}, + toRecipients: listToEmailAddress.toSet(), + ccRecipients: listCcEmailAddress.toSet(), + bccRecipients: listBccEmailAddress.toSet(), + replyToRecipients: listReplyToEmailAddress.toSet(), + hasRequestReadReceipt: hasRequestReadReceipt.value, + isMarkAsImportant: isMarkAsImportant.value, + identity: identitySelected.value, + attachments: uploadController.attachmentsUploaded, + inlineAttachments: uploadController.mapInlineAttachments, + outboxMailboxId: getOutboxMailboxIdForComposer(), + sentMailboxId: getSentMailboxIdForComposer(), + draftsMailboxId: getDraftMailboxIdForComposer(), + draftsEmailId: getDraftEmailId(), + answerForwardEmailId: arguments.presentationEmail?.id, + unsubscribeEmailId: arguments.previousEmailId, + messageId: arguments.messageId, + references: arguments.references, + emailSendingQueue: arguments.sendingEmail, + displayMode: screenDisplayMode.value, + uploadUri: uploadUri, + composerIndex: composerIndex, + composerId: composerId, + ); + } + + Future saveLocalEmailDraftAction() async { + final username = mailboxDashBoardController.sessionCurrent?.username; + final accountId = mailboxDashBoardController.accountId.value; + + if (username == null || + accountId == null || + saveLocalEmailDraftInteractor == null) { + return; + } + + autoCreateEmailTag(); + + final createEmailRequest = await generateCreateEmailRequest(); + if (createEmailRequest == null) return; + + await saveLocalEmailDraftInteractor!.execute( + createEmailRequest, + accountId, + username, + ); + } +} diff --git a/lib/features/email/presentation/model/composer_arguments.dart b/lib/features/email/presentation/model/composer_arguments.dart index 45a5847a77..d9910467c5 100644 --- a/lib/features/email/presentation/model/composer_arguments.dart +++ b/lib/features/email/presentation/model/composer_arguments.dart @@ -4,9 +4,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; - import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart'; import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_action_type.dart'; import 'package:tmail_ui_user/main/routes/router_arguments.dart'; @@ -124,24 +122,6 @@ class ComposerArguments extends RouterArguments { savedEmailTemplateId: savedEmailTemplateId, ); - factory ComposerArguments.fromSessionStorageBrowser(LocalEmailDraft composerCache) => - ComposerArguments( - emailActionType: EmailActionType.reopenComposerBrowser, - presentationEmail: composerCache.email?.toPresentationEmail(), - emailContents: composerCache.email?.emailContentList.asHtmlString, - attachments: composerCache.email?.allAttachments.getListAttachmentsDisplayedOutside(composerCache.email?.htmlBodyAttachments ?? []), - selectedIdentityId: composerCache.email?.identityIdFromHeader, - inlineImages: composerCache.email?.allAttachments.listAttachmentsDisplayedInContent, - hasRequestReadReceipt: composerCache.hasRequestReadReceipt, - displayMode: composerCache.displayMode, - isMarkAsImportant: composerCache.isMarkAsImportant, - composerId: composerCache.composerId, - savedDraftHash: composerCache.draftHash, - savedActionType: composerCache.actionType, - savedEmailDraftId: composerCache.draftEmailId, - savedEmailTemplateId: composerCache.templateEmailId, - ); - factory ComposerArguments.replyEmail({ required PresentationEmail presentationEmail, required String? content, diff --git a/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart index 5e58a24290..caca42ab05 100644 --- a/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart +++ b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart @@ -4,13 +4,9 @@ import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; abstract class LocalEmailDraftDatasource { - Future saveLocalEmailDraft({ - required AccountId accountId, - required UserName userName, - required LocalEmailDraft composerCache, - }); + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft); - Future> getLocalEmailDraft( + Future> getAllLocalEmailDraft( AccountId accountId, UserName userName); diff --git a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart index e1f836fd87..6b1a200f79 100644 --- a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart +++ b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; -import 'package:core/domain/exceptions/web_session_exception.dart'; import 'package:core/presentation/utils/html_transformer/html_transform.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; @@ -8,58 +6,47 @@ import 'package:model/email/email_action_type.dart'; import 'package:model/extensions/account_id_extensions.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_manager.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; +import 'package:tmail_ui_user/features/offline_mode/hive_worker/hive_task.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; import 'package:universal_html/html.dart' as html; class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { - LocalEmailDraftDataSourceImpl(this._htmlTransform, this._exceptionThrower); final HtmlTransform _htmlTransform; + final LocalEmailDraftManager _localEmailDraftManager; + final LocalEmailDraftWorkerQueue _localEmailDraftWorkerQueue; final ExceptionThrower _exceptionThrower; + LocalEmailDraftDataSourceImpl( + this._htmlTransform, + this._localEmailDraftManager, + this._localEmailDraftWorkerQueue, + this._exceptionThrower, + ); + @override - Future> getLocalEmailDraft( + Future> getAllLocalEmailDraft( AccountId accountId, UserName userName - ) async { + ) { return Future.sync(() async { - final keyWithIdentity = TupleKey( - EmailActionType.reopenComposerBrowser.name, - accountId.asString, - userName.value).toString(); - - final listEntries = html.window.sessionStorage.entries.where( - (entry) => entry.key.startsWith(keyWithIdentity), - ); - - if (listEntries.isNotEmpty) { - return listEntries - .map((entry) => LocalEmailDraft.fromJson(jsonDecode(entry.value))) - .toList(); - } else { - throw NotFoundInWebSessionException(); - } + return await _localEmailDraftManager.getAllLocalEmailDraft(accountId, userName); }).catchError(_exceptionThrower.throwException); } @override - Future saveLocalEmailDraft({ - required AccountId accountId, - required UserName userName, - required LocalEmailDraft composerCache, - }) async { - return Future.sync(() { - final composerCacheKey = TupleKey( - EmailActionType.reopenComposerBrowser.name, - accountId.asString, - userName.value, - composerCache.composerId, - ).toString(); - Map entries = { - composerCacheKey: jsonEncode(composerCache.toJson()) - }; - html.window.sessionStorage.addAll(entries); + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft) { + return Future.sync(() async { + final task = HiveTask( + id: localEmailDraft.id, + runnable: () async { + return await _localEmailDraftManager.saveLocalEmailDraft(localEmailDraft); + }, + ); + return _localEmailDraftWorkerQueue.addTask(task); }).catchError(_exceptionThrower.throwException); } diff --git a/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart new file mode 100644 index 0000000000..2453e678bd --- /dev/null +++ b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart @@ -0,0 +1,35 @@ + +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/local_email_draft_client.dart'; +import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/local_email_draft_exception.dart'; + +class LocalEmailDraftManager { + + final LocalEmailDraftClient _localEmailDraftClient; + + LocalEmailDraftManager(this._localEmailDraftClient); + + Future> getAllLocalEmailDraft(AccountId accountId, UserName userName) async { + final nestedKey = TupleKey(accountId.asString, userName.value).encodeKey; + final listLocalEmailDraft = await _localEmailDraftClient.getListByNestedKey(nestedKey); + + if (listLocalEmailDraft.isEmpty) { + throw NotFoundLocalEmailDraftException(); + } + + return listLocalEmailDraft; + } + + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft) async { + log('LocalEmailDraftManager::saveLocalEmailDraft: ID = ${localEmailDraft.id}'); + await _localEmailDraftClient.insertItem( + localEmailDraft.id, + localEmailDraft, + ); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart b/lib/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart new file mode 100644 index 0000000000..4ea55c3896 --- /dev/null +++ b/lib/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart @@ -0,0 +1,8 @@ + +import 'package:tmail_ui_user/features/offline_mode/hive_worker/hive_worker_queue.dart'; + +class LocalEmailDraftWorkerQueue extends WorkerQueue { + + @override + String get workerName => 'LocalEmailDraft'; +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/data/model/local_email_draft.dart b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart index 4f5b20ac12..fc93b06a5f 100644 --- a/lib/features/mailbox_dashboard/data/model/local_email_draft.dart +++ b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart @@ -1,57 +1,67 @@ import 'package:equatable/equatable.dart'; -import 'package:jmap_dart_client/http/converter/email_id_nullable_converter.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:model/email/email_action_type.dart'; -import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; +import 'package:hive_ce/hive.dart'; +import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; part 'local_email_draft.g.dart'; -@JsonSerializable( - explicitToJson: true, - includeIfNull: false, - converters: [ - EmailIdNullableConverter(), - ] -) +@HiveType(typeId: CachingConstants.LOCAL_EMAIL_DRAFT_CACHE_ID) class LocalEmailDraft with EquatableMixin { - final String? id; - final DateTime? timeStamp; - final Email? email; + @HiveField(0) + final String id; + + @HiveField(1) + final String composerId; + + @HiveField(2) + final DateTime savedTime; + + @HiveField(3) + final String? email; + + @HiveField(4) final bool? hasRequestReadReceipt; + + @HiveField(5) final bool? isMarkAsImportant; - final ScreenDisplayMode displayMode; + + @HiveField(6) + final String? displayMode; + + @HiveField(7) final int? composerIndex; - final String? composerId; + + @HiveField(8) final int? draftHash; - final EmailActionType? actionType; - final EmailId? draftEmailId; - final EmailId? templateEmailId; + + @HiveField(9) + final String? actionType; + + @HiveField(10) + final String? draftEmailId; + + @HiveField(11) + final String? templateEmailId; LocalEmailDraft({ - this.id, - this.timeStamp, + required this.id, + required this.composerId, + required this.savedTime, this.email, this.hasRequestReadReceipt, this.isMarkAsImportant, - this.displayMode = ScreenDisplayMode.normal, + this.displayMode, this.composerIndex, - this.composerId, this.draftHash, this.actionType, this.draftEmailId, this.templateEmailId, }); - factory LocalEmailDraft.fromJson(Map json) => _$LocalEmailDraftFromJson(json); - - Map toJson() => _$LocalEmailDraftToJson(this); - @override List get props => [ id, - timeStamp, + savedTime, email, hasRequestReadReceipt, isMarkAsImportant, diff --git a/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart index 1d5660323f..ccf7f832df 100644 --- a/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart +++ b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart @@ -12,11 +12,11 @@ class LocalEmailDraftRepositoryImpl extends LocalEmailDraftRepository { LocalEmailDraftRepositoryImpl(this._localEmailDraftDatasource); @override - Future> getLocalEmailDraft( + Future> getAllLocalEmailDraft( AccountId accountId, UserName userName ) { - return _localEmailDraftDatasource.getLocalEmailDraft(accountId, userName); + return _localEmailDraftDatasource.getAllLocalEmailDraft(accountId, userName); } @override @@ -30,15 +30,8 @@ class LocalEmailDraftRepositoryImpl extends LocalEmailDraftRepository { } @override - Future saveLocalEmailDraft({ - required AccountId accountId, - required UserName userName, - required LocalEmailDraft composerCache, - }) { - return _localEmailDraftDatasource.saveLocalEmailDraft( - accountId: accountId, - userName: userName, - composerCache: composerCache); + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft) { + return _localEmailDraftDatasource.saveLocalEmailDraft(localEmailDraft); } @override diff --git a/lib/features/mailbox_dashboard/domain/exceptions/local_email_draft_exception.dart b/lib/features/mailbox_dashboard/domain/exceptions/local_email_draft_exception.dart new file mode 100644 index 0000000000..e39087cd60 --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/exceptions/local_email_draft_exception.dart @@ -0,0 +1 @@ +class NotFoundLocalEmailDraftException implements Exception {} diff --git a/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart index 81376c12f0..698c584f0a 100644 --- a/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart +++ b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart @@ -4,13 +4,9 @@ import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; abstract class LocalEmailDraftRepository { - Future saveLocalEmailDraft({ - required AccountId accountId, - required UserName userName, - required LocalEmailDraft composerCache, - }); + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft); - Future> getLocalEmailDraft( + Future> getAllLocalEmailDraft( AccountId accountId, UserName userName); diff --git a/lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart b/lib/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart similarity index 51% rename from lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart rename to lib/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart index 32f560cfb1..47f2e1672c 100644 --- a/lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart +++ b/lib/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart @@ -2,17 +2,19 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; -class GetLocalEmailDraftSuccess extends UIState { +class GetAllLocalEmailDraftLoading extends LoadingState {} + +class GetAllLocalEmailDraftSuccess extends UIState { final List listLocalEmailDraft; - GetLocalEmailDraftSuccess(this.listLocalEmailDraft); + GetAllLocalEmailDraftSuccess(this.listLocalEmailDraft); @override List get props => [listLocalEmailDraft]; } -class GetLocalEmailDraftFailure extends FeatureFailure { +class GetAllLocalEmailDraftFailure extends FeatureFailure { - GetLocalEmailDraftFailure(dynamic exception) : super(exception: exception); + GetAllLocalEmailDraftFailure(dynamic exception) : super(exception: exception); } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart index 59f5361fab..4ee4ae393c 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart @@ -4,7 +4,7 @@ import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart'; class GetAllLocalEmailDraftInteractor { final LocalEmailDraftRepository _localEmailDraftRepository; @@ -13,13 +13,12 @@ class GetAllLocalEmailDraftInteractor { Stream> execute(AccountId accountId, UserName userName) async* { try { - final listLocalEmailDraft = await _localEmailDraftRepository.getLocalEmailDraft( - accountId, - userName, - ); - yield Right(GetLocalEmailDraftSuccess(listLocalEmailDraft)); + yield Right(GetAllLocalEmailDraftLoading()); + final listLocalEmailDraft = await _localEmailDraftRepository + .getAllLocalEmailDraft(accountId, userName); + yield Right(GetAllLocalEmailDraftSuccess(listLocalEmailDraft)); } catch (exception) { - yield Left(GetLocalEmailDraftFailure(exception)); + yield Left(GetAllLocalEmailDraftFailure(exception)); } } } \ No newline at end of file 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 0c39d585a1..6b0b1d76cf 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -69,6 +69,8 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/lo import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/local_spam_report_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/search_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_sort_order_manager.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_manager.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/network/linagora_ecosystem_api.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/app_grid_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart'; @@ -276,6 +278,8 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find())); Get.lazyPut(() => LocalEmailDraftDataSourceImpl( Get.find(), + Get.find(), + Get.find(), Get.find())); Get.lazyPut(() => LocalSpamReportDataSourceImpl( Get.find(), diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 03683263a6..dff8d5d755 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -99,8 +99,8 @@ import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentat import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/spam_report_exception.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_stored_email_sort_order_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; @@ -124,7 +124,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/initialize_app_language.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/notify_thread_detail_setting_updated.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_paywall_extension.dart'; @@ -478,8 +478,8 @@ class MailboxDashBoardController extends ReloadableController _handleGetRestoredDeletedMessageSuccess(success); } else if (success is GetAllIdentitiesSuccess) { _handleGetAllIdentitiesSuccess(success); - } else if (success is GetLocalEmailDraftSuccess) { - handleGetLocalEmailDraftSuccess(success); + } else if (success is GetAllLocalEmailDraftSuccess) { + handleGetAllLocalEmailDraftSuccess(success); } else if (success is GetIdentityCacheOnWebSuccess) { goToSettings(); } else if (success is MarkAsStarEmailSuccess) { @@ -539,7 +539,7 @@ class MailboxDashBoardController extends ReloadableController _handleEmptyTrashFolderFailure(failure); } else if (failure is MoveMultipleEmailToMailboxFailure) { toastManager.showMessageFailure(failure); - } else if (failure is GetLocalEmailDraftFailure) { + } else if (failure is GetAllLocalEmailDraftFailure) { _handleIdentityCache(); } else if (failure is GetServerSettingFailure) { isSenderImportantFlagEnabled.value = true; diff --git a/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart new file mode 100644 index 0000000000..6664eac54c --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart @@ -0,0 +1,25 @@ + +import 'dart:convert'; + +import 'package:collection/collection.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; + +extension LocalEmailDraftExtension on LocalEmailDraft { + PresentationLocalEmailDraft toPresentation() { + return PresentationLocalEmailDraft( + id: id, + composerId: composerId, + savedTime: savedTime, + email: email != null ? Email.fromJson(jsonDecode(email!)) : null, + hasRequestReadReceipt: hasRequestReadReceipt, + isMarkAsImportant: isMarkAsImportant, + displayMode: ScreenDisplayMode.values.firstWhereOrNull( + (type) => type.name == displayMode, + ), + composerIndex: composerIndex, + ); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart deleted file mode 100644 index 9a92658d99..0000000000 --- a/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart +++ /dev/null @@ -1,21 +0,0 @@ - -import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; - -extension ReopenLocalEmailDraftExtension on MailboxDashBoardController { - - void handleGetLocalEmailDraftSuccess(GetLocalEmailDraftSuccess success) { - removeAllLocalEmailDraft(); - - final listLocalEmailDraftSortByIndex = success.listLocalEmailDraft - ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); - - final listArguments = listLocalEmailDraftSortByIndex - .map((composerCache) => ComposerArguments.fromSessionStorageBrowser(composerCache)) - .toList(); - - openListComposer(listArguments); - } -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart new file mode 100644 index 0000000000..081926a843 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart @@ -0,0 +1,17 @@ + +import 'package:core/utils/app_logger.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart'; + +extension ReopenLocalEmailDraftExtension on MailboxDashBoardController { + + void handleGetAllLocalEmailDraftSuccess(GetAllLocalEmailDraftSuccess success) { + final listPresentationLocalEmailDraft = success.listLocalEmailDraft + .map((localEmailDraft) => localEmailDraft.toPresentation()) + .toList(); + final listLocalEmailDraftSortByIndex = listPresentationLocalEmailDraft + ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); + log('ReopenLocalEmailDraftExtension::handleGetAllLocalEmailDraftSuccess:listLocalEmailDraftSortByIndex_length = ${listLocalEmailDraftSortByIndex.length}'); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart b/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart new file mode 100644 index 0000000000..5300f22fcd --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart @@ -0,0 +1,38 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; + +class PresentationLocalEmailDraft with EquatableMixin { + + final String id; + final String composerId; + final DateTime savedTime; + final Email? email; + final bool? hasRequestReadReceipt; + final bool? isMarkAsImportant; + final ScreenDisplayMode? displayMode; + final int? composerIndex; + + PresentationLocalEmailDraft({ + required this.id, + required this.composerId, + required this.savedTime, + this.email, + this.hasRequestReadReceipt, + this.isMarkAsImportant, + this.displayMode, + this.composerIndex, + }); + + @override + List get props => [ + id, + savedTime, + email, + hasRequestReadReceipt, + isMarkAsImportant, + displayMode, + composerIndex, + composerId, + ]; +} diff --git a/lib/main/bindings/local/local_bindings.dart b/lib/main/bindings/local/local_bindings.dart index 5d9fd1ea18..4aa1fd4155 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/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/local_email_draft_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/oidc_configuration_cache_client.dart'; @@ -34,6 +35,8 @@ import 'package:tmail_ui_user/features/login/data/local/token_oidc_cache_manager 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_dashboard/data/local/local_sort_order_manager.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_manager.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_manager.dart'; @@ -94,6 +97,8 @@ class LocalBindings extends Bindings { Get.put(SessionHiveCacheClient()); Get.put(SessionCacheManager(Get.find())); Get.put(LocalSortOrderManager(Get.find())); + Get.put(LocalEmailDraftClient()); + Get.put(LocalEmailDraftManager(Get.find())); Get.put(CachingManager( Get.find(), Get.find(), @@ -124,6 +129,7 @@ class LocalBindings extends Bindings { void _bindingWorkerQueue() { Get.put(NewEmailCacheWorkerQueue()); Get.put(OpenedEmailCacheWorkerQueue()); + Get.put(LocalEmailDraftWorkerQueue()); } void _bindingKeychainSharing() { diff --git a/test/features/composer/presentation/composer_controller_test.dart b/test/features/composer/presentation/composer_controller_test.dart index edf1a2980f..14c0e9592f 100644 --- a/test/features/composer/presentation/composer_controller_test.dart +++ b/test/features/composer/presentation/composer_controller_test.dart @@ -33,7 +33,6 @@ import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart'; -import 'package:tmail_ui_user/features/composer/domain/usecases/save_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart'; @@ -50,7 +49,6 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; @@ -168,8 +166,6 @@ class MockMailboxDashBoardController extends Mock implements MailboxDashBoardCon MockSpec(), MockSpec(), MockSpec(fallbackGenerators: fallbackGenerators), - MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -213,8 +209,6 @@ void main() { late MockGetEmailContentInteractor mockGetEmailContentInteractor; late MockGetAllIdentitiesInteractor mockGetAllIdentitiesInteractor; late MockUploadController mockUploadController; - late MockRemoveLocalEmailDraftInteractor mockRemoveLocalEmailDraftInteractor; - late MockSaveLocalEmailDraftInteractor mockSaveLocalEmailDraftInteractor; late MockDownloadImageAsBase64Interactor mockDownloadImageAsBase64Interactor; late MockTransformHtmlEmailContentInteractor mockTransformHtmlEmailContentInteractor; late MockGetServerSettingInteractor mockGetServerSettingInteractor; @@ -283,8 +277,6 @@ void main() { mockGetEmailContentInteractor = MockGetEmailContentInteractor(); mockGetAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); mockUploadController = MockUploadController(); - mockRemoveLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); - mockSaveLocalEmailDraftInteractor = MockSaveLocalEmailDraftInteractor(); mockDownloadImageAsBase64Interactor = MockDownloadImageAsBase64Interactor(); mockTransformHtmlEmailContentInteractor = MockTransformHtmlEmailContentInteractor(); mockGetServerSettingInteractor = MockGetServerSettingInteractor(); @@ -300,8 +292,6 @@ void main() { mockGetEmailContentInteractor, mockGetAllIdentitiesInteractor, mockUploadController, - mockRemoveLocalEmailDraftInteractor, - mockSaveLocalEmailDraftInteractor, mockDownloadImageAsBase64Interactor, mockTransformHtmlEmailContentInteractor, mockGetServerSettingInteractor, From 6bfc4e7c14006c44afdd82b56e26a752c3440fbc Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 25 Mar 2025 17:43:10 +0700 Subject: [PATCH 03/11] TF-3358 Show list draft locally dialog --- .../base/widget/email_avatar_builder.dart | 12 +- .../presentation/composer_controller.dart | 2 +- ...formation_sender_and_receiver_builder.dart | 3 +- .../data/local/local_email_draft_manager.dart | 2 - .../mailbox_dashboard_controller.dart | 4 +- ...sentation_local_email_draft_extension.dart | 64 ++++++ .../reopen_local_email_draft_extension.dart | 17 -- .../restore_local_email_draft_extension.dart | 33 +++ .../local_email_draft_item_widget.dart | 183 ++++++++++++++++ ...local_email_draft_list_dialog_builder.dart | 203 ++++++++++++++++++ lib/l10n/intl_messages.arb | 18 ++ lib/main/localizations/app_localizations.dart | 21 ++ 12 files changed, 533 insertions(+), 29 deletions(-) create mode 100644 lib/features/mailbox_dashboard/presentation/extensions/presentation_local_email_draft_extension.dart delete mode 100644 lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart create mode 100644 lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart create mode 100644 lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart create mode 100644 lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart diff --git a/lib/features/base/widget/email_avatar_builder.dart b/lib/features/base/widget/email_avatar_builder.dart index f3d978dd03..5d98301b6c 100644 --- a/lib/features/base/widget/email_avatar_builder.dart +++ b/lib/features/base/widget/email_avatar_builder.dart @@ -3,31 +3,31 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/theme_utils.dart'; import 'package:core/presentation/views/image/avatar_builder.dart'; import 'package:flutter/material.dart'; -import 'package:model/email/presentation_email.dart'; -import 'package:model/extensions/presentation_email_extension.dart'; class EmailAvatarBuilder extends StatelessWidget { - final PresentationEmail emailSelected; + final String avatarText; final OnTapAvatarActionClick? onTapAvatarActionClick; final double? size; + final List? avatarColors; const EmailAvatarBuilder({ Key? key, - required this.emailSelected, + required this.avatarText, this.onTapAvatarActionClick, this.size, + this.avatarColors, }) : super(key: key); @override Widget build(BuildContext context) { return (AvatarBuilder() - ..text(emailSelected.getAvatarText()) + ..text(avatarText) ..size(size ?? 50) ..addTextStyle(ThemeUtils.textStyleHeadingH4(color: Colors.white)) ..backgroundColor(AppColor.colorAvatar) ..addOnTapActionClick(onTapAvatarActionClick ?? () {}) - ..avatarColor(emailSelected.avatarColors)) + ..avatarColor(avatarColors)) .build(); } } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 345c0515c3..757a4efe02 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -415,7 +415,7 @@ class ComposerController extends BaseController } @override - Future onUnloadBrowserListener(html.Event event) async { + Future onBeforeUnloadBrowserListener(html.Event event) async { await saveLocalEmailDraftAction(); } diff --git a/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart b/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart index c752145a1c..c0eabe4392 100644 --- a/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart +++ b/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart @@ -75,7 +75,8 @@ class InformationSenderAndReceiverBuilder extends StatelessWidget { : CrossAxisAlignment.center, children: [ EmailAvatarBuilder( - emailSelected: emailSelected, + avatarText: emailSelected.getAvatarText(), + avatarColors: emailSelected.avatarColors, onTapAvatarActionClick: onTapAvatarActionClick, size: 56, ), diff --git a/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart index 2453e678bd..9bd62e695d 100644 --- a/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart +++ b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart @@ -1,5 +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/user_name.dart'; import 'package:model/extensions/account_id_extensions.dart'; @@ -26,7 +25,6 @@ class LocalEmailDraftManager { } Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft) async { - log('LocalEmailDraftManager::saveLocalEmailDraft: ID = ${localEmailDraft.id}'); await _localEmailDraftClient.insertItem( localEmailDraft.id, localEmailDraft, diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index dff8d5d755..18ef1c9912 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -124,7 +124,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/initialize_app_language.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/notify_thread_detail_setting_updated.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_paywall_extension.dart'; @@ -479,7 +479,7 @@ class MailboxDashBoardController extends ReloadableController } else if (success is GetAllIdentitiesSuccess) { _handleGetAllIdentitiesSuccess(success); } else if (success is GetAllLocalEmailDraftSuccess) { - handleGetAllLocalEmailDraftSuccess(success); + restoreLocalEmailDraft(success.listLocalEmailDraft); } else if (success is GetIdentityCacheOnWebSuccess) { goToSettings(); } else if (success is MarkAsStarEmailSuccess) { diff --git a/lib/features/mailbox_dashboard/presentation/extensions/presentation_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/presentation_local_email_draft_extension.dart new file mode 100644 index 0000000000..8999f5d9d3 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/presentation_local_email_draft_extension.dart @@ -0,0 +1,64 @@ + +import 'dart:ui'; + +import 'package:core/domain/extensions/datetime_extension.dart'; +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/extensions/string_extension.dart'; +import 'package:flutter_date_range_picker/flutter_date_range_picker.dart'; +import 'package:model/extensions/email_address_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; + +extension PresentationLocalEmailDraftExtension on PresentationLocalEmailDraft { + + String get avatarText { + final recipientName = firstRecipientName; + if (recipientName.isNotEmpty) { + return recipientName.firstCharacterToUpperCase; + } + return '?'; + } + + List get avatarColors { + if (email?.from?.isNotEmpty == true) { + return email!.from!.first.avatarColors; + } else { + return AppColor.mapGradientColor.first; + } + } + + String get firstRecipientName { + if (email?.to?.isNotEmpty == true) { + return email!.to!.first.asString(); + } if (email?.cc?.isNotEmpty == true) { + return email!.cc!.first.asString(); + } if (email?.bcc?.isNotEmpty == true) { + return email!.bcc!.first.asString(); + } else { + return senderName; + } + } + + String get senderName { + if (email?.from?.isNotEmpty == true) { + return email!.from!.first.asString(); + } else { + return ''; + } + } + + String get emailSubject => email?.subject?.trim() ?? ''; + + String get emailContent { + if (email?.bodyValues?.isNotEmpty == true) { + return email?.bodyValues?.values.first.value ?? ''; + } else { + return ''; + } + } + + bool get hasAttachment => email?.attachments?.isNotEmpty == true; + + String getSavedTime(String locale) { + return DateFormat(savedTime.toPattern(), locale).format(savedTime); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart deleted file mode 100644 index 081926a843..0000000000 --- a/lib/features/mailbox_dashboard/presentation/extensions/reopen_local_email_draft_extension.dart +++ /dev/null @@ -1,17 +0,0 @@ - -import 'package:core/utils/app_logger.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart'; - -extension ReopenLocalEmailDraftExtension on MailboxDashBoardController { - - void handleGetAllLocalEmailDraftSuccess(GetAllLocalEmailDraftSuccess success) { - final listPresentationLocalEmailDraft = success.listLocalEmailDraft - .map((localEmailDraft) => localEmailDraft.toPresentation()) - .toList(); - final listLocalEmailDraftSortByIndex = listPresentationLocalEmailDraft - ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); - log('ReopenLocalEmailDraftExtension::handleGetAllLocalEmailDraftSuccess:listLocalEmailDraftSortByIndex_length = ${listLocalEmailDraftSortByIndex.length}'); - } -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart new file mode 100644 index 0000000000..7d32559ba8 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -0,0 +1,33 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:get/get.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart'; + +extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { + + void restoreLocalEmailDraft(List localEmailDrafts) { + final listPresentationLocalEmailDraft = localEmailDrafts + .map((localEmailDraft) => localEmailDraft.toPresentation()) + .toList(); + final listLocalEmailDraftSortByIndex = listPresentationLocalEmailDraft + ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); + + showLocalEmailDraftListDialog(listLocalEmailDraftSortByIndex); + } + + void showLocalEmailDraftListDialog(List presentationLocalEmailDrafts) { + Get.dialog( + PointerInterceptor( + child: LocalEmailDraftListDialogBuilder( + presentationLocalEmailDrafts: presentationLocalEmailDrafts, + ), + ), + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + ); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart new file mode 100644 index 0000000000..6c03366234 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart @@ -0,0 +1,183 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:tmail_ui_user/features/base/widget/email_avatar_builder.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/presentation_local_email_draft_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +typedef OnSelectLocalEmailDraftAction = void Function( + PresentationLocalEmailDraft); + +class LocalEmailDraftItemWidget extends StatelessWidget { + final PresentationLocalEmailDraft draftLocal; + final bool isOldest; + final ImagePaths imagePaths; + final OnSelectLocalEmailDraftAction? onSelectLocalEmailDraftAction; + + const LocalEmailDraftItemWidget({ + super.key, + required this.draftLocal, + required this.imagePaths, + required this.isOldest, + this.onSelectLocalEmailDraftAction, + }); + + @override + Widget build(BuildContext context) { + return Material( + type: MaterialType.transparency, + child: InkWell( + onTap: () => onSelectLocalEmailDraftAction?.call(draftLocal), + child: Padding( + padding: EdgeInsetsDirectional.only( + start: 12, + end: 12, + top: 12, + bottom: isOldest ? 12 : 0, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + EmailAvatarBuilder( + avatarText: draftLocal.avatarText, + avatarColors: draftLocal.avatarColors, + ), + const SizedBox(width: 12), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(children: [ + Expanded( + child: Text( + draftLocal.firstRecipientName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(color: Colors.black), + ), + ), + if (draftLocal.isMarkAsImportant == true) + SvgPicture.asset( + imagePaths.icMarkAsImportant, + width: 20, + height: 20, + fit: BoxFit.fill, + colorFilter: AppColor.steelGray200.asFilter(), + ), + if (draftLocal.hasAttachment) + Padding( + padding: const EdgeInsetsDirectional.only(start: 8), + child: SvgPicture.asset( + imagePaths.icAttachment, + width: 16, + height: 16, + colorFilter: AppColor.steelGray200.asFilter(), + fit: BoxFit.fill, + ), + ), + Padding( + padding: + const EdgeInsetsDirectional.only(end: 4, start: 8), + child: Text( + draftLocal.getSavedTime( + Localizations.localeOf(context).toLanguageTag()), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: AppColor.steelGray400), + ), + ), + ]), + if (draftLocal.emailSubject.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 2), + child: Text( + draftLocal.emailSubject, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: AppColor.steelGray400), + ), + ), + if (draftLocal.emailContent.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 2), + child: Text( + draftLocal.emailContent, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: AppColor.steelGray400), + ), + ), + const SizedBox(height: 12), + Row( + children: [ + Flexible( + child: TMailButtonWidget( + text: AppLocalizations.of(context).edit, + textStyle: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(color: AppColor.primaryColor, fontSize: 12), + maxLines: 1, + padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 8), + margin: const EdgeInsetsDirectional.only(end: 8), + onTapActionCallback: () {}, + ), + ), + Flexible( + child: TMailButtonWidget( + text: AppLocalizations.of(context).saveAsDraft, + textStyle: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(color: Colors.black, fontSize: 12), + maxLines: 1, + padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 8), + margin: const EdgeInsetsDirectional.only(end: 8), + onTapActionCallback: () {}, + ), + ), + Flexible( + child: TMailButtonWidget( + text: AppLocalizations.of(context).discard, + textStyle: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(color: AppColor.colorActionDeleteConfirmDialog, fontSize: 12), + maxLines: 1, + padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 8), + margin: const EdgeInsetsDirectional.only(end: 8), + onTapActionCallback: () {}, + ), + ), + ], + ), + if (!isOldest) + const Padding( + padding: EdgeInsets.only(top: 12), + child: Divider(color: AppColor.colorDivider, height: 0.5)), + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart new file mode 100644 index 0000000000..a15e438363 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -0,0 +1,203 @@ +import 'dart:ui'; + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; + +class LocalEmailDraftListDialogBuilder extends StatefulWidget { + final List presentationLocalEmailDrafts; + + const LocalEmailDraftListDialogBuilder({ + super.key, + required this.presentationLocalEmailDrafts, + }); + + @override + State createState() => + _LocalEmailDraftListDialogBuilderState(); +} + +class _LocalEmailDraftListDialogBuilderState + extends State { + static const double _maxHeight = 656.0; + static const double _maxWidth = 556.0; + + late final ResponsiveUtils _responsiveUtils; + late final ImagePaths _imagePaths; + late final ScrollController _scrollController; + + @override + void initState() { + super.initState(); + _responsiveUtils = Get.find(); + _imagePaths = Get.find(); + _scrollController = ScrollController(); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: _getBorderRadius(context), + ), + insetPadding: _getMargin(context), + alignment: Alignment.center, + backgroundColor: Colors.white, + child: Container( + decoration: BoxDecoration( + borderRadius: _getBorderRadius(context), + ), + width: _getWidth(context), + height: _getHeight(context), + clipBehavior: Clip.antiAlias, + child: Column( + children: [ + SizedBox( + height: 52, + child: Row( + children: [ + const SizedBox(width: 40), + Expanded( + child: Text( + AppLocalizations.of(context).localDraftList, + textAlign: TextAlign.center, + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(color: Colors.black), + ), + ), + TMailButtonWidget.fromIcon( + icon: _imagePaths.icComposerClose, + backgroundColor: Colors.transparent, + margin: const EdgeInsetsDirectional.only(end: 12), + onTapActionCallback: popBack, + ) + ], + ), + ), + const Divider(color: AppColor.colorDivider, height: 1), + Expanded( + child: ScrollbarListView( + scrollBehavior: ScrollConfiguration.of(context).copyWith( + physics: const BouncingScrollPhysics(), + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad + }, + scrollbars: false, + ), + scrollController: _scrollController, + child: ListView.builder( + itemCount: widget.presentationLocalEmailDrafts.length, + shrinkWrap: true, + controller: _scrollController, + primary: false, + itemBuilder: (_, index) { + final draftLocal = + widget.presentationLocalEmailDrafts[index]; + return LocalEmailDraftItemWidget( + draftLocal: draftLocal, + isOldest: index == widget.presentationLocalEmailDrafts.length - 1, + imagePaths: _imagePaths, + onSelectLocalEmailDraftAction: (draftLocal) {}, + ); + }, + ), + ), + ), + const Divider(color: AppColor.colorDivider, height: 1), + Padding( + padding: const EdgeInsets.all(12), + child: Row( + children: [ + const Spacer(), + TMailButtonWidget( + text: AppLocalizations.of(context).discardAll, + backgroundColor: AppColor.grayBackgroundColor, + maxLines: 1, + textStyle: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(color: AppColor.steelGray600), + borderRadius: 10, + margin: const EdgeInsetsDirectional.only(end: 8), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + onTapActionCallback: () {}, + ), + TMailButtonWidget( + text: AppLocalizations.of(context).openAll, + backgroundColor: AppColor.blue700, + textStyle: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(color: Colors.white), + maxLines: 1, + borderRadius: 10, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + onTapActionCallback: () {}, + ), + ], + ), + ) + ], + ), + ), + ); + } + + EdgeInsets _getMargin(BuildContext context) { + if (_responsiveUtils.isMobile(context)) { + return EdgeInsets.zero; + } else { + if (_responsiveUtils.getSizeScreenHeight(context) > _maxHeight) { + return const EdgeInsets.symmetric(vertical: 12); + } else { + return const EdgeInsets.symmetric(vertical: 50); + } + } + } + + BorderRadius _getBorderRadius(BuildContext context) { + if (_responsiveUtils.isMobile(context)) { + return const BorderRadius.only( + topRight: Radius.circular(16), + topLeft: Radius.circular(16), + ); + } else { + return const BorderRadius.all(Radius.circular(16)); + } + } + + double _getWidth(BuildContext context) { + if (_responsiveUtils.isMobile(context)) { + return double.infinity; + } else { + return _maxWidth; + } + } + + double _getHeight(BuildContext context) { + if (!_responsiveUtils.isMobile(context) && + _responsiveUtils.getSizeScreenHeight(context) > _maxHeight) { + return _maxHeight; + } else { + return double.infinity; + } + } +} diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 66e27e6315..c72a560068 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4887,5 +4887,23 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "localDraftList": "Local Draft List", + "@localDraftList": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "openAll": "Open all", + "@openAll": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "discardAll": "Discard all", + "@discardAll": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 04de6749e3..ac27c80592 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5160,4 +5160,25 @@ class AppLocalizations { name: 'spamReportToggleDescription', ); } + + String get localDraftList { + return Intl.message( + 'Local Draft List', + name: 'localDraftList', + ); + } + + String get openAll { + return Intl.message( + 'Open all', + name: 'openAll', + ); + } + + String get discardAll { + return Intl.message( + 'Discard all', + name: 'discardAll', + ); + } } From 7f451e545bbc36b50bb7cd06e1f58adfc95d9ea9 Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 22 Sep 2025 11:45:23 +0700 Subject: [PATCH 04/11] TF-3358 Handle `Edit` & `Discard` each local email draft item --- .../presentation/composer_controller.dart | 4 +- .../create_email_request_extension.dart | 1 - .../email_action_type_extension.dart | 2 +- .../setup_email_attachments_extension.dart | 2 +- .../setup_email_content_extension.dart | 2 +- .../setup_email_important_flag_extension.dart | 2 +- ...etup_email_other_components_extension.dart | 2 +- .../setup_email_recipients_extension.dart | 2 +- ...l_request_read_receipt_flag_extension.dart | 2 +- .../setup_email_subject_extension.dart | 2 +- .../setup_email_template_id_extension.dart | 2 +- .../setup_selected_identity_extension.dart | 2 +- .../view/mobile/mobile_editor_view.dart | 2 +- .../view/web/web_editor_view.dart | 2 +- .../model/composer_arguments.dart | 22 +++++ .../local_email_draft_datasource.dart | 6 +- .../local_email_draft_datasource_impl.dart | 15 +-- .../data/local/local_email_draft_manager.dart | 4 + .../data/model/local_email_draft.dart | 5 - .../local_email_draft_repository_impl.dart | 4 +- .../local_email_draft_repository.dart | 6 +- .../remove_local_email_draft_interactor.dart | 14 +-- .../bindings/mailbox_dashboard_bindings.dart | 3 - .../mailbox_dashboard_controller.dart | 37 ++------ .../local_email_draft_extension.dart | 9 +- .../open_and_close_composer_extension.dart | 4 - .../restore_local_email_draft_extension.dart | 32 ++++++- .../model/presentation_local_email_draft.dart | 40 +++++++- .../local_email_draft_item_widget.dart | 20 +++- ...local_email_draft_list_dialog_builder.dart | 91 ++++++++++++++++--- lib/l10n/intl_messages.arb | 6 ++ lib/main/localizations/app_localizations.dart | 7 ++ model/lib/email/email_action_type.dart | 2 +- .../mailbox_dashboard_controller_test.dart | 14 --- .../mailbox_dashboard_view_widget_test.dart | 14 --- ...fore_time_in_search_email_filter_test.dart | 15 --- 36 files changed, 242 insertions(+), 157 deletions(-) diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 757a4efe02..a812420228 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -1172,7 +1172,7 @@ class ComposerController extends BaseController ); if (emailIdEditing != null && savedActionType == EmailActionType.compose && - currentEmailActionType == EmailActionType.reopenComposerBrowser) { + currentEmailActionType == EmailActionType.composeFromLocalEmailDraft) { emailContent = await _composerRepository.removeStyleLazyLoadDisplayInlineImages( emailContent: emailContent, ); @@ -1208,7 +1208,7 @@ class ComposerController extends BaseController if (currentEmailActionType == EmailActionType.compose || currentEmailActionType == EmailActionType.editDraft) { _savedEmailDraftHash = currentDraftHash; - } else if (currentEmailActionType == EmailActionType.reopenComposerBrowser) { + } else if (currentEmailActionType == EmailActionType.composeFromLocalEmailDraft) { _savedEmailDraftHash = oldSavedDraftHash; } log('ComposerController::initEmailDraftHash:oldSavedDraftHash = $oldSavedDraftHash | currentDraftHash = $currentDraftHash | _savedEmailDraftHash = $_savedEmailDraftHash'); diff --git a/lib/features/composer/presentation/extensions/create_email_request_extension.dart b/lib/features/composer/presentation/extensions/create_email_request_extension.dart index aaca7b02d5..a47b4d7bf3 100644 --- a/lib/features/composer/presentation/extensions/create_email_request_extension.dart +++ b/lib/features/composer/presentation/extensions/create_email_request_extension.dart @@ -245,7 +245,6 @@ extension CreateEmailRequestExtension on CreateEmailRequest { draftHash: savedDraftHash, actionType: savedActionType?.name, draftEmailId: draftsEmailId?.asString, - templateEmailId: templateEmailId?.asString, ); } } \ No newline at end of file diff --git a/lib/features/composer/presentation/extensions/email_action_type_extension.dart b/lib/features/composer/presentation/extensions/email_action_type_extension.dart index 99263639d0..e4879a84d8 100644 --- a/lib/features/composer/presentation/extensions/email_action_type_extension.dart +++ b/lib/features/composer/presentation/extensions/email_action_type_extension.dart @@ -32,7 +32,7 @@ extension EmailActionTypeExtension on EmailActionType { } case EmailActionType.editDraft: case EmailActionType.editSendingEmail: - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: case EmailActionType.editAsNewEmail: case EmailActionType.composeFromMailtoUri: case EmailActionType.composeFromUnsubscribeMailtoLink: diff --git a/lib/features/composer/presentation/extensions/setup_email_attachments_extension.dart b/lib/features/composer/presentation/extensions/setup_email_attachments_extension.dart index f75a3cf2f5..eb58758ca0 100644 --- a/lib/features/composer/presentation/extensions/setup_email_attachments_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_attachments_extension.dart @@ -35,7 +35,7 @@ extension SetupEmailAttachmentsExtension on ComposerController { attachments = arguments.attachments; inlineImages = arguments.inlineImages; break; - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: attachments = arguments.attachments; inlineImages = arguments.inlineImages; break; diff --git a/lib/features/composer/presentation/extensions/setup_email_content_extension.dart b/lib/features/composer/presentation/extensions/setup_email_content_extension.dart index e689fabfb6..b36e2d1ab1 100644 --- a/lib/features/composer/presentation/extensions/setup_email_content_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_content_extension.dart @@ -104,7 +104,7 @@ extension SetupEmailContentExtension on ComposerController { } } break; - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: final inlineImages = arguments.inlineImages ?? []; final content = arguments.emailContents ?? ''; final displayMode = arguments.displayMode; diff --git a/lib/features/composer/presentation/extensions/setup_email_important_flag_extension.dart b/lib/features/composer/presentation/extensions/setup_email_important_flag_extension.dart index 362b6026ad..3fce258d11 100644 --- a/lib/features/composer/presentation/extensions/setup_email_important_flag_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_important_flag_extension.dart @@ -11,7 +11,7 @@ extension SetupEmailImportantFlagExtension on ComposerController { case EmailActionType.editDraft: isMarkAsImportant.value = arguments.presentationEmail?.isMarkAsImportant ?? false; break; - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: isMarkAsImportant.value = arguments.isMarkAsImportant ?? false; break; case EmailActionType.editSendingEmail: diff --git a/lib/features/composer/presentation/extensions/setup_email_other_components_extension.dart b/lib/features/composer/presentation/extensions/setup_email_other_components_extension.dart index ab321761b2..8eaf5af42d 100644 --- a/lib/features/composer/presentation/extensions/setup_email_other_components_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_other_components_extension.dart @@ -13,7 +13,7 @@ extension SetupEmailOtherComponentsExtension on ComposerController { case EmailActionType.editSendingEmail: emailIdEditing = arguments.sendingEmail?.presentationEmail.id; break; - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: screenDisplayMode.value = arguments.displayMode; break; default: diff --git a/lib/features/composer/presentation/extensions/setup_email_recipients_extension.dart b/lib/features/composer/presentation/extensions/setup_email_recipients_extension.dart index 03dc63bcaa..d7342a4bc3 100644 --- a/lib/features/composer/presentation/extensions/setup_email_recipients_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_recipients_extension.dart @@ -11,7 +11,7 @@ extension SetupEmailRecipientsExtension on ComposerController { switch(currentEmailActionType) { case EmailActionType.editAsNewEmail: case EmailActionType.editDraft: - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: initEmailAddress( presentationEmail: arguments.presentationEmail!, actionType: currentEmailActionType!, diff --git a/lib/features/composer/presentation/extensions/setup_email_request_read_receipt_flag_extension.dart b/lib/features/composer/presentation/extensions/setup_email_request_read_receipt_flag_extension.dart index 70d8f3a13d..d32b2a66fa 100644 --- a/lib/features/composer/presentation/extensions/setup_email_request_read_receipt_flag_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_request_read_receipt_flag_extension.dart @@ -10,7 +10,7 @@ import 'package:tmail_ui_user/features/server_settings/domain/state/get_server_s extension SetupEmailRequestReadReceiptFlagExtension on ComposerController { void setupEmailRequestReadReceiptFlag(ComposerArguments arguments) { - if (currentEmailActionType == EmailActionType.reopenComposerBrowser) { + if (currentEmailActionType == EmailActionType.composeFromLocalEmailDraft) { hasRequestReadReceipt.value = arguments.hasRequestReadReceipt ?? false; } else if (currentEmailActionType == EmailActionType.editSendingEmail) { hasRequestReadReceipt.value = arguments.sendingEmail?.email.hasRequestReadReceipt ?? false; diff --git a/lib/features/composer/presentation/extensions/setup_email_subject_extension.dart b/lib/features/composer/presentation/extensions/setup_email_subject_extension.dart index 6c963a9b49..3818e363ed 100644 --- a/lib/features/composer/presentation/extensions/setup_email_subject_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_subject_extension.dart @@ -17,7 +17,7 @@ extension SetupEmailSubjectExtension on ComposerController { case EmailActionType.replyToList: case EmailActionType.replyAll: case EmailActionType.forward: - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: subject = arguments.presentationEmail!.getEmailTitle().trim(); break; case EmailActionType.editSendingEmail: diff --git a/lib/features/composer/presentation/extensions/setup_email_template_id_extension.dart b/lib/features/composer/presentation/extensions/setup_email_template_id_extension.dart index 03736ead9f..8b957e2b4b 100644 --- a/lib/features/composer/presentation/extensions/setup_email_template_id_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_email_template_id_extension.dart @@ -5,7 +5,7 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen extension SetupEmailTemplateIdExtension on ComposerController { void setupEmailTemplateId(ComposerArguments arguments) { if (currentEmailActionType == EmailActionType.editAsNewEmail || - currentEmailActionType == EmailActionType.reopenComposerBrowser + currentEmailActionType == EmailActionType.composeFromLocalEmailDraft ) { currentTemplateEmailId = arguments.savedEmailTemplateId; } diff --git a/lib/features/composer/presentation/extensions/setup_selected_identity_extension.dart b/lib/features/composer/presentation/extensions/setup_selected_identity_extension.dart index 76b9a7b0cd..ae0f4a2761 100644 --- a/lib/features/composer/presentation/extensions/setup_selected_identity_extension.dart +++ b/lib/features/composer/presentation/extensions/setup_selected_identity_extension.dart @@ -30,7 +30,7 @@ extension SetupSelectedIdentityExtension on ComposerController { ) ?? listFromIdentities.first; if (currentEmailActionType == EmailActionType.editDraft || - currentEmailActionType == EmailActionType.reopenComposerBrowser && + currentEmailActionType == EmailActionType.composeFromLocalEmailDraft && savedActionType == EmailActionType.editDraft) { identitySelected.value = currentIdentity; } else if (currentEmailActionType == EmailActionType.editAsNewEmail) { diff --git a/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart b/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart index 9d9e002910..fd168a8a96 100644 --- a/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart +++ b/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart @@ -107,7 +107,7 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { EmailActionType.editDraft, EmailActionType.editSendingEmail, EmailActionType.composeFromContentShared, - EmailActionType.reopenComposerBrowser, + EmailActionType.composeFromLocalEmailDraft, EmailActionType.composeFromMailtoUri, EmailActionType.composeFromUnsubscribeMailtoLink, EmailActionType.editAsNewEmail, diff --git a/lib/features/composer/presentation/view/web/web_editor_view.dart b/lib/features/composer/presentation/view/web/web_editor_view.dart index 97ef69b95a..464fb281e8 100644 --- a/lib/features/composer/presentation/view/web/web_editor_view.dart +++ b/lib/features/composer/presentation/view/web/web_editor_view.dart @@ -89,7 +89,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin { case EmailActionType.editDraft: case EmailActionType.editSendingEmail: case EmailActionType.composeFromContentShared: - case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromLocalEmailDraft: case EmailActionType.composeFromUnsubscribeMailtoLink: case EmailActionType.composeFromMailtoUri: case EmailActionType.editAsNewEmail: diff --git a/lib/features/email/presentation/model/composer_arguments.dart b/lib/features/email/presentation/model/composer_arguments.dart index d9910467c5..4b18ef7b4c 100644 --- a/lib/features/email/presentation/model/composer_arguments.dart +++ b/lib/features/email/presentation/model/composer_arguments.dart @@ -5,6 +5,7 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart'; import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_action_type.dart'; import 'package:tmail_ui_user/main/routes/router_arguments.dart'; @@ -122,6 +123,27 @@ class ComposerArguments extends RouterArguments { savedEmailTemplateId: savedEmailTemplateId, ); + factory ComposerArguments.fromLocalEmailDraft(PresentationLocalEmailDraft localDraft) { + final email = localDraft.email; + final allAttachments = email?.allAttachments; + + return ComposerArguments( + emailActionType: EmailActionType.composeFromLocalEmailDraft, + presentationEmail: email?.toPresentationEmail(), + emailContents: email?.emailContentList.asHtmlString, + attachments: allAttachments?.getListAttachmentsDisplayedOutside(email?.htmlBodyAttachments ?? []), + selectedIdentityId: email?.identityIdFromHeader, + inlineImages: email?.allAttachments.listAttachmentsDisplayedInContent, + hasRequestReadReceipt: localDraft.hasRequestReadReceipt, + displayMode: localDraft.displayMode, + isMarkAsImportant: localDraft.isMarkAsImportant, + composerId: localDraft.composerId, + savedDraftHash: localDraft.draftHash, + savedActionType: localDraft.actionType, + savedEmailDraftId: localDraft.draftEmailId, + ); + } + factory ComposerArguments.replyEmail({ required PresentationEmail presentationEmail, required String? content, diff --git a/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart index caca42ab05..6a7cf984f0 100644 --- a/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart +++ b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart @@ -15,11 +15,7 @@ abstract class LocalEmailDraftDatasource { UserName userName, ); - Future removeLocalEmailDraft( - AccountId accountId, - UserName userName, - String composerId, - ); + Future removeLocalEmailDraft(String draftLocalId); Future restoreEmailInlineImages( String htmlContent, diff --git a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart index 6b1a200f79..9c984f29ef 100644 --- a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart +++ b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart @@ -67,7 +67,7 @@ class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { Future removeAllLocalEmailDraft(AccountId accountId, UserName userName) { return Future.sync(() { final keyWithIdentity = TupleKey( - EmailActionType.reopenComposerBrowser.name, + EmailActionType.composeFromLocalEmailDraft.name, accountId.asString, userName.value, ).toString(); @@ -77,16 +77,9 @@ class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { } @override - Future removeLocalEmailDraft(AccountId accountId, UserName userName, String composerId) { - return Future.sync(() { - final keyWithIdentity = TupleKey( - EmailActionType.reopenComposerBrowser.name, - accountId.asString, - userName.value, - composerId, - ).toString(); - - html.window.sessionStorage.removeWhere((key, value) => key == keyWithIdentity); + Future removeLocalEmailDraft(String draftLocalId) { + return Future.sync(() async { + return await _localEmailDraftManager.removeLocalEmailDraft(draftLocalId); }).catchError(_exceptionThrower.throwException); } } diff --git a/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart index 9bd62e695d..0c3efa64c4 100644 --- a/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart +++ b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart @@ -30,4 +30,8 @@ class LocalEmailDraftManager { localEmailDraft, ); } + + Future removeLocalEmailDraft(String id) async { + await _localEmailDraftClient.deleteItem(id); + } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/data/model/local_email_draft.dart b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart index fc93b06a5f..7c0539e03b 100644 --- a/lib/features/mailbox_dashboard/data/model/local_email_draft.dart +++ b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart @@ -40,9 +40,6 @@ class LocalEmailDraft with EquatableMixin { @HiveField(10) final String? draftEmailId; - @HiveField(11) - final String? templateEmailId; - LocalEmailDraft({ required this.id, required this.composerId, @@ -55,7 +52,6 @@ class LocalEmailDraft with EquatableMixin { this.draftHash, this.actionType, this.draftEmailId, - this.templateEmailId, }); @override @@ -71,6 +67,5 @@ class LocalEmailDraft with EquatableMixin { draftHash, actionType, draftEmailId, - templateEmailId, ]; } diff --git a/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart index ccf7f832df..002fb89d63 100644 --- a/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart +++ b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart @@ -25,8 +25,8 @@ class LocalEmailDraftRepositoryImpl extends LocalEmailDraftRepository { } @override - Future removeLocalEmailDraft(AccountId accountId, UserName userName, String composerId) { - return _localEmailDraftDatasource.removeLocalEmailDraft(accountId, userName, composerId); + Future removeLocalEmailDraft(String draftLocalId) { + return _localEmailDraftDatasource.removeLocalEmailDraft(draftLocalId); } @override diff --git a/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart index 698c584f0a..89eac52e75 100644 --- a/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart +++ b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart @@ -15,11 +15,7 @@ abstract class LocalEmailDraftRepository { UserName userName, ); - Future removeLocalEmailDraft( - AccountId accountId, - UserName userName, - String composerId, - ); + Future removeLocalEmailDraft(String draftLocalId); Future restoreEmailInlineImages( String htmlContent, diff --git a/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart index 1b7abfa042..ed4c569523 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart @@ -1,8 +1,6 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; -import 'package:jmap_dart_client/jmap/account_id.dart'; -import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart'; @@ -11,17 +9,9 @@ class RemoveLocalEmailDraftInteractor { RemoveLocalEmailDraftInteractor(this._localEmailDraftRepository); - Future> execute( - AccountId accountId, - UserName userName, - String composerId, - ) async { + Future> execute(String draftLocalId) async { try { - _localEmailDraftRepository.removeLocalEmailDraft( - accountId, - userName, - composerId, - ); + _localEmailDraftRepository.removeLocalEmailDraft(draftLocalId); return Right(RemoveLocalEmailDraftSuccess()); } catch (exception) { return Left(RemoveLocalEmailDraftFailure(exception)); 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 6b0b1d76cf..e19a80abda 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -188,7 +188,6 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find(), Get.find(), Get.find(), Get.find(), @@ -208,8 +207,6 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find(), - Get.find(), Get.find(), Get.find(), Get.find(), diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 18ef1c9912..0fa11582ac 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -107,7 +107,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart'; @@ -228,7 +227,6 @@ class MailboxDashBoardController extends ReloadableController final MoveToMailboxInteractor _moveToMailboxInteractor; final DeleteEmailPermanentlyInteractor _deleteEmailPermanentlyInteractor; final MarkAsMailboxReadInteractor _markAsMailboxReadInteractor; - final GetAllLocalEmailDraftInteractor _getAllLocalEmailDraftInteractor; final GetIdentityCacheOnWebInteractor _getIdentityCacheOnWebInteractor; final MarkAsEmailReadInteractor _markAsEmailReadInteractor; final MarkAsStarEmailInteractor _markAsStarEmailInteractor; @@ -248,8 +246,6 @@ class MailboxDashBoardController extends ReloadableController final UnsubscribeEmailInteractor _unsubscribeEmailInteractor; final RestoredDeletedMessageInteractor _restoreDeletedMessageInteractor; final GetRestoredDeletedMessageInterator _getRestoredDeletedMessageInteractor; - final RemoveLocalEmailDraftInteractor _removeLocalEmailDraftInteractor; - final RemoveAllLocalEmailDraftInteractor _removeAllLocalEmailDraftInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; final ClearMailboxInteractor clearMailboxInteractor; final StoreEmailSortOrderInteractor storeEmailSortOrderInteractor; @@ -262,6 +258,8 @@ class MailboxDashBoardController extends ReloadableController GetServerSettingInteractor? getServerSettingInteractor; CreateNewEmailRuleFilterInteractor? createNewEmailRuleFilterInteractor; SaveLanguageInteractor? saveLanguageInteractor; + GetAllLocalEmailDraftInteractor? getAllLocalEmailDraftInteractor; + RemoveAllLocalEmailDraftInteractor? removeAllLocalEmailDraftInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -329,7 +327,6 @@ class MailboxDashBoardController extends ReloadableController this._moveToMailboxInteractor, this._deleteEmailPermanentlyInteractor, this._markAsMailboxReadInteractor, - this._getAllLocalEmailDraftInteractor, this._getIdentityCacheOnWebInteractor, this._markAsEmailReadInteractor, this._markAsStarEmailInteractor, @@ -349,8 +346,6 @@ class MailboxDashBoardController extends ReloadableController this._unsubscribeEmailInteractor, this._restoreDeletedMessageInteractor, this._getRestoredDeletedMessageInteractor, - this._removeAllLocalEmailDraftInteractor, - this._removeLocalEmailDraftInteractor, this._getAllIdentitiesInteractor, this.clearMailboxInteractor, this.storeEmailSortOrderInteractor, @@ -377,6 +372,7 @@ class MailboxDashBoardController extends ReloadableController listSearchFilterScrollController = ScrollController(); twakeAppManager.setExecutingBeforeReconnect(false); isRetryGetPaywallUrl = false; + getAllLocalEmailDraftInteractor = getBinding(); } if (PlatformInfo.isIOS) { _registerPendingCurrentEmailIdInNotification(); @@ -386,15 +382,6 @@ class MailboxDashBoardController extends ReloadableController super.onReady(); } - void _handleLocalEmailDraft() async { - if (accountId.value == null || sessionCurrent == null) return; - - consumeState( - _getAllLocalEmailDraftInteractor.execute( - accountId.value!, - sessionCurrent!.username)); - } - void _handleIdentityCache() async { if (accountId.value == null || sessionCurrent == null) return; @@ -479,7 +466,7 @@ class MailboxDashBoardController extends ReloadableController } else if (success is GetAllIdentitiesSuccess) { _handleGetAllIdentitiesSuccess(success); } else if (success is GetAllLocalEmailDraftSuccess) { - restoreLocalEmailDraft(success.listLocalEmailDraft); + handlerGetAllLocalEmailDraft(success.listLocalEmailDraft); } else if (success is GetIdentityCacheOnWebSuccess) { goToSettings(); } else if (success is MarkAsStarEmailSuccess) { @@ -817,7 +804,7 @@ class MailboxDashBoardController extends ReloadableController _setUpComponentsFromSession(session); if (PlatformInfo.isWeb) { - _handleLocalEmailDraft(); + restoreLocalEmailDraft(); } if (PlatformInfo.isAndroid && !_notificationManager.isNotificationClickedOnTerminate) { @@ -1860,7 +1847,7 @@ class MailboxDashBoardController extends ReloadableController _getRouteParameters(); _setUpComponentsFromSession(session); if (PlatformInfo.isWeb) { - _handleLocalEmailDraft(); + restoreLocalEmailDraft(); } } @@ -3206,20 +3193,10 @@ class MailboxDashBoardController extends ReloadableController isRecoveringDeletedMessage.value = true; } - Future removeLocalEmailDraft(String composerId) async { - if (accountId.value == null || sessionCurrent == null) return; - - await _removeLocalEmailDraftInteractor.execute( - accountId.value!, - sessionCurrent!.username, - composerId, - ); - } - Future removeAllLocalEmailDraft() async { if (accountId.value == null || sessionCurrent == null) return; - await _removeAllLocalEmailDraftInteractor.execute( + await removeAllLocalEmailDraftInteractor?.execute( accountId.value!, sessionCurrent!.username, ); diff --git a/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart index 6664eac54c..36aeefc0fa 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart @@ -2,7 +2,9 @@ import 'dart:convert'; import 'package:collection/collection.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:model/email/email_action_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; @@ -18,8 +20,13 @@ extension LocalEmailDraftExtension on LocalEmailDraft { isMarkAsImportant: isMarkAsImportant, displayMode: ScreenDisplayMode.values.firstWhereOrNull( (type) => type.name == displayMode, - ), + ) ?? ScreenDisplayMode.normal, composerIndex: composerIndex, + draftHash: draftHash, + actionType: EmailActionType.values.firstWhereOrNull( + (type) => type.name == actionType, + ), + draftEmailId: draftEmailId != null ? EmailId(Id(draftEmailId!)) : null, ); } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart index 3fd78493e4..da3d717a3e 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart @@ -112,10 +112,6 @@ extension OpenAndCloseComposerExtension on MailboxDashBoardController { } _handleResultAfterCloseComposer(result); - - if (composerId != null) { - await removeLocalEmailDraft(composerId); - } } void _handleResultAfterCloseComposer(dynamic result) { diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart index 7d32559ba8..f8807b54f0 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -2,15 +2,30 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:get/get.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { - void restoreLocalEmailDraft(List localEmailDrafts) { + void restoreLocalEmailDraft() { + if (accountId.value == null || + sessionCurrent == null || + getAllLocalEmailDraftInteractor == null) return; + + consumeState(getAllLocalEmailDraftInteractor!.execute( + accountId.value!, + sessionCurrent!.username, + )); + } + + void handlerGetAllLocalEmailDraft(List localEmailDrafts) { final listPresentationLocalEmailDraft = localEmailDrafts .map((localEmailDraft) => localEmailDraft.toPresentation()) .toList(); @@ -24,10 +39,25 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { Get.dialog( PointerInterceptor( child: LocalEmailDraftListDialogBuilder( + accountId: accountId.value, + userName: sessionCurrent?.username, presentationLocalEmailDrafts: presentationLocalEmailDrafts, + onEditLocalEmailDraftAction: _editLocalEmailDraft, + onSaveAsDraftLocalEmailDraftAction: _saveAsDraftLocalEmailDraft, ), ), barrierColor: AppColor.colorDefaultCupertinoActionSheet, ); } + + void _editLocalEmailDraft(PresentationLocalEmailDraft draftLocal) { + popBack(); + openComposer(ComposerArguments.fromLocalEmailDraft( + draftLocal.copyWith(displayMode: ScreenDisplayMode.normal), + )); + } + + void _saveAsDraftLocalEmailDraft(PresentationLocalEmailDraft draftLocal) { + popBack(); + } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart b/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart index 5300f22fcd..1c8293c0de 100644 --- a/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart +++ b/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart @@ -1,5 +1,6 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:model/email/email_action_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; class PresentationLocalEmailDraft with EquatableMixin { @@ -10,8 +11,11 @@ class PresentationLocalEmailDraft with EquatableMixin { final Email? email; final bool? hasRequestReadReceipt; final bool? isMarkAsImportant; - final ScreenDisplayMode? displayMode; + final ScreenDisplayMode displayMode; final int? composerIndex; + final int? draftHash; + final EmailActionType? actionType; + final EmailId? draftEmailId; PresentationLocalEmailDraft({ required this.id, @@ -20,10 +24,39 @@ class PresentationLocalEmailDraft with EquatableMixin { this.email, this.hasRequestReadReceipt, this.isMarkAsImportant, - this.displayMode, + this.displayMode = ScreenDisplayMode.normal, this.composerIndex, + this.draftHash, + this.actionType, + this.draftEmailId, }); + PresentationLocalEmailDraft copyWith({ + String? id, + String? composerId, + DateTime? savedTime, + Email? email, + bool? hasRequestReadReceipt, + bool? isMarkAsImportant, + ScreenDisplayMode? displayMode, + int? composerIndex, + int? draftHash, + EmailActionType? actionType, + EmailId? draftEmailId, + }) => PresentationLocalEmailDraft( + id: id ?? this.id, + composerId: composerId ?? this.composerId, + savedTime: savedTime ?? this.savedTime, + email: email ?? this.email, + hasRequestReadReceipt: hasRequestReadReceipt ?? this.hasRequestReadReceipt, + isMarkAsImportant: isMarkAsImportant ?? this.isMarkAsImportant, + displayMode: displayMode ?? this.displayMode, + composerIndex: composerIndex ?? this.composerIndex, + draftHash: draftHash ?? this.draftHash, + actionType: actionType ?? this.actionType, + draftEmailId: draftEmailId ?? this.draftEmailId, + ); + @override List get props => [ id, @@ -34,5 +67,8 @@ class PresentationLocalEmailDraft with EquatableMixin { displayMode, composerIndex, composerId, + draftHash, + actionType, + draftEmailId, ]; } diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart index 6c03366234..11a75395da 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart @@ -10,12 +10,21 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; typedef OnSelectLocalEmailDraftAction = void Function( PresentationLocalEmailDraft); +typedef OnDiscardLocalEmailDraftAction = void Function( + PresentationLocalEmailDraft); +typedef OnEditLocalEmailDraftAction = void Function( + PresentationLocalEmailDraft); +typedef OnSaveAsDraftLocalEmailDraftAction = void Function( + PresentationLocalEmailDraft); class LocalEmailDraftItemWidget extends StatelessWidget { final PresentationLocalEmailDraft draftLocal; final bool isOldest; final ImagePaths imagePaths; final OnSelectLocalEmailDraftAction? onSelectLocalEmailDraftAction; + final OnEditLocalEmailDraftAction? onEditLocalEmailDraftAction; + final OnSaveAsDraftLocalEmailDraftAction? onSaveAsDraftLocalEmailDraftAction; + final OnDiscardLocalEmailDraftAction? onDiscardLocalEmailDraftAction; const LocalEmailDraftItemWidget({ super.key, @@ -23,6 +32,9 @@ class LocalEmailDraftItemWidget extends StatelessWidget { required this.imagePaths, required this.isOldest, this.onSelectLocalEmailDraftAction, + this.onEditLocalEmailDraftAction, + this.onSaveAsDraftLocalEmailDraftAction, + this.onDiscardLocalEmailDraftAction, }); @override @@ -136,7 +148,7 @@ class LocalEmailDraftItemWidget extends StatelessWidget { maxLines: 1, padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 8), margin: const EdgeInsetsDirectional.only(end: 8), - onTapActionCallback: () {}, + onTapActionCallback: () => onEditLocalEmailDraftAction?.call(draftLocal), ), ), Flexible( @@ -149,7 +161,7 @@ class LocalEmailDraftItemWidget extends StatelessWidget { maxLines: 1, padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 8), margin: const EdgeInsetsDirectional.only(end: 8), - onTapActionCallback: () {}, + onTapActionCallback: () => onSaveAsDraftLocalEmailDraftAction?.call(draftLocal), ), ), Flexible( @@ -162,7 +174,7 @@ class LocalEmailDraftItemWidget extends StatelessWidget { maxLines: 1, padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 8), margin: const EdgeInsetsDirectional.only(end: 8), - onTapActionCallback: () {}, + onTapActionCallback: () => onDiscardLocalEmailDraftAction?.call(draftLocal), ), ), ], @@ -170,7 +182,7 @@ class LocalEmailDraftItemWidget extends StatelessWidget { if (!isOldest) const Padding( padding: EdgeInsets.only(top: 12), - child: Divider(color: AppColor.colorDivider, height: 0.5)), + child: Divider(color: AppColor.colorDivider, height: 0.5,)), ], ), ), diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart index a15e438363..7dd4df4a96 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -4,20 +4,34 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/user_name.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class LocalEmailDraftListDialogBuilder extends StatefulWidget { + final AccountId? accountId; + final UserName? userName; final List presentationLocalEmailDrafts; + final OnEditLocalEmailDraftAction? onEditLocalEmailDraftAction; + final OnSaveAsDraftLocalEmailDraftAction? onSaveAsDraftLocalEmailDraftAction; const LocalEmailDraftListDialogBuilder({ super.key, + required this.accountId, + required this.userName, required this.presentationLocalEmailDrafts, + this.onEditLocalEmailDraftAction, + this.onSaveAsDraftLocalEmailDraftAction, }); @override @@ -33,17 +47,23 @@ class _LocalEmailDraftListDialogBuilderState late final ResponsiveUtils _responsiveUtils; late final ImagePaths _imagePaths; late final ScrollController _scrollController; + late final RemoveLocalEmailDraftInteractor? _removeLocalEmailDraftInteractor; + + final ValueNotifier> _listLocalEmailDraftsNotifier = ValueNotifier([]); @override void initState() { super.initState(); _responsiveUtils = Get.find(); _imagePaths = Get.find(); + _removeLocalEmailDraftInteractor = getBinding(); _scrollController = ScrollController(); + _listLocalEmailDraftsNotifier.value = widget.presentationLocalEmailDrafts; } @override void dispose() { + _listLocalEmailDraftsNotifier.dispose(); _scrollController.dispose(); super.dispose(); } @@ -103,19 +123,31 @@ class _LocalEmailDraftListDialogBuilderState scrollbars: false, ), scrollController: _scrollController, - child: ListView.builder( - itemCount: widget.presentationLocalEmailDrafts.length, - shrinkWrap: true, - controller: _scrollController, - primary: false, - itemBuilder: (_, index) { - final draftLocal = - widget.presentationLocalEmailDrafts[index]; - return LocalEmailDraftItemWidget( - draftLocal: draftLocal, - isOldest: index == widget.presentationLocalEmailDrafts.length - 1, - imagePaths: _imagePaths, - onSelectLocalEmailDraftAction: (draftLocal) {}, + child: ValueListenableBuilder( + valueListenable: _listLocalEmailDraftsNotifier, + builder: (context, localDrafts, _) { + log('_LocalEmailDraftListDialogBuilderState::build:_listLocalEmailDraftsNotifier:localDrafts = ${localDrafts.length}'); + return ListView.builder( + itemCount: localDrafts.length, + shrinkWrap: true, + controller: _scrollController, + primary: false, + itemBuilder: (_, index) { + final draftLocal = localDrafts[index]; + return LocalEmailDraftItemWidget( + draftLocal: draftLocal, + isOldest: index == localDrafts.length - 1, + imagePaths: _imagePaths, + onSelectLocalEmailDraftAction: widget.onEditLocalEmailDraftAction, + onEditLocalEmailDraftAction: widget.onEditLocalEmailDraftAction, + onSaveAsDraftLocalEmailDraftAction: widget.onSaveAsDraftLocalEmailDraftAction, + onDiscardLocalEmailDraftAction: (draftLocal) => + _handleDiscardLocalEmailDraftAction( + draftLocal, + AppLocalizations.of(context), + ) + ); + }, ); }, ), @@ -200,4 +232,37 @@ class _LocalEmailDraftListDialogBuilderState return double.infinity; } } + + void _handleDiscardLocalEmailDraftAction( + PresentationLocalEmailDraft emailDraft, + AppLocalizations appLocalizations, + ) { + Get.dialog( + PointerInterceptor(child: ConfirmationDialogBuilder( + imagePath: _imagePaths, + useIconAsBasicLogo: true, + textContent: appLocalizations.messageWarningDialogDiscardLocalDraft, + confirmText: appLocalizations.yes, + cancelText: appLocalizations.no, + cancelBackgroundButtonColor: AppColor.blue700, + cancelLabelButtonColor: Colors.white, + confirmBackgroundButtonColor: AppColor.grayBackgroundColor, + confirmLabelButtonColor: AppColor.steelGray600, + onConfirmButtonAction: () => removeLocalEmailDraft(emailDraft.id), + onCancelButtonAction: popBack, + onCloseButtonAction: popBack, + )), + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + ); + } + + void removeLocalEmailDraft(String draftLocalId) { + log('_LocalEmailDraftListDialogBuilderState::removeLocalEmailDraft:draftLocalId = $draftLocalId'); + popBack(); + + _listLocalEmailDraftsNotifier.value = List.from(_listLocalEmailDraftsNotifier.value) + ..removeWhere((draftLocal) => draftLocal.id == draftLocalId); + + _removeLocalEmailDraftInteractor?.execute(draftLocalId); + } } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index c72a560068..545af12446 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4905,5 +4905,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "messageWarningDialogDiscardLocalDraft": "Are you sure you want to delete this local draft? You will not be able to restore it.", + "@messageWarningDialogDiscardLocalDraft": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index ac27c80592..3bb1c946a0 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5181,4 +5181,11 @@ class AppLocalizations { name: 'discardAll', ); } + + String get messageWarningDialogDiscardLocalDraft { + return Intl.message( + 'Are you sure you want to delete this local draft? You will not be able to restore it.', + name: 'messageWarningDialogDiscardLocalDraft', + ); + } } diff --git a/model/lib/email/email_action_type.dart b/model/lib/email/email_action_type.dart index b56c6d057b..81ffb85d7a 100644 --- a/model/lib/email/email_action_type.dart +++ b/model/lib/email/email_action_type.dart @@ -17,7 +17,7 @@ enum EmailActionType { composeFromEmailAddress(), composeFromMailtoUri(), editAsNewEmail(4), - reopenComposerBrowser(), + composeFromLocalEmailDraft(), moveToTrash(3), deletePermanently(3), preview(), diff --git a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart index b91efe658b..3227d434fa 100644 --- a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart +++ b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart @@ -58,13 +58,10 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multipl import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart'; @@ -124,7 +121,6 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -184,8 +180,6 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -204,7 +198,6 @@ void main() { final deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); final markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); - final getEmailCacheOnWebInteractor = MockGetAllLocalEmailDraftInteractor(); final getIdentityCacheOnWebInteractor = MockGetIdentityCacheOnWebInteractor(); final markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); final markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); @@ -283,8 +276,6 @@ void main() { final verifyNameInteractor = MockVerifyNameInteractor(); final getAllMailboxInteractor = MockGetAllMailboxInteractor(); final refreshAllMailboxInteractor = MockRefreshAllMailboxInteractor(); - final removeAllLocalEmailDraftInteractor = MockRemoveAllLocalEmailDraftInteractor(); - final removeLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); final clearMailboxInteractor = MockClearMailboxInteractor(); final getAuthenticationInfoInteractor = MockGetAuthenticationInfoInteractor(); @@ -343,8 +334,6 @@ void main() { Get.put(updateAccountCacheInteractor); Get.put(getAllIdentitiesInteractor); Get.put(clearMailboxInteractor); - Get.put(removeAllLocalEmailDraftInteractor); - Get.put(removeLocalEmailDraftInteractor); Get.put(composerManager); Get.put(getAuthenticationInfoInteractor); Get.put(getStoredOidcConfigurationInteractor); @@ -362,7 +351,6 @@ void main() { moveToMailboxInteractor, deleteEmailPermanentlyInteractor, markAsMailboxReadInteractor, - getEmailCacheOnWebInteractor, getIdentityCacheOnWebInteractor, markAsEmailReadInteractor, markAsStarEmailInteractor, @@ -382,8 +370,6 @@ void main() { unsubscribeEmailInteractor, restoreDeletedMessageInteractor, getRestoredDeletedMessageInteractor, - removeAllLocalEmailDraftInteractor, - removeLocalEmailDraftInteractor, getAllIdentitiesInteractor, clearMailboxInteractor, storeEmailSortOrderInteractor, diff --git a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart index d08db51875..9c9921a3e9 100644 --- a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart +++ b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart @@ -56,13 +56,10 @@ import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.d import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; @@ -125,7 +122,6 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -184,8 +180,6 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -203,7 +197,6 @@ void main() { final moveToMailboxInteractor = MockMoveToMailboxInteractor(); final deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); final markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); - final getEmailCacheOnWebInteractor = MockGetAllLocalEmailDraftInteractor(); final getIdentityCacheOnWebInteractor = MockGetIdentityCacheOnWebInteractor(); final markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); final markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); @@ -269,8 +262,6 @@ void main() { final verifyNameInteractor = MockVerifyNameInteractor(); final getAllMailboxInteractor = MockGetAllMailboxInteractor(); final refreshAllMailboxInteractor = MockRefreshAllMailboxInteractor(); - final removeAllLocalEmailDraftInteractor = MockRemoveAllLocalEmailDraftInteractor(); - final removeLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); final clearMailboxInteractor = MockClearMailboxInteractor(); final composerManager = MockComposerManager(); @@ -339,8 +330,6 @@ void main() { Get.put(updateAccountCacheInteractor); Get.put(getAllIdentitiesInteractor); Get.put(clearMailboxInteractor); - Get.put(removeAllLocalEmailDraftInteractor); - Get.put(removeLocalEmailDraftInteractor); Get.put(composerManager); Get.put(getAuthenticationInfoInteractor); Get.put(getStoredOidcConfigurationInteractor); @@ -359,7 +348,6 @@ void main() { moveToMailboxInteractor, deleteEmailPermanentlyInteractor, markAsMailboxReadInteractor, - getEmailCacheOnWebInteractor, getIdentityCacheOnWebInteractor, markAsEmailReadInteractor, markAsStarEmailInteractor, @@ -379,8 +367,6 @@ void main() { unsubscribeEmailInteractor, restoreDeletedMessageInteractor, getRestoredDeletedMessageInteractor, - removeAllLocalEmailDraftInteractor, - removeLocalEmailDraftInteractor, getAllIdentitiesInteractor, clearMailboxInteractor, storeEmailSortOrderInteractor, diff --git a/test/features/search/verify_before_time_in_search_email_filter_test.dart b/test/features/search/verify_before_time_in_search_email_filter_test.dart index 2742e31b81..400e032dac 100644 --- a/test/features/search/verify_before_time_in_search_email_filter_test.dart +++ b/test/features/search/verify_before_time_in_search_email_filter_test.dart @@ -43,13 +43,10 @@ import 'package:tmail_ui_user/features/login/domain/usecases/get_token_oidc_inte import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cache_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/mark_as_mailbox_read_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; @@ -143,7 +140,6 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -160,8 +156,6 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), - MockSpec(), MockSpec(), MockSpec(fallbackGenerators: fallbackGenerators), MockSpec(), @@ -209,7 +203,6 @@ void main() { late MockMoveToMailboxInteractor moveToMailboxInteractor; late MockDeleteEmailPermanentlyInteractor deleteEmailPermanentlyInteractor; late MockMarkAsMailboxReadInteractor markAsMailboxReadInteractor; - late MockGetAllLocalEmailDraftInteractor getEmailCacheOnWebInteractor; late MockGetIdentityCacheOnWebInteractor getIdentityCacheOnWebInteractor; late MockMarkAsEmailReadInteractor markAsEmailReadInteractor; late MockMarkAsStarEmailInteractor markAsStarEmailInteractor; @@ -228,8 +221,6 @@ void main() { late MockUnsubscribeEmailInteractor unsubscribeEmailInteractor; late MockRestoredDeletedMessageInteractor restoreDeletedMessageInteractor; late MockGetRestoredDeletedMessageInterator getRestoredDeletedMessageInteractor; - late MockRemoveAllLocalEmailDraftInteractor removeAllLocalEmailDraftInteractor; - late MockRemoveLocalEmailDraftInteractor removeLocalEmailDraftInteractor; late MockGetAllIdentitiesInteractor getAllIdentitiesInteractor; late MockClearMailboxInteractor clearMailboxInteractor; late MockGetAuthenticationInfoInteractor getAuthenticationInfoInteractor; @@ -309,7 +300,6 @@ void main() { moveToMailboxInteractor = MockMoveToMailboxInteractor(); deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); - getEmailCacheOnWebInteractor = MockGetAllLocalEmailDraftInteractor(); getIdentityCacheOnWebInteractor = MockGetIdentityCacheOnWebInteractor(); markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); @@ -328,8 +318,6 @@ void main() { unsubscribeEmailInteractor = MockUnsubscribeEmailInteractor(); restoreDeletedMessageInteractor = MockRestoredDeletedMessageInteractor(); getRestoredDeletedMessageInteractor = MockGetRestoredDeletedMessageInterator(); - removeAllLocalEmailDraftInteractor = MockRemoveAllLocalEmailDraftInteractor(); - removeLocalEmailDraftInteractor = MockRemoveLocalEmailDraftInteractor(); getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); clearMailboxInteractor = MockClearMailboxInteractor(); getAuthenticationInfoInteractor = MockGetAuthenticationInfoInteractor(); @@ -361,7 +349,6 @@ void main() { moveToMailboxInteractor, deleteEmailPermanentlyInteractor, markAsMailboxReadInteractor, - getEmailCacheOnWebInteractor, getIdentityCacheOnWebInteractor, markAsEmailReadInteractor, markAsStarEmailInteractor, @@ -381,8 +368,6 @@ void main() { unsubscribeEmailInteractor, restoreDeletedMessageInteractor, getRestoredDeletedMessageInteractor, - removeAllLocalEmailDraftInteractor, - removeLocalEmailDraftInteractor, getAllIdentitiesInteractor, clearMailboxInteractor, mockStoreEmailSortOrderInteractor, From e21a2eca06a2812c8bf96d408541666511ac5bbd Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 25 Mar 2025 23:01:44 +0700 Subject: [PATCH 05/11] TF-3358 Handle `Save as draft` each local email draft item --- ...w_and_save_email_to_drafts_interactor.dart | 3 +- .../presentation/composer_controller.dart | 7 +- .../handle_local_email_draft_extension.dart | 4 - .../handle_message_failure_mixin.dart} | 3 +- .../model/create_email_request.dart | 31 +++- .../bindings/mailbox_dashboard_bindings.dart | 34 +++++ .../mailbox_dashboard_controller.dart | 4 + .../restore_local_email_draft_extension.dart | 12 +- ...local_email_draft_list_dialog_builder.dart | 138 +++++++++++++++--- lib/l10n/intl_messages.arb | 6 + lib/main/localizations/app_localizations.dart | 7 + 11 files changed, 213 insertions(+), 36 deletions(-) rename lib/features/composer/presentation/{extensions/handle_message_failure_extension.dart => mixin/handle_message_failure_mixin.dart} (90%) diff --git a/lib/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart b/lib/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart index 35d9bc56ab..b3706b9e9e 100644 --- a/lib/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart +++ b/lib/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart @@ -30,7 +30,8 @@ class CreateNewAndSaveEmailToDraftsInteractor { try { yield dartz.Right(GenerateEmailLoading()); - final emailCreated = await _createEmailObject(createEmailRequest); + final emailCreated = createEmailRequest.emailCreated + ?? await _createEmailObject(createEmailRequest); if (emailCreated != null) { if (createEmailRequest.draftsEmailId == null) { diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index a812420228..506bcde105 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -62,7 +62,6 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/get_draf import 'package:tmail_ui_user/features/composer/presentation/extensions/get_outbox_mailbox_id_for_composer_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/get_sent_mailbox_id_for_composer_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_local_email_draft_extension.dart'; -import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_message_failure_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/list_identities_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/sanitize_signature_in_email_content_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/setup_email_attachments_extension.dart'; @@ -77,6 +76,7 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/setup_li import 'package:tmail_ui_user/features/composer/presentation/extensions/setup_selected_identity_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/update_screen_display_mode_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/mixin/drag_drog_file_mixin.dart'; +import 'package:tmail_ui_user/features/composer/presentation/mixin/handle_message_failure_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart'; @@ -127,7 +127,10 @@ import 'package:tmail_ui_user/main/universal_import/html_stub.dart' as html; import 'package:tmail_ui_user/main/utils/app_config.dart'; class ComposerController extends BaseController - with DragDropFileMixin, AutoCompleteResultMixin, EditorViewMixin + with DragDropFileMixin, + AutoCompleteResultMixin, + EditorViewMixin, + HandleMessageFailureMixin implements BeforeReconnectHandler { final mailboxDashBoardController = Get.find(); diff --git a/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart index bb82dcdc8e..73de4feeda 100644 --- a/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart +++ b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart @@ -2,8 +2,6 @@ import 'package:core/utils/app_logger.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/auto_create_tag_for_recipients_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/get_draft_mailbox_id_for_composer_extension.dart'; -import 'package:tmail_ui_user/features/composer/presentation/extensions/get_outbox_mailbox_id_for_composer_extension.dart'; -import 'package:tmail_ui_user/features/composer/presentation/extensions/get_sent_mailbox_id_for_composer_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; extension HandleLocalEmailDraftExtension on ComposerController { @@ -42,8 +40,6 @@ extension HandleLocalEmailDraftExtension on ComposerController { identity: identitySelected.value, attachments: uploadController.attachmentsUploaded, inlineAttachments: uploadController.mapInlineAttachments, - outboxMailboxId: getOutboxMailboxIdForComposer(), - sentMailboxId: getSentMailboxIdForComposer(), draftsMailboxId: getDraftMailboxIdForComposer(), draftsEmailId: getDraftEmailId(), answerForwardEmailId: arguments.presentationEmail?.id, diff --git a/lib/features/composer/presentation/extensions/handle_message_failure_extension.dart b/lib/features/composer/presentation/mixin/handle_message_failure_mixin.dart similarity index 90% rename from lib/features/composer/presentation/extensions/handle_message_failure_extension.dart rename to lib/features/composer/presentation/mixin/handle_message_failure_mixin.dart index 9c2b2fb912..2bc66e921d 100644 --- a/lib/features/composer/presentation/extensions/handle_message_failure_extension.dart +++ b/lib/features/composer/presentation/mixin/handle_message_failure_mixin.dart @@ -2,11 +2,10 @@ import 'package:jmap_dart_client/jmap/core/error/error_type.dart'; import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart'; -import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -extension HandleMessageFailureExtension on ComposerController { +mixin HandleMessageFailureMixin { ({String message, ErrorType? errorType}) getMessageFailure({ required AppLocalizations appLocalizations, diff --git a/lib/features/composer/presentation/model/create_email_request.dart b/lib/features/composer/presentation/model/create_email_request.dart index b21069b32e..e5506ff83e 100644 --- a/lib/features/composer/presentation/model/create_email_request.dart +++ b/lib/features/composer/presentation/model/create_email_request.dart @@ -9,6 +9,7 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/attachment.dart'; import 'package:model/email/email_action_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart'; class CreateEmailRequest with EquatableMixin { @@ -47,14 +48,15 @@ class CreateEmailRequest with EquatableMixin { final int? savedDraftHash; final EmailActionType? savedActionType; final EmailId? savedEmailDraftId; + final Email? emailCreated; CreateEmailRequest({ required this.session, required this.accountId, required this.emailActionType, required this.ownEmailAddress, - required this.subject, - required this.emailContent, + this.subject = '', + this.emailContent = '', this.fromSender, this.toRecipients, this.ccRecipients, @@ -83,8 +85,32 @@ class CreateEmailRequest with EquatableMixin { this.savedDraftHash, this.savedActionType, this.savedEmailDraftId, + this.emailCreated, }); + factory CreateEmailRequest.fromLocalEmailDraft({ + required Session session, + required AccountId accountId, + required String ownEmailAddress, + required PresentationLocalEmailDraft draftLocal, + }) { + return CreateEmailRequest( + session: session, + accountId: accountId, + ownEmailAddress: ownEmailAddress, + emailActionType: EmailActionType.composeFromLocalEmailDraft, + emailCreated: draftLocal.email, + hasRequestReadReceipt: draftLocal.hasRequestReadReceipt ?? false, + isMarkAsImportant: draftLocal.isMarkAsImportant ?? false, + displayMode: draftLocal.displayMode, + composerId: draftLocal.composerId, + composerIndex: draftLocal.composerIndex, + savedDraftHash: draftLocal.draftHash, + savedActionType: draftLocal.actionType, + savedEmailDraftId: draftLocal.draftEmailId, + ); + } + @override List get props => [ session, @@ -121,5 +147,6 @@ class CreateEmailRequest with EquatableMixin { savedDraftHash, savedActionType, savedEmailDraftId, + emailCreated, ]; } \ No newline at end of file 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 e19a80abda..b39892909e 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -1,6 +1,8 @@ import 'package:core/data/model/source_type/data_source_type.dart'; +import 'package:core/data/network/download/download_client.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/html_transformer/html_transform.dart'; +import 'package:core/utils/application_manager.dart'; import 'package:core/utils/config/app_config_loader.dart'; import 'package:core/utils/file_utils.dart'; import 'package:core/utils/preview_eml_file_utils.dart'; @@ -12,8 +14,13 @@ import 'package:tmail_ui_user/features/caching/utils/local_storage_manager.dart' import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dart'; import 'package:tmail_ui_user/features/cleanup/data/local/recent_search_cache_manager.dart'; import 'package:tmail_ui_user/features/cleanup/presentation/cleanup_bindings.dart'; +import 'package:tmail_ui_user/features/composer/data/datasource/composer_datasource.dart'; +import 'package:tmail_ui_user/features/composer/data/datasource_impl/composer_datasource_impl.dart'; +import 'package:tmail_ui_user/features/composer/data/repository/composer_repository_impl.dart'; import 'package:tmail_ui_user/features/composer/data/repository/contact_repository_impl.dart'; +import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart'; import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart'; import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; @@ -144,9 +151,13 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_inter import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_bindings.dart'; import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_bindings.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'; +import 'package:tmail_ui_user/features/upload/data/network/file_uploader.dart'; import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart'; +import 'package:uuid/uuid.dart'; class MailboxDashBoardBindings extends BaseBindings { @@ -231,6 +242,8 @@ class MailboxDashBoardBindings extends BaseBindings { () => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -316,6 +329,15 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), )); + Get.lazyPut(() => AttachmentUploadDataSourceImpl( + Get.find(), + Get.find(), + Get.find(), + )); + Get.lazyPut(() => ComposerDataSourceImpl( + Get.find(), + Get.find(), + )); } @override @@ -369,6 +391,10 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find() )); Get.lazyPut(() => ClearMailboxInteractor(Get.find())); + Get.lazyPut(() => CreateNewAndSaveEmailToDraftsInteractor( + Get.find(), + Get.find(), + )); IdentityInteractorsBindings().dependencies(); Get.lazyPut(() => GetAllIdentitiesInteractor( @@ -394,6 +420,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -446,5 +473,12 @@ class MailboxDashBoardBindings extends BaseBindings { DataSourceType.network: Get.find(), DataSourceType.local: Get.find() },)); + Get.lazyPut(() => ComposerRepositoryImpl( + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + )); } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 0fa11582ac..6a41e2c930 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -40,6 +40,7 @@ import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_st import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; @@ -260,6 +261,7 @@ class MailboxDashBoardController extends ReloadableController SaveLanguageInteractor? saveLanguageInteractor; GetAllLocalEmailDraftInteractor? getAllLocalEmailDraftInteractor; RemoveAllLocalEmailDraftInteractor? removeAllLocalEmailDraftInteractor; + CreateNewAndSaveEmailToDraftsInteractor? createNewAndSaveEmailToDraftsInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -373,6 +375,8 @@ class MailboxDashBoardController extends ReloadableController twakeAppManager.setExecutingBeforeReconnect(false); isRetryGetPaywallUrl = false; getAllLocalEmailDraftInteractor = getBinding(); + removeAllLocalEmailDraftInteractor = getBinding(); + createNewAndSaveEmailToDraftsInteractor = getBinding(); } if (PlatformInfo.isIOS) { _registerPendingCurrentEmailIdInNotification(); diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart index f8807b54f0..19a7638520 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -17,7 +17,9 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { void restoreLocalEmailDraft() { if (accountId.value == null || sessionCurrent == null || - getAllLocalEmailDraftInteractor == null) return; + getAllLocalEmailDraftInteractor == null) { + return; + } consumeState(getAllLocalEmailDraftInteractor!.execute( accountId.value!, @@ -40,10 +42,10 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { PointerInterceptor( child: LocalEmailDraftListDialogBuilder( accountId: accountId.value, - userName: sessionCurrent?.username, + session: sessionCurrent, + ownEmailAddress: ownEmailAddress.value, presentationLocalEmailDrafts: presentationLocalEmailDrafts, onEditLocalEmailDraftAction: _editLocalEmailDraft, - onSaveAsDraftLocalEmailDraftAction: _saveAsDraftLocalEmailDraft, ), ), barrierColor: AppColor.colorDefaultCupertinoActionSheet, @@ -56,8 +58,4 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { draftLocal.copyWith(displayMode: ScreenDisplayMode.normal), )); } - - void _saveAsDraftLocalEmailDraft(PresentationLocalEmailDraft draftLocal) { - popBack(); - } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart index 7dd4df4a96..e4b01f3338 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -2,16 +2,24 @@ import 'dart:ui'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:core/utils/app_logger.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:get/get.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/core/session/session.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; +import 'package:tmail_ui_user/features/composer/domain/exceptions/compose_email_exception.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/mixin/handle_message_failure_mixin.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/saving_message_dialog_view.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart'; @@ -20,18 +28,18 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class LocalEmailDraftListDialogBuilder extends StatefulWidget { final AccountId? accountId; - final UserName? userName; + final Session? session; + final String ownEmailAddress; final List presentationLocalEmailDrafts; final OnEditLocalEmailDraftAction? onEditLocalEmailDraftAction; - final OnSaveAsDraftLocalEmailDraftAction? onSaveAsDraftLocalEmailDraftAction; const LocalEmailDraftListDialogBuilder({ super.key, required this.accountId, - required this.userName, + required this.session, + required this.ownEmailAddress, required this.presentationLocalEmailDrafts, this.onEditLocalEmailDraftAction, - this.onSaveAsDraftLocalEmailDraftAction, }); @override @@ -40,14 +48,17 @@ class LocalEmailDraftListDialogBuilder extends StatefulWidget { } class _LocalEmailDraftListDialogBuilderState - extends State { + extends State + with HandleMessageFailureMixin { static const double _maxHeight = 656.0; static const double _maxWidth = 556.0; late final ResponsiveUtils _responsiveUtils; late final ImagePaths _imagePaths; + late final AppToast _appToast; late final ScrollController _scrollController; late final RemoveLocalEmailDraftInteractor? _removeLocalEmailDraftInteractor; + late final CreateNewAndSaveEmailToDraftsInteractor? _createNewAndSaveEmailToDraftsInteractor; final ValueNotifier> _listLocalEmailDraftsNotifier = ValueNotifier([]); @@ -56,7 +67,9 @@ class _LocalEmailDraftListDialogBuilderState super.initState(); _responsiveUtils = Get.find(); _imagePaths = Get.find(); + _appToast = Get.find(); _removeLocalEmailDraftInteractor = getBinding(); + _createNewAndSaveEmailToDraftsInteractor = getBinding(); _scrollController = ScrollController(); _listLocalEmailDraftsNotifier.value = widget.presentationLocalEmailDrafts; } @@ -140,12 +153,10 @@ class _LocalEmailDraftListDialogBuilderState imagePaths: _imagePaths, onSelectLocalEmailDraftAction: widget.onEditLocalEmailDraftAction, onEditLocalEmailDraftAction: widget.onEditLocalEmailDraftAction, - onSaveAsDraftLocalEmailDraftAction: widget.onSaveAsDraftLocalEmailDraftAction, + onSaveAsDraftLocalEmailDraftAction: (draftLocal) => + _saveAsDraftLocalEmailDraft(draftLocal, context), onDiscardLocalEmailDraftAction: (draftLocal) => - _handleDiscardLocalEmailDraftAction( - draftLocal, - AppLocalizations.of(context), - ) + _handleDiscardLocalEmailDraftAction(draftLocal, context) ); }, ); @@ -235,8 +246,9 @@ class _LocalEmailDraftListDialogBuilderState void _handleDiscardLocalEmailDraftAction( PresentationLocalEmailDraft emailDraft, - AppLocalizations appLocalizations, + BuildContext context, ) { + final appLocalizations = AppLocalizations.of(context); Get.dialog( PointerInterceptor(child: ConfirmationDialogBuilder( imagePath: _imagePaths, @@ -248,7 +260,10 @@ class _LocalEmailDraftListDialogBuilderState cancelLabelButtonColor: Colors.white, confirmBackgroundButtonColor: AppColor.grayBackgroundColor, confirmLabelButtonColor: AppColor.steelGray600, - onConfirmButtonAction: () => removeLocalEmailDraft(emailDraft.id), + onConfirmButtonAction: () { + popBack(); + removeLocalEmailDraft(context, emailDraft.id); + }, onCancelButtonAction: popBack, onCloseButtonAction: popBack, )), @@ -256,13 +271,100 @@ class _LocalEmailDraftListDialogBuilderState ); } - void removeLocalEmailDraft(String draftLocalId) { - log('_LocalEmailDraftListDialogBuilderState::removeLocalEmailDraft:draftLocalId = $draftLocalId'); - popBack(); - + Future removeLocalEmailDraft(BuildContext context, String draftLocalId) async { _listLocalEmailDraftsNotifier.value = List.from(_listLocalEmailDraftsNotifier.value) ..removeWhere((draftLocal) => draftLocal.id == draftLocalId); - _removeLocalEmailDraftInteractor?.execute(draftLocalId); + await _removeLocalEmailDraftInteractor?.execute(draftLocalId); + + if (context.mounted) { + _appToast.showToastSuccessMessage( + context, + AppLocalizations.of(context).deleteLocalDraftSuccessfully, + ); + } + + if (_listLocalEmailDraftsNotifier.value.isEmpty) { + popBack(); + } + } + + Future _saveAsDraftLocalEmailDraft( + PresentationLocalEmailDraft draftLocal, + BuildContext context, + ) async { + if (widget.accountId == null || + widget.session == null || + _createNewAndSaveEmailToDraftsInteractor == null) { + return; + } + + final resultState = await _showSavingMessageToDraftsDialog( + session: widget.session!, + accountId: widget.accountId!, + ownEmailAddress: widget.ownEmailAddress, + draftLocal: draftLocal, + createNewAndSaveEmailToDraftsInteractor: _createNewAndSaveEmailToDraftsInteractor!, + cancelToken: CancelToken(), + ); + + if (!context.mounted) return; + + if (resultState is SaveEmailAsDraftsSuccess) { + _appToast.showToastSuccessMessage( + context, + AppLocalizations.of(context).drafts_saved, + leadingSVGIcon: _imagePaths.icMailboxDrafts, + leadingSVGIconColor: Colors.white, + ); + + removeLocalEmailDraft(context, draftLocal.id); + } else if (resultState is SaveEmailAsDraftsFailure) { + final errorMessage = getMessageFailure( + appLocalizations: AppLocalizations.of(context), + exception: resultState.exception, + isDraft: true, + ); + + _appToast.showToastErrorMessage( + context, + errorMessage.message, + leadingSVGIcon: _imagePaths.icMailboxDrafts, + leadingSVGIconColor: Colors.white, + ); + } + } + + Future _showSavingMessageToDraftsDialog({ + required Session session, + required AccountId accountId, + required String ownEmailAddress, + required PresentationLocalEmailDraft draftLocal, + required CreateNewAndSaveEmailToDraftsInteractor createNewAndSaveEmailToDraftsInteractor, + CancelToken? cancelToken, + }) { + final childWidget = PointerInterceptor( + child: SavingMessageDialogView( + createEmailRequest: CreateEmailRequest.fromLocalEmailDraft( + session: session, + accountId: accountId, + ownEmailAddress: ownEmailAddress, + draftLocal: draftLocal, + ), + createNewAndSaveEmailToDraftsInteractor: createNewAndSaveEmailToDraftsInteractor, + onCancelSavingEmailToDraftsAction: _handleCancelSavingMessageToDrafts, + cancelToken: cancelToken, + ), + ); + + return Get.dialog( + childWidget, + barrierDismissible: false, + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + ); + } + + void _handleCancelSavingMessageToDrafts({CancelToken? cancelToken}) { + cancelToken?.cancel([SavingEmailToDraftsCanceledException()]); } } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 545af12446..f8bf6aa063 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4911,5 +4911,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "deleteLocalDraftSuccessfully": "Delete local draft successfully", + "@deleteLocalDraftSuccessfully": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 3bb1c946a0..ddd5c535f0 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5188,4 +5188,11 @@ class AppLocalizations { name: 'messageWarningDialogDiscardLocalDraft', ); } + + String get deleteLocalDraftSuccessfully { + return Intl.message( + 'Delete local draft successfully', + name: 'deleteLocalDraftSuccessfully', + ); + } } From d1b56e450eae293ec16068745eb932d57f2d8b64 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 25 Mar 2025 23:47:36 +0700 Subject: [PATCH 06/11] TF-3358 Handle `Discard all` local email draft list --- .../local_email_draft_datasource.dart | 2 +- .../local_email_draft_datasource_impl.dart | 16 +---- .../data/local/local_email_draft_manager.dart | 5 ++ .../local_email_draft_repository_impl.dart | 4 +- .../local_email_draft_repository.dart | 2 +- .../remove_all_local_email_draft_state.dart | 9 +++ ...rt => remove_local_email_draft_state.dart} | 8 +-- ...ve_all_local_email_drafts_interactor.dart} | 12 ++-- .../remove_local_email_draft_interactor.dart | 2 +- .../bindings/mailbox_dashboard_bindings.dart | 4 +- .../mailbox_dashboard_controller.dart | 15 ----- .../restore_local_email_draft_extension.dart | 5 +- ...local_email_draft_list_dialog_builder.dart | 60 +++++++++++++++++-- lib/l10n/intl_messages.arb | 16 ++++- lib/main/localizations/app_localizations.dart | 20 ++++++- 15 files changed, 121 insertions(+), 59 deletions(-) create mode 100644 lib/features/mailbox_dashboard/domain/state/remove_all_local_email_draft_state.dart rename lib/features/mailbox_dashboard/domain/state/{remove_composer_cache_state.dart => remove_local_email_draft_state.dart} (65%) rename lib/features/mailbox_dashboard/domain/usecases/{remove_all_local_email_draft_interactor.dart => remove_all_local_email_drafts_interactor.dart} (63%) diff --git a/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart index 6a7cf984f0..79afe5ced2 100644 --- a/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart +++ b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart @@ -10,7 +10,7 @@ abstract class LocalEmailDraftDatasource { AccountId accountId, UserName userName); - Future removeAllLocalEmailDraft( + Future removeAllLocalEmailDrafts( AccountId accountId, UserName userName, ); diff --git a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart index 9c984f29ef..03149b7333 100644 --- a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart +++ b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart @@ -2,16 +2,12 @@ import 'package:core/presentation/utils/html_transformer/html_transform.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; -import 'package:model/email/email_action_type.dart'; -import 'package:model/extensions/account_id_extensions.dart'; -import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_manager.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_email_draft_worker_queue.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; import 'package:tmail_ui_user/features/offline_mode/hive_worker/hive_task.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; -import 'package:universal_html/html.dart' as html; class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { @@ -64,15 +60,9 @@ class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { } @override - Future removeAllLocalEmailDraft(AccountId accountId, UserName userName) { - return Future.sync(() { - final keyWithIdentity = TupleKey( - EmailActionType.composeFromLocalEmailDraft.name, - accountId.asString, - userName.value, - ).toString(); - - html.window.sessionStorage.removeWhere((key, value) => key.startsWith(keyWithIdentity)); + Future removeAllLocalEmailDrafts(AccountId accountId, UserName userName) { + return Future.sync(() async { + return await _localEmailDraftManager.removeAllLocalEmailDrafts(accountId, userName); }).catchError(_exceptionThrower.throwException); } diff --git a/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart index 0c3efa64c4..05747ee95e 100644 --- a/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart +++ b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart @@ -34,4 +34,9 @@ class LocalEmailDraftManager { Future removeLocalEmailDraft(String id) async { await _localEmailDraftClient.deleteItem(id); } + + Future removeAllLocalEmailDrafts(AccountId accountId, UserName userName) async { + final nestedKey = TupleKey(accountId.asString, userName.value).encodeKey; + await _localEmailDraftClient.clearAllDataContainKey(nestedKey); + } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart index 002fb89d63..86a970d2ae 100644 --- a/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart +++ b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart @@ -20,8 +20,8 @@ class LocalEmailDraftRepositoryImpl extends LocalEmailDraftRepository { } @override - Future removeAllLocalEmailDraft(AccountId accountId, UserName userName) { - return _localEmailDraftDatasource.removeAllLocalEmailDraft(accountId, userName); + Future removeAllLocalEmailDrafts(AccountId accountId, UserName userName) { + return _localEmailDraftDatasource.removeAllLocalEmailDrafts(accountId, userName); } @override diff --git a/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart index 89eac52e75..b11ddc5f1b 100644 --- a/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart +++ b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart @@ -10,7 +10,7 @@ abstract class LocalEmailDraftRepository { AccountId accountId, UserName userName); - Future removeAllLocalEmailDraft( + Future removeAllLocalEmailDrafts( AccountId accountId, UserName userName, ); diff --git a/lib/features/mailbox_dashboard/domain/state/remove_all_local_email_draft_state.dart b/lib/features/mailbox_dashboard/domain/state/remove_all_local_email_draft_state.dart new file mode 100644 index 0000000000..3b80b2ce00 --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/state/remove_all_local_email_draft_state.dart @@ -0,0 +1,9 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; + +class RemoveAllLocalEmailDraftsSuccess extends UIState {} + +class RemoveAllLocalEmailDraftsFailure extends FeatureFailure { + + RemoveAllLocalEmailDraftsFailure(dynamic exception) : super(exception: exception); +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart b/lib/features/mailbox_dashboard/domain/state/remove_local_email_draft_state.dart similarity index 65% rename from lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart rename to lib/features/mailbox_dashboard/domain/state/remove_local_email_draft_state.dart index f12941d16d..a80c261dc3 100644 --- a/lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart +++ b/lib/features/mailbox_dashboard/domain/state/remove_local_email_draft_state.dart @@ -1,13 +1,7 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; -class RemoveLocalEmailDraftSuccess extends UIState { - - RemoveLocalEmailDraftSuccess(); - - @override - List get props => []; -} +class RemoveLocalEmailDraftSuccess extends UIState {} class RemoveLocalEmailDraftFailure extends FeatureFailure { diff --git a/lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_drafts_interactor.dart similarity index 63% rename from lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart rename to lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_drafts_interactor.dart index bda2a36089..c4677a702a 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_all_local_email_drafts_interactor.dart @@ -4,19 +4,19 @@ import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_all_local_email_draft_state.dart'; -class RemoveAllLocalEmailDraftInteractor { +class RemoveAllLocalEmailDraftsInteractor { final LocalEmailDraftRepository _localEmailDraftRepository; - RemoveAllLocalEmailDraftInteractor(this._localEmailDraftRepository); + RemoveAllLocalEmailDraftsInteractor(this._localEmailDraftRepository); Future> execute(AccountId accountId, UserName userName) async { try { - _localEmailDraftRepository.removeAllLocalEmailDraft(accountId, userName); - return Right(RemoveLocalEmailDraftSuccess()); + await _localEmailDraftRepository.removeAllLocalEmailDrafts(accountId, userName); + return Right(RemoveAllLocalEmailDraftsSuccess()); } catch (exception) { - return Left(RemoveLocalEmailDraftFailure(exception)); + return Left(RemoveAllLocalEmailDraftsFailure(exception)); } } } diff --git a/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart index ed4c569523..a09fd5a3e3 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart @@ -2,7 +2,7 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_local_email_draft_state.dart'; class RemoveLocalEmailDraftInteractor { final LocalEmailDraftRepository _localEmailDraftRepository; 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 b39892909e..bde29fc43a 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -95,7 +95,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spa import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spam_report_state_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; @@ -356,7 +356,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => MarkAsMailboxReadInteractor(Get.find())); Get.lazyPut(() => GetAllLocalEmailDraftInteractor(Get.find())); Get.lazyPut(() => RemoveLocalEmailDraftInteractor(Get.find())); - Get.lazyPut(() => RemoveAllLocalEmailDraftInteractor(Get.find())); + Get.lazyPut(() => RemoveAllLocalEmailDraftsInteractor(Get.find())); Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find())); Get.lazyPut(() => MarkAsStarEmailInteractor(Get.find())); Get.lazyPut(() => MarkAsMultipleEmailReadInteractor( diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 6a41e2c930..b32520db44 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -40,7 +40,6 @@ import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_st import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; -import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; @@ -105,7 +104,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_lo import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; @@ -260,8 +258,6 @@ class MailboxDashBoardController extends ReloadableController CreateNewEmailRuleFilterInteractor? createNewEmailRuleFilterInteractor; SaveLanguageInteractor? saveLanguageInteractor; GetAllLocalEmailDraftInteractor? getAllLocalEmailDraftInteractor; - RemoveAllLocalEmailDraftInteractor? removeAllLocalEmailDraftInteractor; - CreateNewAndSaveEmailToDraftsInteractor? createNewAndSaveEmailToDraftsInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -375,8 +371,6 @@ class MailboxDashBoardController extends ReloadableController twakeAppManager.setExecutingBeforeReconnect(false); isRetryGetPaywallUrl = false; getAllLocalEmailDraftInteractor = getBinding(); - removeAllLocalEmailDraftInteractor = getBinding(); - createNewAndSaveEmailToDraftsInteractor = getBinding(); } if (PlatformInfo.isIOS) { _registerPendingCurrentEmailIdInNotification(); @@ -3197,15 +3191,6 @@ class MailboxDashBoardController extends ReloadableController isRecoveringDeletedMessage.value = true; } - Future removeAllLocalEmailDraft() async { - if (accountId.value == null || sessionCurrent == null) return; - - await removeAllLocalEmailDraftInteractor?.execute( - accountId.value!, - sessionCurrent!.username, - ); - } - bool validateSendingEmailFailedWhenNetworkIsLostOnMobile(dynamic failure) { return failure is SendEmailFailure && failure.exception is NoNetworkError && diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart index 19a7638520..2029a2e208 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -5,6 +5,7 @@ import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; @@ -15,13 +16,15 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { void restoreLocalEmailDraft() { + final getAllLocalEmailDraftInteractor = getBinding(); + if (accountId.value == null || sessionCurrent == null || getAllLocalEmailDraftInteractor == null) { return; } - consumeState(getAllLocalEmailDraftInteractor!.execute( + consumeState(getAllLocalEmailDraftInteractor.execute( accountId.value!, sessionCurrent!.username, )); diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart index e4b01f3338..a4a408cad6 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -9,6 +9,7 @@ import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart' import 'package:core/utils/app_logger.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; @@ -20,6 +21,7 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_s import 'package:tmail_ui_user/features/composer/presentation/mixin/handle_message_failure_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/saving_message_dialog_view.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_all_local_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart'; @@ -59,6 +61,7 @@ class _LocalEmailDraftListDialogBuilderState late final ScrollController _scrollController; late final RemoveLocalEmailDraftInteractor? _removeLocalEmailDraftInteractor; late final CreateNewAndSaveEmailToDraftsInteractor? _createNewAndSaveEmailToDraftsInteractor; + late final RemoveAllLocalEmailDraftsInteractor? _removeAllLocalEmailDraftsInteractor; final ValueNotifier> _listLocalEmailDraftsNotifier = ValueNotifier([]); @@ -70,6 +73,7 @@ class _LocalEmailDraftListDialogBuilderState _appToast = Get.find(); _removeLocalEmailDraftInteractor = getBinding(); _createNewAndSaveEmailToDraftsInteractor = getBinding(); + _removeAllLocalEmailDraftsInteractor = getBinding(); _scrollController = ScrollController(); _listLocalEmailDraftsNotifier.value = widget.presentationLocalEmailDrafts; } @@ -78,6 +82,7 @@ class _LocalEmailDraftListDialogBuilderState void dispose() { _listLocalEmailDraftsNotifier.dispose(); _scrollController.dispose(); + if (SmartDialog.checkExist()) SmartDialog.dismiss(); super.dispose(); } @@ -181,10 +186,10 @@ class _LocalEmailDraftListDialogBuilderState borderRadius: 10, margin: const EdgeInsetsDirectional.only(end: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), - onTapActionCallback: () {}, + onTapActionCallback: () => _handleDiscardAllLocalEmailDraftAction(context), ), TMailButtonWidget( - text: AppLocalizations.of(context).openAll, + text: AppLocalizations.of(context).restoreAll, backgroundColor: AppColor.blue700, textStyle: Theme.of(context) .textTheme @@ -262,7 +267,7 @@ class _LocalEmailDraftListDialogBuilderState confirmLabelButtonColor: AppColor.steelGray600, onConfirmButtonAction: () { popBack(); - removeLocalEmailDraft(context, emailDraft.id); + _removeLocalEmailDraft(context, emailDraft.id); }, onCancelButtonAction: popBack, onCloseButtonAction: popBack, @@ -271,7 +276,7 @@ class _LocalEmailDraftListDialogBuilderState ); } - Future removeLocalEmailDraft(BuildContext context, String draftLocalId) async { + Future _removeLocalEmailDraft(BuildContext context, String draftLocalId) async { _listLocalEmailDraftsNotifier.value = List.from(_listLocalEmailDraftsNotifier.value) ..removeWhere((draftLocal) => draftLocal.id == draftLocalId); @@ -318,7 +323,7 @@ class _LocalEmailDraftListDialogBuilderState leadingSVGIconColor: Colors.white, ); - removeLocalEmailDraft(context, draftLocal.id); + _removeLocalEmailDraft(context, draftLocal.id); } else if (resultState is SaveEmailAsDraftsFailure) { final errorMessage = getMessageFailure( appLocalizations: AppLocalizations.of(context), @@ -367,4 +372,49 @@ class _LocalEmailDraftListDialogBuilderState void _handleCancelSavingMessageToDrafts({CancelToken? cancelToken}) { cancelToken?.cancel([SavingEmailToDraftsCanceledException()]); } + + void _handleDiscardAllLocalEmailDraftAction(BuildContext context) { + final appLocalizations = AppLocalizations.of(context); + Get.dialog( + PointerInterceptor(child: ConfirmationDialogBuilder( + imagePath: _imagePaths, + useIconAsBasicLogo: true, + textContent: appLocalizations.messageWarningDialogDiscardAllLocalDrafts, + confirmText: appLocalizations.yes, + cancelText: appLocalizations.no, + cancelBackgroundButtonColor: AppColor.blue700, + cancelLabelButtonColor: Colors.white, + confirmBackgroundButtonColor: AppColor.grayBackgroundColor, + confirmLabelButtonColor: AppColor.steelGray600, + onConfirmButtonAction: () { + popBack(); + _removeAllLocalEmailDrafts(context); + }, + onCancelButtonAction: popBack, + onCloseButtonAction: popBack, + )), + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + ); + } + + Future _removeAllLocalEmailDrafts(BuildContext context) async { + if (widget.accountId == null || + widget.session == null || + _removeAllLocalEmailDraftsInteractor == null) { + return; + } + + SmartDialog.showLoading( + msg: AppLocalizations.of(context).deletingLocalDraft, + ); + _listLocalEmailDraftsNotifier.value = []; + + await _removeAllLocalEmailDraftsInteractor!.execute( + widget.accountId!, + widget.session!.username, + ); + + SmartDialog.dismiss(); + popBack(); + } } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index f8bf6aa063..11278d068a 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4894,8 +4894,8 @@ "placeholders_order": [], "placeholders": {} }, - "openAll": "Open all", - "@openAll": { + "restoreAll": "Restore all", + "@restoreAll": { "type": "text", "placeholders_order": [], "placeholders": {} @@ -4917,5 +4917,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "messageWarningDialogDiscardAllLocalDrafts": "Are you sure you want to delete all local drafts? They cannot be restored.", + "@messageWarningDialogDiscardAllLocalDrafts": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "deletingLocalDraft": "Deleting local draft...", + "@deletingLocalDraft": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index ddd5c535f0..eba9d66737 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5168,10 +5168,10 @@ class AppLocalizations { ); } - String get openAll { + String get restoreAll { return Intl.message( - 'Open all', - name: 'openAll', + 'Restore all', + name: 'restoreAll', ); } @@ -5195,4 +5195,18 @@ class AppLocalizations { name: 'deleteLocalDraftSuccessfully', ); } + + String get messageWarningDialogDiscardAllLocalDrafts { + return Intl.message( + 'Are you sure you want to delete all local drafts? They cannot be restored.', + name: 'messageWarningDialogDiscardAllLocalDrafts', + ); + } + + String get deletingLocalDraft { + return Intl.message( + 'Deleting local draft...', + name: 'deletingLocalDraft', + ); + } } From 7515dbd051e6a610e17c8dd593e0bc86892119f4 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 26 Mar 2025 00:02:41 +0700 Subject: [PATCH 07/11] TF-3358 Handle `Restore all` local email draft list Signed-off-by: dab246 --- .../restore_local_email_draft_extension.dart | 11 +++++++++++ .../local_email_draft_list_dialog_builder.dart | 11 ++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart index 2029a2e208..1f9761b36d 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -49,6 +49,7 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { ownEmailAddress: ownEmailAddress.value, presentationLocalEmailDrafts: presentationLocalEmailDrafts, onEditLocalEmailDraftAction: _editLocalEmailDraft, + onRestoreAllLocalEmailDraftsAction: _restoreAllLocalEmailDrafts, ), ), barrierColor: AppColor.colorDefaultCupertinoActionSheet, @@ -61,4 +62,14 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { draftLocal.copyWith(displayMode: ScreenDisplayMode.normal), )); } + + void _restoreAllLocalEmailDrafts(List localDrafts) { + popBack(); + + final listComposerArguments = localDrafts + .map(ComposerArguments.fromLocalEmailDraft) + .toList(); + + openListComposer(listComposerArguments); + } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart index a4a408cad6..e6506ab7f8 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -6,7 +6,6 @@ import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; -import 'package:core/utils/app_logger.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -28,12 +27,15 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/lo import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +typedef OnRestoreAllLocalEmailDraftsAction = Function(List); + class LocalEmailDraftListDialogBuilder extends StatefulWidget { final AccountId? accountId; final Session? session; final String ownEmailAddress; final List presentationLocalEmailDrafts; final OnEditLocalEmailDraftAction? onEditLocalEmailDraftAction; + final OnRestoreAllLocalEmailDraftsAction? onRestoreAllLocalEmailDraftsAction; const LocalEmailDraftListDialogBuilder({ super.key, @@ -42,6 +44,7 @@ class LocalEmailDraftListDialogBuilder extends StatefulWidget { required this.ownEmailAddress, required this.presentationLocalEmailDrafts, this.onEditLocalEmailDraftAction, + this.onRestoreAllLocalEmailDraftsAction, }); @override @@ -144,7 +147,6 @@ class _LocalEmailDraftListDialogBuilderState child: ValueListenableBuilder( valueListenable: _listLocalEmailDraftsNotifier, builder: (context, localDrafts, _) { - log('_LocalEmailDraftListDialogBuilderState::build:_listLocalEmailDraftsNotifier:localDrafts = ${localDrafts.length}'); return ListView.builder( itemCount: localDrafts.length, shrinkWrap: true, @@ -198,7 +200,10 @@ class _LocalEmailDraftListDialogBuilderState maxLines: 1, borderRadius: 10, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), - onTapActionCallback: () {}, + onTapActionCallback: () => + widget.onRestoreAllLocalEmailDraftsAction?.call( + _listLocalEmailDraftsNotifier.value, + ), ), ], ), From 7f8703f626a2450bcf162fe4718a8cdf194f4051 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 26 Mar 2025 02:05:20 +0700 Subject: [PATCH 08/11] TF-3358 Auto save draft locally periodically Signed-off-by: dab246 --- .../manager/composer_manager.dart | 35 +++++++++++++++++++ .../presentation/manager/composer_timer.dart | 29 +++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 lib/features/composer/presentation/manager/composer_timer.dart diff --git a/lib/features/composer/presentation/manager/composer_manager.dart b/lib/features/composer/presentation/manager/composer_manager.dart index ee2e276c78..18517af1cd 100644 --- a/lib/features/composer/presentation/manager/composer_manager.dart +++ b/lib/features/composer/presentation/manager/composer_manager.dart @@ -7,7 +7,9 @@ import 'package:get/get.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_local_email_draft_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/update_screen_display_mode_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/manager/composer_timer.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; @@ -19,6 +21,8 @@ class ComposerManager extends GetxController { final ResponsiveUtils _responsiveUtils = Get.find(); + ComposerTimer? _composerTimer; + void addComposer(ComposerArguments composerArguments) { final id = DateTime.now().millisecondsSinceEpoch.toString(); log('ComposerManager::addComposer:Id = $id'); @@ -28,6 +32,8 @@ class ComposerManager extends GetxController { composerIdsQueue.add(id); _arrangeComposerIfNeeded(); + + _initializeTimerIfNeeded(); } void addListComposer(List listArguments) { @@ -49,6 +55,8 @@ class ComposerManager extends GetxController { } _arrangeComposerIfNeeded(); + + _initializeTimerIfNeeded(); } void removeComposer(String id) { @@ -60,6 +68,10 @@ class ComposerManager extends GetxController { ComposerBindings(composerId: id).dispose(); _arrangeComposerIfNeeded(); + + if (!hasComposer) { + _clearTimerIfNeeded(); + } } void _arrangeComposerIfNeeded() { @@ -293,8 +305,31 @@ class ComposerManager extends GetxController { ComposerView getComposerView(String id) => composers[id]!; + void _initializeTimerIfNeeded() { + _composerTimer ??= ComposerTimer(onTick: _handleOnTick); + + if (!_composerTimer!.isRunning) { + _composerTimer!.start(); + } + } + + void _clearTimerIfNeeded() { + _composerTimer?.stop(); + _composerTimer = null; + } + + void _handleOnTick() { + if (!hasComposer) return; + + for (var id in composerIdsQueue) { + final controller = getComposerView(id).controller; + controller.saveLocalEmailDraftAction(); + } + } + @override void onClose() { + _clearTimerIfNeeded(); composerIdsQueue.clear(); super.onClose(); } diff --git a/lib/features/composer/presentation/manager/composer_timer.dart b/lib/features/composer/presentation/manager/composer_timer.dart new file mode 100644 index 0000000000..6679def99f --- /dev/null +++ b/lib/features/composer/presentation/manager/composer_timer.dart @@ -0,0 +1,29 @@ +import 'dart:async'; +import 'dart:ui'; + +class ComposerTimer { + static const int _delaySecondTime = 15; + + Timer? _timer; + final Duration interval; + final VoidCallback onTick; + + ComposerTimer({ + required this.onTick, + this.interval = const Duration(seconds: _delaySecondTime), + }); + + void start() { + stop(); + _timer = Timer.periodic(interval, (timer) { + onTick(); + }); + } + + void stop() { + _timer?.cancel(); + _timer = null; + } + + bool get isRunning => _timer?.isActive ?? false; +} From 815ea742f4516d4c48ed5e0b9bf91bd7ecf6a4c3 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 26 Mar 2025 03:14:40 +0700 Subject: [PATCH 09/11] TF-3358 Remove local email draft when `Delete, Save as draft or Send` successfully --- .../presentation/composer_controller.dart | 10 +++++ .../local_email_draft_datasource_impl.dart | 8 +++- .../mailbox_dashboard_controller.dart | 3 ++ .../remove_local_email_draft_extension.dart | 37 +++++++++++++++++++ .../restore_local_email_draft_extension.dart | 8 ++++ ...local_email_draft_list_dialog_builder.dart | 7 ++++ lib/l10n/intl_messages.arb | 12 ++++++ lib/main/localizations/app_localizations.dart | 14 +++++++ 8 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 lib/features/mailbox_dashboard/presentation/extensions/remove_local_email_draft_extension.dart diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 506bcde105..202e9c6514 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -102,6 +102,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_r import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_paywall_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/remove_local_email_draft_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; @@ -887,6 +888,9 @@ class ComposerController extends BaseController mailboxDashBoardController .validateSendingEmailFailedWhenNetworkIsLostOnMobile(resultState)) { _sendButtonState = ButtonState.enabled; + if (composerId != null) { + mailboxDashBoardController.removeLocalEmailDraft(composerId!); + } _closeComposerAction(result: resultState); } else if (resultState is SendEmailFailure && resultState.exception is SendingEmailCanceledException) { @@ -1686,6 +1690,9 @@ class ComposerController extends BaseController void handleClickDeleteComposer(BuildContext context) { clearFocus(context); + if (composerId != null) { + mailboxDashBoardController.removeLocalEmailDraft(composerId!); + } _closeComposerAction(); } @@ -2083,6 +2090,9 @@ class ComposerController extends BaseController if (resultState is SaveEmailAsDraftsSuccess || resultState is UpdateEmailDraftsSuccess) { _closeComposerButtonState = ButtonState.enabled; + if (composerId != null) { + mailboxDashBoardController.removeLocalEmailDraft(composerId!); + } _closeComposerAction(result: resultState); } else if ((resultState is SaveEmailAsDraftsFailure && resultState.exception is SavingEmailToDraftsCanceledException) || (resultState is UpdateEmailDraftsFailure && resultState.exception is SavingEmailToDraftsCanceledException)) { diff --git a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart index 03149b7333..51755c5b46 100644 --- a/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart +++ b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart @@ -69,7 +69,13 @@ class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { @override Future removeLocalEmailDraft(String draftLocalId) { return Future.sync(() async { - return await _localEmailDraftManager.removeLocalEmailDraft(draftLocalId); + final task = HiveTask( + id: draftLocalId, + runnable: () async { + return await _localEmailDraftManager.removeLocalEmailDraft(draftLocalId); + }, + ); + return _localEmailDraftWorkerQueue.addTask(task); }).catchError(_exceptionThrower.throwException); } } diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index b32520db44..e4bf2bc738 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -106,6 +106,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_sto import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart'; @@ -258,6 +259,7 @@ class MailboxDashBoardController extends ReloadableController CreateNewEmailRuleFilterInteractor? createNewEmailRuleFilterInteractor; SaveLanguageInteractor? saveLanguageInteractor; GetAllLocalEmailDraftInteractor? getAllLocalEmailDraftInteractor; + RemoveLocalEmailDraftInteractor? removeLocalEmailDraftInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -371,6 +373,7 @@ class MailboxDashBoardController extends ReloadableController twakeAppManager.setExecutingBeforeReconnect(false); isRetryGetPaywallUrl = false; getAllLocalEmailDraftInteractor = getBinding(); + removeLocalEmailDraftInteractor = getBinding(); } if (PlatformInfo.isIOS) { _registerPendingCurrentEmailIdInNotification(); diff --git a/lib/features/mailbox_dashboard/presentation/extensions/remove_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/remove_local_email_draft_extension.dart new file mode 100644 index 0000000000..cc51f32dca --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/remove_local_email_draft_extension.dart @@ -0,0 +1,37 @@ + +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/utils/cache_utils.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; + +extension RemoveLocalEmailDraftExtension on MailboxDashBoardController { + + Future removeLocalEmailDraft(String composerId) async { + if (accountId.value == null || + sessionCurrent == null || + removeLocalEmailDraftInteractor == null) { + return; + } + + final draftLocalId = _generateDraftLocalId( + composerId: composerId, + accountId: accountId.value!, + userName: sessionCurrent!.username, + ); + + await removeLocalEmailDraftInteractor!.execute(draftLocalId); + } + + String _generateDraftLocalId({ + required String composerId, + required AccountId accountId, + required UserName userName, + }) { + return TupleKey( + composerId, + accountId.asString, + userName.value, + ).encodeKey; + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart index 1f9761b36d..1fa1bd5a64 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -11,6 +11,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { @@ -71,5 +72,12 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { .toList(); openListComposer(listComposerArguments); + + if (currentOverlayContext != null && currentContext != null) { + appToast.showToastSuccessMessage( + currentOverlayContext!, + AppLocalizations.of(currentContext!).restoreAllLocalDraftsSuccessfully, + ); + } } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart index e6506ab7f8..49bb28d5a4 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -419,6 +419,13 @@ class _LocalEmailDraftListDialogBuilderState widget.session!.username, ); + if (context.mounted) { + _appToast.showToastSuccessMessage( + context, + AppLocalizations.of(context).deleteAllLocalDraftsSuccessfully, + ); + } + SmartDialog.dismiss(); popBack(); } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 11278d068a..0efae688df 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4929,5 +4929,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "deleteAllLocalDraftsSuccessfully": "Delete all local drafts successfully", + "@deleteAllLocalDraftsSuccessfully": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "restoreAllLocalDraftsSuccessfully": "Restore all local drafts successfully", + "@restoreAllLocalDraftsSuccessfully": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index eba9d66737..32e2ed1a5f 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5209,4 +5209,18 @@ class AppLocalizations { name: 'deletingLocalDraft', ); } + + String get deleteAllLocalDraftsSuccessfully { + return Intl.message( + 'Delete all local drafts successfully', + name: 'deleteAllLocalDraftsSuccessfully', + ); + } + + String get restoreAllLocalDraftsSuccessfully { + return Intl.message( + 'Restore all local drafts successfully', + name: 'restoreAllLocalDraftsSuccessfully', + ); + } } From 1ca994e3e0dafac106a0fe456e1e32a088a07647 Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 4 Apr 2025 18:55:29 +0700 Subject: [PATCH 10/11] TF-3358 Sort list local email draft by time --- .../presentation/composer_controller.dart | 19 +++++------ .../create_email_request_extension.dart | 3 +- .../handle_local_email_draft_extension.dart | 3 ++ .../manager/composer_manager.dart | 33 +++++++------------ .../restore_local_email_draft_extension.dart | 13 +++++--- ...local_email_draft_list_dialog_builder.dart | 10 ++++-- 6 files changed, 41 insertions(+), 40 deletions(-) diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 202e9c6514..8552cec10d 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -238,7 +238,7 @@ class ComposerController extends BaseController ButtonState _saveToDraftButtonState = ButtonState.enabled; ButtonState _sendButtonState = ButtonState.enabled; ButtonState printDraftButtonState = ButtonState.enabled; - int? _savedEmailDraftHash; + int? savedEmailDraftHash; bool restoringSignatureButton = false; bool synchronizeInitDraftHash = false; GlobalKey? responsiveContainerKey; @@ -247,9 +247,6 @@ class ComposerController extends BaseController int minInputLengthAutocomplete = AppConfig.defaultMinInputLengthAutocomplete; EmailId? currentTemplateEmailId; - @visibleForTesting - int? get savedEmailDraftHash => _savedEmailDraftHash; - GetEmailContentInteractor get getEmailContentInteractor => _getEmailContentInteractor; GetServerSettingInteractor get getServerSettingInteractor => _getServerSettingInteractor; @@ -320,7 +317,7 @@ class ComposerController extends BaseController void onClose() { _textEditorWeb = null; savedActionType = null; - _savedEmailDraftHash = null; + savedEmailDraftHash = null; currentEmailActionType = null; emailIdEditing = null; maxWithEditor = null; @@ -1168,7 +1165,7 @@ class ComposerController extends BaseController Future _validateEmailChange() async { final newDraftHash = await _hashComposingEmail(); - return _savedEmailDraftHash != newDraftHash; + return savedEmailDraftHash != newDraftHash; } Future _hashComposingEmail() async { @@ -1204,7 +1201,7 @@ class ComposerController extends BaseController } Future _updateSavedEmailDraftHash() async { - _savedEmailDraftHash = await _hashComposingEmail(); + savedEmailDraftHash = await _hashComposingEmail(); } Future initEmailDraftHash() async { @@ -1214,13 +1211,13 @@ class ComposerController extends BaseController if (currentEmailActionType == EmailActionType.compose || currentEmailActionType == EmailActionType.editDraft) { - _savedEmailDraftHash = currentDraftHash; + savedEmailDraftHash = currentDraftHash; } else if (currentEmailActionType == EmailActionType.composeFromLocalEmailDraft) { - _savedEmailDraftHash = oldSavedDraftHash; + savedEmailDraftHash = oldSavedDraftHash; } - log('ComposerController::initEmailDraftHash:oldSavedDraftHash = $oldSavedDraftHash | currentDraftHash = $currentDraftHash | _savedEmailDraftHash = $_savedEmailDraftHash'); + log('ComposerController::initEmailDraftHash:oldSavedDraftHash = $oldSavedDraftHash | currentDraftHash = $currentDraftHash | savedEmailDraftHash = $savedEmailDraftHash'); - isEmailChanged.value = currentDraftHash != _savedEmailDraftHash; + isEmailChanged.value = currentDraftHash != savedEmailDraftHash; } void handleClickSaveAsDraftsButton(BuildContext context) async { diff --git a/lib/features/composer/presentation/extensions/create_email_request_extension.dart b/lib/features/composer/presentation/extensions/create_email_request_extension.dart index a47b4d7bf3..e417a38137 100644 --- a/lib/features/composer/presentation/extensions/create_email_request_extension.dart +++ b/lib/features/composer/presentation/extensions/create_email_request_extension.dart @@ -1,4 +1,5 @@ -import 'package:core/core.dart'; +import 'package:core/data/constants/constant.dart'; +import 'package:core/presentation/extensions/capitalize_extension.dart'; import 'package:http_parser/http_parser.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; diff --git a/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart index 73de4feeda..31e3f4d231 100644 --- a/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart +++ b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart @@ -51,6 +51,9 @@ extension HandleLocalEmailDraftExtension on ComposerController { uploadUri: uploadUri, composerIndex: composerIndex, composerId: composerId, + savedDraftHash: arguments.savedDraftHash ?? savedEmailDraftHash, + savedActionType: savedActionType ?? currentEmailActionType, + savedEmailDraftId: emailIdEditing, ); } diff --git a/lib/features/composer/presentation/manager/composer_manager.dart b/lib/features/composer/presentation/manager/composer_manager.dart index 18517af1cd..3e5c425d8a 100644 --- a/lib/features/composer/presentation/manager/composer_manager.dart +++ b/lib/features/composer/presentation/manager/composer_manager.dart @@ -23,39 +23,30 @@ class ComposerManager extends GetxController { ComposerTimer? _composerTimer; - void addComposer(ComposerArguments composerArguments) { - final id = DateTime.now().millisecondsSinceEpoch.toString(); + void addComposer(ComposerArguments composerArguments, {bool isSynchronous = true}) { + final id = composerArguments.composerId + ?? DateTime.now().millisecondsSinceEpoch.toString(); log('ComposerManager::addComposer:Id = $id'); - ComposerBindings(composerId: id, composerArguments: composerArguments).dependencies(); + ComposerBindings( + composerId: id, + composerArguments: composerArguments, + ).dependencies(); composers[id] = ComposerView(key: Key(id), composerId: id); composerIdsQueue.add(id); - _arrangeComposerIfNeeded(); - - _initializeTimerIfNeeded(); + if (isSynchronous) { + _arrangeComposerIfNeeded(); + _initializeTimerIfNeeded(); + } } void addListComposer(List listArguments) { for (var argument in listArguments) { - final composerId = argument.composerId; - - if (composerId == null) continue; - - ComposerBindings( - composerId: composerId, - composerArguments: argument, - ).dependencies(); - - composers[composerId] = ComposerView( - key: Key(composerId), - composerId: composerId, - ); - composerIdsQueue.add(composerId); + addComposer(argument, isSynchronous: false); } _arrangeComposerIfNeeded(); - _initializeTimerIfNeeded(); } diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart index 1fa1bd5a64..9420aedced 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -35,10 +35,11 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { final listPresentationLocalEmailDraft = localEmailDrafts .map((localEmailDraft) => localEmailDraft.toPresentation()) .toList(); - final listLocalEmailDraftSortByIndex = listPresentationLocalEmailDraft - ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); - showLocalEmailDraftListDialog(listLocalEmailDraftSortByIndex); + final listLocalEmailDraftSortByTime = listPresentationLocalEmailDraft + ..sort((a, b) => b.savedTime.compareTo(a.savedTime)); + + showLocalEmailDraftListDialog(listLocalEmailDraftSortByTime); } void showLocalEmailDraftListDialog(List presentationLocalEmailDrafts) { @@ -67,7 +68,11 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { void _restoreAllLocalEmailDrafts(List localDrafts) { popBack(); - final listComposerArguments = localDrafts + + final listLocalEmailDraftSortByIndex = localDrafts + ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); + + final listComposerArguments = listLocalEmailDraftSortByIndex .map(ComposerArguments.fromLocalEmailDraft) .toList(); diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart index 49bb28d5a4..de4378d479 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -281,13 +281,17 @@ class _LocalEmailDraftListDialogBuilderState ); } - Future _removeLocalEmailDraft(BuildContext context, String draftLocalId) async { + Future _removeLocalEmailDraft( + BuildContext context, + String draftLocalId, + {bool showToast = true} + ) async { _listLocalEmailDraftsNotifier.value = List.from(_listLocalEmailDraftsNotifier.value) ..removeWhere((draftLocal) => draftLocal.id == draftLocalId); await _removeLocalEmailDraftInteractor?.execute(draftLocalId); - if (context.mounted) { + if (showToast && context.mounted) { _appToast.showToastSuccessMessage( context, AppLocalizations.of(context).deleteLocalDraftSuccessfully, @@ -328,7 +332,7 @@ class _LocalEmailDraftListDialogBuilderState leadingSVGIconColor: Colors.white, ); - _removeLocalEmailDraft(context, draftLocal.id); + _removeLocalEmailDraft(context, draftLocal.id, showToast: false); } else if (resultState is SaveEmailAsDraftsFailure) { final errorMessage = getMessageFailure( appLocalizations: AppLocalizations.of(context), From 02a1b0fbf8c503e6147a1885bde0f6ed61a95c0c Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 22 Sep 2025 12:42:38 +0700 Subject: [PATCH 11/11] TF-3358 Auto close draft list dialog when click outside --- .../dialog_builder_manager.dart | 41 ++++++++++++++ .../presentation/composer_view_web.dart | 2 + .../email/presentation/email_view.dart | 2 + .../restore_local_email_draft_extension.dart | 24 +++------ ...local_email_draft_list_dialog_builder.dart | 54 ++++++------------- 5 files changed, 68 insertions(+), 55 deletions(-) create mode 100644 lib/features/base/widget/dialog_builder/dialog_builder_manager.dart diff --git a/lib/features/base/widget/dialog_builder/dialog_builder_manager.dart b/lib/features/base/widget/dialog_builder/dialog_builder_manager.dart new file mode 100644 index 0000000000..0bc3381ec9 --- /dev/null +++ b/lib/features/base/widget/dialog_builder/dialog_builder_manager.dart @@ -0,0 +1,41 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart'; + +class DialogBuilderManager { + static final _instance = DialogBuilderManager._(); + + factory DialogBuilderManager() => _instance; + + DialogBuilderManager._(); + + final _isOpened = RxBool(false); + + RxBool get isOpened => _isOpened; + + Future showLocalEmailDraftListDialog({ + required List emailDrafts, + required AccountId? accountId, + required Session? session, + required String ownEmailAddress, + OnEditLocalEmailDraftAction? onEditLocalEmailDraftAction, + OnRestoreAllLocalEmailDraftsAction? onRestoreAllLocalEmailDraftsAction, + }) { + _isOpened.value = true; + return Get.dialog( + LocalEmailDraftListDialogBuilder( + accountId: accountId, + session: session, + ownEmailAddress: ownEmailAddress, + presentationLocalEmailDrafts: emailDrafts, + onEditLocalEmailDraftAction: onEditLocalEmailDraftAction, + onRestoreAllLocalEmailDraftsAction: onRestoreAllLocalEmailDraftsAction, + ), + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + ).whenComplete(() => _isOpened.value = false); + } +} diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 333ba84455..2dd0f388ec 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:model/email/prefix_email_address.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; +import 'package:tmail_ui_user/features/base/widget/dialog_builder/dialog_builder_manager.dart'; import 'package:tmail_ui_user/features/base/widget/dialog_picker/color_dialog_picker.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/composer_print_draft_extension.dart'; @@ -47,6 +48,7 @@ class ComposerView extends GetWidget { bool isOverlayEnabled = controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame || MessageDialogActionManager().isDialogOpened || ColorDialogPicker().isOpened.isTrue || + DialogBuilderManager().isOpened.isTrue || DialogRouter.isRuleFilterDialogOpened.isTrue || DialogRouter.isDialogOpened; diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 763e395d08..830fa4098f 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -14,6 +14,7 @@ import 'package:model/extensions/presentation_email_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; +import 'package:tmail_ui_user/features/base/widget/dialog_builder/dialog_builder_manager.dart'; import 'package:tmail_ui_user/features/base/widget/dialog_picker/color_dialog_picker.dart'; import 'package:tmail_ui_user/features/base/widget/optional_expanded.dart'; import 'package:tmail_ui_user/features/base/widget/optional_scroll.dart'; @@ -541,6 +542,7 @@ class EmailView extends GetWidget { MessageDialogActionManager().isDialogOpened || EmailActionReactor.isDialogOpened || ColorDialogPicker().isOpened.isTrue || + DialogBuilderManager().isOpened.isTrue || DialogRouter.isRuleFilterDialogOpened.isTrue || DialogRouter.isDialogOpened; diff --git a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart index 9420aedced..a8af159ea6 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -1,7 +1,5 @@ -import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:get/get.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/widget/dialog_builder/dialog_builder_manager.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/local_email_draft.dart'; @@ -10,7 +8,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -43,18 +40,13 @@ extension RestoreLocalEmailDraftExtension on MailboxDashBoardController { } void showLocalEmailDraftListDialog(List presentationLocalEmailDrafts) { - Get.dialog( - PointerInterceptor( - child: LocalEmailDraftListDialogBuilder( - accountId: accountId.value, - session: sessionCurrent, - ownEmailAddress: ownEmailAddress.value, - presentationLocalEmailDrafts: presentationLocalEmailDrafts, - onEditLocalEmailDraftAction: _editLocalEmailDraft, - onRestoreAllLocalEmailDraftsAction: _restoreAllLocalEmailDrafts, - ), - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + DialogBuilderManager().showLocalEmailDraftListDialog( + emailDrafts: presentationLocalEmailDrafts, + accountId: accountId.value, + session: sessionCurrent, + ownEmailAddress: ownEmailAddress.value, + onEditLocalEmailDraftAction: _editLocalEmailDraft, + onRestoreAllLocalEmailDraftsAction: _restoreAllLocalEmailDrafts, ); } diff --git a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart index de4378d479..c8d9cfa31d 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -5,7 +5,6 @@ import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -13,6 +12,7 @@ import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; import 'package:tmail_ui_user/features/composer/domain/exceptions/compose_email_exception.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; @@ -259,25 +259,13 @@ class _LocalEmailDraftListDialogBuilderState BuildContext context, ) { final appLocalizations = AppLocalizations.of(context); - Get.dialog( - PointerInterceptor(child: ConfirmationDialogBuilder( - imagePath: _imagePaths, - useIconAsBasicLogo: true, - textContent: appLocalizations.messageWarningDialogDiscardLocalDraft, - confirmText: appLocalizations.yes, - cancelText: appLocalizations.no, - cancelBackgroundButtonColor: AppColor.blue700, - cancelLabelButtonColor: Colors.white, - confirmBackgroundButtonColor: AppColor.grayBackgroundColor, - confirmLabelButtonColor: AppColor.steelGray600, - onConfirmButtonAction: () { - popBack(); - _removeLocalEmailDraft(context, emailDraft.id); - }, - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - )), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + context, + appLocalizations.messageWarningDialogDiscardLocalDraft, + appLocalizations.yes, + cancelTitle: appLocalizations.no, + onConfirmAction: () => _removeLocalEmailDraft(context, emailDraft.id), + onCloseButtonAction: popBack, ); } @@ -384,25 +372,13 @@ class _LocalEmailDraftListDialogBuilderState void _handleDiscardAllLocalEmailDraftAction(BuildContext context) { final appLocalizations = AppLocalizations.of(context); - Get.dialog( - PointerInterceptor(child: ConfirmationDialogBuilder( - imagePath: _imagePaths, - useIconAsBasicLogo: true, - textContent: appLocalizations.messageWarningDialogDiscardAllLocalDrafts, - confirmText: appLocalizations.yes, - cancelText: appLocalizations.no, - cancelBackgroundButtonColor: AppColor.blue700, - cancelLabelButtonColor: Colors.white, - confirmBackgroundButtonColor: AppColor.grayBackgroundColor, - confirmLabelButtonColor: AppColor.steelGray600, - onConfirmButtonAction: () { - popBack(); - _removeAllLocalEmailDrafts(context); - }, - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - )), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + context, + appLocalizations.messageWarningDialogDiscardAllLocalDrafts, + appLocalizations.yes, + cancelTitle: appLocalizations.no, + onConfirmAction: () => _removeAllLocalEmailDrafts(context), + onCloseButtonAction: popBack, ); }