TF-3707 Handle empty trash with clear mailbox method

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-05-06 16:44:56 +07:00
committed by Dat H. Pham
parent e415077738
commit 322c449d49
10 changed files with 93 additions and 10 deletions
@@ -1,16 +1,18 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
class ClearingMailbox extends LoadingState {}
class ClearMailboxSuccess extends UIState {
final UnsignedInt totalDeletedMessages;
final MailboxId mailboxId;
ClearMailboxSuccess(this.totalDeletedMessages);
ClearMailboxSuccess(this.mailboxId, this.totalDeletedMessages);
@override
List<Object> get props => [totalDeletedMessages];
List<Object> get props => [mailboxId, totalDeletedMessages];
}
class ClearMailboxFailure extends FeatureFailure {
@@ -24,7 +24,7 @@ class ClearMailboxInteractor {
accountId,
mailboxId,
);
yield Right<Failure, Success>(ClearMailboxSuccess(totalDeletedMessages));
yield Right<Failure, Success>(ClearMailboxSuccess(mailboxId, totalDeletedMessages));
} catch (e) {
yield Left<Failure, Success>(ClearMailboxFailure(e));
}
@@ -46,6 +46,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_right_reques
import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_multiple_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/create_default_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/create_new_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/delete_multiple_mailbox_state.dart';
@@ -397,6 +398,11 @@ class MailboxController extends BaseMailboxController
destinationMailboxId: reactionState.destinationMailboxId,
emailIdsWithReadStatus: reactionState.moveSucceededEmailIdsWithReadStatus,
);
} else if (reactionState is ClearMailboxSuccess) {
_handleDeleteEmailsFromMailbox(
affectedMailboxId: reactionState.mailboxId,
totalEmailsChanged: -reactionState.totalDeletedMessages.value.toInt(),
);
}
});
}
@@ -55,6 +55,7 @@ import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_isolate_worker.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/domain/usecases/clear_mailbox_interactor.dart';
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/app_grid_datasource.dart';
@@ -200,6 +201,7 @@ class MailboxDashBoardBindings extends BaseBindings {
Get.find<RemoveAllComposerCacheOnWebInteractor>(),
Get.find<RemoveComposerCacheByIdOnWebInteractor>(),
Get.find<GetAllIdentitiesInteractor>(),
Get.find<ClearMailboxInteractor>(),
));
Get.put(AdvancedFilterController());
}
@@ -352,6 +354,7 @@ class MailboxDashBoardBindings extends BaseBindings {
Get.find<EmailRepository>(),
Get.find<MailboxRepository>()
));
Get.lazyPut(() => ClearMailboxInteractor(Get.find<MailboxRepository>()));
IdentityInteractorsBindings().dependencies();
Get.lazyPut(() => GetAllIdentitiesInteractor(
@@ -81,8 +81,10 @@ import 'package:tmail_ui_user/features/login/domain/exceptions/logout_exception.
import 'package:tmail_ui_user/features/login/presentation/model/login_navigate_arguments.dart';
import 'package:tmail_ui_user/features/mailbox/domain/exceptions/mailbox_exception.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/refresh_all_mailboxes_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/mark_as_mailbox_read_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
@@ -101,6 +103,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart' as search;
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/delete_emails_in_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_clear_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preferences_setting_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/reopen_composer_cache_extension.dart';
@@ -166,6 +169,7 @@ import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_t
import 'package:tmail_ui_user/main/deep_links/deep_link_data.dart';
import 'package:tmail_ui_user/main/deep_links/deep_links_manager.dart';
import 'package:tmail_ui_user/main/deep_links/open_app_deep_link_data.dart';
import 'package:tmail_ui_user/main/error/capability_validator.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
@@ -218,6 +222,7 @@ class MailboxDashBoardController extends ReloadableController
final RemoveComposerCacheByIdOnWebInteractor _removeComposerCacheByIdOnWebInteractor;
final RemoveAllComposerCacheOnWebInteractor _removeAllComposerCacheOnWebInteractor;
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
final ClearMailboxInteractor clearMailboxInteractor;
GetAllVacationInteractor? _getAllVacationInteractor;
UpdateVacationInteractor? _updateVacationInteractor;
@@ -310,6 +315,7 @@ class MailboxDashBoardController extends ReloadableController
this._removeAllComposerCacheOnWebInteractor,
this._removeComposerCacheByIdOnWebInteractor,
this._getAllIdentitiesInteractor,
this.clearMailboxInteractor,
);
@override
@@ -448,6 +454,8 @@ class MailboxDashBoardController extends ReloadableController
);
} else if (success is GetServerSettingSuccess) {
isSenderImportantFlagEnabled.value = success.settingOption.isDisplaySenderPriority;
} else if (success is ClearMailboxSuccess) {
clearMailboxSuccess(success);
}
}
@@ -1608,15 +1616,26 @@ class MailboxDashBoardController extends ReloadableController
onCancelSelectionEmail?.call();
final trashMailboxId = trashFolderId ?? mapDefaultMailboxIdByRole[PresentationMailbox.roleTrash];
final trashMailbox = mapMailboxById[trashMailboxId];
final totalEmailsInTrash = totalEmails == 0 ? trashMailbox?.countTotalEmails : totalEmails;
if (sessionCurrent != null && accountId.value != null && trashMailboxId != null) {
final accountId = this.accountId.value;
if (sessionCurrent == null ||
accountId == null ||
trashMailboxId == null) {
return;
}
if (CapabilityIdentifier.jmapMailboxClear.isSupported(sessionCurrent!, accountId)) {
clearMailbox(sessionCurrent!, accountId, trashMailboxId);
} else {
final totalEmailsInTrash = totalEmails == 0
? mapMailboxById[trashMailboxId]?.countTotalEmails ?? 0
: totalEmails;
consumeState(_emptyTrashFolderInteractor.execute(
sessionCurrent!,
accountId.value!,
accountId,
trashMailboxId,
totalEmailsInTrash ?? 0,
_progressStateController
totalEmailsInTrash,
_progressStateController,
));
}
}
@@ -0,0 +1,36 @@
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension HandleClearMailboxExtension on MailboxDashBoardController {
void clearMailbox(Session session, AccountId accountId, MailboxId mailboxId) {
consumeState(clearMailboxInteractor.execute(
session,
accountId,
mailboxId,
));
}
void clearMailboxSuccess(ClearMailboxSuccess success) {
viewStateMailboxActionProgress.value = Right(UIState.idle);
if (currentOverlayContext != null && currentContext != null) {
appToast.showToastSuccessMessage(
currentOverlayContext!,
AppLocalizations.of(currentContext!).toast_message_empty_trash_folder_success,
);
}
if (selectedMailbox.value?.id == success.mailboxId) {
emailsInCurrentMailbox.clear();
}
}
}
@@ -11,6 +11,7 @@ import 'package:tmail_ui_user/features/base/mixin/popup_menu_widget_mixin.dart';
import 'package:tmail_ui_user/features/base/widget/compose_floating_button.dart';
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mixin/filter_email_popup_menu_mixin.dart';
@@ -969,7 +970,8 @@ class _MailboxActionProgressBanner extends StatelessWidget with AppLoaderMixin {
(success) {
if (success is MarkAsMailboxReadLoading ||
success is EmptySpamFolderLoading ||
success is EmptyTrashFolderLoading) {
success is EmptyTrashFolderLoading ||
success is ClearingMailbox) {
return Padding(
padding: EdgeInsets.only(
top: responsiveUtils.isDesktop(context) ? 16 : 0,
@@ -39,6 +39,7 @@ import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_a
import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cache_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/exceptions/empty_folder_name_exception.dart';
import 'package:tmail_ui_user/features/mailbox/domain/exceptions/invalid_mail_format_exception.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_default_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart';
@@ -184,6 +185,7 @@ const fallbackGenerators = {
MockSpec<GetIdentityCacheOnWebInteractor>(),
MockSpec<ComposerManager>(fallbackGenerators: fallbackGenerators),
MockSpec<CleanAndGetEmailsInMailboxInteractor>(),
MockSpec<ClearMailboxInteractor>(),
])
void main() {
// mock mailbox dashboard controller direct dependencies
@@ -271,6 +273,7 @@ void main() {
final removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor();
final removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor();
final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor();
final clearMailboxInteractor = MockClearMailboxInteractor();
final composerManager = MockComposerManager();
late MailboxController mailboxController;
@@ -322,6 +325,7 @@ void main() {
Get.put<GetAuthenticatedAccountInteractor>(getAuthenticatedAccountInteractor);
Get.put<UpdateAccountCacheInteractor>(updateAccountCacheInteractor);
Get.put<GetAllIdentitiesInteractor>(getAllIdentitiesInteractor);
Get.put<ClearMailboxInteractor>(clearMailboxInteractor);
Get.put<RemoveAllComposerCacheOnWebInteractor>(removeAllComposerCacheOnWebInteractor);
Get.put<RemoveComposerCacheByIdOnWebInteractor>(removeComposerCacheByIdOnWebInteractor);
Get.put<ComposerManager>(composerManager);
@@ -361,6 +365,7 @@ void main() {
removeAllComposerCacheOnWebInteractor,
removeComposerCacheByIdOnWebInteractor,
getAllIdentitiesInteractor,
clearMailboxInteractor,
);
});
@@ -37,6 +37,7 @@ import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oi
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cache_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_default_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart';
@@ -186,6 +187,7 @@ const fallbackGenerators = {
MockSpec<GetIdentityCacheOnWebInteractor>(),
MockSpec<ComposerManager>(fallbackGenerators: fallbackGenerators),
MockSpec<CleanAndGetEmailsInMailboxInteractor>(),
MockSpec<ClearMailboxInteractor>(),
])
void main() {
final moveToMailboxInteractor = MockMoveToMailboxInteractor();
@@ -258,6 +260,7 @@ void main() {
final removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor();
final removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor();
final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor();
final clearMailboxInteractor = MockClearMailboxInteractor();
final composerManager = MockComposerManager();
final getEmailsInMailboxInteractor = MockGetEmailsInMailboxInteractor();
@@ -320,6 +323,7 @@ void main() {
Get.put<GetAuthenticatedAccountInteractor>(getAuthenticatedAccountInteractor);
Get.put<UpdateAccountCacheInteractor>(updateAccountCacheInteractor);
Get.put<GetAllIdentitiesInteractor>(getAllIdentitiesInteractor);
Get.put<ClearMailboxInteractor>(clearMailboxInteractor);
Get.put<RemoveAllComposerCacheOnWebInteractor>(removeAllComposerCacheOnWebInteractor);
Get.put<RemoveComposerCacheByIdOnWebInteractor>(removeComposerCacheByIdOnWebInteractor);
Get.put<ComposerManager>(composerManager);
@@ -360,6 +364,7 @@ void main() {
removeAllComposerCacheOnWebInteractor,
removeComposerCacheByIdOnWebInteractor,
getAllIdentitiesInteractor,
clearMailboxInteractor,
);
Get.put(mailboxDashboardController);
mailboxDashboardController.onReady();
@@ -38,6 +38,7 @@ import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oi
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cache_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/mark_as_mailbox_read_interactor.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';
@@ -159,6 +160,7 @@ const fallbackGenerators = {
MockSpec<GetAllIdentitiesInteractor>(),
MockSpec<ComposerManager>(fallbackGenerators: fallbackGenerators),
MockSpec<CleanAndGetEmailsInMailboxInteractor>(),
MockSpec<ClearMailboxInteractor>(),
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@@ -217,6 +219,7 @@ void main() {
late MockRemoveAllComposerCacheOnWebInteractor removeAllComposerCacheOnWebInteractor;
late MockRemoveComposerCacheByIdOnWebInteractor removeComposerCacheByIdOnWebInteractor;
late MockGetAllIdentitiesInteractor getAllIdentitiesInteractor;
late MockClearMailboxInteractor clearMailboxInteractor;
// Declaration base controller
late MockCachingManager mockCachingManager;
@@ -311,6 +314,7 @@ void main() {
removeAllComposerCacheOnWebInteractor = MockRemoveAllComposerCacheOnWebInteractor();
removeComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor();
getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor();
clearMailboxInteractor = MockClearMailboxInteractor();
searchController = SearchController(
mockQuickSearchEmailInteractor,
@@ -357,6 +361,7 @@ void main() {
removeAllComposerCacheOnWebInteractor,
removeComposerCacheByIdOnWebInteractor,
getAllIdentitiesInteractor,
clearMailboxInteractor,
);
when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([]));