From 43cbd0d818c993839c76c3ed47c21228d7320347 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 16 Dec 2025 16:09:44 +0700 Subject: [PATCH] TF-4141 Perform load all unread action required emails when open Action required folder --- .../email_action_reactor.dart | 2 +- .../mixin/mailbox_widget_mixin.dart | 2 +- .../mailbox_dashboard_view_web.dart | 3 +- ..._pull_to_refresh_list_email_extension.dart | 6 +- ...andle_select_message_filter_extension.dart | 3 +- .../presentation/thread_controller.dart | 148 +++++++++++++----- .../thread/presentation/thread_view.dart | 2 +- .../presentation_mailbox_extension.dart | 4 + 8 files changed, 124 insertions(+), 46 deletions(-) diff --git a/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart b/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart index 9a23d84e6..35cd624e1 100644 --- a/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart +++ b/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart @@ -715,7 +715,7 @@ class EmailActionReactor { }) { if (selectedMailbox == null || isSearchEmailRunning || - selectedMailbox.isFavorite == true) { + selectedMailbox.isVirtualFolder == true) { return presentationEmail.findMailboxContain(mapMailbox); } diff --git a/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart b/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart index 97962bd6c..ac7c396a5 100644 --- a/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart +++ b/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart @@ -21,7 +21,7 @@ mixin MailboxWidgetMixin { bool spamReportEnabled, bool deletedMessageVaultSupported ) { - if (mailbox.isFavorite) { + if (mailbox.isVirtualFolder) { return [ if (PlatformInfo.isWeb) MailboxActions.openInNewTab, 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 d0fd08b4d..cbb6fdbd5 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -544,7 +544,8 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { final popupMenuItems = [ if (!controller.searchController.isSearchEmailRunning) FilterMessageOption.attachments, - FilterMessageOption.unread, + if (controller.selectedMailbox.value?.isActionRequired != true) + FilterMessageOption.unread, if (controller.selectedMailbox.value?.isFavorite != true) FilterMessageOption.starred, ].map((filterOption) { diff --git a/lib/features/thread/presentation/extensions/handle_pull_to_refresh_list_email_extension.dart b/lib/features/thread/presentation/extensions/handle_pull_to_refresh_list_email_extension.dart index 2612f5fbf..fa8f5b85d 100644 --- a/lib/features/thread/presentation/extensions/handle_pull_to_refresh_list_email_extension.dart +++ b/lib/features/thread/presentation/extensions/handle_pull_to_refresh_list_email_extension.dart @@ -1,11 +1,9 @@ import 'package:core/utils/app_logger.dart'; import 'package:dartz/dartz.dart'; -import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; -import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/domain/state/clean_and_get_all_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/loading_more_status.dart'; @@ -40,7 +38,7 @@ extension HandlePullToRefreshListEmailExtension on ThreadController { consumeState(cleanAndGetEmailsInMailboxInteractor.execute( session, accountId, - limit: ThreadConstants.defaultLimit, + limit: limitEmailFetchedInFolder, sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), emailFilter: getEmailFilterForLoadMailbox(), propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(session, accountId), @@ -49,7 +47,7 @@ extension HandlePullToRefreshListEmailExtension on ThreadController { accountId, ), getLatestChanges: true, - useCache: selectedMailbox?.isFavorite != true, + useCache: !shouldBypassCache, )); } } \ No newline at end of file diff --git a/lib/features/thread/presentation/extensions/handle_select_message_filter_extension.dart b/lib/features/thread/presentation/extensions/handle_select_message_filter_extension.dart index f7e5d0480..04d292bec 100644 --- a/lib/features/thread/presentation/extensions/handle_select_message_filter_extension.dart +++ b/lib/features/thread/presentation/extensions/handle_select_message_filter_extension.dart @@ -13,7 +13,8 @@ extension HandleSelectMessageFilterExtension on ThreadController { ) { final contextMenuActions = [ FilterMessageOption.attachments, - FilterMessageOption.unread, + if (selectedMailbox?.isActionRequired != true) + FilterMessageOption.unread, if (selectedMailbox?.isFavorite != true) FilterMessageOption.starred, ].map((filter) { diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 5a0a37ca8..c68b6c8bb 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -10,9 +10,12 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart' show Filter; +import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart'; +import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +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_filter_condition.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; @@ -505,7 +508,7 @@ class ThreadController extends BaseController with EmailActionController { mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess())); if (success.currentMailboxId != selectedMailboxId && - selectedMailbox?.isFavorite != true) { + selectedMailbox?.isVirtualFolder != true) { log('ThreadController::_getAllEmailSuccess: GetAllForMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}'); return; } @@ -546,7 +549,7 @@ class ThreadController extends BaseController with EmailActionController { void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) { if (success.currentMailboxId != selectedMailboxId && - selectedMailbox?.isFavorite != true) { + selectedMailbox?.isVirtualFolder != true) { log('ThreadController::_refreshChangesAllEmailSuccess: RefreshedMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}'); return; } @@ -572,6 +575,14 @@ class ThreadController extends BaseController with EmailActionController { } } + bool get shouldBypassCache => + selectedMailbox?.isVirtualFolder ?? false; + + UnsignedInt? get limitEmailFetchedInFolder => + selectedMailbox?.isActionRequired == true + ? null + : ThreadConstants.defaultLimit; + void getAllEmailAction({ bool getLatestChanges = true, }) { @@ -580,7 +591,7 @@ class ThreadController extends BaseController with EmailActionController { consumeState(_getEmailsInMailboxInteractor.execute( _session!, _accountId!, - limit: ThreadConstants.defaultLimit, + limit: limitEmailFetchedInFolder, sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), emailFilter: getEmailFilterForLoadMailbox(), propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), @@ -589,7 +600,7 @@ class ThreadController extends BaseController with EmailActionController { _accountId!, ), getLatestChanges: getLatestChanges, - useCache: selectedMailbox?.isFavorite != true, + useCache: !shouldBypassCache, )); } else { consumeState(Stream.value(Left(GetAllEmailFailure(NotFoundSessionException())))); @@ -597,7 +608,7 @@ class ThreadController extends BaseController with EmailActionController { } EmailFilter getEmailFilterForLoadMailbox({PresentationEmail? oldestEmail}) { - if (selectedMailbox?.isFavorite == true) { + if (selectedMailbox?.isVirtualFolder == true) { return EmailFilter( filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), ); @@ -610,33 +621,96 @@ class ThreadController extends BaseController with EmailActionController { } } - Filter getFilterConditionForLoadMailbox({PresentationEmail? oldestEmail}) { - if (selectedMailbox?.isFavorite == true) { - switch (mailboxDashBoardController.filterMessageOption.value) { - case FilterMessageOption.unread: - return EmailFilterCondition( - notKeyword: KeyWordIdentifier.emailSeen.value, - hasKeyword: KeyWordIdentifier.emailFlagged.value, - before: oldestEmail?.receivedAt, - ); - case FilterMessageOption.attachments: - return EmailFilterCondition( - hasAttachment: true, - hasKeyword: KeyWordIdentifier.emailFlagged.value, - before: oldestEmail?.receivedAt, - ); - default: - return EmailFilterCondition( - hasKeyword: KeyWordIdentifier.emailFlagged.value, - before: oldestEmail?.receivedAt, - ); - } - } else { - return getFilterCondition( - mailboxIdSelected: selectedMailboxId, - oldestEmail: oldestEmail, + Filter getFilterConditionForLoadMailbox({ + PresentationEmail? oldestEmail, + }) { + final mailbox = selectedMailbox; + final filterOption = + mailboxDashBoardController.filterMessageOption.value; + final before = oldestEmail?.receivedAt; + + if (mailbox?.isFavorite == true) { + return _buildFavoriteMailboxFilter( + filterOption: filterOption, + before: before, ); } + + if (mailbox?.isActionRequired == true) { + return _buildActionRequiredMailboxFilter( + filterOption: filterOption, + before: before, + ); + } + + return getFilterCondition( + mailboxIdSelected: selectedMailboxId, + oldestEmail: oldestEmail, + ); + } + + Filter _buildFavoriteMailboxFilter({ + required FilterMessageOption filterOption, + UTCDate? before, + }) { + switch (filterOption) { + case FilterMessageOption.unread: + return EmailFilterCondition( + notKeyword: KeyWordIdentifier.emailSeen.value, + hasKeyword: KeyWordIdentifier.emailFlagged.value, + before: before, + ); + + case FilterMessageOption.attachments: + return EmailFilterCondition( + hasAttachment: true, + hasKeyword: KeyWordIdentifier.emailFlagged.value, + before: before, + ); + + default: + return EmailFilterCondition( + hasKeyword: KeyWordIdentifier.emailFlagged.value, + before: before, + ); + } + } + + Filter _buildActionRequiredMailboxFilter({ + required FilterMessageOption filterOption, + UTCDate? before, + }) { + switch (filterOption) { + case FilterMessageOption.starred: + return LogicFilterOperator( + Operator.AND, + { + EmailFilterCondition( + hasKeyword: KeyWordIdentifier.emailFlagged.value, + ), + EmailFilterCondition( + notKeyword: KeyWordIdentifier.emailSeen.value, + hasKeyword: KeyWordIdentifierExtension.needActionMail.value, + before: before, + ), + }, + ); + + case FilterMessageOption.attachments: + return EmailFilterCondition( + hasAttachment: true, + notKeyword: KeyWordIdentifier.emailSeen.value, + hasKeyword: KeyWordIdentifierExtension.needActionMail.value, + before: before, + ); + + default: + return EmailFilterCondition( + notKeyword: KeyWordIdentifier.emailSeen.value, + hasKeyword: KeyWordIdentifierExtension.needActionMail.value, + before: before, + ); + } } EmailFilterCondition getFilterCondition({PresentationEmail? oldestEmail, MailboxId? mailboxIdSelected}) { @@ -709,8 +783,8 @@ class ThreadController extends BaseController with EmailActionController { try { if (searchController.isSearchEmailRunning && PlatformInfo.isWeb) { await _refreshChangeSearchEmail(); - } else if (selectedMailbox?.isFavorite == true) { - await _refreshChangeListEmailsInFavoriteFolder(); + } else if (selectedMailbox?.isVirtualFolder == true) { + await _refreshChangeListEmailsInVirtualFolder(); } else { await _refreshChangeListEmail(); } @@ -815,8 +889,8 @@ class ThreadController extends BaseController with EmailActionController { } } - Future _refreshChangeListEmailsInFavoriteFolder() async { - log('ThreadController::_refreshChangeListEmailsInFavoriteFolder:'); + Future _refreshChangeListEmailsInVirtualFolder() async { + log('ThreadController::_refreshChangeListEmailsInVirtualFolder:'); await _refreshChangeListEmailCache(); @@ -860,20 +934,20 @@ class ThreadController extends BaseController with EmailActionController { GetEmailRequest( _session!, _accountId!, - limit: ThreadConstants.defaultLimit, + limit: limitEmailFetchedInFolder, sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), filterOption: mailboxDashBoardController.filterMessageOption.value, filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), lastEmailId: oldestEmail?.id, - useCache: selectedMailbox?.isFavorite != true, + useCache: !shouldBypassCache, ) )); } } bool _validatePresentationEmail(PresentationEmail email) { - return (_belongToCurrentMailboxId(email) || selectedMailbox?.isFavorite == true) + return (_belongToCurrentMailboxId(email) || selectedMailbox?.isVirtualFolder == true) && _notDuplicatedInCurrentList(email); } diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index a6b2c692d..c64f64822 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -780,7 +780,7 @@ class ThreadView extends GetWidget if (success is GetAllEmailSuccess && success.currentMailboxId != controller.selectedMailboxId && - controller.selectedMailbox?.isFavorite != true) { + controller.selectedMailbox?.isVirtualFolder != true) { return const SizedBox.shrink(); } else { return PullToRefreshWidget( diff --git a/model/lib/extensions/presentation_mailbox_extension.dart b/model/lib/extensions/presentation_mailbox_extension.dart index 52ea5e2c3..2a35c1a3d 100644 --- a/model/lib/extensions/presentation_mailbox_extension.dart +++ b/model/lib/extensions/presentation_mailbox_extension.dart @@ -36,6 +36,10 @@ extension PresentationMailboxExtension on PresentationMailbox { bool get isFavorite => role == PresentationMailbox.roleFavorite; + bool get isActionRequired => role == PresentationMailbox.roleActionRequired; + + bool get isVirtualFolder => isFavorite || isActionRequired; + bool get isTrash => role == PresentationMailbox.roleTrash; bool get isDrafts => role == PresentationMailbox.roleDrafts;