diff --git a/lib/features/email/presentation/email_controller.dart b/lib/features/email/presentation/email_controller.dart index 3605662c2..81f98fe09 100644 --- a/lib/features/email/presentation/email_controller.dart +++ b/lib/features/email/presentation/email_controller.dart @@ -707,7 +707,16 @@ class EmailController extends BaseController with AppLoaderMixin { void closeEmailView(BuildContext context) { mailboxDashBoardController.clearSelectedEmail(); - mailboxDashBoardController.dispatchRoute(AppRoutes.THREAD); + + if (BuildUtils.isWeb) { + mailboxDashBoardController.dispatchRoute(AppRoutes.THREAD); + } else { + if (mailboxDashBoardController.searchController.isSearchEmailRunning) { + mailboxDashBoardController.dispatchRoute(AppRoutes.SEARCH_EMAIL); + } else { + mailboxDashBoardController.dispatchRoute(AppRoutes.THREAD); + } + } } void pressEmailAction(EmailActionType emailActionType) { diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 0b03900a4..ce5058e53 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -199,25 +199,18 @@ class MailboxController extends BaseMailboxController { if (state is Either) { state.fold((failure) => null, (success) { if (success is MarkAsMultipleEmailReadAllSuccess) { - mailboxDashBoardController.clearState(); refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is MarkAsMultipleEmailReadHasSomeEmailFailure) { - mailboxDashBoardController.clearState(); refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is MoveMultipleEmailToMailboxAllSuccess) { - mailboxDashBoardController.clearState(); refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is MoveMultipleEmailToMailboxHasSomeEmailFailure) { - mailboxDashBoardController.clearState(); refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is DeleteMultipleEmailsPermanentlyAllSuccess) { - mailboxDashBoardController.clearState(); refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is DeleteMultipleEmailsPermanentlyHasSomeEmailFailure) { - mailboxDashBoardController.clearState(); refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is EmptyTrashFolderSuccess) { - mailboxDashBoardController.clearState(); refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is MarkAsEmailReadSuccess) { refreshMailboxChanges(currentMailboxState: success.currentMailboxState); 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 c8ea6dfb6..2d6624c76 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -14,6 +14,14 @@ 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/delete_multiple_emails_permanently_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/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/get_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/email_bindings.dart'; import 'package:tmail_ui_user/features/login/data/datasource/account_datasource.dart'; @@ -47,15 +55,10 @@ import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_reposit 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/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/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/repository/composer_cache_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/domain/repository/composer_cache_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/search_repository.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/quick_search_email_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; @@ -66,6 +69,8 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; +import 'package:tmail_ui_user/features/search/domain/usecases/refresh_changes_search_email_interactor.dart'; +import 'package:tmail_ui_user/features/search/presentation/search_email_bindings.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; import 'package:tmail_ui_user/features/thread/data/datasource_impl/local_thread_datasource_impl.dart'; import 'package:tmail_ui_user/features/thread/data/datasource_impl/thread_datasource_impl.dart'; @@ -74,6 +79,12 @@ import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:tmail_ui_user/features/thread/data/network/thread_isolate_worker.dart'; import 'package:tmail_ui_user/features/thread/data/repository/thread_repository_impl.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/empty_trash_folder_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/move_multiple_email_to_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_interactor.dart'; +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'; class MailboxDashBoardBindings extends BaseBindings { @@ -84,6 +95,7 @@ class MailboxDashBoardBindings extends BaseBindings { MailboxBindings().dependencies(); ThreadBindings().dependencies(); EmailBindings().dependencies(); + SearchEmailBindings().dependencies(); } @override @@ -101,7 +113,14 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find() + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), )); Get.put(AdvancedFilterController()); } @@ -155,6 +174,9 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find())); Get.lazyPut(() => SaveRecentSearchInteractor(Get.find())); Get.lazyPut(() => GetAllRecentSearchLatestInteractor(Get.find())); + Get.lazyPut(() => SearchEmailInteractor(Get.find())); + Get.lazyPut(() => SearchMoreEmailInteractor(Get.find())); + Get.lazyPut(() => RefreshChangesSearchEmailInteractor(Get.find())); Get.lazyPut(() => QuickSearchEmailInteractor(Get.find())); Get.lazyPut(() => MarkAsMailboxReadInteractor( Get.find(), @@ -179,6 +201,27 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => GetComposerCacheOnWebInteractor(Get.find())); Get.lazyPut(() => SaveComposerCacheOnWebInteractor(Get.find())); Get.lazyPut(() => RemoveComposerCacheOnWebInteractor(Get.find())); + Get.lazyPut(() => MarkAsEmailReadInteractor( + Get.find(), + Get.find() + )); + Get.lazyPut(() => MarkAsStarEmailInteractor(Get.find())); + Get.lazyPut(() => MarkAsMultipleEmailReadInteractor( + Get.find(), + Get.find() + )); + Get.lazyPut(() => MarkAsStarMultipleEmailInteractor(Get.find())); + Get.lazyPut(() => MoveMultipleEmailToMailboxInteractor( + Get.find(), + Get.find() + )); + Get.lazyPut(() => DeleteMultipleEmailsPermanentlyInteractor( + Get.find(), + Get.find())); + Get.lazyPut(() => EmptyTrashFolderInteractor( + Get.find(), + Get.find(), + Get.find())); } @override 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 8f277e5c0..c40c812b2 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -5,6 +5,7 @@ import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.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/core/capability/capability_identifier.dart'; @@ -16,6 +17,7 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/vacation/vacation_response.dart'; import 'package:model/model.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart'; import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; @@ -23,17 +25,23 @@ import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.da import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; +import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.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/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/move_to_mailbox_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/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/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/mark_as_mailbox_read_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.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/remove_email_drafts_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart'; @@ -55,6 +63,15 @@ import 'package:tmail_ui_user/features/manage_account/presentation/model/account import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_as_star_multiple_email_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/move_multiple_email_to_mailbox_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/empty_trash_folder_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/move_multiple_email_to_mailbox_interactor.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'; @@ -76,6 +93,14 @@ class MailboxDashBoardController extends ReloadableController { final DeleteEmailPermanentlyInteractor _deleteEmailPermanentlyInteractor; final MarkAsMailboxReadInteractor _markAsMailboxReadInteractor; final GetComposerCacheOnWebInteractor _getEmailCacheOnWebInteractor; + final MarkAsEmailReadInteractor _markAsEmailReadInteractor; + final MarkAsStarEmailInteractor _markAsStarEmailInteractor; + final MarkAsMultipleEmailReadInteractor _markAsMultipleEmailReadInteractor; + final MarkAsStarMultipleEmailInteractor _markAsStarMultipleEmailInteractor; + final MoveMultipleEmailToMailboxInteractor _moveMultipleEmailToMailboxInteractor; + final EmptyTrashFolderInteractor _emptyTrashFolderInteractor; + final DeleteMultipleEmailsPermanentlyInteractor _deleteMultipleEmailsPermanentlyInteractor; + GetAllVacationInteractor? _getAllVacationInteractor; UpdateVacationInteractor? _updateVacationInteractor; @@ -112,7 +137,14 @@ class MailboxDashBoardController extends ReloadableController { this._moveToMailboxInteractor, this._deleteEmailPermanentlyInteractor, this._markAsMailboxReadInteractor, - this._getEmailCacheOnWebInteractor + this._getEmailCacheOnWebInteractor, + this._markAsEmailReadInteractor, + this._markAsStarEmailInteractor, + this._markAsMultipleEmailReadInteractor, + this._markAsStarMultipleEmailInteractor, + this._moveMultipleEmailToMailboxInteractor, + this._emptyTrashFolderInteractor, + this._deleteMultipleEmailsPermanentlyInteractor, ) : super(logoutOidcInteractor, deleteAuthorityOidcInteractor, getAuthenticatedAccountInteractor); @@ -225,6 +257,20 @@ class MailboxDashBoardController extends ReloadableController { } } else if (success is UpdateVacationSuccess) { _handleUpdateVacationSuccess(success); + } else if (success is MarkAsMultipleEmailReadAllSuccess + || success is MarkAsMultipleEmailReadHasSomeEmailFailure) { + _markAsReadSelectedMultipleEmailSuccess(success); + } else if (success is MarkAsStarMultipleEmailAllSuccess + || success is MarkAsStarMultipleEmailHasSomeEmailFailure) { + _markAsStarMultipleEmailSuccess(success); + } else if (success is MoveMultipleEmailToMailboxAllSuccess + || success is MoveMultipleEmailToMailboxHasSomeEmailFailure) { + _moveSelectedMultipleEmailToMailboxSuccess(success); + } else if (success is EmptyTrashFolderSuccess) { + _emptyTrashFolderSuccess(success); + } else if (success is DeleteMultipleEmailsPermanentlyAllSuccess + || success is DeleteMultipleEmailsPermanentlyHasSomeEmailFailure) { + _deleteMultipleEmailsPermanentlySuccess(success); } } ); @@ -457,6 +503,357 @@ class MailboxDashBoardController extends ReloadableController { } } + void markAsEmailRead(PresentationEmail presentationEmail, ReadActions readActions) async { + if (accountId.value != null) { + consumeState(_markAsEmailReadInteractor.execute( + accountId.value!, + presentationEmail.toEmail(), + readActions)); + } + } + + void markAsStarEmail(PresentationEmail presentationEmail, MarkStarAction action) { + if (accountId.value != null) { + consumeState(_markAsStarEmailInteractor.execute( + accountId.value!, + presentationEmail.toEmail(), + action)); + } + } + + void markAsReadSelectedMultipleEmail(List listPresentationEmail, ReadActions readActions) { + final listEmail = listPresentationEmail + .map((presentationEmail) => presentationEmail.toEmail()) + .toList(); + log('MailboxDashBoardController::markAsReadSelectedMultipleEmail(): listEmail: ${listEmail.length}'); + if (accountId.value != null) { + consumeState(_markAsMultipleEmailReadInteractor.execute( + accountId.value!, + listEmail, + readActions)); + } + } + + void _markAsReadSelectedMultipleEmailSuccess(Success success) { + ReadActions? readActions; + + if (success is MarkAsMultipleEmailReadAllSuccess) { + readActions = success.readActions; + } else if (success is MarkAsMultipleEmailReadHasSomeEmailFailure) { + readActions = success.readActions; + } + + if (currentContext != null && readActions != null && currentOverlayContext != null) { + final message = readActions == ReadActions.markAsUnread + ? AppLocalizations.of(currentContext!).marked_message_toast(AppLocalizations.of(currentContext!).unread) + : AppLocalizations.of(currentContext!).marked_message_toast(AppLocalizations.of(currentContext!).read); + _appToast.showToastWithIcon( + currentOverlayContext!, + message: message, + icon: readActions == ReadActions.markAsUnread + ? _imagePaths.icUnreadToast + : _imagePaths.icReadToast); + } + } + + void markAsStarSelectedMultipleEmail(List listPresentationEmail, MarkStarAction markStarAction) { + final listEmail = listPresentationEmail + .map((presentationEmail) => presentationEmail.toEmail()) + .toList(); + if (accountId.value != null) { + consumeState(_markAsStarMultipleEmailInteractor.execute( + accountId.value!, + listEmail, + markStarAction)); + } + } + + void _markAsStarMultipleEmailSuccess(Success success) { + MarkStarAction? markStarAction; + int countMarkStarSuccess = 0; + + if (success is MarkAsStarMultipleEmailAllSuccess) { + markStarAction = success.markStarAction; + countMarkStarSuccess = success.countMarkStarSuccess; + } else if (success is MarkAsStarMultipleEmailHasSomeEmailFailure) { + markStarAction = success.markStarAction; + countMarkStarSuccess = success.countMarkStarSuccess; + } + + if (currentContext != null && markStarAction != null && currentOverlayContext != null) { + final message = markStarAction == MarkStarAction.unMarkStar + ? AppLocalizations.of(currentContext!).marked_unstar_multiple_item(countMarkStarSuccess) + : AppLocalizations.of(currentContext!).marked_star_multiple_item(countMarkStarSuccess); + _appToast.showToastWithIcon( + currentOverlayContext!, + message: message, + icon: markStarAction == MarkStarAction.unMarkStar + ? _imagePaths.icUnStar + : _imagePaths.icStar); + } + } + + void moveSelectedMultipleEmailToMailbox( + List listEmails, + PresentationMailbox mailboxCurrent + ) async { + if (accountId.value != null) { + final destinationMailbox = await push( + AppRoutes.DESTINATION_PICKER, + arguments: DestinationPickerArguments(accountId.value!, MailboxActions.moveEmail)); + + if (destinationMailbox != null && destinationMailbox is PresentationMailbox) { + if (destinationMailbox.isTrash) { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmails.listEmailIds, + mailboxCurrent.id, + destinationMailbox.id, + MoveAction.moving, + EmailActionType.moveToTrash)); + } else if (destinationMailbox.isSpam) { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmails.listEmailIds, + mailboxCurrent.id, + destinationMailbox.id, + MoveAction.moving, + EmailActionType.moveToSpam)); + } else { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmails.listEmailIds, + mailboxCurrent.id, + destinationMailbox.id, + MoveAction.moving, + EmailActionType.moveToMailbox, + destinationPath: destinationMailbox.mailboxPath)); + } + } + } + } + + void _moveSelectedEmailMultipleToMailboxAction( + AccountId accountId, + MoveToMailboxRequest moveRequest + ) { + consumeState(_moveMultipleEmailToMailboxInteractor.execute(accountId, moveRequest)); + } + + void _moveSelectedMultipleEmailToMailboxSuccess(Success success) { + String? destinationPath; + List movedEmailIds = []; + MailboxId? currentMailboxId; + MailboxId? destinationMailboxId; + MoveAction? moveAction; + EmailActionType? emailActionType; + + if (success is MoveMultipleEmailToMailboxAllSuccess) { + destinationPath = success.destinationPath; + movedEmailIds = success.movedListEmailId; + currentMailboxId = success.currentMailboxId; + destinationMailboxId = success.destinationMailboxId; + moveAction = success.moveAction; + emailActionType = success.emailActionType; + } else if (success is MoveMultipleEmailToMailboxHasSomeEmailFailure) { + destinationPath = success.destinationPath; + movedEmailIds = success.movedListEmailId; + currentMailboxId = success.currentMailboxId; + destinationMailboxId = success.destinationMailboxId; + moveAction = success.moveAction; + emailActionType = success.emailActionType; + } + + if (currentContext != null && + currentOverlayContext != null && + emailActionType != null && + moveAction == MoveAction.moving) { + _appToast.showToastWithAction( + currentOverlayContext!, + emailActionType.getToastMessageMoveToMailboxSuccess( + currentContext!, + destinationPath: destinationPath), + AppLocalizations.of(currentContext!).undo_action, + () { + final newCurrentMailboxId = destinationMailboxId; + final newDestinationMailboxId = currentMailboxId; + if (newCurrentMailboxId != null && newDestinationMailboxId != null) { + _revertedSelectionEmailToOriginalMailbox(MoveToMailboxRequest( + movedEmailIds, + newCurrentMailboxId, + newDestinationMailboxId, + MoveAction.undo, + emailActionType!, + destinationPath: destinationPath)); + } + }, + maxWidth: _responsiveUtils.getMaxWidthToast(currentContext!) + ); + } + } + + void _revertedSelectionEmailToOriginalMailbox(MoveToMailboxRequest newMoveRequest) { + if (accountId.value != null) { + consumeState(_moveMultipleEmailToMailboxInteractor.execute( + accountId.value!, + newMoveRequest)); + } + } + + void moveSelectedMultipleEmailToTrash(List listEmails, PresentationMailbox mailboxCurrent) { + final trashMailboxId = getMailboxIdByRole(PresentationMailbox.roleTrash); + if (accountId.value != null && trashMailboxId != null) { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmails.listEmailIds, + mailboxCurrent.id, + trashMailboxId, + MoveAction.moving, + EmailActionType.moveToTrash) + ); + } + } + + void moveSelectedMultipleEmailToSpam(List listEmail, PresentationMailbox mailboxCurrent) { + final spamMailboxId = getMailboxIdByRole(PresentationMailbox.roleSpam); + if (accountId.value != null && spamMailboxId != null) { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmail.listEmailIds, + mailboxCurrent.id, + spamMailboxId, + MoveAction.moving, + EmailActionType.moveToSpam) + ); + } + } + + void unSpamSelectedMultipleEmail(List listEmail) { + final spamMailboxId = getMailboxIdByRole(PresentationMailbox.roleSpam); + final inboxMailboxId = getMailboxIdByRole(PresentationMailbox.roleInbox); + if (inboxMailboxId != null && accountId.value != null && spamMailboxId != null) { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmail.listEmailIds, + spamMailboxId, + inboxMailboxId, + MoveAction.moving, + EmailActionType.unSpam) + ); + } + } + + void deleteSelectionEmailsPermanently( + BuildContext context, + DeleteActionType actionType, + { + List? listEmails, + PresentationMailbox? mailboxCurrent, + Function? onCancelSelectionEmail, + } + ) { + if (_responsiveUtils.isMobile(context)) { + (ConfirmationDialogActionSheetBuilder(context) + ..messageText(actionType.getContentDialog( + context, + count: listEmails?.length, + mailboxName: mailboxCurrent?.name?.name)) + ..onCancelAction(AppLocalizations.of(context).cancel, () => popBack()) + ..onConfirmAction( + actionType.getConfirmActionName(context), + () => _deleteSelectionEmailsPermanentlyAction( + actionType, + listEmails: listEmails, + onCancelSelectionEmail: onCancelSelectionEmail))) + .show(); + } else { + showDialog( + context: context, + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + builder: (BuildContext context) => PointerInterceptor(child: (ConfirmDialogBuilder(_imagePaths) + ..key(const Key('confirm_dialog_delete_emails_permanently')) + ..title(actionType.getTitleDialog(context)) + ..content(actionType.getContentDialog( + context, + count: listEmails?.length, + mailboxName: mailboxCurrent?.name?.name)) + ..addIcon(SvgPicture.asset(_imagePaths.icRemoveDialog, fit: BoxFit.fill)) + ..colorConfirmButton(AppColor.colorConfirmActionDialog) + ..styleTextConfirmButton(const TextStyle( + fontSize: 17, + fontWeight: FontWeight.w500, + color: AppColor.colorActionDeleteConfirmDialog)) + ..onCloseButtonAction(() => popBack()) + ..onConfirmButtonAction( + actionType.getConfirmActionName(context), + () => _deleteSelectionEmailsPermanentlyAction( + actionType, + listEmails: listEmails, + onCancelSelectionEmail: onCancelSelectionEmail)) + ..onCancelButtonAction(AppLocalizations.of(context).cancel, () => popBack())) + .build())); + } + } + + void _deleteSelectionEmailsPermanentlyAction( + DeleteActionType actionType, { + List? listEmails, + Function? onCancelSelectionEmail, + }) { + popBack(); + + switch(actionType) { + case DeleteActionType.all: + _emptyTrashFolderAction(onCancelSelectionEmail: onCancelSelectionEmail); + break; + case DeleteActionType.multiple: + _deleteMultipleEmailsPermanently(listEmails ?? [], onCancelSelectionEmail: onCancelSelectionEmail); + break; + case DeleteActionType.single: + break; + } + } + + void _emptyTrashFolderAction({Function? onCancelSelectionEmail}) { + onCancelSelectionEmail?.call(); + + final trashMailboxId = mapDefaultMailboxId[PresentationMailbox.roleTrash]; + if (accountId.value != null && trashMailboxId != null) { + consumeState(_emptyTrashFolderInteractor.execute(accountId.value!, trashMailboxId)); + } + } + + void _emptyTrashFolderSuccess(EmptyTrashFolderSuccess success) { + if (currentContext != null && currentOverlayContext != null) { + _appToast.showToastWithIcon( + currentOverlayContext!, + widthToast: _responsiveUtils.isDesktop(currentContext!) ? 360 : null, + message: AppLocalizations.of(currentContext!).toast_message_empty_trash_folder_success, + icon: _imagePaths.icDeleteToast); + } + } + + void _deleteMultipleEmailsPermanently(List listEmails, {Function? onCancelSelectionEmail}) { + onCancelSelectionEmail?.call(); + + if (accountId.value != null) { + consumeState(_deleteMultipleEmailsPermanentlyInteractor.execute( + accountId.value!, + listEmails.listEmailIds)); + } + } + + void _deleteMultipleEmailsPermanentlySuccess(Success success) { + List listEmailIdResult = []; + if (success is DeleteMultipleEmailsPermanentlyAllSuccess) { + listEmailIdResult = success.emailIds; + } else if (success is DeleteMultipleEmailsPermanentlyHasSomeEmailFailure) { + listEmailIdResult = success.emailIds; + } + + if (currentContext != null && currentOverlayContext != null && listEmailIdResult.isNotEmpty) { + _appToast.showToastWithIcon( + currentOverlayContext!, + widthToast: _responsiveUtils.isDesktop(currentContext!) ? 360 : null, + message: AppLocalizations.of(currentContext!).toast_message_delete_multiple_email_permanently_success(listEmailIdResult.length), + icon: _imagePaths.icDeleteToast); + } + } + void dispatchAction(UIAction action) { log('MailboxDashBoardController::dispatchAction(): ${action.runtimeType}'); dashBoardAction.value = action; @@ -476,7 +873,10 @@ class MailboxDashBoardController extends ReloadableController { void dispatchRoute(String route) { routePath.value = route; - log('MailboxDashBoardController::dispatchRoute(): $route'); + + if (routePath.value == AppRoutes.SEARCH_EMAIL) { + searchController.enableSearch(); + } } @override diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart index f9e049357..16513461c 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart @@ -1,17 +1,14 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/base/mixin/network_connection_mixin.dart'; import 'package:tmail_ui_user/features/email/presentation/email_view.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/base_mailbox_dashboard_view.dart'; +import 'package:tmail_ui_user/features/search/presentation/search_email_view.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; -class MailboxDashBoardView extends GetWidget - with NetworkConnectionMixin { - - final _responsiveUtils = Get.find(); +class MailboxDashBoardView extends BaseMailboxDashBoardView { MailboxDashBoardView({Key? key}) : super(key: key); @@ -30,7 +27,7 @@ class MailboxDashBoardView extends GetWidget return Scaffold( key: controller.scaffoldKey, drawer: ResponsiveWidget( - responsiveUtils: _responsiveUtils, + responsiveUtils: responsiveUtils, mobile: SizedBox(child: MailboxView(), width: double.infinity), landscapeMobile: SizedBox( child: MailboxView(), @@ -47,30 +44,50 @@ class MailboxDashBoardView extends GetWidget desktop: SizedBox( child: MailboxView(), width: ResponsiveUtils.defaultSizeLeftMenuMobile)), - drawerEnableOpenDragGesture: _responsiveUtils.hasLeftMenuDrawerActive(context), + drawerEnableOpenDragGesture: responsiveUtils.hasLeftMenuDrawerActive(context), body: Stack(children: [ Obx(() { switch(controller.routePath.value) { case AppRoutes.THREAD: return ResponsiveWidget( - responsiveUtils: _responsiveUtils, - desktop: bodyLandscapeTablet, - tabletLarge: bodyLandscapeTablet, - landscapeTablet: bodyLandscapeTablet, + responsiveUtils: responsiveUtils, + desktop: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, + tabletLarge: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, + landscapeTablet: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, mobile: ThreadView()); case AppRoutes.EMAIL: return ResponsiveWidget( - responsiveUtils: _responsiveUtils, - desktop: bodyLandscapeTablet, - tabletLarge: bodyLandscapeTablet, - landscapeTablet: bodyLandscapeTablet, + responsiveUtils: responsiveUtils, + desktop: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, + tabletLarge: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, + landscapeTablet: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, mobile: EmailView()); + case AppRoutes.SEARCH_EMAIL: + return SafeArea(child: SearchEmailView()); default: return ResponsiveWidget( - responsiveUtils: _responsiveUtils, - desktop: bodyLandscapeTablet, - tabletLarge: bodyLandscapeTablet, - landscapeTablet: bodyLandscapeTablet, + responsiveUtils: responsiveUtils, + desktop: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, + tabletLarge: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, + landscapeTablet: controller.searchController.isSearchEmailRunning + ? EmailView() + : bodyLandscapeTablet, mobile: ThreadView()); } }), diff --git a/lib/features/mailbox_dashboard/presentation/widgets/email_quick_search_item_tile_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/email_quick_search_item_tile_widget.dart index 328aad276..3b56c10ae 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/email_quick_search_item_tile_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/email_quick_search_item_tile_widget.dart @@ -13,12 +13,14 @@ class EmailQuickSearchItemTileWidget extends StatelessWidget { final PresentationEmail _presentationEmail; final PresentationMailbox? _presentationMailbox; + final EdgeInsets? contentPadding; EmailQuickSearchItemTileWidget( this._presentationEmail, - this._presentationMailbox, - {Key? key} - ) : super(key: key); + this._presentationMailbox, { + Key? key, + this.contentPadding, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -27,7 +29,7 @@ class EmailQuickSearchItemTileWidget extends StatelessWidget { final maxWidthItem = constraints.maxWidth; log('EmailQuickSearchItemTileWidget::build(): maxWidthItem: $maxWidthItem'); return Padding( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14), + padding: contentPadding ?? const EdgeInsets.all(12), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, @@ -48,7 +50,8 @@ class EmailQuickSearchItemTileWidget extends StatelessWidget { constraints: BoxConstraints(maxWidth: maxWidthItem / 3), child: Text(_getInformationSender(), maxLines: 1, - overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis, + overflow: CommonTextStyle.defaultTextOverFlow, + softWrap: CommonTextStyle.defaultSoftWrap, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600, @@ -58,7 +61,8 @@ class EmailQuickSearchItemTileWidget extends StatelessWidget { Expanded( child: Text(_presentationEmail.getEmailTitle(), maxLines: 1, - overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis, + overflow: CommonTextStyle.defaultTextOverFlow, + softWrap: CommonTextStyle.defaultSoftWrap, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.normal, @@ -71,6 +75,9 @@ class EmailQuickSearchItemTileWidget extends StatelessWidget { ), Text(_presentationEmail.getReceivedAt(Localizations.localeOf(context).toLanguageTag()), textAlign: TextAlign.right, + maxLines: 1, + overflow: CommonTextStyle.defaultTextOverFlow, + softWrap: CommonTextStyle.defaultSoftWrap, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.normal, @@ -79,7 +86,8 @@ class EmailQuickSearchItemTileWidget extends StatelessWidget { const SizedBox(height: 3), Text(_presentationEmail.getPartialContent(), maxLines: 1, - overflow: BuildUtils.isWeb ? null : TextOverflow.ellipsis, + overflow: CommonTextStyle.defaultTextOverFlow, + softWrap: CommonTextStyle.defaultSoftWrap, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.normal, diff --git a/lib/features/mailbox_dashboard/presentation/widgets/recent_search_item_tile_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/recent_search_item_tile_widget.dart index bd1314797..5e112c590 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/recent_search_item_tile_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/recent_search_item_tile_widget.dart @@ -10,13 +10,18 @@ class RecentSearchItemTileWidget extends StatelessWidget { final imagePath = Get.find(); final RecentSearch recentSearch; + final EdgeInsets? contentPadding; - RecentSearchItemTileWidget(this.recentSearch, {Key? key}) : super(key: key); + RecentSearchItemTileWidget( + this.recentSearch, { + Key? key, + this.contentPadding, + }) : super(key: key); @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), + padding: contentPadding ?? const EdgeInsets.all(12), child: Row( children: [ SvgPicture.asset(imagePath.icClockSB), diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 117f0e365..ce70600e0 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -42,6 +42,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart'; +import 'package:tmail_ui_user/features/search/presentation/search_email_bindings.dart'; import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_filter.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; @@ -1350,4 +1351,9 @@ class ThreadController extends BaseController { mailboxDashBoardController.goToComposer(arguments); } + + void goToSearchView() { + SearchEmailBindings().dependencies(); + mailboxDashBoardController.dispatchRoute(AppRoutes.SEARCH_EMAIL); + } } \ 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 cc644362b..029e9d5f2 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -89,16 +89,35 @@ class ThreadView extends GetWidget with AppLoaderMixin, } Widget _buildSearchBarView(BuildContext context) { - return Obx(() => Container( - color: Colors.white, - padding: EdgeInsets.symmetric( - horizontal: 16, - vertical: _responsiveUtils.isWebNotDesktop(context) ? 8 : 0), - margin: const EdgeInsets.only( - bottom: !BuildUtils.isWeb ? 16 : 0), - child: !controller.isSearchActive() - ? _buildSearchFormInActive(context) - : _buildSearchFormActive(context))); + if (BuildUtils.isWeb) { + return Obx(() => Container( + color: Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 16, + vertical: _responsiveUtils.isWebNotDesktop(context) ? 8 : 0), + margin: const EdgeInsets.only( + bottom: !BuildUtils.isWeb ? 16 : 0), + child: !controller.isSearchActive() + ? _buildSearchFormInActive(context) + : _buildSearchFormActive(context))); + } else { + return Obx(() { + if (!controller.searchController.isSearchActive()) { + return Container( + color: Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 16, + vertical: _responsiveUtils.isWebNotDesktop(context) ? 8 : 0), + margin: const EdgeInsets.only( + bottom: !BuildUtils.isWeb ? 16 : 0), + child: SearchBarView(_imagePaths, + hintTextSearch: AppLocalizations.of(context).search_emails, + onOpenSearchViewAction: () => controller.goToSearchView())); + } else { + return const SizedBox.shrink(); + } + }); + } } Widget _buildVacationNotificationMessage(BuildContext context) { diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 30295978a..ef03cc03e 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-09-16T10:29:51.348820", + "@@last_modified": "2022-09-16T03:16:09.866930", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2179,5 +2179,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "clearAll": "Clear all", + "@clearAll": { + "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 eae873a52..cdf6e08eb 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2252,4 +2252,11 @@ class AppLocalizations { ); } + + String get clearAll { + return Intl.message( + 'Clear all', + name: 'clearAll', + ); + } } \ No newline at end of file diff --git a/lib/main/routes/app_routes.dart b/lib/main/routes/app_routes.dart index 8ea883e19..572c36334 100644 --- a/lib/main/routes/app_routes.dart +++ b/lib/main/routes/app_routes.dart @@ -13,4 +13,5 @@ abstract class AppRoutes { static const IDENTITY_CREATOR = '$MANAGE_ACCOUNT/identity_creator'; static const RULES_FILTER_CREATOR = '$MANAGE_ACCOUNT/rules_filter_creator'; static const EMAILS_FORWARD_CREATOR = '$MANAGE_ACCOUNT/emails_forward_creator'; + static const SEARCH_EMAIL = '$MAILBOX_DASHBOARD/search_email'; } \ No newline at end of file diff --git a/model/lib/extensions/list_presentation_email_extension.dart b/model/lib/extensions/list_presentation_email_extension.dart index a93f6178f..309609413 100644 --- a/model/lib/extensions/list_presentation_email_extension.dart +++ b/model/lib/extensions/list_presentation_email_extension.dart @@ -8,12 +8,18 @@ extension ListPresentationEmailExtension on List { bool get isAllEmailStarred => every((email) => email.hasStarred); + bool get isAllSelectionInActive { + return every((email) => email.selectMode == SelectMode.INACTIVE); + } + List get listEmail => map((presentationEmail) => presentationEmail.toEmail()).toList(); List get listEmailSelected { return where((email) => email.selectMode == SelectMode.ACTIVE).toList(); } + List get listEmailIds => map((email) => email.id).toList(); + bool isAllCanDeletePermanently(Map mapMailbox) { final listMailboxContain = map((email) => email.findMailboxContain(mapMailbox)) .whereType()