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/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/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/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/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/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_composer_cache_on_web_interactor.dart deleted file mode 100644 index 4f5c71d339..0000000000 --- a/lib/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart +++ /dev/null @@ -1,52 +0,0 @@ -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/composer/domain/repository/composer_repository.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'; - -class SaveComposerCacheOnWebInteractor { - final ComposerCacheRepository _composerCacheRepository; - final ComposerRepository _composerRepository; - - SaveComposerCacheOnWebInteractor( - this._composerCacheRepository, - this._composerRepository, - ); - - Future> execute( - CreateEmailRequest createEmailRequest, - AccountId accountId, - UserName userName, - ) async { - try { - final emailCreated = await _composerRepository.generateEmail( - createEmailRequest, - withIdentityHeader: true, - isDraft: true, - ); - await _composerCacheRepository.saveComposerCacheOnWeb( - accountId: accountId, - userName: userName, - composerCache: ComposerCache( - 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, - )); - return Right(SaveComposerCacheSuccess()); - } catch (exception) { - return Left(SaveComposerCacheFailure(exception)); - } - } -} 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 new file mode 100644 index 0000000000..0a4533e0d2 --- /dev/null +++ b/lib/features/composer/domain/usecases/save_local_email_draft_interactor.dart @@ -0,0 +1,44 @@ +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/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/domain/repository/local_email_draft_repository.dart'; + +class SaveLocalEmailDraftInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; + final ComposerRepository _composerRepository; + + SaveLocalEmailDraftInteractor( + this._localEmailDraftRepository, + this._composerRepository, + ); + + Future> execute( + CreateEmailRequest createEmailRequest, + AccountId accountId, + UserName userName, + ) async { + try { + final emailCreated = await _composerRepository.generateEmail( + createEmailRequest, + withIdentityHeader: true, + isDraft: true, + ); + await _localEmailDraftRepository.saveLocalEmailDraft( + createEmailRequest.generateLocalEmailDraftFromEmail( + email: emailCreated, + 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 27cc6b6ad9..f0dfcb88b8 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,13 @@ 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/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'; 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,8 +146,10 @@ class ComposerBindings extends BaseBindings { Get.find(), Get.find(), ), tag: composerId); - Get.lazyPut(() => SessionStorageComposerDatasourceImpl( + Get.lazyPut(() => LocalEmailDraftDataSourceImpl( Get.find(), + Get.find(), + Get.find(), Get.find(), ), tag: composerId); } @@ -184,8 +188,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 +204,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 +237,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 +274,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 +298,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 +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), @@ -364,7 +366,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 +376,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 +394,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..8552cec10d 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'; @@ -61,7 +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_message_failure_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/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'; @@ -76,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'; @@ -98,10 +99,10 @@ 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/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'; @@ -110,8 +111,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'; @@ -127,7 +128,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(); @@ -160,8 +164,6 @@ class ComposerController extends BaseController final GetEmailContentInteractor _getEmailContentInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; final UploadController uploadController; - final RemoveComposerCacheByIdOnWebInteractor _removeComposerCacheByIdOnWebInteractor; - final SaveComposerCacheOnWebInteractor _saveComposerCacheOnWebInteractor; final DownloadImageAsBase64Interactor _downloadImageAsBase64Interactor; final TransformHtmlEmailContentInteractor _transformHtmlEmailContentInteractor; final GetServerSettingInteractor _getServerSettingInteractor; @@ -177,6 +179,7 @@ class ComposerController extends BaseController GetAutoCompleteInteractor? _getAutoCompleteInteractor; GetDeviceContactSuggestionsInteractor? _getDeviceContactSuggestionsInteractor; RestoreEmailInlineImagesInteractor? restoreEmailInlineImagesInteractor; + SaveLocalEmailDraftInteractor? saveLocalEmailDraftInteractor; List listToEmailAddress = []; List listCcEmailAddress = []; @@ -235,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; @@ -244,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; @@ -268,8 +268,6 @@ class ComposerController extends BaseController this._getEmailContentInteractor, this._getAllIdentitiesInteractor, this.uploadController, - this._removeComposerCacheByIdOnWebInteractor, - this._saveComposerCacheOnWebInteractor, this._downloadImageAsBase64Interactor, this._transformHtmlEmailContentInteractor, this._getServerSettingInteractor, @@ -292,6 +290,7 @@ class ComposerController extends BaseController richTextWebController = getBinding(tag: composerId); restoreEmailInlineImagesInteractor = getBinding(tag: composerId); menuMoreOptionController = CustomPopupMenuController(); + saveLocalEmailDraftInteractor = getBinding(tag: composerId); } else { richTextMobileTabletController = getBinding(tag: composerId); } @@ -318,7 +317,7 @@ class ComposerController extends BaseController void onClose() { _textEditorWeb = null; savedActionType = null; - _savedEmailDraftHash = null; + savedEmailDraftHash = null; currentEmailActionType = null; emailIdEditing = null; maxWithEditor = null; @@ -417,17 +416,8 @@ 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 _removeComposerCacheByIdOnWebInteractor.execute( - accountId, - username, - composerId!, - ); - } - await _saveComposerCacheOnWebAction(); + Future onBeforeUnloadBrowserListener(html.Event event) async { + await saveLocalEmailDraftAction(); } void _listenStreamEvent() { @@ -480,86 +470,15 @@ class ComposerController extends BaseController }); } - Future _saveComposerCacheOnWebAction() async { - autoCreateEmailTag(); - - final createEmailRequest = await _generateCreateEmailRequestToSaveAsCache(); - if (createEmailRequest == null) return; - - await _saveComposerCacheOnWebInteractor.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 +870,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, @@ -966,6 +885,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) { @@ -1243,7 +1165,7 @@ class ComposerController extends BaseController Future _validateEmailChange() async { final newDraftHash = await _hashComposingEmail(); - return _savedEmailDraftHash != newDraftHash; + return savedEmailDraftHash != newDraftHash; } Future _hashComposingEmail() async { @@ -1254,7 +1176,7 @@ class ComposerController extends BaseController ); if (emailIdEditing != null && savedActionType == EmailActionType.compose && - currentEmailActionType == EmailActionType.reopenComposerBrowser) { + currentEmailActionType == EmailActionType.composeFromLocalEmailDraft) { emailContent = await _composerRepository.removeStyleLazyLoadDisplayInlineImages( emailContent: emailContent, ); @@ -1279,7 +1201,7 @@ class ComposerController extends BaseController } Future _updateSavedEmailDraftHash() async { - _savedEmailDraftHash = await _hashComposingEmail(); + savedEmailDraftHash = await _hashComposingEmail(); } Future initEmailDraftHash() async { @@ -1289,13 +1211,13 @@ class ComposerController extends BaseController if (currentEmailActionType == EmailActionType.compose || currentEmailActionType == EmailActionType.editDraft) { - _savedEmailDraftHash = currentDraftHash; - } else if (currentEmailActionType == EmailActionType.reopenComposerBrowser) { - _savedEmailDraftHash = oldSavedDraftHash; + savedEmailDraftHash = currentDraftHash; + } else if (currentEmailActionType == EmailActionType.composeFromLocalEmailDraft) { + 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 { @@ -1321,7 +1243,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, @@ -1765,6 +1687,9 @@ class ComposerController extends BaseController void handleClickDeleteComposer(BuildContext context) { clearFocus(context); + if (composerId != null) { + mailboxDashBoardController.removeLocalEmailDraft(composerId!); + } _closeComposerAction(); } @@ -2146,7 +2071,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(); @@ -2162,6 +2087,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)) { @@ -2377,11 +2305,7 @@ class ComposerController extends BaseController @override Future onBeforeReconnect() async { - if (mailboxDashBoardController.accountId.value != null && - mailboxDashBoardController.sessionCurrent?.username != null - ) { - await _saveComposerCacheOnWebAction(); - } + await saveLocalEmailDraftAction(); } void _setUpMaxWidthInlineImage({ 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/composer/presentation/extensions/create_email_request_extension.dart b/lib/features/composer/presentation/extensions/create_email_request_extension.dart index 090546baeb..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,5 +1,8 @@ -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'; 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 +12,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 +228,24 @@ 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, + ); + } } \ 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/handle_local_email_draft_extension.dart b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart new file mode 100644 index 0000000000..31e3f4d231 --- /dev/null +++ b/lib/features/composer/presentation/extensions/handle_local_email_draft_extension.dart @@ -0,0 +1,81 @@ +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/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, + 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, + ); + } + + 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/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/manager/composer_manager.dart b/lib/features/composer/presentation/manager/composer_manager.dart index ee2e276c78..3e5c425d8a 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,36 +21,33 @@ class ComposerManager extends GetxController { final ResponsiveUtils _responsiveUtils = Get.find(); - void addComposer(ComposerArguments composerArguments) { - final id = DateTime.now().millisecondsSinceEpoch.toString(); + ComposerTimer? _composerTimer; + + 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(); + 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(); } void removeComposer(String id) { @@ -60,6 +59,10 @@ class ComposerManager extends GetxController { ComposerBindings(composerId: id).dispose(); _arrangeComposerIfNeeded(); + + if (!hasComposer) { + _clearTimerIfNeeded(); + } } void _arrangeComposerIfNeeded() { @@ -293,8 +296,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; +} 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/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/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/email/presentation/model/composer_arguments.dart b/lib/features/email/presentation/model/composer_arguments.dart index c6fd05eeb3..4b18ef7b4c 100644 --- a/lib/features/email/presentation/model/composer_arguments.dart +++ b/lib/features/email/presentation/model/composer_arguments.dart @@ -4,9 +4,8 @@ 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/composer_cache.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'; @@ -124,23 +123,26 @@ class ComposerArguments extends RouterArguments { savedEmailTemplateId: savedEmailTemplateId, ); - factory ComposerArguments.fromSessionStorageBrowser(ComposerCache 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.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, 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/datasource/session_storage_composer_datasource.dart b/lib/features/mailbox_dashboard/data/datasource/local_email_draft_datasource.dart similarity index 54% 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..79afe5ced2 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,29 +1,21 @@ 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({ - required AccountId accountId, - required UserName userName, - required ComposerCache composerCache, - }); +abstract class LocalEmailDraftDatasource { + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft); - Future> getComposerCacheOnWeb( + Future> getAllLocalEmailDraft( AccountId accountId, UserName userName); - Future removeAllComposerCacheOnWeb( + Future removeAllLocalEmailDrafts( AccountId accountId, UserName userName, ); - Future removeComposerCacheByIdOnWeb( - 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 new file mode 100644 index 0000000000..51755c5b46 --- /dev/null +++ b/lib/features/mailbox_dashboard/data/datasource_impl/local_email_draft_datasource_impl.dart @@ -0,0 +1,81 @@ +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: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'; + +class LocalEmailDraftDataSourceImpl extends LocalEmailDraftDatasource { + + final HtmlTransform _htmlTransform; + final LocalEmailDraftManager _localEmailDraftManager; + final LocalEmailDraftWorkerQueue _localEmailDraftWorkerQueue; + final ExceptionThrower _exceptionThrower; + + LocalEmailDraftDataSourceImpl( + this._htmlTransform, + this._localEmailDraftManager, + this._localEmailDraftWorkerQueue, + this._exceptionThrower, + ); + + @override + Future> getAllLocalEmailDraft( + AccountId accountId, + UserName userName + ) { + return Future.sync(() async { + return await _localEmailDraftManager.getAllLocalEmailDraft(accountId, userName); + }).catchError(_exceptionThrower.throwException); + } + + @override + 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); + } + + @override + Future restoreEmailInlineImages( + String htmlContent, + TransformConfiguration transformConfiguration, + Map mapUrlDownloadCID) { + return Future.sync(() async { + return await _htmlTransform.transformToHtml( + htmlContent: htmlContent, + transformConfiguration: transformConfiguration, + mapCidImageDownloadUrl: mapUrlDownloadCID); + }).catchError(_exceptionThrower.throwException); + } + + @override + Future removeAllLocalEmailDrafts(AccountId accountId, UserName userName) { + return Future.sync(() async { + return await _localEmailDraftManager.removeAllLocalEmailDrafts(accountId, userName); + }).catchError(_exceptionThrower.throwException); + } + + @override + Future removeLocalEmailDraft(String draftLocalId) { + return Future.sync(() async { + 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/data/datasource_impl/session_storage_composer_datasoure_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart deleted file mode 100644 index 824140b429..0000000000 --- a/lib/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart +++ /dev/null @@ -1,106 +0,0 @@ -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'; -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/main/exceptions/exception_thrower.dart'; -import 'package:universal_html/html.dart' as html; - -class SessionStorageComposerDatasourceImpl - extends SessionStorageComposerDatasource { - SessionStorageComposerDatasourceImpl(this._htmlTransform, this._exceptionThrower); - - final HtmlTransform _htmlTransform; - final ExceptionThrower _exceptionThrower; - - @override - Future> getComposerCacheOnWeb( - 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) => ComposerCache.fromJson(jsonDecode(entry.value))) - .toList(); - } else { - throw NotFoundInWebSessionException(); - } - }).catchError(_exceptionThrower.throwException); - } - - @override - Future saveComposerCacheOnWeb({ - required AccountId accountId, - required UserName userName, - required ComposerCache 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); - }).catchError(_exceptionThrower.throwException); - } - - @override - Future restoreEmailInlineImages( - String htmlContent, - TransformConfiguration transformConfiguration, - Map mapUrlDownloadCID) { - return Future.sync(() async { - return await _htmlTransform.transformToHtml( - htmlContent: htmlContent, - transformConfiguration: transformConfiguration, - mapCidImageDownloadUrl: mapUrlDownloadCID); - }).catchError(_exceptionThrower.throwException); - } - - @override - Future removeAllComposerCacheOnWeb(AccountId accountId, UserName userName) { - return Future.sync(() { - final keyWithIdentity = TupleKey( - EmailActionType.reopenComposerBrowser.name, - accountId.asString, - userName.value, - ).toString(); - - html.window.sessionStorage.removeWhere((key, value) => key.startsWith(keyWithIdentity)); - }).catchError(_exceptionThrower.throwException); - } - - @override - Future removeComposerCacheByIdOnWeb(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); - }).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..05747ee95e --- /dev/null +++ b/lib/features/mailbox_dashboard/data/local/local_email_draft_manager.dart @@ -0,0 +1,42 @@ + +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 { + await _localEmailDraftClient.insertItem( + localEmailDraft.id, + localEmailDraft, + ); + } + + 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/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/composer_cache.dart b/lib/features/mailbox_dashboard/data/model/composer_cache.dart deleted file mode 100644 index 428a4ee8f2..0000000000 --- a/lib/features/mailbox_dashboard/data/model/composer_cache.dart +++ /dev/null @@ -1,60 +0,0 @@ -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'; - -part 'composer_cache.g.dart'; - -@JsonSerializable( - explicitToJson: true, - includeIfNull: false, - converters: [ - EmailIdNullableConverter(), - ] -) -class ComposerCache with EquatableMixin { - - final Email? email; - final bool? hasRequestReadReceipt; - final bool? isMarkAsImportant; - final ScreenDisplayMode displayMode; - final int? composerIndex; - final String? composerId; - final int? draftHash; - final EmailActionType? actionType; - final EmailId? draftEmailId; - final EmailId? templateEmailId; - - ComposerCache({ - this.email, - this.hasRequestReadReceipt, - this.isMarkAsImportant, - this.displayMode = ScreenDisplayMode.normal, - this.composerIndex, - this.composerId, - this.draftHash, - this.actionType, - this.draftEmailId, - this.templateEmailId, - }); - - factory ComposerCache.fromJson(Map json) => _$ComposerCacheFromJson(json); - - Map toJson() => _$ComposerCacheToJson(this); - - @override - List get props => [ - email, - hasRequestReadReceipt, - isMarkAsImportant, - displayMode, - composerIndex, - composerId, - draftHash, - actionType, - draftEmailId, - templateEmailId, - ]; -} diff --git a/lib/features/mailbox_dashboard/data/model/local_email_draft.dart b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart new file mode 100644 index 0000000000..7c0539e03b --- /dev/null +++ b/lib/features/mailbox_dashboard/data/model/local_email_draft.dart @@ -0,0 +1,71 @@ +import 'package:equatable/equatable.dart'; +import 'package:hive_ce/hive.dart'; +import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; + +part 'local_email_draft.g.dart'; + +@HiveType(typeId: CachingConstants.LOCAL_EMAIL_DRAFT_CACHE_ID) +class LocalEmailDraft with EquatableMixin { + + @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; + + @HiveField(6) + final String? displayMode; + + @HiveField(7) + final int? composerIndex; + + @HiveField(8) + final int? draftHash; + + @HiveField(9) + final String? actionType; + + @HiveField(10) + final String? draftEmailId; + + LocalEmailDraft({ + required this.id, + required this.composerId, + required this.savedTime, + this.email, + this.hasRequestReadReceipt, + this.isMarkAsImportant, + this.displayMode, + this.composerIndex, + this.draftHash, + this.actionType, + this.draftEmailId, + }); + + @override + List get props => [ + id, + savedTime, + email, + hasRequestReadReceipt, + isMarkAsImportant, + displayMode, + composerIndex, + composerId, + draftHash, + actionType, + draftEmailId, + ]; +} 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..86a970d2ae --- /dev/null +++ b/lib/features/mailbox_dashboard/data/repository/local_email_draft_repository_impl.dart @@ -0,0 +1,47 @@ +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> getAllLocalEmailDraft( + AccountId accountId, + UserName userName + ) { + return _localEmailDraftDatasource.getAllLocalEmailDraft(accountId, userName); + } + + @override + Future removeAllLocalEmailDrafts(AccountId accountId, UserName userName) { + return _localEmailDraftDatasource.removeAllLocalEmailDrafts(accountId, userName); + } + + @override + Future removeLocalEmailDraft(String draftLocalId) { + return _localEmailDraftDatasource.removeLocalEmailDraft(draftLocalId); + } + + @override + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft) { + return _localEmailDraftDatasource.saveLocalEmailDraft(localEmailDraft); + } + + @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/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/composer_cache_repository.dart b/lib/features/mailbox_dashboard/domain/repository/local_email_draft_repository.dart similarity index 55% 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..b11ddc5f1b 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,29 +1,21 @@ 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({ - required AccountId accountId, - required UserName userName, - required ComposerCache composerCache, - }); +abstract class LocalEmailDraftRepository { + Future saveLocalEmailDraft(LocalEmailDraft localEmailDraft); - Future> getComposerCacheOnWeb( + Future> getAllLocalEmailDraft( AccountId accountId, UserName userName); - Future removeAllComposerCacheOnWeb( + Future removeAllLocalEmailDrafts( AccountId accountId, UserName userName, ); - Future removeComposerCacheByIdOnWeb( - AccountId accountId, - UserName userName, - String composerId, - ); + Future removeLocalEmailDraft(String draftLocalId); Future restoreEmailInlineImages( String htmlContent, diff --git a/lib/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart b/lib/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart new file mode 100644 index 0000000000..47f2e1672c --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/state/get_all_local_email_draft_state.dart @@ -0,0 +1,20 @@ +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 GetAllLocalEmailDraftLoading extends LoadingState {} + +class GetAllLocalEmailDraftSuccess extends UIState { + + final List listLocalEmailDraft; + + GetAllLocalEmailDraftSuccess(this.listLocalEmailDraft); + + @override + List get props => [listLocalEmailDraft]; +} + +class GetAllLocalEmailDraftFailure extends FeatureFailure { + + GetAllLocalEmailDraftFailure(dynamic exception) : super(exception: exception); +} \ No newline at end of file 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 deleted file mode 100644 index d80a71abf6..0000000000 --- a/lib/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart +++ /dev/null @@ -1,18 +0,0 @@ -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'; - -class GetComposerCacheSuccess extends UIState { - - final List listComposerCache; - - GetComposerCacheSuccess(this.listComposerCache); - - @override - List get props => [listComposerCache]; -} - -class GetComposerCacheFailure extends FeatureFailure { - - GetComposerCacheFailure(dynamic exception) : super(exception: exception); -} \ No newline at end of file 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_composer_cache_state.dart deleted file mode 100644 index 04460eda13..0000000000 --- a/lib/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:core/presentation/state/failure.dart'; -import 'package:core/presentation/state/success.dart'; - -class RemoveComposerCacheSuccess extends UIState { - - RemoveComposerCacheSuccess(); - - @override - List get props => []; -} - -class RemoveComposerCacheFailure extends FeatureFailure { - - RemoveComposerCacheFailure(dynamic exception) : super(exception: exception); -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/state/remove_local_email_draft_state.dart b/lib/features/mailbox_dashboard/domain/state/remove_local_email_draft_state.dart new file mode 100644 index 0000000000..a80c261dc3 --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/state/remove_local_email_draft_state.dart @@ -0,0 +1,9 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; + +class RemoveLocalEmailDraftSuccess extends UIState {} + +class RemoveLocalEmailDraftFailure extends FeatureFailure { + + 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_all_local_email_draft_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart new file mode 100644 index 0000000000..4ee4ae393c --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/usecases/get_all_local_email_draft_interactor.dart @@ -0,0 +1,24 @@ +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/get_all_local_email_draft_state.dart'; + +class GetAllLocalEmailDraftInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; + + GetAllLocalEmailDraftInteractor(this._localEmailDraftRepository); + + Stream> execute(AccountId accountId, UserName userName) async* { + try { + yield Right(GetAllLocalEmailDraftLoading()); + final listLocalEmailDraft = await _localEmailDraftRepository + .getAllLocalEmailDraft(accountId, userName); + yield Right(GetAllLocalEmailDraftSuccess(listLocalEmailDraft)); + } catch (exception) { + yield Left(GetAllLocalEmailDraftFailure(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_composer_cache_on_web_interactor.dart deleted file mode 100644 index 4a96959d70..0000000000 --- a/lib/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart +++ /dev/null @@ -1,25 +0,0 @@ -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/composer_cache_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart'; - -class GetComposerCacheOnWebInteractor { - final ComposerCacheRepository composerCacheRepository; - - GetComposerCacheOnWebInteractor(this.composerCacheRepository); - - Stream> execute(AccountId accountId, UserName userName) async* { - try { - final listComposerCache = await composerCacheRepository.getComposerCacheOnWeb( - accountId, - userName, - ); - yield Right(GetComposerCacheSuccess(listComposerCache)); - } catch (exception) { - yield Left(GetComposerCacheFailure(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_drafts_interactor.dart similarity index 52% 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_drafts_interactor.dart index 31bc522897..c4677a702a 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_drafts_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/state/remove_composer_cache_state.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_all_local_email_draft_state.dart'; -class RemoveAllComposerCacheOnWebInteractor { - final ComposerCacheRepository composerCacheRepository; +class RemoveAllLocalEmailDraftsInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; - RemoveAllComposerCacheOnWebInteractor(this.composerCacheRepository); + RemoveAllLocalEmailDraftsInteractor(this._localEmailDraftRepository); Future> execute(AccountId accountId, UserName userName) async { try { - composerCacheRepository.removeAllComposerCacheOnWeb(accountId, userName); - return Right(RemoveComposerCacheSuccess()); + await _localEmailDraftRepository.removeAllLocalEmailDrafts(accountId, userName); + return Right(RemoveAllLocalEmailDraftsSuccess()); } catch (exception) { - return Left(RemoveComposerCacheFailure(exception)); + return Left(RemoveAllLocalEmailDraftsFailure(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_composer_cache_by_id_on_web_interactor.dart deleted file mode 100644 index 08bdc06e5a..0000000000 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart +++ /dev/null @@ -1,30 +0,0 @@ -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/composer_cache_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_composer_cache_state.dart'; - -class RemoveComposerCacheByIdOnWebInteractor { - final ComposerCacheRepository composerCacheRepository; - - RemoveComposerCacheByIdOnWebInteractor(this.composerCacheRepository); - - Future> execute( - AccountId accountId, - UserName userName, - String composerId, - ) async { - try { - composerCacheRepository.removeComposerCacheByIdOnWeb( - accountId, - userName, - composerId, - ); - return Right(RemoveComposerCacheSuccess()); - } catch (exception) { - return Left(RemoveComposerCacheFailure(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 new file mode 100644 index 0000000000..a09fd5a3e3 --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_local_email_draft_interactor.dart @@ -0,0 +1,20 @@ +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_local_email_draft_state.dart'; + +class RemoveLocalEmailDraftInteractor { + final LocalEmailDraftRepository _localEmailDraftRepository; + + RemoveLocalEmailDraftInteractor(this._localEmailDraftRepository); + + Future> execute(String draftLocalId) async { + try { + _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 3a6f8c8d26..bde29fc43a 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'; @@ -60,34 +67,36 @@ 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/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/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_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'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; @@ -142,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 { @@ -186,7 +199,6 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find(), Get.find(), Get.find(), Get.find(), @@ -206,8 +218,6 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find(), - Get.find(), Get.find(), Get.find(), Get.find(), @@ -225,13 +235,15 @@ 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()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -274,8 +286,10 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => MailboxCacheDataSourceImpl( Get.find(), Get.find())); - Get.lazyPut(() => SessionStorageComposerDatasourceImpl( + Get.lazyPut(() => LocalEmailDraftDataSourceImpl( Get.find(), + Get.find(), + Get.find(), Get.find())); Get.lazyPut(() => LocalSpamReportDataSourceImpl( Get.find(), @@ -315,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 @@ -331,9 +354,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(() => RemoveAllLocalEmailDraftsInteractor(Get.find())); Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find())); Get.lazyPut(() => MarkAsStarEmailInteractor(Get.find())); Get.lazyPut(() => MarkAsMultipleEmailReadInteractor( @@ -368,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( @@ -387,12 +414,13 @@ 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()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -423,7 +451,7 @@ class MailboxDashBoardBindings extends BaseBindings { }, Get.find(), )); - Get.lazyPut(() => ComposerCacheRepositoryImpl(Get.find())); + Get.lazyPut(() => LocalEmailDraftRepositoryImpl(Get.find())); Get.lazyPut(() => SpamReportRepositoryImpl( { DataSourceType.local: Get.find(), @@ -445,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 660240fd41..e4bf2bc738 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -99,15 +99,14 @@ 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_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_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'; @@ -124,7 +123,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/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'; @@ -228,7 +227,6 @@ class MailboxDashBoardController extends ReloadableController final MoveToMailboxInteractor _moveToMailboxInteractor; final DeleteEmailPermanentlyInteractor _deleteEmailPermanentlyInteractor; final MarkAsMailboxReadInteractor _markAsMailboxReadInteractor; - final GetComposerCacheOnWebInteractor _getEmailCacheOnWebInteractor; 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 RemoveComposerCacheByIdOnWebInteractor _removeComposerCacheByIdOnWebInteractor; - final RemoveAllComposerCacheOnWebInteractor _removeAllComposerCacheOnWebInteractor; 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; + RemoveLocalEmailDraftInteractor? removeLocalEmailDraftInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -329,7 +327,6 @@ class MailboxDashBoardController extends ReloadableController this._moveToMailboxInteractor, this._deleteEmailPermanentlyInteractor, this._markAsMailboxReadInteractor, - this._getEmailCacheOnWebInteractor, this._getIdentityCacheOnWebInteractor, this._markAsEmailReadInteractor, this._markAsStarEmailInteractor, @@ -349,8 +346,6 @@ class MailboxDashBoardController extends ReloadableController this._unsubscribeEmailInteractor, this._restoreDeletedMessageInteractor, this._getRestoredDeletedMessageInteractor, - this._removeAllComposerCacheOnWebInteractor, - this._removeComposerCacheByIdOnWebInteractor, this._getAllIdentitiesInteractor, this.clearMailboxInteractor, this.storeEmailSortOrderInteractor, @@ -377,6 +372,8 @@ class MailboxDashBoardController extends ReloadableController listSearchFilterScrollController = ScrollController(); twakeAppManager.setExecutingBeforeReconnect(false); isRetryGetPaywallUrl = false; + getAllLocalEmailDraftInteractor = getBinding(); + removeLocalEmailDraftInteractor = getBinding(); } if (PlatformInfo.isIOS) { _registerPendingCurrentEmailIdInNotification(); @@ -386,15 +383,6 @@ class MailboxDashBoardController extends ReloadableController super.onReady(); } - void _handleComposerCache() async { - if (accountId.value == null || sessionCurrent == null) return; - - consumeState( - _getEmailCacheOnWebInteractor.execute( - accountId.value!, - sessionCurrent!.username)); - } - void _handleIdentityCache() async { if (accountId.value == null || sessionCurrent == null) return; @@ -478,8 +466,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 GetAllLocalEmailDraftSuccess) { + handlerGetAllLocalEmailDraft(success.listLocalEmailDraft); } else if (success is GetIdentityCacheOnWebSuccess) { goToSettings(); } else if (success is MarkAsStarEmailSuccess) { @@ -539,7 +527,7 @@ class MailboxDashBoardController extends ReloadableController _handleEmptyTrashFolderFailure(failure); } else if (failure is MoveMultipleEmailToMailboxFailure) { toastManager.showMessageFailure(failure); - } else if (failure is GetComposerCacheFailure) { + } else if (failure is GetAllLocalEmailDraftFailure) { _handleIdentityCache(); } else if (failure is GetServerSettingFailure) { isSenderImportantFlagEnabled.value = true; @@ -817,7 +805,7 @@ class MailboxDashBoardController extends ReloadableController _setUpComponentsFromSession(session); if (PlatformInfo.isWeb) { - _handleComposerCache(); + restoreLocalEmailDraft(); } if (PlatformInfo.isAndroid && !_notificationManager.isNotificationClickedOnTerminate) { @@ -1860,7 +1848,7 @@ class MailboxDashBoardController extends ReloadableController _getRouteParameters(); _setUpComponentsFromSession(session); if (PlatformInfo.isWeb) { - _handleComposerCache(); + restoreLocalEmailDraft(); } } @@ -3206,25 +3194,6 @@ class MailboxDashBoardController extends ReloadableController isRecoveringDeletedMessage.value = true; } - Future removeComposerCacheByIdOnWeb(String composerId) async { - if (accountId.value == null || sessionCurrent == null) return; - - await _removeComposerCacheByIdOnWebInteractor.execute( - accountId.value!, - sessionCurrent!.username, - composerId, - ); - } - - Future removeAllComposerCacheOnWeb() async { - if (accountId.value == null || sessionCurrent == null) return; - - await _removeAllComposerCacheOnWebInteractor.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/local_email_draft_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart new file mode 100644 index 0000000000..36aeefc0fa --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/local_email_draft_extension.dart @@ -0,0 +1,32 @@ + +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'; + +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, + ) ?? 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 0bf967b5a0..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 removeComposerCacheByIdOnWeb(composerId); - } } void _handleResultAfterCloseComposer(dynamic result) { 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/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/reopen_composer_cache_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart deleted file mode 100644 index c914b1abac..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 ReopenComposerCacheExtension on MailboxDashBoardController { - - void handleGetComposerCacheSuccess(GetComposerCacheSuccess success) { - removeAllComposerCacheOnWeb(); - - final listComposerCacheSortByIndex = success.listComposerCache - ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); - - final listArguments = listComposerCacheSortByIndex - .map((composerCache) => ComposerArguments.fromSessionStorageBrowser(composerCache)) - .toList(); - - openListComposer(listArguments); - } -} \ 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..a8af159ea6 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/restore_local_email_draft_extension.dart @@ -0,0 +1,80 @@ + +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'; +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'; +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'; +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( + accountId.value!, + sessionCurrent!.username, + )); + } + + void handlerGetAllLocalEmailDraft(List localEmailDrafts) { + final listPresentationLocalEmailDraft = localEmailDrafts + .map((localEmailDraft) => localEmailDraft.toPresentation()) + .toList(); + + final listLocalEmailDraftSortByTime = listPresentationLocalEmailDraft + ..sort((a, b) => b.savedTime.compareTo(a.savedTime)); + + showLocalEmailDraftListDialog(listLocalEmailDraftSortByTime); + } + + void showLocalEmailDraftListDialog(List presentationLocalEmailDrafts) { + DialogBuilderManager().showLocalEmailDraftListDialog( + emailDrafts: presentationLocalEmailDrafts, + accountId: accountId.value, + session: sessionCurrent, + ownEmailAddress: ownEmailAddress.value, + onEditLocalEmailDraftAction: _editLocalEmailDraft, + onRestoreAllLocalEmailDraftsAction: _restoreAllLocalEmailDrafts, + ); + } + + void _editLocalEmailDraft(PresentationLocalEmailDraft draftLocal) { + popBack(); + openComposer(ComposerArguments.fromLocalEmailDraft( + draftLocal.copyWith(displayMode: ScreenDisplayMode.normal), + )); + } + + void _restoreAllLocalEmailDrafts(List localDrafts) { + popBack(); + + + final listLocalEmailDraftSortByIndex = localDrafts + ..sort((a, b) => (a.composerIndex ?? 0).compareTo(b.composerIndex ?? 0)); + + final listComposerArguments = listLocalEmailDraftSortByIndex + .map(ComposerArguments.fromLocalEmailDraft) + .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/model/presentation_local_email_draft.dart b/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart new file mode 100644 index 0000000000..1c8293c0de --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/model/presentation_local_email_draft.dart @@ -0,0 +1,74 @@ +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 { + + final String id; + final String composerId; + final DateTime savedTime; + final Email? email; + final bool? hasRequestReadReceipt; + final bool? isMarkAsImportant; + final ScreenDisplayMode displayMode; + final int? composerIndex; + final int? draftHash; + final EmailActionType? actionType; + final EmailId? draftEmailId; + + PresentationLocalEmailDraft({ + required this.id, + required this.composerId, + required this.savedTime, + this.email, + this.hasRequestReadReceipt, + this.isMarkAsImportant, + 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, + savedTime, + email, + hasRequestReadReceipt, + isMarkAsImportant, + 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 new file mode 100644 index 0000000000..11a75395da --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_item_widget.dart @@ -0,0 +1,195 @@ +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); +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, + required this.draftLocal, + required this.imagePaths, + required this.isOldest, + this.onSelectLocalEmailDraftAction, + this.onEditLocalEmailDraftAction, + this.onSaveAsDraftLocalEmailDraftAction, + this.onDiscardLocalEmailDraftAction, + }); + + @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: () => onEditLocalEmailDraftAction?.call(draftLocal), + ), + ), + 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: () => onSaveAsDraftLocalEmailDraftAction?.call(draftLocal), + ), + ), + 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: () => onDiscardLocalEmailDraftAction?.call(draftLocal), + ), + ), + ], + ), + 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..c8d9cfa31d --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/widgets/local_email_draft/local_email_draft_list_dialog_builder.dart @@ -0,0 +1,412 @@ +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: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'; +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'; +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_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'; +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, + required this.accountId, + required this.session, + required this.ownEmailAddress, + required this.presentationLocalEmailDrafts, + this.onEditLocalEmailDraftAction, + this.onRestoreAllLocalEmailDraftsAction, + }); + + @override + State createState() => + _LocalEmailDraftListDialogBuilderState(); +} + +class _LocalEmailDraftListDialogBuilderState + 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; + late final RemoveAllLocalEmailDraftsInteractor? _removeAllLocalEmailDraftsInteractor; + + final ValueNotifier> _listLocalEmailDraftsNotifier = ValueNotifier([]); + + @override + void initState() { + super.initState(); + _responsiveUtils = Get.find(); + _imagePaths = Get.find(); + _appToast = Get.find(); + _removeLocalEmailDraftInteractor = getBinding(); + _createNewAndSaveEmailToDraftsInteractor = getBinding(); + _removeAllLocalEmailDraftsInteractor = getBinding(); + _scrollController = ScrollController(); + _listLocalEmailDraftsNotifier.value = widget.presentationLocalEmailDrafts; + } + + @override + void dispose() { + _listLocalEmailDraftsNotifier.dispose(); + _scrollController.dispose(); + if (SmartDialog.checkExist()) SmartDialog.dismiss(); + 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: ValueListenableBuilder( + valueListenable: _listLocalEmailDraftsNotifier, + builder: (context, localDrafts, _) { + 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: (draftLocal) => + _saveAsDraftLocalEmailDraft(draftLocal, context), + onDiscardLocalEmailDraftAction: (draftLocal) => + _handleDiscardLocalEmailDraftAction(draftLocal, context) + ); + }, + ); + }, + ), + ), + ), + 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: () => _handleDiscardAllLocalEmailDraftAction(context), + ), + TMailButtonWidget( + text: AppLocalizations.of(context).restoreAll, + 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: () => + widget.onRestoreAllLocalEmailDraftsAction?.call( + _listLocalEmailDraftsNotifier.value, + ), + ), + ], + ), + ) + ], + ), + ), + ); + } + + 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; + } + } + + void _handleDiscardLocalEmailDraftAction( + PresentationLocalEmailDraft emailDraft, + BuildContext context, + ) { + final appLocalizations = AppLocalizations.of(context); + MessageDialogActionManager().showConfirmDialogAction( + context, + appLocalizations.messageWarningDialogDiscardLocalDraft, + appLocalizations.yes, + cancelTitle: appLocalizations.no, + onConfirmAction: () => _removeLocalEmailDraft(context, emailDraft.id), + onCloseButtonAction: popBack, + ); + } + + 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 (showToast && 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, showToast: false); + } 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()]); + } + + void _handleDiscardAllLocalEmailDraftAction(BuildContext context) { + final appLocalizations = AppLocalizations.of(context); + MessageDialogActionManager().showConfirmDialogAction( + context, + appLocalizations.messageWarningDialogDiscardAllLocalDrafts, + appLocalizations.yes, + cancelTitle: appLocalizations.no, + onConfirmAction: () => _removeAllLocalEmailDrafts(context), + onCloseButtonAction: popBack, + ); + } + + 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, + ); + + 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 66e27e6315..0efae688df 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4887,5 +4887,59 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "localDraftList": "Local Draft List", + "@localDraftList": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "restoreAll": "Restore all", + "@restoreAll": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "discardAll": "Discard all", + "@discardAll": { + "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": {} + }, + "deleteLocalDraftSuccessfully": "Delete local draft successfully", + "@deleteLocalDraftSuccessfully": { + "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": {} + }, + "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/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/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 04de6749e3..32e2ed1a5f 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5160,4 +5160,67 @@ class AppLocalizations { name: 'spamReportToggleDescription', ); } + + String get localDraftList { + return Intl.message( + 'Local Draft List', + name: 'localDraftList', + ); + } + + String get restoreAll { + return Intl.message( + 'Restore all', + name: 'restoreAll', + ); + } + + String get discardAll { + return Intl.message( + 'Discard all', + 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', + ); + } + + String get deleteLocalDraftSuccessfully { + return Intl.message( + 'Delete local draft successfully', + 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', + ); + } + + 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', + ); + } } 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/composer/presentation/composer_controller_test.dart b/test/features/composer/presentation/composer_controller_test.dart index 5f1355f506..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_composer_cache_on_web_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_composer_cache_by_id_on_web_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 MockRemoveComposerCacheByIdOnWebInteractor mockRemoveComposerCacheByIdOnWebInteractor; - late MockSaveComposerCacheOnWebInteractor mockSaveComposerCacheOnWebInteractor; late MockDownloadImageAsBase64Interactor mockDownloadImageAsBase64Interactor; late MockTransformHtmlEmailContentInteractor mockTransformHtmlEmailContentInteractor; late MockGetServerSettingInteractor mockGetServerSettingInteractor; @@ -283,8 +277,6 @@ void main() { mockGetEmailContentInteractor = MockGetEmailContentInteractor(); mockGetAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); mockUploadController = MockUploadController(); - mockRemoveComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); - mockSaveComposerCacheOnWebInteractor = MockSaveComposerCacheOnWebInteractor(); mockDownloadImageAsBase64Interactor = MockDownloadImageAsBase64Interactor(); mockTransformHtmlEmailContentInteractor = MockTransformHtmlEmailContentInteractor(); mockGetServerSettingInteractor = MockGetServerSettingInteractor(); @@ -300,8 +292,6 @@ void main() { mockGetEmailContentInteractor, mockGetAllIdentitiesInteractor, mockUploadController, - mockRemoveComposerCacheByIdOnWebInteractor, - mockSaveComposerCacheOnWebInteractor, 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..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 @@ -59,11 +59,8 @@ 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/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_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'; @@ -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 = MockGetComposerCacheOnWebInteractor(); 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 removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor(); - final removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); 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(removeAllComposerCacheOnWebInteractor); - Get.put(removeComposerCacheByIdOnWebInteractor); 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, - removeAllComposerCacheOnWebInteractor, - removeComposerCacheByIdOnWebInteractor, 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..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 @@ -57,11 +57,8 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_b 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_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_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'; @@ -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 = MockGetComposerCacheOnWebInteractor(); 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 removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor(); - final removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); 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(removeAllComposerCacheOnWebInteractor); - Get.put(removeComposerCacheByIdOnWebInteractor); 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, - removeAllComposerCacheOnWebInteractor, - removeComposerCacheByIdOnWebInteractor, 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..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 @@ -44,11 +44,8 @@ import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cach 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_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_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'; @@ -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 MockGetComposerCacheOnWebInteractor 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 MockRemoveAllComposerCacheOnWebInteractor removeAllComposerCacheOnWebInteractor; - late MockRemoveComposerCacheByIdOnWebInteractor removeComposerCacheByIdOnWebInteractor; late MockGetAllIdentitiesInteractor getAllIdentitiesInteractor; late MockClearMailboxInteractor clearMailboxInteractor; late MockGetAuthenticationInfoInteractor getAuthenticationInfoInteractor; @@ -309,7 +300,6 @@ void main() { moveToMailboxInteractor = MockMoveToMailboxInteractor(); deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); - getEmailCacheOnWebInteractor = MockGetComposerCacheOnWebInteractor(); getIdentityCacheOnWebInteractor = MockGetIdentityCacheOnWebInteractor(); markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); @@ -328,8 +318,6 @@ void main() { unsubscribeEmailInteractor = MockUnsubscribeEmailInteractor(); restoreDeletedMessageInteractor = MockRestoredDeletedMessageInteractor(); getRestoredDeletedMessageInteractor = MockGetRestoredDeletedMessageInterator(); - removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor(); - removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); 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, - removeAllComposerCacheOnWebInteractor, - removeComposerCacheByIdOnWebInteractor, getAllIdentitiesInteractor, clearMailboxInteractor, mockStoreEmailSortOrderInteractor,