From 059185660e55523fd209277ba3594f6a01f5fcf0 Mon Sep 17 00:00:00 2001 From: DatDang Date: Thu, 2 Jan 2025 08:55:08 +0700 Subject: [PATCH] TF-3385 Update save and remove draft email --- .../base/base_mailbox_controller.dart | 15 ++++++++++++ .../state/save_email_as_drafts_state.dart | 6 +++-- ...w_and_save_email_to_drafts_interactor.dart | 5 +++- .../presentation/mailbox_controller.dart | 24 +++++++++++++++++++ .../presentation/model/mailbox_tree.dart | 14 +++++++++++ .../state/remove_email_drafts_state.dart | 10 +++++++- .../remove_email_drafts_interactor.dart | 10 ++++++-- .../mailbox_dashboard_controller.dart | 11 ++++++--- .../composer_controller_test.dart | 4 ++-- 9 files changed, 88 insertions(+), 11 deletions(-) diff --git a/lib/features/base/base_mailbox_controller.dart b/lib/features/base/base_mailbox_controller.dart index 62ba44dc2..73e619415 100644 --- a/lib/features/base/base_mailbox_controller.dart +++ b/lib/features/base/base_mailbox_controller.dart @@ -605,4 +605,19 @@ abstract class BaseMailboxController extends BaseController { break; } } + + void updateMailboxTotalEmailsCountById(MailboxId mailboxId, int totalEmails) { + final mailboxTrees = [ + defaultMailboxTree, + personalMailboxTree, + teamMailboxesTree, + ]; + + for (var mailboxTree in mailboxTrees) { + if (mailboxTree.value.updateMailboxTotalEmailsCountById(mailboxId, totalEmails)) { + mailboxTree.refresh(); + break; + } + } + } } \ No newline at end of file diff --git a/lib/features/composer/domain/state/save_email_as_drafts_state.dart b/lib/features/composer/domain/state/save_email_as_drafts_state.dart index 1eddfdeea..e9e9f7682 100644 --- a/lib/features/composer/domain/state/save_email_as_drafts_state.dart +++ b/lib/features/composer/domain/state/save_email_as_drafts_state.dart @@ -1,17 +1,19 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; class SaveEmailAsDraftsLoading extends LoadingState {} class SaveEmailAsDraftsSuccess extends UIState { final EmailId emailId; + final MailboxId? draftMailboxId; - SaveEmailAsDraftsSuccess(this.emailId); + SaveEmailAsDraftsSuccess(this.emailId, this.draftMailboxId); @override - List get props => [emailId, ...super.props]; + List get props => [emailId, draftMailboxId, ...super.props]; } class SaveEmailAsDraftsFailure extends FeatureFailure { 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 ac651fc18..65a3bd226 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 @@ -44,7 +44,10 @@ class CreateNewAndSaveEmailToDraftsInteractor { ); yield dartz.Right( - SaveEmailAsDraftsSuccess(emailDraftSaved.id!) + SaveEmailAsDraftsSuccess( + emailDraftSaved.id!, + createEmailRequest.draftsMailboxId, + ) ); } else { yield dartz.Right(UpdatingEmailDrafts()); diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 3e4aff9e4..80f914625 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -19,6 +19,7 @@ import 'package:rxdart/transformers.dart'; import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/contact_support_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/mailbox_action_handler_mixin.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_action.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'; @@ -66,6 +67,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils. import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_mailbox_arguments.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.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/dashboard_routes.dart'; @@ -310,6 +312,16 @@ class MailboxController extends BaseMailboxController ?.value .toInt() ?? 0, ); + } else if (reactionState is SaveEmailAsDraftsSuccess) { + _handleDraftSaved( + affectedMailboxId: reactionState.draftMailboxId, + totalEmailsChanged: 1, + ); + } else if (reactionState is RemoveEmailDraftsSuccess) { + _handleDraftSaved( + affectedMailboxId: reactionState.draftMailboxId, + totalEmailsChanged: -1, + ); } }); } @@ -335,6 +347,18 @@ class MailboxController extends BaseMailboxController clearUnreadCount(affectedMailboxId); } + void _handleDraftSaved({ + required MailboxId? affectedMailboxId, + required int totalEmailsChanged, + }) { + if (affectedMailboxId == null) return; + + updateMailboxTotalEmailsCountById( + affectedMailboxId, + totalEmailsChanged, + ); + } + void _initWebSocketQueueHandler() { _webSocketQueueHandler = WebSocketQueueHandler( processMessageCallback: _handleWebSocketMessage, diff --git a/lib/features/mailbox/presentation/model/mailbox_tree.dart b/lib/features/mailbox/presentation/model/mailbox_tree.dart index 97bff1f3f..2b1b54ecc 100644 --- a/lib/features/mailbox/presentation/model/mailbox_tree.dart +++ b/lib/features/mailbox/presentation/model/mailbox_tree.dart @@ -107,6 +107,20 @@ class MailboxTree with EquatableMixin { return false; } + bool updateMailboxTotalEmailsCountById(MailboxId mailboxId, int totalEmailsCount) { + final matchedNode = findNode((node) => node.item.id == mailboxId); + if (matchedNode != null) { + final currentTotalEmailsCount = matchedNode.item.totalEmails?.value.value ?? 0; + final updatedTotalEmailsCount = currentTotalEmailsCount + totalEmailsCount; + if (updatedTotalEmailsCount < 0) return true; + matchedNode.item = matchedNode.item.copyWith( + totalEmails: TotalEmails(UnsignedInt(updatedTotalEmailsCount)), + ); + return true; + } + return false; + } + String? getNodePath(MailboxId mailboxId) { final matchedNode = findNode((node) => node.item.id == mailboxId); if (matchedNode == null) { diff --git a/lib/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart b/lib/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart index 5c79d586b..f78337851 100644 --- a/lib/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart +++ b/lib/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart @@ -1,7 +1,15 @@ 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 RemoveEmailDraftsSuccess extends UIState {} +class RemoveEmailDraftsSuccess extends UIState { + final MailboxId? draftMailboxId; + + RemoveEmailDraftsSuccess(this.draftMailboxId); + + @override + List get props => [draftMailboxId]; +} class RemoveEmailDraftsFailure extends FeatureFailure { diff --git a/lib/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart index a832a29a1..e0894477c 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart @@ -4,6 +4,7 @@ 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/mail/email/email.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/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; @@ -12,11 +13,16 @@ class RemoveEmailDraftsInteractor { RemoveEmailDraftsInteractor(this._emailRepository); - Stream> execute(Session session, AccountId accountId, EmailId emailId) async* { + Stream> execute( + Session session, + AccountId accountId, + EmailId emailId, + MailboxId? draftMailboxId, + ) async* { try { final result = await _emailRepository.removeEmailDrafts(session, accountId, emailId); if (result) { - yield Right(RemoveEmailDraftsSuccess()); + yield Right(RemoveEmailDraftsSuccess(draftMailboxId)); } else { yield Left(RemoveEmailDraftsFailure(result)); } 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 b2791f064..c0862c726 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -811,7 +811,7 @@ class MailboxDashBoardController extends ReloadableController currentOverlayContext!, AppLocalizations.of(currentContext!).drafts_saved, actionName: AppLocalizations.of(currentContext!).discard, - onActionClick: () => _discardEmail(success.emailId), + onActionClick: () => _discardEmail(success.emailId, success.draftMailboxId), leadingSVGIcon: imagePaths.icMailboxDrafts, leadingSVGIconColor: Colors.white, backgroundColor: AppColor.toastSuccessBackgroundColor, @@ -854,11 +854,16 @@ class MailboxDashBoardController extends ReloadableController } } - void _discardEmail(EmailId emailId) { + void _discardEmail(EmailId emailId, MailboxId? draftMailboxId) { final currentAccountId = accountId.value; final session = sessionCurrent; if (currentAccountId != null && session != null) { - consumeState(_removeEmailDraftsInteractor.execute(session, currentAccountId, emailId)); + consumeState(_removeEmailDraftsInteractor.execute( + session, + currentAccountId, + emailId, + draftMailboxId, + )); } } diff --git a/test/features/composer/presentation/composer_controller_test.dart b/test/features/composer/presentation/composer_controller_test.dart index fa4e11ed4..6315f219e 100644 --- a/test/features/composer/presentation/composer_controller_test.dart +++ b/test/features/composer/presentation/composer_controller_test.dart @@ -591,7 +591,7 @@ void main() { createEmailRequest: anyNamed('createEmailRequest'), cancelToken: anyNamed('cancelToken'))) .thenAnswer((_) => Stream.value( - Right(SaveEmailAsDraftsSuccess(EmailId(Id('123')))))); + Right(SaveEmailAsDraftsSuccess(EmailId(Id('123')), null)))); final savedEmailDraft = SavedEmailDraft( content: emailContent, @@ -1039,7 +1039,7 @@ void main() { createEmailRequest: anyNamed('createEmailRequest'), cancelToken: anyNamed('cancelToken'))) .thenAnswer((_) => Stream.value( - Right(SaveEmailAsDraftsSuccess(EmailId(Id('123')))))); + Right(SaveEmailAsDraftsSuccess(EmailId(Id('123')), null)))); final savedEmailDraft = SavedEmailDraft( content: emailContent,