From 30b7d046f996e75de4a80a56cc80a1f42664af48 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 1 Jun 2022 15:37:07 +0700 Subject: [PATCH] TF-599 Handle mark as read action for mailbox --- .../destination_picker_bindings.dart | 14 +++- .../repository/mailbox_repository_impl.dart | 70 ++++++++++++++++++- .../domain/repository/mailbox_repository.dart | 2 + .../presentation/mailbox_bindings.dart | 12 ++++ .../presentation/mailbox_controller.dart | 16 ++++- .../presentation/mailbox_view_web.dart | 16 +++-- .../bottom_bar_selection_mailbox_widget.dart | 44 +++++++++--- .../state/mark_as_mailbox_read_state.dart | 37 ++++++++++ .../mark_as_mailbox_read_interactor.dart | 27 +++++++ .../presentation/action/dashboard_action.dart | 8 --- .../mailbox_dashboard_bindings.dart | 23 ++++++ .../mailbox_dashboard_controller.dart | 31 ++++++++ .../mailbox_dashboard_view_web.dart | 4 +- .../presentation/thread_controller.dart | 26 +++---- lib/l10n/intl_messages.arb | 12 +++- lib/main/localizations/app_localizations.dart | 7 ++ 16 files changed, 301 insertions(+), 48 deletions(-) create mode 100644 lib/features/mailbox_dashboard/domain/state/mark_as_mailbox_read_state.dart create mode 100644 lib/features/mailbox_dashboard/domain/usecases/mark_as_mailbox_read_interactor.dart diff --git a/lib/features/destination_picker/presentation/destination_picker_bindings.dart b/lib/features/destination_picker/presentation/destination_picker_bindings.dart index 0f0140eed..cba7f972e 100644 --- a/lib/features/destination_picker/presentation/destination_picker_bindings.dart +++ b/lib/features/destination_picker/presentation/destination_picker_bindings.dart @@ -3,6 +3,9 @@ import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; import 'package:tmail_ui_user/features/caching/state_cache_client.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/destination_picker_controller.dart'; +import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; +import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart'; +import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart'; @@ -15,6 +18,9 @@ import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_reposit import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/search_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; +import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; +import 'package:tmail_ui_user/features/thread/data/datasource_impl/thread_datasource_impl.dart'; +import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; class DestinationPickerBindings extends BaseBindings { @@ -41,6 +47,8 @@ class DestinationPickerBindings extends BaseBindings { void bindingsDataSource() { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -48,6 +56,8 @@ class DestinationPickerBindings extends BaseBindings { Get.lazyPut(() => MailboxDataSourceImpl(Get.find())); Get.lazyPut(() => MailboxCacheDataSourceImpl(Get.find())); Get.lazyPut(() => StateDataSourceImpl(Get.find())); + Get.lazyPut(() => EmailDataSourceImpl(Get.find())); + Get.lazyPut(() => ThreadDataSourceImpl(Get.find())); } @override @@ -68,7 +78,9 @@ class DestinationPickerBindings extends BaseBindings { DataSourceType.network: Get.find(), DataSourceType.local: Get.find() }, - Get.find() + Get.find(), + Get.find(), + Get.find() )); } } \ 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 624d86e8e..76ba34b58 100644 --- a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart +++ b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart @@ -3,8 +3,17 @@ import 'package:jmap_dart_client/jmap/account_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/utc_date.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_comparator.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_comparator_property.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; +import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/extensions/state_extension.dart'; @@ -13,13 +22,22 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_r import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; +import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; class MailboxRepositoryImpl extends MailboxRepository { final Map mapDataSource; final StateDataSource stateDataSource; + final ThreadDataSource threadDataSource; + final EmailDataSource emailDataSource; - MailboxRepositoryImpl(this.mapDataSource, this.stateDataSource); + MailboxRepositoryImpl( + this.mapDataSource, + this.stateDataSource, + this.threadDataSource, + this.emailDataSource + ); @override Stream getAllMailbox(AccountId accountId, {Properties? properties}) async* { @@ -152,4 +170,54 @@ class MailboxRepositoryImpl extends MailboxRepository { Future renameMailbox(AccountId accountId, RenameMailboxRequest request) { return mapDataSource[DataSourceType.network]!.renameMailbox(accountId, request); } + + @override + Future markAsMailboxRead(AccountId accountId, MailboxId mailboxId, MailboxName mailboxName) async { + bool mailboxHasEmails = true; + UTCDate? lastReceivedDate; + EmailId? lastEmailId; + + while(mailboxHasEmails) { + final emailResponse = await threadDataSource.getAllEmail(accountId, + limit: UnsignedInt(20), + filter: EmailFilterCondition( + inMailbox: mailboxId, + notKeyword: KeyWordIdentifier.emailSeen.value, + before: lastReceivedDate), + sort: {} + ..add(EmailComparator(EmailComparatorProperty.receivedAt) + ..setIsAscending(false)), + properties: Properties({ + EmailProperty.id, + EmailProperty.keywords, + EmailProperty.receivedAt, + }) + ).then((response) { + var listEmails = response.emailList; + if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) { + listEmails = listEmails + .where((email) => email.id != lastEmailId) + .toList(); + } + return EmailsResponse(emailList: listEmails, state: response.state); + }); + log('MailboxRepositoryImpl::markAsMailboxRead(): listEmails: ${emailResponse.emailList?.length}'); + final listEmailUnread = emailResponse.emailList; + + if (listEmailUnread == null || listEmailUnread.isEmpty) { + mailboxHasEmails = false; + } else { + log('MailboxRepositoryImpl::markAsMailboxRead(): listEmailUnread: ${listEmailUnread.length}'); + final result = await emailDataSource.markAsRead(accountId, + listEmailUnread, ReadActions.markAsRead); + + if (result.length != listEmailUnread.length) { + mailboxHasEmails = false; + return false; + } + } + } + + return true; + } } \ 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 d4ac5e742..d6724e407 100644 --- a/lib/features/mailbox/domain/repository/mailbox_repository.dart +++ b/lib/features/mailbox/domain/repository/mailbox_repository.dart @@ -17,4 +17,6 @@ abstract class MailboxRepository { Future deleteMultipleMailbox(Session session, AccountId accountId, List mailboxIds); Future renameMailbox(AccountId accountId, RenameMailboxRequest request); + + Future markAsMailboxRead(AccountId accountId, MailboxId mailboxId, MailboxName mailboxName); } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_bindings.dart b/lib/features/mailbox/presentation/mailbox_bindings.dart index b3c846aa1..50b10ba54 100644 --- a/lib/features/mailbox/presentation/mailbox_bindings.dart +++ b/lib/features/mailbox/presentation/mailbox_bindings.dart @@ -3,6 +3,9 @@ import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; import 'package:tmail_ui_user/features/caching/state_cache_client.dart'; +import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; +import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart'; +import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/login/data/repository/credential_repository_impl.dart'; import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart'; @@ -23,6 +26,9 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/search_mailbox_in import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; +import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; +import 'package:tmail_ui_user/features/thread/data/datasource_impl/thread_datasource_impl.dart'; +import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:uuid/uuid.dart'; class MailboxBindings extends BaseBindings { @@ -57,6 +63,8 @@ class MailboxBindings extends BaseBindings { void bindingsDataSource() { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -64,6 +72,8 @@ class MailboxBindings extends BaseBindings { Get.lazyPut(() => MailboxDataSourceImpl(Get.find())); Get.lazyPut(() => MailboxCacheDataSourceImpl(Get.find())); Get.lazyPut(() => StateDataSourceImpl(Get.find())); + Get.lazyPut(() => EmailDataSourceImpl(Get.find())); + Get.lazyPut(() => ThreadDataSourceImpl(Get.find())); } @override @@ -92,6 +102,8 @@ class MailboxBindings extends BaseBindings { DataSourceType.local: Get.find() }, Get.find(), + Get.find(), + Get.find(), )); } } \ 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 7f99d6fe6..93587503d 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -49,6 +49,7 @@ import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_na import 'package:tmail_ui_user/features/mailbox_creator/presentation/extensions/validator_failure_extension.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/mark_as_mailbox_read_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/presentation/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; @@ -215,6 +216,7 @@ class MailboxController extends BaseMailboxController { success is SaveEmailAsDraftsSuccess || success is RemoveEmailDraftsSuccess || success is SendEmailSuccess || + success is MarkAsMailboxReadAllSuccess || success is UpdateEmailDraftsSuccess) { refreshMailboxChanges(); } @@ -478,6 +480,9 @@ class MailboxController extends BaseMailboxController { case MailboxActions.rename: _openDialogRenameMailboxAction(context, selectionMailbox.first); break; + case MailboxActions.markAsRead: + _markAsReadMailboxAction(selectionMailbox.first); + break; default: break; } @@ -650,6 +655,15 @@ class MailboxController extends BaseMailboxController { _cancelSelectMailbox(); } + void _markAsReadMailboxAction(PresentationMailbox presentationMailbox) { + final accountId = mailboxDashBoardController.accountId.value; + final mailboxId = presentationMailbox.id; + final mailboxName = presentationMailbox.name; + if (accountId != null && mailboxName != null) { + mailboxDashBoardController.markAsReadMailbox(accountId, mailboxId, mailboxName); + } + } + void _createListMailboxNameAsStringInMailboxParent(PresentationMailbox mailboxRenamed) { if (mailboxRenamed.parentId == null) { final allChildrenAtMailboxLocation = (defaultMailboxTree.value.root.childrenItems ?? []) + (folderMailboxTree.value.root.childrenItems ?? []); @@ -704,7 +718,7 @@ class MailboxController extends BaseMailboxController { _appToast.showToast(AppLocalizations.of(context).the_feature_is_under_development); break; case MailboxActions.markAsRead: - _appToast.showToast(AppLocalizations.of(context).the_feature_is_under_development); + _markAsReadMailboxAction(mailbox); break; default: break; diff --git a/lib/features/mailbox/presentation/mailbox_view_web.dart b/lib/features/mailbox/presentation/mailbox_view_web.dart index 5958ea68d..82261d626 100644 --- a/lib/features/mailbox/presentation/mailbox_view_web.dart +++ b/lib/features/mailbox/presentation/mailbox_view_web.dart @@ -373,18 +373,20 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu void _openMailboxMenuAction(BuildContext context, RelativeRect position, PresentationMailbox mailbox) { final listMailboxActions = [ - MailboxActions.markAsRead, + if (mailbox.getCountUnReadEmails().isNotEmpty) MailboxActions.markAsRead, if (!mailbox.hasRole()) MailboxActions.move, if (!mailbox.hasRole()) MailboxActions.rename, if (!mailbox.hasRole()) MailboxActions.delete, ]; - if (_responsiveUtils.isScreenWithShortestSide(context)) { - controller.openContextMenuAction(context, - _bottomSheetIdentityActionTiles(context, mailbox, listMailboxActions)); - } else { - controller.openPopupMenuAction(context, position, - _popupMenuMailboxActionTiles(context, mailbox, listMailboxActions)); + if (listMailboxActions.isNotEmpty) { + if (_responsiveUtils.isScreenWithShortestSide(context)) { + controller.openContextMenuAction(context, + _bottomSheetIdentityActionTiles(context, mailbox, listMailboxActions)); + } else { + controller.openPopupMenuAction(context, position, + _popupMenuMailboxActionTiles(context, mailbox, listMailboxActions)); + } } } diff --git a/lib/features/mailbox/presentation/widgets/bottom_bar_selection_mailbox_widget.dart b/lib/features/mailbox/presentation/widgets/bottom_bar_selection_mailbox_widget.dart index 08a371650..64f7e1223 100644 --- a/lib/features/mailbox/presentation/widgets/bottom_bar_selection_mailbox_widget.dart +++ b/lib/features/mailbox/presentation/widgets/bottom_bar_selection_mailbox_widget.dart @@ -54,8 +54,12 @@ class BottomBarSelectionMailboxWidget { ..paddingIcon(const EdgeInsets.all(8)) ..textStyle(TextStyle( fontSize: 12, - color: _isRenameMailboxValid ? AppColor.colorTextButton : AppColor.colorTextButton.withOpacity(0.3))) - ..iconColor(_isRenameMailboxValid ? AppColor.colorTextButton : AppColor.colorTextButton.withOpacity(0.3)) + color: _isRenameMailboxValid + ? AppColor.colorTextButton + : AppColor.colorTextButton.withOpacity(0.3))) + ..iconColor(_isRenameMailboxValid + ? AppColor.colorTextButton + : AppColor.colorTextButton.withOpacity(0.3)) ..onPressActionClick(() { if (_isRenameMailboxValid) { _onMailboxActionsClick?.call(MailboxActions.rename, _listSelectionMailbox); @@ -66,9 +70,19 @@ class BottomBarSelectionMailboxWidget { Expanded(child: (ButtonBuilder(_imagePaths.icRead) ..key(const Key('button_mark_read_all_mailbox')) ..paddingIcon(const EdgeInsets.all(8)) - ..textStyle(TextStyle(fontSize: 12, color: AppColor.colorTextButton.withOpacity(0.3))) - ..iconColor(AppColor.colorTextButton.withOpacity(0.3)) - ..onPressActionClick(() => {}) + ..textStyle(TextStyle( + fontSize: 12, + color: _isDeleteMailboxValid + ? AppColor.colorTextButton + : AppColor.colorTextButton.withOpacity(0.3))) + ..iconColor(_isDeleteMailboxValid + ? AppColor.colorTextButton + : AppColor.colorTextButton.withOpacity(0.3)) + ..onPressActionClick(() { + if (_isMarkAsReadMailboxValid) { + _onMailboxActionsClick?.call(MailboxActions.markAsRead, _listSelectionMailbox); + } + }) ..text(AppLocalizations.of(_context).mark_as_read, isVertical: true)) .build()), Expanded(child: (ButtonBuilder(_imagePaths.icDelete) @@ -76,8 +90,12 @@ class BottomBarSelectionMailboxWidget { ..paddingIcon(const EdgeInsets.all(8)) ..textStyle(TextStyle( fontSize: 12, - color: _isDeleteMailboxValid ? AppColor.colorTextButton : AppColor.colorTextButton.withOpacity(0.3))) - ..iconColor(_isDeleteMailboxValid ? AppColor.colorTextButton : AppColor.colorTextButton.withOpacity(0.3)) + color: _isDeleteMailboxValid + ? AppColor.colorTextButton + : AppColor.colorTextButton.withOpacity(0.3))) + ..iconColor(_isDeleteMailboxValid + ? AppColor.colorTextButton + : AppColor.colorTextButton.withOpacity(0.3)) ..onPressActionClick(() { if (_isDeleteMailboxValid) { _onMailboxActionsClick?.call(MailboxActions.delete, _listSelectionMailbox); @@ -89,9 +107,15 @@ class BottomBarSelectionMailboxWidget { ); } - bool get _isDeleteMailboxValid => _listSelectionMailbox.length == 1 && _isAllFolderMailbox; + bool get _isDeleteMailboxValid => _listSelectionMailbox.length == 1 + && _isAllFolderMailbox; - bool get _isRenameMailboxValid => _listSelectionMailbox.length == 1 && _isAllFolderMailbox; + bool get _isRenameMailboxValid => _listSelectionMailbox.length == 1 + && _isAllFolderMailbox; - bool get _isAllFolderMailbox => _listSelectionMailbox.every((mailbox) => !mailbox.hasRole()); + bool get _isMarkAsReadMailboxValid => _listSelectionMailbox.length == 1 + && _listSelectionMailbox.first.getCountUnReadEmails().isNotEmpty; + + bool get _isAllFolderMailbox => + _listSelectionMailbox.every((mailbox) => !mailbox.hasRole()); } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/state/mark_as_mailbox_read_state.dart b/lib/features/mailbox_dashboard/domain/state/mark_as_mailbox_read_state.dart new file mode 100644 index 000000000..925144b02 --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/state/mark_as_mailbox_read_state.dart @@ -0,0 +1,37 @@ +import 'package:core/core.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; + +class MarkAsMailboxReadLoading extends UIState { + + MarkAsMailboxReadLoading(); + + @override + List get props => []; +} + +class MarkAsMailboxReadAllSuccess extends UIState { + + final MailboxName mailboxName; + + MarkAsMailboxReadAllSuccess(this.mailboxName); + + @override + List get props => [mailboxName]; +} + +class MarkAsMailboxReadHasSomeEmailFailure extends FeatureFailure { + + MarkAsMailboxReadHasSomeEmailFailure(); + + @override + List get props => []; +} + +class MarkAsMailboxReadFailure extends FeatureFailure { + final dynamic exception; + + MarkAsMailboxReadFailure(this.exception); + + @override + List get props => [exception]; +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/usecases/mark_as_mailbox_read_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/mark_as_mailbox_read_interactor.dart new file mode 100644 index 000000000..a763bd05d --- /dev/null +++ b/lib/features/mailbox_dashboard/domain/usecases/mark_as_mailbox_read_interactor.dart @@ -0,0 +1,27 @@ +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/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/mark_as_mailbox_read_state.dart'; + +class MarkAsMailboxReadInteractor { + final MailboxRepository _mailboxRepository; + + MarkAsMailboxReadInteractor(this._mailboxRepository); + + Stream> execute(AccountId accountId, + MailboxId mailboxId, MailboxName mailboxName) async* { + try { + yield Right(MarkAsMailboxReadLoading()); + final result = await _mailboxRepository.markAsMailboxRead(accountId, mailboxId, mailboxName); + if (result) { + yield Right(MarkAsMailboxReadAllSuccess(mailboxName)); + } else { + yield Left(MarkAsMailboxReadHasSomeEmailFailure()); + } + } catch (e) { + yield Left(MarkAsMailboxReadFailure(e)); + } + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart index 965490da7..bcc9c6dce 100644 --- a/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart +++ b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart @@ -57,14 +57,6 @@ class CancelSelectionAllEmailAction extends DashBoardAction { List get props => []; } -class MarkAsReadAllEmailAction extends DashBoardAction { - - MarkAsReadAllEmailAction(); - - @override - List get props => []; -} - class FilterMessageAction extends DashBoardAction { final BuildContext context; diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart index f5d103091..05379351c 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart @@ -15,8 +15,15 @@ import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_perman 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/domain/repository/credential_repository.dart'; +import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart'; +import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart'; +import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/state_datasource_impl.dart'; +import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart'; +import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart'; +import 'package:tmail_ui_user/features/mailbox/data/repository/mailbox_repository_impl.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox/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_impl/search_datasource_impl.dart'; @@ -24,6 +31,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/search_ 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_user_profile_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/mark_as_mailbox_read_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_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; @@ -55,6 +63,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); } @@ -65,6 +74,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -78,6 +88,8 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => ThreadDataSourceImpl(Get.find())); Get.lazyPut(() => LocalThreadDataSourceImpl(Get.find())); Get.lazyPut(() => StateDataSourceImpl(Get.find())); + Get.lazyPut(() => MailboxDataSourceImpl(Get.find())); + Get.lazyPut(() => MailboxCacheDataSourceImpl(Get.find())); } @override @@ -89,6 +101,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => SaveRecentSearchInteractor(Get.find())); Get.lazyPut(() => GetAllRecentSearchLatestInteractor(Get.find())); Get.lazyPut(() => QuickSearchEmailInteractor(Get.find())); + Get.lazyPut(() => MarkAsMailboxReadInteractor(Get.find())); } @override @@ -96,6 +109,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } @override @@ -113,5 +127,14 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), )); + Get.lazyPut(() => MailboxRepositoryImpl( + { + DataSourceType.network: Get.find(), + DataSourceType.local: Get.find() + }, + Get.find(), + Get.find(), + Get.find(), + )); } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart index 1ead6cf70..83c61216d 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart @@ -37,10 +37,13 @@ import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_int import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_recent_search_latest_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_user_profile_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/mark_as_mailbox_read_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/quick_search_email_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_all_recent_search_latest_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_user_profile_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/mark_as_mailbox_read_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_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; @@ -75,6 +78,7 @@ class MailboxDashBoardController extends ReloadableController { final SaveRecentSearchInteractor _saveRecentSearchInteractor; final GetAllRecentSearchLatestInteractor _getAllRecentSearchLatestInteractor; final QuickSearchEmailInteractor _quickSearchEmailInteractor; + final MarkAsMailboxReadInteractor _markAsMailboxReadInteractor; final scaffoldKey = GlobalKey(); final selectedMailbox = Rxn(); @@ -107,6 +111,7 @@ class MailboxDashBoardController extends ReloadableController { this._saveRecentSearchInteractor, this._getAllRecentSearchLatestInteractor, this._quickSearchEmailInteractor, + this._markAsMailboxReadInteractor, ); @override @@ -176,6 +181,8 @@ class MailboxDashBoardController extends ReloadableController { _moveToMailboxSuccess(success); } else if (success is DeleteEmailPermanentlySuccess) { _deleteEmailPermanentlySuccess(success); + } else if (success is MarkAsMailboxReadAllSuccess) { + _markAsReadMailboxSuccess(success); } } ); @@ -506,6 +513,30 @@ class MailboxDashBoardController extends ReloadableController { return filterMessageOption.value == FilterMessageOption.starred; } + void markAsReadMailboxAction() { + final currentAccountId = accountId.value; + final mailboxId = selectedMailbox.value?.id; + final mailboxName = selectedMailbox.value?.name; + if (currentAccountId != null && mailboxId != null && mailboxName != null) { + markAsReadMailbox(currentAccountId, mailboxId, mailboxName); + } + } + + void markAsReadMailbox(AccountId accountId, MailboxId mailboxId, MailboxName mailboxName) { + consumeState(_markAsMailboxReadInteractor.execute(accountId, mailboxId, mailboxName)); + } + + void _markAsReadMailboxSuccess(MarkAsMailboxReadAllSuccess success) { + if (currentContext != null && currentOverlayContext != null) { + _appToast.showToastWithIcon( + currentOverlayContext!, + widthToast: _responsiveUtils.isDesktop(currentContext!) ? 360 : null, + message: AppLocalizations.of(currentContext!) + .toastMessageMarkAsMailboxReadSuccess(success.mailboxName.name), + icon: _imagePaths.icReadToast); + } + } + void composeEmailAction() { if (kIsWeb) { if (dashBoardAction.value is! ComposeEmailAction) { 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 187fcc2f3..bcb989462 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -227,7 +227,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { ..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8)) ..radiusSplash(10) ..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread)) - ..onPressActionClick(() => controller.dispatchAction(MarkAsReadAllEmailAction())) + ..onPressActionClick(() => controller.markAsReadMailboxAction()) ..text(AppLocalizations.of(context).mark_all_as_read, isVertical: false)) .build(), const SizedBox(width: 16), @@ -287,7 +287,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { ..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8)) ..radiusSplash(10) ..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread)) - ..onPressActionClick(() => controller.dispatchAction(MarkAsReadAllEmailAction())) + ..onPressActionClick(() => controller.markAsReadMailboxAction()) ..text(AppLocalizations.of(context).mark_all_as_read, isVertical: false)) .build(), ]); diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 6d9ef36ff..704522325 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -36,6 +36,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_ 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/mailbox/presentation/model/mailbox_actions.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/mark_as_mailbox_read_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/presentation/action/dashboard_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart'; @@ -194,7 +195,7 @@ class ThreadController extends BaseController { _markAsStarMultipleEmailFailure(failure); } else if (failure is EmptyTrashFolderFailure) { _emptyTrashFolderFailure(failure); - } else if (failure is LoadMoreEmailsFailure) { + } else if (failure is LoadMoreEmailsFailure) { stopFpsMeter(); } }, @@ -253,25 +254,22 @@ class ThreadController extends BaseController { if (action is RefreshAllEmailAction) { refreshAllEmail(); mailboxDashBoardController.clearDashBoardAction(); - } else if (action is MarkAsReadAllEmailAction) { - markAsReadAllEmails(); - mailboxDashBoardController.clearDashBoardAction(); - } if (action is SelectionAllEmailAction) { + } else if (action is SelectionAllEmailAction) { setSelectAllEmailAction(); mailboxDashBoardController.clearDashBoardAction(); - } if (action is CancelSelectionAllEmailAction) { + } else if (action is CancelSelectionAllEmailAction) { cancelSelectEmail(); mailboxDashBoardController.clearDashBoardAction(); - } if (action is FilterMessageAction) { + } else if (action is FilterMessageAction) { filterMessagesAction(action.context, action.option); mailboxDashBoardController.clearDashBoardAction(); - } if (action is HandleEmailActionTypeAction) { + } else if (action is HandleEmailActionTypeAction) { pressEmailSelectionAction(action.context, action.emailAction, action.listEmailSelected); mailboxDashBoardController.clearDashBoardAction(); - } if (action is OpenEmailDetailedAction) { + } else if (action is OpenEmailDetailedAction) { pressEmailAction(action.context, EmailActionType.preview, action.presentationEmail); mailboxDashBoardController.clearDashBoardAction(); - } if (action is DisableSearchEmailAction) { + } else if (action is DisableSearchEmailAction) { closeSearchEmailAction(); mailboxDashBoardController.clearDashBoardAction(); } @@ -291,6 +289,7 @@ class ThreadController extends BaseController { || success is SaveEmailAsDraftsSuccess || success is RemoveEmailDraftsSuccess || success is SendEmailSuccess + || success is MarkAsMailboxReadAllSuccess || success is UpdateEmailDraftsSuccess) { _refreshEmailChanges(); } @@ -496,13 +495,6 @@ class ThreadController extends BaseController { mailboxDashBoardController.listEmailSelected.clear(); } - void markAsReadAllEmails() { - final listEmail = emailList.allEmailUnread; - if (listEmail.isNotEmpty) { - markAsReadSelectedMultipleEmail(listEmail); - } - } - void markAsReadSelectedMultipleEmail(List listPresentationEmail) { final listEmail = listPresentationEmail.map((presentationEmail) => presentationEmail.toEmail()).toList(); final readAction = listPresentationEmail.isAllEmailRead ? ReadActions.markAsUnread : ReadActions.markAsRead; diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index d50a5ca45..2495f2c66 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-05-31T15:17:59.229845", + "@@last_modified": "2022-06-01T15:37:34.038431", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1383,5 +1383,15 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "toastMessageMarkAsMailboxReadSuccess": "You’ve marked all messages in \"{mailboxName}\" as read", + "@toastMessageMarkAsMailboxReadSuccess": { + "type": "text", + "placeholders_order": [ + "mailboxName" + ], + "placeholders": { + "mailboxName": {} + } } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 17fea2c4a..3e55c7835 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1418,4 +1418,11 @@ class AppLocalizations { 'Delete mailbox', name: 'deleteMailbox'); } + + String toastMessageMarkAsMailboxReadSuccess(String mailboxName) { + return Intl.message( + 'You’ve marked all messages in "$mailboxName" as read', + name: 'toastMessageMarkAsMailboxReadSuccess', + args: [mailboxName]); + } } \ No newline at end of file