From e675f98a6c85d9c4a90efc686e6ff72d23b4c678 Mon Sep 17 00:00:00 2001 From: hieubt Date: Thu, 21 Dec 2023 16:56:06 +0700 Subject: [PATCH] TF-2101 Handle restore deleted messages --- .../get_restored_deleted_message_state.dart | 45 ++++++- .../state/restore_deleted_message_state.dart | 15 ++- ...t_restored_deleted_message_interactor.dart | 39 +++++- ...> restore_deleted_message_interactor.dart} | 11 +- .../email_recovery_controller.dart | 11 +- .../email_recovery_form_desktop_builder.dart | 1 - .../email_recovery_form_mobile_builder.dart | 1 - .../email_recovery_form_tablet_builder.dart | 1 - .../avatar_suggestion_item_widget.dart | 2 +- .../text_input_field_suggestion_widget.dart | 4 +- .../data/datasource/mailbox_datasource.dart | 3 + .../mailbox_cache_datasource_impl.dart | 7 ++ .../mailbox_datasource_impl.dart | 9 ++ .../mailbox/data/network/mailbox_api.dart | 47 ++++++++ .../repository/mailbox_repository_impl.dart | 7 ++ .../set_mailbox_method_exception.dart | 4 +- .../model/get_mailbox_by_role_response.dart | 15 +++ .../domain/repository/mailbox_repository.dart | 4 + .../state/get_mailbox_by_role_state.dart | 20 ++++ .../get_mailbox_by_role_interactor.dart | 42 +++++++ .../presentation/mailbox_controller.dart | 3 + .../mixin/mailbox_widget_mixin.dart | 3 +- .../bindings/mailbox_dashboard_bindings.dart | 22 ++++ .../mailbox_dashboard_controller.dart | 111 ++++++++++++++++-- .../mailbox_dashboard_view_web.dart | 2 +- ...deleted_message_loading_banner_widget.dart | 102 +++++++--------- .../thread/presentation/thread_view.dart | 2 +- lib/l10n/intl_messages.arb | 10 +- lib/main/localizations/app_localizations.dart | 9 +- .../presentation_mailbox_extension.dart | 2 + 30 files changed, 456 insertions(+), 98 deletions(-) rename lib/features/email/domain/usecases/{restore_deleted_message_interactor.dart.dart => restore_deleted_message_interactor.dart} (64%) create mode 100644 lib/features/mailbox/domain/model/get_mailbox_by_role_response.dart create mode 100644 lib/features/mailbox/domain/state/get_mailbox_by_role_state.dart create mode 100644 lib/features/mailbox/domain/usecases/get_mailbox_by_role_interactor.dart diff --git a/lib/features/email/domain/state/get_restored_deleted_message_state.dart b/lib/features/email/domain/state/get_restored_deleted_message_state.dart index e1c52d1e75..d640d1ca4d 100644 --- a/lib/features/email/domain/state/get_restored_deleted_message_state.dart +++ b/lib/features/email/domain/state/get_restored_deleted_message_state.dart @@ -1,16 +1,55 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:email_recovery/email_recovery/email_recovery_action.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; +import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; class GetRestoredDeletedMessageLoading extends LoadingState {} -class GetRestoredDeletedMessageSuccess extends UIState { +class GetRestoredDeletedMessageSuccess extends UIActionState { final EmailRecoveryAction emailRecoveryAction; + + + GetRestoredDeletedMessageSuccess( + this.emailRecoveryAction, + { + jmap.State? currentMailboxState, + } + ) : super(null, currentMailboxState); - GetRestoredDeletedMessageSuccess(this.emailRecoveryAction); + @override + List get props => [emailRecoveryAction, ...super.props]; +} + +class GetRestoredDeletedMessageCompleted extends GetRestoredDeletedMessageSuccess { + final Mailbox? recoveredMailbox; + + GetRestoredDeletedMessageCompleted( + EmailRecoveryAction emailRecoveryAction, + {this.recoveredMailbox} + ) : super(emailRecoveryAction); @override - List get props => [emailRecoveryAction]; + List get props => [emailRecoveryAction, recoveredMailbox]; +} + +class GetRestoredDeletedMessageWaiting extends GetRestoredDeletedMessageSuccess { + GetRestoredDeletedMessageWaiting( + EmailRecoveryAction emailRecoveryAction, + ) : super(emailRecoveryAction); +} + +class GetRestoredDeletedMessageInProgress extends GetRestoredDeletedMessageSuccess { + GetRestoredDeletedMessageInProgress( + EmailRecoveryAction emailRecoveryAction, + ) : super(emailRecoveryAction); +} + +class GetRestoredDeletedMessageCanceled extends GetRestoredDeletedMessageSuccess { + GetRestoredDeletedMessageCanceled( + EmailRecoveryAction emailRecoveryAction, + ) : super(emailRecoveryAction); } class GetRestoredDeletedMessageFailure extends FeatureFailure { diff --git a/lib/features/email/domain/state/restore_deleted_message_state.dart b/lib/features/email/domain/state/restore_deleted_message_state.dart index ef3a5be910..c946367aac 100644 --- a/lib/features/email/domain/state/restore_deleted_message_state.dart +++ b/lib/features/email/domain/state/restore_deleted_message_state.dart @@ -1,16 +1,23 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:email_recovery/email_recovery/email_recovery_action.dart'; +import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; class RestoreDeletedMessageLoading extends LoadingState {} -class RestoreDeletedMessageSuccess extends UIState { +class RestoreDeletedMessageSuccess extends UIActionState { final EmailRecoveryAction emailRecoveryAction; - - RestoreDeletedMessageSuccess(this.emailRecoveryAction); + + RestoreDeletedMessageSuccess( + this.emailRecoveryAction, + { + jmap.State? currentMailboxState, + } + ) : super(null, currentMailboxState); @override - List get props => [emailRecoveryAction]; + List get props => [emailRecoveryAction, ...super.props]; } class RestoreDeletedMessageFailure extends FeatureFailure { diff --git a/lib/features/email/domain/usecases/get_restored_deleted_message_interactor.dart b/lib/features/email/domain/usecases/get_restored_deleted_message_interactor.dart index 6c16c6690c..ff3c5cf848 100644 --- a/lib/features/email/domain/usecases/get_restored_deleted_message_interactor.dart +++ b/lib/features/email/domain/usecases/get_restored_deleted_message_interactor.dart @@ -4,21 +4,56 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; import 'package:email_recovery/email_recovery/email_recovery_action_id.dart'; +import 'package:email_recovery/email_recovery/email_recovery_status.dart.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_restored_deleted_message_state.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; class GetRestoredDeletedMessageInterator { final EmailRepository _emailRepository; + final MailboxRepository _mailboxRepository; - GetRestoredDeletedMessageInterator(this._emailRepository); + GetRestoredDeletedMessageInterator(this._emailRepository, this._mailboxRepository); Stream> execute( + Session session, + AccountId accountId, EmailRecoveryActionId emailRecoveryActionId, ) async* { try { yield Right(GetRestoredDeletedMessageLoading()); + final emailRecovery = await _emailRepository.getRestoredDeletedMessage(emailRecoveryActionId); - yield Right(GetRestoredDeletedMessageSuccess(emailRecovery)); + + switch (emailRecovery.status) { + case EmailRecoveryStatus.completed: + final getMailboxByRoleResponse = await _mailboxRepository.getMailboxByRole( + session, + accountId, + Role('Restored-Messages') + ); + final recoveredMailbox = getMailboxByRoleResponse.mailbox; + + yield Right(GetRestoredDeletedMessageCompleted(emailRecovery, recoveredMailbox: recoveredMailbox)); + break; + case EmailRecoveryStatus.failed: + yield Left(GetRestoredDeletedMessageFailure(null)); + break; + case EmailRecoveryStatus.inProgress: + yield Right(GetRestoredDeletedMessageInProgress(emailRecovery)); + break; + case EmailRecoveryStatus.waiting: + yield Right(GetRestoredDeletedMessageWaiting(emailRecovery)); + break; + case EmailRecoveryStatus.canceled: + yield Right(GetRestoredDeletedMessageCanceled(emailRecovery)); + break; + default: + yield Left(GetRestoredDeletedMessageFailure(null)); + } } catch (e) { yield Left(GetRestoredDeletedMessageFailure(e)); } diff --git a/lib/features/email/domain/usecases/restore_deleted_message_interactor.dart.dart b/lib/features/email/domain/usecases/restore_deleted_message_interactor.dart similarity index 64% rename from lib/features/email/domain/usecases/restore_deleted_message_interactor.dart.dart rename to lib/features/email/domain/usecases/restore_deleted_message_interactor.dart index 9e243f1f25..4a68bdd841 100644 --- a/lib/features/email/domain/usecases/restore_deleted_message_interactor.dart.dart +++ b/lib/features/email/domain/usecases/restore_deleted_message_interactor.dart @@ -3,22 +3,29 @@ import 'dart:async'; 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/session/session.dart'; import 'package:tmail_ui_user/features/email/domain/model/restore_deleted_message_request.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/restore_deleted_message_state.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; class RestoredDeletedMessageInteractor { final EmailRepository _emailRepository; + final MailboxRepository _mailboxRepository; - RestoredDeletedMessageInteractor(this._emailRepository); + RestoredDeletedMessageInteractor(this._emailRepository, this._mailboxRepository); Stream> execute( + Session session, + AccountId accountId, RestoredDeletedMessageRequest newRecoveryRequest, ) async* { try { yield Right(RestoreDeletedMessageLoading()); + final currentMailboxState = await _mailboxRepository.getMailboxState(session, accountId); final emailRecovery = await _emailRepository.restoreDeletedMessage(newRecoveryRequest); - yield Right(RestoreDeletedMessageSuccess(emailRecovery)); + yield Right(RestoreDeletedMessageSuccess(emailRecovery, currentMailboxState: currentMailboxState)); } catch (e) { yield Left(RestoreDeletedMessageFailure(e)); } diff --git a/lib/features/email_recovery/presentation/email_recovery_controller.dart b/lib/features/email_recovery/presentation/email_recovery_controller.dart index 97ac13b79d..1122da6041 100644 --- a/lib/features/email_recovery/presentation/email_recovery_controller.dart +++ b/lib/features/email_recovery/presentation/email_recovery_controller.dart @@ -297,10 +297,10 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin { void onRestore(BuildContext context) { KeyboardUtils.hideKeyboard(context); - final UTCDate? deletedBefore; - final UTCDate? deletedAfter; - final UTCDate? receivedBefore; - final UTCDate? receivedAfter; + UTCDate? deletedBefore; + UTCDate? deletedAfter; + UTCDate? receivedBefore; + UTCDate? receivedAfter; if (deletionDateFieldSelected.value == EmailRecoveryTimeType.customRange) { deletedBefore = endDeletionDate.value?.toUTCDate(); deletedAfter = startDeletionDate.value?.toUTCDate(); @@ -343,6 +343,9 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin { focusManager.subjectFieldFocusNode.removeListener(_onSubjectFieldFocusChanged); focusManager.recipientsFieldFocusNode.removeListener(_onRecipientsFieldFocusChanged); focusManager.senderFieldFocusNode.removeListener(_onSenderFieldFocusChanged); + subjectFieldInputController.dispose(); + recipientsFieldInputController.dispose(); + senderFieldInputController.dispose(); focusManager.dispose(); super.dispose(); } diff --git a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart index 58be0f2072..bd6059faee 100644 --- a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart +++ b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart @@ -109,7 +109,6 @@ class EmailRecoveryFormDesktopBuilder extends GetWidget Obx(() => CheckBoxHasAttachmentWidget( hasAttachmentValue: controller.hasAttachment.value, currentFocusNode: controller.focusManager.attachmentCheckboxFocusNode, - nextFocusNode: controller.focusManager.createButtonFocusNode, onChanged: (value) => controller.onChangeHasAttachment(value), )), SizedBox(width: controller.responsiveUtils.getDeviceWidth(context) * 0.04), diff --git a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_mobile_builder.dart b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_mobile_builder.dart index 3e2815b867..732ab48d8f 100644 --- a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_mobile_builder.dart +++ b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_mobile_builder.dart @@ -94,7 +94,6 @@ class EmailRecoveryFormMobileBuilder extends GetWidget Obx(() => CheckBoxHasAttachmentWidget( hasAttachmentValue: controller.hasAttachment.value, currentFocusNode: controller.focusManager.attachmentCheckboxFocusNode, - nextFocusNode: controller.focusManager.deletionDateFieldFocusNode, onChanged: (value) => controller.onChangeHasAttachment(value), )) ], diff --git a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_tablet_builder.dart b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_tablet_builder.dart index 81670aa588..257a32cdc8 100644 --- a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_tablet_builder.dart +++ b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_tablet_builder.dart @@ -107,7 +107,6 @@ class EmailRecoveryFormTabletBuilder extends GetWidget Obx(() => CheckBoxHasAttachmentWidget( hasAttachmentValue: controller.hasAttachment.value, currentFocusNode: controller.focusManager.attachmentCheckboxFocusNode, - nextFocusNode: controller.focusManager.deletionDateFieldFocusNode, onChanged: (value) => controller.onChangeHasAttachment(value), )), SizedBox(width: controller.responsiveUtils.getDeviceWidth(context) * 0.04), diff --git a/lib/features/email_recovery/presentation/widgets/text_input_field/avatar_suggestion_item_widget.dart b/lib/features/email_recovery/presentation/widgets/text_input_field/avatar_suggestion_item_widget.dart index f7eed318a7..6e68a63842 100644 --- a/lib/features/email_recovery/presentation/widgets/text_input_field/avatar_suggestion_item_widget.dart +++ b/lib/features/email_recovery/presentation/widgets/text_input_field/avatar_suggestion_item_widget.dart @@ -1,5 +1,5 @@ -import 'package:core/core.dart'; import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/extensions/string_extension.dart'; import 'package:flutter/material.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/model.dart'; diff --git a/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart b/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart index 4aeee74eb0..6bc6270549 100644 --- a/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart +++ b/lib/features/email_recovery/presentation/widgets/text_input_field/text_input_field_suggestion_widget.dart @@ -15,7 +15,7 @@ import 'package:tmail_ui_user/features/email_recovery/presentation/styles/text_i import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/suggestion_item_widget.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/suggestion_tag_item_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart'; -import 'package:tmail_ui_user/main/utils/app_constants.dart'; +import 'package:tmail_ui_user/main/utils/app_config.dart'; typedef OnSuggestionEmailAddress = Future> Function(String word); typedef OnUpdateListEmailAddressAction = void Function(EmailRecoveryField field, List newDate); @@ -325,7 +325,7 @@ class _TextInputFieldSuggestionWidgetState extends State.empty(growable: true); if ( - processedQuery.length >= AppConstants.limitCharToStartSearch + processedQuery.length >= AppConfig.limitCharToStartSearch && widget.onSuggestionEmailAddress != null ) { final listEmailAddress = await widget.onSuggestionEmailAddress!(processedQuery); diff --git a/lib/features/mailbox/data/datasource/mailbox_datasource.dart b/lib/features/mailbox/data/datasource/mailbox_datasource.dart index 40325b1b49..d18fe6f9aa 100644 --- a/lib/features/mailbox/data/datasource/mailbox_datasource.dart +++ b/lib/features/mailbox/data/datasource/mailbox_datasource.dart @@ -14,6 +14,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; @@ -51,4 +52,6 @@ abstract class MailboxDataSource { Future> createDefaultMailbox(Session session, AccountId accountId, List listRole); Future setRoleDefaultMailbox(Session session, AccountId accountId, List listMailbox); + + Future getMailboxByRole(Session session, AccountId accountId, Role role); } \ No newline at end of file diff --git a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart index 3ed368bd57..6e4096c14c 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart @@ -9,6 +9,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.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/mailbox/mailbox.dart'; @@ -16,6 +17,7 @@ import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasourc import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; @@ -104,4 +106,9 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource { Future> setRoleDefaultMailbox(Session session, AccountId accountId, List listMailbox) { throw UnimplementedError(); } + + @override + Future getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}) { + throw UnimplementedError(); + } } \ No newline at end of file diff --git a/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart b/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart index 7d88da370a..0adc888fe8 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart @@ -9,6 +9,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.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/mailbox/mailbox.dart'; @@ -17,6 +18,7 @@ import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_respons 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/domain/model/create_new_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; @@ -132,4 +134,11 @@ class MailboxDataSourceImpl extends MailboxDataSource { return await mailboxAPI.setRoleDefaultMailbox(session, accountId, listMailbox); }).catchError(_exceptionThrower.throwException); } + + @override + Future getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}) { + return Future.sync(() async { + return await mailboxAPI.getMailboxByRole(session, accountId, role); + }).catchError(_exceptionThrower.throwException); + } } \ No newline at end of file diff --git a/lib/features/mailbox/data/network/mailbox_api.dart b/lib/features/mailbox/data/network/mailbox_api.dart index db123fe7ed..e51569d40a 100644 --- a/lib/features/mailbox/data/network/mailbox_api.dart +++ b/lib/features/mailbox/data/network/mailbox_api.dart @@ -21,6 +21,8 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/changes/changes_mailbox_respo import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_method.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_filter_condition.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/query/query_mailbox_method.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/set/set_mailbox_method.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/set/set_mailbox_response.dart'; import 'package:model/error_type_handler/set_method_error_handler_mixin.dart'; @@ -32,6 +34,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_met import 'package:tmail_ui_user/features/mailbox/domain/extensions/list_mailbox_id_extension.dart'; import 'package:tmail_ui_user/features/mailbox/domain/extensions/role_extension.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart'; @@ -499,4 +502,48 @@ class MailboxAPI with HandleSetErrorMixin { throw SetMailboxMethodException(mapErrors); } } + + Future getMailboxByRole( + Session session, + AccountId accountId, + Role role, + { + UnsignedInt? limit + } + ) async { + const int defaultLimit = 1; + final processingInvocation = ProcessingInvocation(); + final requestBuilder = JmapRequestBuilder(httpClient, processingInvocation); + final mailboxQueryMethod = QueryMailboxMethod(accountId)..addLimit(limit ?? UnsignedInt(defaultLimit)); + + final mailboxFilterCondition = MailboxFilterCondition(role: role); + mailboxQueryMethod.addFilters(mailboxFilterCondition); + + final mailboxQueryMethodInvocation = requestBuilder.invocation(mailboxQueryMethod); + final getMailBoxMethod = GetMailboxMethod(accountId) + ..addReferenceIds(processingInvocation.createResultReference( + mailboxQueryMethodInvocation.methodCallId, + ReferencePath.idsPath, + )); + final getMailboxInvocation = requestBuilder.invocation(getMailBoxMethod); + + final capabilities = getMailBoxMethod.requiredCapabilities + .toCapabilitiesSupportTeamMailboxes(session, accountId); + + final result = await (requestBuilder + ..usings(capabilities)) + .build() + .execute(); + + final mailboxResponse = result.parse( + getMailboxInvocation.methodCallId, + GetMailboxResponse.deserialize + ); + + if (mailboxResponse?.list.isNotEmpty == true) { + return GetMailboxByRoleResponse(mailbox: mailboxResponse!.list.first); + } else { + throw NotFoundMailboxException(); + } + } } \ No newline at end of file diff --git a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart index 62f249aa59..24148e2949 100644 --- a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart +++ b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart @@ -11,6 +11,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/extensions/list_mailbox_extension.dart'; @@ -20,6 +21,7 @@ import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource. import 'package:tmail_ui_user/features/mailbox/data/extensions/state_extension.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; @@ -219,4 +221,9 @@ class MailboxRepositoryImpl extends MailboxRepository { Future setRoleDefaultMailbox(Session session, AccountId accountId, List listMailbox) { return mapDataSource[DataSourceType.network]!.setRoleDefaultMailbox(session, accountId, listMailbox); } + + @override + Future getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}) { + return mapDataSource[DataSourceType.network]!.getMailboxByRole(session, accountId, role); + } } \ No newline at end of file diff --git a/lib/features/mailbox/domain/exceptions/set_mailbox_method_exception.dart b/lib/features/mailbox/domain/exceptions/set_mailbox_method_exception.dart index 9578d67274..fed18f8e1e 100644 --- a/lib/features/mailbox/domain/exceptions/set_mailbox_method_exception.dart +++ b/lib/features/mailbox/domain/exceptions/set_mailbox_method_exception.dart @@ -11,4 +11,6 @@ class SetMailboxMethodException implements Exception { class NotFoundMailboxCreatedException implements Exception {} -class NotFoundMailboxUpdatedRoleException implements Exception {} \ No newline at end of file +class NotFoundMailboxUpdatedRoleException implements Exception {} + +class NotFoundMailboxException implements Exception {} \ No newline at end of file diff --git a/lib/features/mailbox/domain/model/get_mailbox_by_role_response.dart b/lib/features/mailbox/domain/model/get_mailbox_by_role_response.dart new file mode 100644 index 0000000000..f26d8790d0 --- /dev/null +++ b/lib/features/mailbox/domain/model/get_mailbox_by_role_response.dart @@ -0,0 +1,15 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; + +class GetMailboxByRoleResponse with EquatableMixin { + final Mailbox? mailbox; + + GetMailboxByRoleResponse({ + this.mailbox, + }); + + @override + List get props => [ + mailbox, + ]; +} \ No newline at end of file diff --git a/lib/features/mailbox/domain/repository/mailbox_repository.dart b/lib/features/mailbox/domain/repository/mailbox_repository.dart index e9aa3363e5..a3f40851e4 100644 --- a/lib/features/mailbox/domain/repository/mailbox_repository.dart +++ b/lib/features/mailbox/domain/repository/mailbox_repository.dart @@ -9,9 +9,11 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; @@ -47,4 +49,6 @@ abstract class MailboxRepository { Future> createDefaultMailbox(Session session, AccountId accountId, List listRole); Future setRoleDefaultMailbox(Session session, AccountId accountId, List listMailbox); + + Future getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}); } \ No newline at end of file diff --git a/lib/features/mailbox/domain/state/get_mailbox_by_role_state.dart b/lib/features/mailbox/domain/state/get_mailbox_by_role_state.dart new file mode 100644 index 0000000000..c8a64f6edd --- /dev/null +++ b/lib/features/mailbox/domain/state/get_mailbox_by_role_state.dart @@ -0,0 +1,20 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; + +class GetMailboxByRoleLoading extends LoadingState {} + +class GetMailboxByRoleSuccess extends UIState { + final Mailbox mailbox; + + GetMailboxByRoleSuccess(this.mailbox); + + @override + List get props => [mailbox]; +} + +class InvalidMailboxRole extends FeatureFailure {} + +class GetMailboxByRoleFailure extends FeatureFailure { + GetMailboxByRoleFailure(dynamic exception) : super(exception: exception); +} \ No newline at end of file diff --git a/lib/features/mailbox/domain/usecases/get_mailbox_by_role_interactor.dart b/lib/features/mailbox/domain/usecases/get_mailbox_by_role_interactor.dart new file mode 100644 index 0000000000..e9c4ec2e00 --- /dev/null +++ b/lib/features/mailbox/domain/usecases/get_mailbox_by_role_interactor.dart @@ -0,0 +1,42 @@ +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/session/session.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/state/get_mailbox_by_role_state.dart'; + +class GetMailboxByRoleInteractor { + final MailboxRepository _mailboxRepository; + + GetMailboxByRoleInteractor(this._mailboxRepository); + + Stream> execute( + Session session, + AccountId accountId, + Role role, + { + UnsignedInt? limit, + } + ) async* { + try { + yield Right(GetMailboxByRoleLoading()); + final response = await _mailboxRepository.getMailboxByRole( + session, + accountId, + role, + limit: limit + ); + final mailbox = response.mailbox; + if (mailbox != null) { + yield Right(GetMailboxByRoleSuccess(mailbox)); + } else { + yield Left(InvalidMailboxRole()); + } + } catch (e) { + yield Left(GetMailboxByRoleFailure(e)); + } + } +} \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 7a2711ed81..8452d40b04 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -25,6 +25,7 @@ import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_email_permanently_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_emails_permanently_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/get_restored_deleted_message_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; @@ -265,6 +266,8 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM _refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is EmptySpamFolderSuccess) { _refreshMailboxChanges(currentMailboxState: success.currentMailboxState); + } else if (success is GetRestoredDeletedMessageSuccess) { + _refreshMailboxChanges(properties: MailboxConstants.propertiesDefault); } }); }); diff --git a/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart b/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart index 216966f646..cd49df0eae 100644 --- a/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart +++ b/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart @@ -33,7 +33,8 @@ mixin MailboxWidgetMixin { return [ if (PlatformInfo.isWeb) MailboxActions.openInNewTab, - MailboxActions.newSubfolder, + if (!mailbox.isRecovered) + MailboxActions.newSubfolder, if (mailbox.isTrash) ...[ MailboxActions.emptyTrash, 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 b4b5a317ed..939570cb35 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -20,9 +20,11 @@ import 'package:tmail_ui_user/features/email/data/repository/email_repository_im import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_permanently_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/get_restored_deleted_message_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/restore_deleted_message_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/bindings/email_bindings.dart'; import 'package:tmail_ui_user/features/home/domain/repository/session_repository.dart'; @@ -162,6 +164,8 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), + Get.find(), )); Get.put(AdvancedFilterController()); } @@ -176,6 +180,8 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -307,6 +313,14 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find() )); Get.lazyPut(() => UnsubscribeEmailInteractor(Get.find())); + Get.lazyPut(() => RestoredDeletedMessageInteractor( + Get.find(), + Get.find() + )); + Get.lazyPut(() => GetRestoredDeletedMessageInterator( + Get.find(), + Get.find() + )); } @override @@ -318,6 +332,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -353,5 +368,12 @@ class MailboxDashBoardBindings extends BaseBindings { DataSourceType.hiveCache: Get.find() }, )); + Get.lazyPut(() => MailboxRepositoryImpl( + { + DataSourceType.network: Get.find(), + DataSourceType.local: 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 3848d268f5..0b6ef7e65e 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -4,6 +4,8 @@ import 'dart:convert'; import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; +import 'package:email_recovery/email_recovery/email_recovery_action.dart'; +import 'package:email_recovery/email_recovery/email_recovery_action_id.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -12,6 +14,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/capability/mail_capability.dart'; import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; @@ -45,18 +48,23 @@ import 'package:tmail_ui_user/features/destination_picker/presentation/model/des import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart'; +import 'package:tmail_ui_user/features/email/domain/model/restore_deleted_message_request.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_email_permanently_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_emails_permanently_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_sending_email_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/get_restored_deleted_message_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/restore_deleted_message_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/store_sending_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_permanently_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/get_restored_deleted_message_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/restore_deleted_message_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; @@ -147,6 +155,7 @@ import 'package:tmail_ui_user/main/routes/navigation_router.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/routes/route_utils.dart'; import 'package:tmail_ui_user/main/utils/email_receive_manager.dart'; +import 'package:uuid/uuid.dart'; import 'package:workmanager/workmanager.dart' as work_manager; class MailboxDashBoardController extends ReloadableController { @@ -181,6 +190,8 @@ class MailboxDashBoardController extends ReloadableController { final UpdateEmailDraftsInteractor _updateEmailDraftsInteractor; final DeleteSendingEmailInteractor _deleteSendingEmailInteractor; final UnsubscribeEmailInteractor _unsubscribeEmailInteractor; + final RestoredDeletedMessageInteractor _restoreDeletedMessageInteractor; + final GetRestoredDeletedMessageInterator _getRestoredDeletedMessageInteractor; GetAllVacationInteractor? _getAllVacationInteractor; UpdateVacationInteractor? _updateVacationInteractor; @@ -212,6 +223,7 @@ class MailboxDashBoardController extends ReloadableController { final listSendingEmails = RxList(); final refreshingMailboxState = Rx>(Right(UIState.idle)); final draggableAppState = Rxn(); + final isRecoveringDeletedMessage = RxBool(false); Session? sessionCurrent; Map mapDefaultMailboxIdByRole = {}; @@ -258,6 +270,8 @@ class MailboxDashBoardController extends ReloadableController { this._updateEmailDraftsInteractor, this._deleteSendingEmailInteractor, this._unsubscribeEmailInteractor, + this._restoreDeletedMessageInteractor, + this._getRestoredDeletedMessageInteractor, ); @override @@ -353,6 +367,11 @@ class MailboxDashBoardController extends ReloadableController { getAllSendingEmails(); } else if (success is UnsubscribeEmailSuccess) { _handleUnsubscribeMailSuccess(success.newEmail); + } else if (success is RestoreDeletedMessageSuccess) { + dispatchMailboxUIAction(RefreshChangeMailboxAction(success.currentMailboxState)); + _handleRestoreDeletedMessageSuccess(success.emailRecoveryAction.id!); + } else if (success is GetRestoredDeletedMessageSuccess) { + _handleGetRestoredDeletedMessageSuccess(success); } } @@ -373,6 +392,10 @@ class MailboxDashBoardController extends ReloadableController { _markAsReadMailboxFailure(failure); } else if (failure is GetEmailByIdFailure) { _handleGetEmailDetailedFailed(failure); + } else if (failure is RestoreDeletedMessageFailure) { + _handleRestoreDeletedMessageFailed(); + } else if (failure is GetRestoredDeletedMessageFailure) { + _handleRestoreDeletedMessageFailed(); } } @@ -2427,28 +2450,96 @@ class MailboxDashBoardController extends ReloadableController { } } + void _handleRestoreDeletedMessageSuccess(EmailRecoveryActionId emailRecoveryActionId) async { + log('MailboxDashBoardController::_handleRestoreDeletedMessageSuccess():emailRecoveryActionId: $emailRecoveryActionId'); + _getRestoredDeletedMessage(emailRecoveryActionId); + } + + void _getRestoredDeletedMessage(EmailRecoveryActionId emailRecoveryActionId) { + consumeState(_getRestoredDeletedMessageInteractor.execute(sessionCurrent!, accountId.value!, emailRecoveryActionId)); + } + + void _handleRestoreDeletedMessageFailed() { + appToast.showToastErrorMessage( + currentOverlayContext!, + AppLocalizations.of(currentOverlayContext!).restoreDeletedMessageFailed + ); + } + + void _handleGetRestoredDeletedMessageSuccess(GetRestoredDeletedMessageSuccess success) async { + if (selectedMailbox.value != null && selectedMailbox.value!.isRecovered) { + dispatchEmailUIAction(RefreshChangeEmailAction(null)); + } + + if (success is GetRestoredDeletedMessageCompleted) { + isRecoveringDeletedMessage.value = false; + if (success.recoveredMailbox != null) { + appToast.showToastMessage( + currentOverlayContext!, + AppLocalizations.of(currentContext!).restoreDeletedMessageSuccess, + actionName: AppLocalizations.of(currentContext!).open, + onActionClick: () => openMailboxAction(success.recoveredMailbox!.toPresentationMailbox()), + leadingSVGIcon: imagePaths.icRecoverDeletedMessages, + leadingSVGIconColor: Colors.white, + backgroundColor: AppColor.toastSuccessBackgroundColor, + textColor: Colors.white, + actionIcon: SvgPicture.asset( + imagePaths.icFolderMailbox, + colorFilter: Colors.white.asFilter(), + ) + ); + } else { + appToast.showToastSuccessMessage( + currentOverlayContext!, + AppLocalizations.of(currentContext!).restoreDeletedMessageSuccess + ); + } + } else if (success is GetRestoredDeletedMessageInProgress || success is GetRestoredDeletedMessageWaiting) { + await Future.delayed(const Duration(seconds: 2)); + _getRestoredDeletedMessage(success.emailRecoveryAction.id!); + } else if (success is GetRestoredDeletedMessageCanceled) { + isRecoveringDeletedMessage.value = false; + appToast.showToastMessage( + currentOverlayContext!, + AppLocalizations.of(currentContext!).restoreDeletedMessageCanceled, + leadingSVGIcon: imagePaths.icRecoverDeletedMessages, + leadingSVGIconColor: Colors.white, + backgroundColor: AppColor.primaryColor, + textColor: Colors.white, + ); + } + } + void gotoEmailRecovery() async { closeMailboxMenuDrawer(); - final currentAccountId = accountId.value; final currentSession = sessionCurrent; if (currentAccountId != null && currentSession != null) { - final arguments = EmailRecoveryArguments(currentAccountId, currentSession); + final arguments = EmailRecoveryArguments(currentAccountId, currentSession); - if (PlatformInfo.isWeb) { - await DialogRouter.pushGeneralDialog( + final result = PlatformInfo.isWeb + ? await DialogRouter.pushGeneralDialog( routeName: AppRoutes.emailRecovery, arguments: arguments, - ); - } else { - await push( - AppRoutes.emailRecovery, - arguments: arguments - ); + ) + : await push(AppRoutes.emailRecovery, arguments: arguments); + + if (result is EmailRecoveryAction) { + log('MailboxDashBoardController::gotoEmailRecovery():result: $result'); + handleRestoreEmailAction(result); } } } + void handleRestoreEmailAction(EmailRecoveryAction emailRecoveryAction) { + log('MailboxController::_handleRestoreEmailAction'); + final generateId = Id(const Uuid().v4()); + final restoreDeletedMessageRequest = RestoredDeletedMessageRequest(generateId, emailRecoveryAction); + + consumeState(_restoreDeletedMessageInteractor.execute(sessionCurrent!, accountId.value!, restoreDeletedMessageRequest)); + isRecoveringDeletedMessage.value = true; + } + @override void onClose() { _emailReceiveManager.closeEmailReceiveManagerStream(); diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index c2d8d1bed6..9c4c96adcf 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -155,7 +155,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { } }), Obx(() => RecoverDeletedMessageLoadingBannerWidget( - viewState: controller.viewStateRestoreDeletedMessage.value, + isLoading: controller.isRecoveringDeletedMessage.value, horizontalLoadingWidget: horizontalLoadingWidget, responsiveUtils: controller.responsiveUtils, )), diff --git a/lib/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart index a94acf8d0a..cebbe7782b 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart @@ -1,81 +1,63 @@ import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:core/presentation/state/failure.dart'; -import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; -import 'package:core/utils/app_logger.dart'; -import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; -import 'package:tmail_ui_user/features/email/domain/state/get_restored_deleted_message_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/restore_deleted_message_state.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class RecoverDeletedMessageLoadingBannerWidget extends StatelessWidget { - final Either viewState; + final bool isLoading; final Widget horizontalLoadingWidget; final ResponsiveUtils responsiveUtils; const RecoverDeletedMessageLoadingBannerWidget({ super.key, - required this.viewState, + required this.isLoading, required this.horizontalLoadingWidget, required this.responsiveUtils, }); @override Widget build(BuildContext context) { - return viewState.fold( - (failure) { - log('RecoverDeletedMessageLoadingBannerWidget:: failure $failure'); - return const SizedBox.shrink(); - - }, - (success) { - if (success is RestoreDeletedMessageLoading - || success is RestoreDeletedMessageSuccess - || success is GetRestoredDeletedMessageLoading - ) { - return Padding( - padding: EdgeInsets.only( - top: responsiveUtils.isDesktop(context) ? 16 : 0, - right: 16, - bottom: responsiveUtils.isDesktop(context) ? 0 : 16, - ), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 12, + if (isLoading) { + return Padding( + padding: EdgeInsetsDirectional.only( + top: responsiveUtils.isDesktop(context) ? 16 : 0, + end: 16, + bottom: responsiveUtils.isDesktop(context) ? 0 : 16, + ), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + decoration: const ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1, + color: AppColor.colorBorderBodyThread, ), - decoration: const ShapeDecoration( - color: Colors.white, - shape: RoundedRectangleBorder( - side: BorderSide( - width: 1, - color: AppColor.colorBorderBodyThread, - ), - borderRadius: BorderRadius.all(Radius.circular(14)), - ) + borderRadius: BorderRadius.all(Radius.circular(14)), + ) + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppLocalizations.of(context).bannerProgressingRecoveryMessage, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: AppColor.primaryColor, + ), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - AppLocalizations.of(context).bannerProgressingRecoveryMessage, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.w400, - color: AppColor.primaryColor, - ), - ), - const SizedBox(height: 12), - horizontalLoadingWidget - ], - ), - ), - ); - } else { - return const SizedBox.shrink(); - } - } - ); + const SizedBox(height: 12), + horizontalLoadingWidget + ], + ), + ), + ); + } else { + return const SizedBox.shrink(); + } } } \ No newline at end of file diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 9bd49d03e3..90cc7af585 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -138,7 +138,7 @@ class ThreadView extends GetWidget } }), Obx(() => RecoverDeletedMessageLoadingBannerWidget( - viewState: controller.mailboxDashBoardController.viewStateRestoreDeletedMessage.value, + isLoading: controller.mailboxDashBoardController.isRecoveringDeletedMessage.value, horizontalLoadingWidget: horizontalLoadingWidget, responsiveUtils: controller.responsiveUtils, )), diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 6f6b7c9a31..727b8700ce 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-12-19T16:58:54.709520", + "@@last_modified": "2024-01-07T14:01:28.226469", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -3618,10 +3618,16 @@ "placeholders_order": [], "placeholders": {} }, - "bannerProgressingRecoveryMessage": "The recovery is in progress. You can continue using TeamMail", + "bannerProgressingRecoveryMessage": "The recovery is in progress. You can continue using Twake Mail", "@bannerProgressingRecoveryMessage": { "type": "text", "placeholders_order": [], "placeholders": {} + }, + "restoreDeletedMessageCanceled": "Restore deleted message canceled", + "@restoreDeletedMessageCanceled": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 821df08732..8e56c52b7d 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -3768,8 +3768,15 @@ class AppLocalizations { String get bannerProgressingRecoveryMessage { return Intl.message( - 'The recovery is in progress. You can continue using TwakeMail', + 'The recovery is in progress. You can continue using Twake Mail', name: 'bannerProgressingRecoveryMessage', ); } + + String get restoreDeletedMessageCanceled { + return Intl.message( + 'Restore deleted message canceled', + name: 'restoreDeletedMessageCanceled', + ); + } } \ No newline at end of file diff --git a/model/lib/extensions/presentation_mailbox_extension.dart b/model/lib/extensions/presentation_mailbox_extension.dart index 56cbb3e397..043e9b6147 100644 --- a/model/lib/extensions/presentation_mailbox_extension.dart +++ b/model/lib/extensions/presentation_mailbox_extension.dart @@ -45,6 +45,8 @@ extension PresentationMailboxExtension on PresentationMailbox { bool get isArchive => role == PresentationMailbox.roleArchive; + bool get isRecovered => role == PresentationMailbox.roleRecovered; + bool get isSubscribedMailbox => isSubscribed != null && isSubscribed?.value == true; bool get allowedToDisplayCountOfUnreadEmails => !(isTrash || isSpam || isDrafts || isTemplates || isSent) && countUnreadEmails > 0;