TF-4141 Perform load all unread action required emails when open Action required folder

This commit is contained in:
dab246
2025-12-16 16:09:44 +07:00
committed by Dat H. Pham
parent 0e49c18f9d
commit 43cbd0d818
8 changed files with 124 additions and 46 deletions
@@ -715,7 +715,7 @@ class EmailActionReactor {
}) { }) {
if (selectedMailbox == null || if (selectedMailbox == null ||
isSearchEmailRunning || isSearchEmailRunning ||
selectedMailbox.isFavorite == true) { selectedMailbox.isVirtualFolder == true) {
return presentationEmail.findMailboxContain(mapMailbox); return presentationEmail.findMailboxContain(mapMailbox);
} }
@@ -21,7 +21,7 @@ mixin MailboxWidgetMixin {
bool spamReportEnabled, bool spamReportEnabled,
bool deletedMessageVaultSupported bool deletedMessageVaultSupported
) { ) {
if (mailbox.isFavorite) { if (mailbox.isVirtualFolder) {
return [ return [
if (PlatformInfo.isWeb) if (PlatformInfo.isWeb)
MailboxActions.openInNewTab, MailboxActions.openInNewTab,
@@ -544,7 +544,8 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
final popupMenuItems = [ final popupMenuItems = [
if (!controller.searchController.isSearchEmailRunning) if (!controller.searchController.isSearchEmailRunning)
FilterMessageOption.attachments, FilterMessageOption.attachments,
FilterMessageOption.unread, if (controller.selectedMailbox.value?.isActionRequired != true)
FilterMessageOption.unread,
if (controller.selectedMailbox.value?.isFavorite != true) if (controller.selectedMailbox.value?.isFavorite != true)
FilterMessageOption.starred, FilterMessageOption.starred,
].map((filterOption) { ].map((filterOption) {
@@ -1,11 +1,9 @@
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.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/email/presentation/utils/email_utils.dart';
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.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/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/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/domain/state/get_all_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/loading_more_status.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( consumeState(cleanAndGetEmailsInMailboxInteractor.execute(
session, session,
accountId, accountId,
limit: ThreadConstants.defaultLimit, limit: limitEmailFetchedInFolder,
sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(),
emailFilter: getEmailFilterForLoadMailbox(), emailFilter: getEmailFilterForLoadMailbox(),
propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(session, accountId), propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(session, accountId),
@@ -49,7 +47,7 @@ extension HandlePullToRefreshListEmailExtension on ThreadController {
accountId, accountId,
), ),
getLatestChanges: true, getLatestChanges: true,
useCache: selectedMailbox?.isFavorite != true, useCache: !shouldBypassCache,
)); ));
} }
} }
@@ -13,7 +13,8 @@ extension HandleSelectMessageFilterExtension on ThreadController {
) { ) {
final contextMenuActions = [ final contextMenuActions = [
FilterMessageOption.attachments, FilterMessageOption.attachments,
FilterMessageOption.unread, if (selectedMailbox?.isActionRequired != true)
FilterMessageOption.unread,
if (selectedMailbox?.isFavorite != true) if (selectedMailbox?.isFavorite != true)
FilterMessageOption.starred, FilterMessageOption.starred,
].map((filter) { ].map((filter) {
@@ -10,9 +10,12 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.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.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/session/session.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; 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/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.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.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/email/keyword_identifier.dart';
@@ -505,7 +508,7 @@ class ThreadController extends BaseController with EmailActionController {
mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess())); mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess()));
if (success.currentMailboxId != selectedMailboxId && 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}'); log('ThreadController::_getAllEmailSuccess: GetAllForMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}');
return; return;
} }
@@ -546,7 +549,7 @@ class ThreadController extends BaseController with EmailActionController {
void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) { void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) {
if (success.currentMailboxId != selectedMailboxId && 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}'); log('ThreadController::_refreshChangesAllEmailSuccess: RefreshedMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}');
return; 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({ void getAllEmailAction({
bool getLatestChanges = true, bool getLatestChanges = true,
}) { }) {
@@ -580,7 +591,7 @@ class ThreadController extends BaseController with EmailActionController {
consumeState(_getEmailsInMailboxInteractor.execute( consumeState(_getEmailsInMailboxInteractor.execute(
_session!, _session!,
_accountId!, _accountId!,
limit: ThreadConstants.defaultLimit, limit: limitEmailFetchedInFolder,
sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(),
emailFilter: getEmailFilterForLoadMailbox(), emailFilter: getEmailFilterForLoadMailbox(),
propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!),
@@ -589,7 +600,7 @@ class ThreadController extends BaseController with EmailActionController {
_accountId!, _accountId!,
), ),
getLatestChanges: getLatestChanges, getLatestChanges: getLatestChanges,
useCache: selectedMailbox?.isFavorite != true, useCache: !shouldBypassCache,
)); ));
} else { } else {
consumeState(Stream.value(Left(GetAllEmailFailure(NotFoundSessionException())))); consumeState(Stream.value(Left(GetAllEmailFailure(NotFoundSessionException()))));
@@ -597,7 +608,7 @@ class ThreadController extends BaseController with EmailActionController {
} }
EmailFilter getEmailFilterForLoadMailbox({PresentationEmail? oldestEmail}) { EmailFilter getEmailFilterForLoadMailbox({PresentationEmail? oldestEmail}) {
if (selectedMailbox?.isFavorite == true) { if (selectedMailbox?.isVirtualFolder == true) {
return EmailFilter( return EmailFilter(
filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail),
); );
@@ -610,33 +621,96 @@ class ThreadController extends BaseController with EmailActionController {
} }
} }
Filter getFilterConditionForLoadMailbox({PresentationEmail? oldestEmail}) { Filter getFilterConditionForLoadMailbox({
if (selectedMailbox?.isFavorite == true) { PresentationEmail? oldestEmail,
switch (mailboxDashBoardController.filterMessageOption.value) { }) {
case FilterMessageOption.unread: final mailbox = selectedMailbox;
return EmailFilterCondition( final filterOption =
notKeyword: KeyWordIdentifier.emailSeen.value, mailboxDashBoardController.filterMessageOption.value;
hasKeyword: KeyWordIdentifier.emailFlagged.value, final before = oldestEmail?.receivedAt;
before: oldestEmail?.receivedAt,
); if (mailbox?.isFavorite == true) {
case FilterMessageOption.attachments: return _buildFavoriteMailboxFilter(
return EmailFilterCondition( filterOption: filterOption,
hasAttachment: true, before: before,
hasKeyword: KeyWordIdentifier.emailFlagged.value,
before: oldestEmail?.receivedAt,
);
default:
return EmailFilterCondition(
hasKeyword: KeyWordIdentifier.emailFlagged.value,
before: oldestEmail?.receivedAt,
);
}
} else {
return getFilterCondition(
mailboxIdSelected: selectedMailboxId,
oldestEmail: oldestEmail,
); );
} }
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}) { EmailFilterCondition getFilterCondition({PresentationEmail? oldestEmail, MailboxId? mailboxIdSelected}) {
@@ -709,8 +783,8 @@ class ThreadController extends BaseController with EmailActionController {
try { try {
if (searchController.isSearchEmailRunning && PlatformInfo.isWeb) { if (searchController.isSearchEmailRunning && PlatformInfo.isWeb) {
await _refreshChangeSearchEmail(); await _refreshChangeSearchEmail();
} else if (selectedMailbox?.isFavorite == true) { } else if (selectedMailbox?.isVirtualFolder == true) {
await _refreshChangeListEmailsInFavoriteFolder(); await _refreshChangeListEmailsInVirtualFolder();
} else { } else {
await _refreshChangeListEmail(); await _refreshChangeListEmail();
} }
@@ -815,8 +889,8 @@ class ThreadController extends BaseController with EmailActionController {
} }
} }
Future<void> _refreshChangeListEmailsInFavoriteFolder() async { Future<void> _refreshChangeListEmailsInVirtualFolder() async {
log('ThreadController::_refreshChangeListEmailsInFavoriteFolder:'); log('ThreadController::_refreshChangeListEmailsInVirtualFolder:');
await _refreshChangeListEmailCache(); await _refreshChangeListEmailCache();
@@ -860,20 +934,20 @@ class ThreadController extends BaseController with EmailActionController {
GetEmailRequest( GetEmailRequest(
_session!, _session!,
_accountId!, _accountId!,
limit: ThreadConstants.defaultLimit, limit: limitEmailFetchedInFolder,
sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(),
filterOption: mailboxDashBoardController.filterMessageOption.value, filterOption: mailboxDashBoardController.filterMessageOption.value,
filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail),
properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!),
lastEmailId: oldestEmail?.id, lastEmailId: oldestEmail?.id,
useCache: selectedMailbox?.isFavorite != true, useCache: !shouldBypassCache,
) )
)); ));
} }
} }
bool _validatePresentationEmail(PresentationEmail email) { bool _validatePresentationEmail(PresentationEmail email) {
return (_belongToCurrentMailboxId(email) || selectedMailbox?.isFavorite == true) return (_belongToCurrentMailboxId(email) || selectedMailbox?.isVirtualFolder == true)
&& _notDuplicatedInCurrentList(email); && _notDuplicatedInCurrentList(email);
} }
@@ -780,7 +780,7 @@ class ThreadView extends GetWidget<ThreadController>
if (success is GetAllEmailSuccess if (success is GetAllEmailSuccess
&& success.currentMailboxId != controller.selectedMailboxId && && success.currentMailboxId != controller.selectedMailboxId &&
controller.selectedMailbox?.isFavorite != true) { controller.selectedMailbox?.isVirtualFolder != true) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} else { } else {
return PullToRefreshWidget( return PullToRefreshWidget(
@@ -36,6 +36,10 @@ extension PresentationMailboxExtension on PresentationMailbox {
bool get isFavorite => role == PresentationMailbox.roleFavorite; 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 isTrash => role == PresentationMailbox.roleTrash;
bool get isDrafts => role == PresentationMailbox.roleDrafts; bool get isDrafts => role == PresentationMailbox.roleDrafts;