From a89c5db744a94d53100ddbf0921e80809d7f55bd Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 5 Apr 2022 11:45:50 +0700 Subject: [PATCH] TF-239 Delete single email permanently --- .../data/datasource/email_datasource.dart | 4 ++- .../email_datasource_impl.dart | 13 +++++-- .../email/data/network/email_api.dart | 21 ++++++++++- .../repository/email_repository_impl.dart | 9 +++-- .../domain/repository/email_repository.dart | 4 ++- .../state/delete_email_permanently_state.dart | 19 ++++++++++ ...te_multiple_emails_permanently_state.dart} | 0 .../delete_email_permanently_interactor.dart | 25 +++++++++++++ ...ultiple_emails_permanently_interactor.dart | 4 +-- .../email/presentation/email_controller.dart | 36 +++++++++++++++++++ .../widgets/app_bar_mail_widget_builder.dart | 21 ++++++----- .../presentation/mailbox_controller.dart | 4 ++- .../mailbox_dashboard_bindings.dart | 3 ++ .../mailbox_dashboard_controller.dart | 24 +++++++++++++ .../presentation/thread_controller.dart | 4 ++- 15 files changed, 171 insertions(+), 20 deletions(-) create mode 100644 lib/features/email/domain/state/delete_email_permanently_state.dart rename lib/features/email/domain/state/{delete_multiple_email_state.dart => delete_multiple_emails_permanently_state.dart} (100%) create mode 100644 lib/features/email/domain/usecases/delete_email_permanently_interactor.dart diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index 08e4aafbc..b5ce6bd03 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -52,5 +52,7 @@ abstract class EmailDataSource { Future updateEmailDrafts(AccountId accountId, Email newEmail, EmailId oldEmailId); - Future> deleteMultipleEmailPermanently(Session session, AccountId accountId, List emailIds); + Future> deleteMultipleEmailsPermanently(Session session, AccountId accountId, List emailIds); + + Future deleteEmailPermanently(AccountId accountId, EmailId emailId); } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/email_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_datasource_impl.dart index 4d7f7ca8e..7e3f8c104 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -135,9 +135,18 @@ class EmailDataSourceImpl extends EmailDataSource { } @override - Future> deleteMultipleEmailPermanently(Session session, AccountId accountId, List emailIds) { + Future> deleteMultipleEmailsPermanently(Session session, AccountId accountId, List emailIds) { return Future.sync(() async { - return await emailAPI.deleteMultipleEmailPermanently(session, accountId, emailIds); + return await emailAPI.deleteMultipleEmailsPermanently(session, accountId, emailIds); + }).catchError((error) { + throw error; + }); + } + + @override + Future deleteEmailPermanently(AccountId accountId, EmailId emailId) { + return Future.sync(() async { + return await emailAPI.deleteEmailPermanently(accountId, emailId); }).catchError((error) { throw error; }); diff --git a/lib/features/email/data/network/email_api.dart b/lib/features/email/data/network/email_api.dart index fe6dc8096..df168479d 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -386,7 +386,7 @@ class EmailAPI { }); } - Future> deleteMultipleEmailPermanently(Session session, AccountId accountId, List emailIds) async { + Future> deleteMultipleEmailsPermanently(Session session, AccountId accountId, List emailIds) async { requireCapability(session, [CapabilityIdentifier.jmapCore, CapabilityIdentifier.jmapMail]); final coreCapability = (session.capabilities[CapabilityIdentifier.jmapCore] as CoreCapability); @@ -430,4 +430,23 @@ class EmailAPI { return listEmailResult; } + + Future deleteEmailPermanently(AccountId accountId, EmailId emailId) async { + final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); + final setEmailMethod = SetEmailMethod(accountId) + ..addDestroy(Set.of([emailId.id])); + + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); + + final response = await (requestBuilder + ..usings(setEmailMethod.requiredCapabilities)) + .build() + .execute(); + + final setEmailResponse = response.parse( + setEmailInvocation.methodCallId, + SetEmailResponse.deserialize); + + return setEmailResponse?.destroyed?.contains(emailId.id) == true; + } } \ No newline at end of file diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index c79f6013a..52064daef 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -117,7 +117,12 @@ class EmailRepositoryImpl extends EmailRepository { } @override - Future> deleteMultipleEmailPermanently(Session session, AccountId accountId, List emailIds) { - return emailDataSource.deleteMultipleEmailPermanently(session, accountId, emailIds); + Future> deleteMultipleEmailsPermanently(Session session, AccountId accountId, List emailIds) { + return emailDataSource.deleteMultipleEmailsPermanently(session, accountId, emailIds); + } + + @override + Future deleteEmailPermanently(AccountId accountId, EmailId emailId) { + return emailDataSource.deleteEmailPermanently(accountId, emailId); } } \ No newline at end of file diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 343c613a4..7148c495e 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -59,5 +59,7 @@ abstract class EmailRepository { Future updateEmailDrafts(AccountId accountId, Email newEmail, EmailId oldEmailId); - Future> deleteMultipleEmailPermanently(Session session, AccountId accountId, List emailIds); + Future> deleteMultipleEmailsPermanently(Session session, AccountId accountId, List emailIds); + + Future deleteEmailPermanently(AccountId accountId, EmailId emailId); } \ No newline at end of file diff --git a/lib/features/email/domain/state/delete_email_permanently_state.dart b/lib/features/email/domain/state/delete_email_permanently_state.dart new file mode 100644 index 000000000..cb19f6637 --- /dev/null +++ b/lib/features/email/domain/state/delete_email_permanently_state.dart @@ -0,0 +1,19 @@ +import 'package:core/core.dart'; + +class DeleteEmailPermanentlySuccess extends UIState { + + DeleteEmailPermanentlySuccess(); + + @override + List get props => []; +} + +class DeleteEmailPermanentlyFailure extends FeatureFailure { + + final exception; + + DeleteEmailPermanentlyFailure(this.exception); + + @override + List get props => [exception]; +} \ No newline at end of file diff --git a/lib/features/email/domain/state/delete_multiple_email_state.dart b/lib/features/email/domain/state/delete_multiple_emails_permanently_state.dart similarity index 100% rename from lib/features/email/domain/state/delete_multiple_email_state.dart rename to lib/features/email/domain/state/delete_multiple_emails_permanently_state.dart diff --git a/lib/features/email/domain/usecases/delete_email_permanently_interactor.dart b/lib/features/email/domain/usecases/delete_email_permanently_interactor.dart new file mode 100644 index 000000000..d3626e502 --- /dev/null +++ b/lib/features/email/domain/usecases/delete_email_permanently_interactor.dart @@ -0,0 +1,25 @@ +import 'package:core/core.dart'; +import 'package:dartz/dartz.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:tmail_ui_user/features/email/domain/state/delete_email_permanently_state.dart'; + +class DeleteEmailPermanentlyInteractor { + final EmailRepository emailRepository; + + DeleteEmailPermanentlyInteractor(this.emailRepository); + + Stream> execute(AccountId accountId, EmailId emailId) async* { + try { + final result = await emailRepository.deleteEmailPermanently(accountId, emailId); + if (result) { + yield Right(DeleteEmailPermanentlySuccess()); + } else { + yield Left(DeleteEmailPermanentlyFailure(null)); + } + } catch (e) { + yield Left(DeleteEmailPermanentlyFailure(e)); + } + } +} \ No newline at end of file diff --git a/lib/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart b/lib/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart index c267492c0..968e2f832 100644 --- a/lib/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart +++ b/lib/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart @@ -4,7 +4,7 @@ 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:tmail_ui_user/features/email/domain/repository/email_repository.dart'; -import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_email_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_emails_permanently_state.dart'; class DeleteMultipleEmailsPermanentlyInteractor { final EmailRepository emailRepository; @@ -13,7 +13,7 @@ class DeleteMultipleEmailsPermanentlyInteractor { Stream> execute(Session session, AccountId accountId, List emailIds) async* { try { - final listResult = await emailRepository.deleteMultipleEmailPermanently(session, accountId, emailIds); + final listResult = await emailRepository.deleteMultipleEmailsPermanently(session, accountId, emailIds); if (listResult.length == emailIds.length) { yield Right(DeleteMultipleEmailsPermanentlyAllSuccess(listResult)); } else if (listResult.isNotEmpty) { diff --git a/lib/features/email/presentation/email_controller.dart b/lib/features/email/presentation/email_controller.dart index a1bdcc097..48d4f1e5e 100644 --- a/lib/features/email/presentation/email_controller.dart +++ b/lib/features/email/presentation/email_controller.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; @@ -36,6 +37,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart'; +import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -442,6 +444,9 @@ class EmailController extends BaseController { case EmailActionType.moveToTrash: moveToTrashAction(context, presentationEmail); break; + case EmailActionType.deletePermanently: + deleteEmailPermanently(context, presentationEmail); + break; default: break; } @@ -513,6 +518,37 @@ class EmailController extends BaseController { } } + void deleteEmailPermanently(BuildContext context, PresentationEmail email) { + if (responsiveUtils.isMobile(context)) { + (ConfirmationDialogActionSheetBuilder(context) + ..messageText(DeleteActionType.single.getContentDialog(context)) + ..onCancelAction(AppLocalizations.of(context).cancel, () => popBack()) + ..onConfirmAction(DeleteActionType.single.getConfirmActionName(context), () => _deleteEmailPermanentlyAction(context, email))) + .show(); + } else { + showDialog( + context: context, + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + builder: (BuildContext context) => PointerInterceptor(child: (ConfirmDialogBuilder(imagePaths) + ..key(Key('confirm_dialog_delete_email_permanently')) + ..title(DeleteActionType.single.getTitleDialog(context)) + ..content(DeleteActionType.single.getContentDialog(context)) + ..addIcon(SvgPicture.asset(imagePaths.icRemoveDialog, fit: BoxFit.fill)) + ..colorConfirmButton(AppColor.colorConfirmActionDialog) + ..styleTextConfirmButton(TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorActionDeleteConfirmDialog)) + ..onCloseButtonAction(() => popBack()) + ..onConfirmButtonAction(DeleteActionType.single.getConfirmActionName(context), () => _deleteEmailPermanentlyAction(context, email)) + ..onCancelButtonAction(AppLocalizations.of(context).cancel, () => popBack())) + .build())); + } + } + + void _deleteEmailPermanentlyAction(BuildContext context, PresentationEmail email) { + popBack(); + backToThreadView(context); + mailboxDashBoardController.deleteEmailPermanently(email); + } + void closeMoreMenu() { popBack(); } diff --git a/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart b/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart index ab61e9f94..8810e5a59 100644 --- a/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart +++ b/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart @@ -113,15 +113,18 @@ class AppBarMailWidgetBuilder { _onEmailActionClick?.call(_presentationEmail!, _presentationEmail!.isFlaggedEmail() ? EmailActionType.markAsUnStar : EmailActionType.markAsStar); } }), - if (_currentMailbox?.role != PresentationMailbox.roleTrash) - buildIconWeb( - icon: SvgPicture.asset(_imagePaths.icDeleteEmail, fit: BoxFit.fill), - tooltip: AppLocalizations.of(_context).move_to_trash, - onTap: () { - if (_presentationEmail != null) { - _onEmailActionClick?.call(_presentationEmail!, EmailActionType.moveToTrash); - } - }), + buildIconWeb( + icon: SvgPicture.asset(_imagePaths.icDeleteEmail, fit: BoxFit.fill), + tooltip: _currentMailbox?.role != PresentationMailbox.roleTrash + ? AppLocalizations.of(_context).move_to_trash + : AppLocalizations.of(_context).delete_permanently, + onTap: () { + if (_currentMailbox?.role != PresentationMailbox.roleTrash) { + _onEmailActionClick?.call(_presentationEmail!, EmailActionType.moveToTrash); + } else { + _onEmailActionClick?.call(_presentationEmail!, EmailActionType.deletePermanently); + } + }), Padding( padding: EdgeInsets.only(left: 10, right: 16), child: buildIconWebHasPosition( diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 8eed5d074..36dad9217 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -16,7 +16,8 @@ import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_email_state.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/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/move_to_trash_state.dart'; @@ -134,6 +135,7 @@ class MailboxController extends BaseMailboxController { } else if (success is MarkAsEmailReadSuccess || success is MoveToMailboxSuccess || success is MoveToTrashSuccess + || success is DeleteEmailPermanentlySuccess || success is SaveEmailAsDraftsSuccess || success is RemoveEmailDraftsSuccess || success is SendEmailSuccess diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart index 567044252..e7697e066 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart @@ -9,6 +9,7 @@ import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart'; 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/move_to_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_trash_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/email_bindings.dart'; @@ -34,6 +35,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.put(MailboxDashBoardController( Get.find(), Get.find(), + Get.find(), )); } @@ -58,6 +60,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => RemoveEmailDraftsInteractor(Get.find())); Get.lazyPut(() => MoveToTrashInteractor(Get.find())); Get.lazyPut(() => MoveToMailboxInteractor(Get.find())); + Get.lazyPut(() => DeleteEmailPermanentlyInteractor(Get.find())); } @override diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart index 69fcaba95..476dac6df 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart @@ -23,7 +23,9 @@ import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.d import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_trash_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/move_to_trash_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/move_to_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_trash_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; @@ -51,9 +53,11 @@ class MailboxDashBoardController extends ReloadableController { final DeleteCredentialInteractor _deleteCredentialInteractor = Get.find(); final CachingManager _cachingManager = Get.find(); final Connectivity _connectivity = Get.find(); + final ResponsiveUtils _responsiveUtils = Get.find(); final MoveToTrashInteractor _moveToTrashInteractor; final MoveToMailboxInteractor _moveToMailboxInteractor; + final DeleteEmailPermanentlyInteractor _deleteEmailPermanentlyInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -77,6 +81,7 @@ class MailboxDashBoardController extends ReloadableController { MailboxDashBoardController( this._moveToTrashInteractor, this._moveToMailboxInteractor, + this._deleteEmailPermanentlyInteractor, ); @override @@ -149,6 +154,8 @@ class MailboxDashBoardController extends ReloadableController { clearState(); } else if (success is MoveToTrashSuccess) { _moveToTrashSuccess(success); + } else if (success is DeleteEmailPermanentlySuccess) { + _deleteEmailPermanentlySuccess(success); } } ); @@ -310,6 +317,23 @@ class MailboxDashBoardController extends ReloadableController { } } + void deleteEmailPermanently(PresentationEmail email) { + final currentAccountId = accountId.value; + if (currentAccountId != null) { + consumeState(_deleteEmailPermanentlyInteractor.execute(currentAccountId, email.id)); + } + } + + void _deleteEmailPermanentlySuccess(DeleteEmailPermanentlySuccess success) { + if (currentContext != null && currentOverlayContext != null) { + _appToast.showToastWithIcon( + currentOverlayContext!, + widthToast: _responsiveUtils.isDesktop(currentContext!) ? 360 : null, + message: AppLocalizations.of(currentContext!).toast_message_delete_a_email_permanently_success, + icon: _imagePaths.icDeleteToast); + } + } + void dispatchDashBoardAction(DashBoardAction action, {RouterArguments? arguments}) { switch(action) { case DashBoardAction.none: diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index b416158d4..7dd7eee1f 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -23,7 +23,8 @@ import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_trash_request.dart'; -import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_email_state.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/mark_as_email_read_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; @@ -148,6 +149,7 @@ class ThreadController extends BaseController { || success is MoveToMailboxSuccess || success is MoveToTrashSuccess || success is MarkAsStarEmailSuccess + || success is DeleteEmailPermanentlySuccess || success is SaveEmailAsDraftsSuccess || success is RemoveEmailDraftsSuccess || success is SendEmailSuccess