diff --git a/lib/features/composer/presentation/widgets/web/web_editor_widget.dart b/lib/features/composer/presentation/widgets/web/web_editor_widget.dart index c95ffd8bc..37c59563b 100644 --- a/lib/features/composer/presentation/widgets/web/web_editor_widget.dart +++ b/lib/features/composer/presentation/widgets/web/web_editor_widget.dart @@ -85,7 +85,9 @@ class _WebEditorState extends State { } } }; - window.addEventListener("message", _dropListener); + if (_dropListener != null) { + window.addEventListener("message", _dropListener!); + } } @override @@ -108,8 +110,10 @@ class _WebEditorState extends State { _htmlEditorHeight.dispose(); _editorController.evaluateJavascriptWeb( HtmlUtils.unregisterDropListener.name); - window.removeEventListener("message", _dropListener); - _dropListener = null; + if (_dropListener != null) { + window.removeEventListener("message", _dropListener!); + _dropListener = null; + } super.dispose(); } diff --git a/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart index 2ad681b61..418a88269 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart @@ -32,8 +32,8 @@ class SpamReportController extends BaseController { final GetSpamReportStateInteractor _getSpamReportStateInteractor; final GetSpamMailboxCachedInteractor _getSpamMailboxCachedInteractor; - final _presentationSpamMailbox = Rxn(); - final _spamReportState = Rxn(SpamReportState.enabled); + final presentationSpamMailbox = Rxn(); + final spamReportState = Rx(SpamReportState.enabled); SpamReportController( this._storeSpamReportInteractor, @@ -47,15 +47,15 @@ class SpamReportController extends BaseController { void handleSuccessViewState(Success success) { super.handleSuccessViewState(success); if (success is GetUnreadSpamMailboxSuccess){ - _presentationSpamMailbox.value = success.unreadSpamMailbox.toPresentationMailbox(); + presentationSpamMailbox.value = success.unreadSpamMailbox.toPresentationMailbox(); } else if (success is StoreLastTimeDismissedSpamReportSuccess) { - _presentationSpamMailbox.value = null; + presentationSpamMailbox.value = null; } else if (success is GetSpamReportStateSuccess) { - _spamReportState.value = success.spamReportState; + spamReportState.value = success.spamReportState; } else if (success is StoreSpamReportStateSuccess) { - _spamReportState.value = success.spamReportState; + spamReportState.value = success.spamReportState; } else if (success is GetSpamMailboxCachedSuccess) { - _presentationSpamMailbox.value = success.spamMailbox.toPresentationMailbox(); + presentationSpamMailbox.value = success.spamMailbox.toPresentationMailbox(); } } @@ -65,14 +65,14 @@ class SpamReportController extends BaseController { if (failure is GetUnreadSpamMailboxFailure || failure is GetSpamMailboxCachedFailure || failure is InvalidSpamReportCondition) { - _presentationSpamMailbox.value = null; + presentationSpamMailbox.value = null; } } void dismissSpamReportAction(BuildContext context) { if (Get.isRegistered()) { final mailboxDashBoardController = Get.find(); - final spamMailbox = _presentationSpamMailbox.value; + final spamMailbox = presentationSpamMailbox.value; final session = mailboxDashBoardController.sessionCurrent; final accountId = mailboxDashBoardController.accountId.value; @@ -86,7 +86,7 @@ class SpamReportController extends BaseController { spamMailbox.getDisplayName(context), spamMailbox.unreadEmails?.value.value.toInt() ?? 0 ); - _presentationSpamMailbox.value = null; + presentationSpamMailbox.value = null; } } } @@ -106,16 +106,14 @@ class SpamReportController extends BaseController { consumeState(_storeSpamReportInteractor.execute(DateTime.now())); } - bool get notShowSpamReportBanner => _presentationSpamMailbox.value == null; + String get numberOfUnreadSpamEmails => presentationSpamMailbox.value?.countUnReadEmailsAsString ?? ''; - String get numberOfUnreadSpamEmails => _presentationSpamMailbox.value?.countUnReadEmailsAsString ?? ''; - - bool get enableSpamReport => _spamReportState.value == SpamReportState.enabled; + bool get enableSpamReport => spamReportState.value == SpamReportState.enabled; void openMailbox() { final mailboxDashBoardController = Get.find(); _storeLastTimeDismissedSpamReportedAction(); - mailboxDashBoardController.openMailboxAction(_presentationSpamMailbox.value!); + mailboxDashBoardController.openMailboxAction(presentationSpamMailbox.value!); } void storeSpamReportStateAction(SpamReportState spamReportState) { 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 e885dc12b..bcb9e8274 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -427,9 +427,8 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { Widget _buildDownloadTaskStateWidget() { return Obx(() { - if (controller.downloadController.notEmptyListDownloadTask) { - final downloadTasks = controller.downloadController.listDownloadTaskState; - + final listDownloadTasks = controller.downloadController.listDownloadTaskState; + if (listDownloadTasks.isNotEmpty) { return Align( alignment: Alignment.bottomCenter, child: Container( @@ -439,7 +438,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { child: ListView.separated( scrollDirection: Axis.horizontal, padding: EdgeInsets.zero, - itemCount: downloadTasks.length, + itemCount: listDownloadTasks.length, separatorBuilder: (context, index) => const Padding( padding: EdgeInsets.symmetric(vertical: 5), @@ -449,7 +448,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { thickness: 0.2), ), itemBuilder: (context, index) => - DownloadTaskItemWidget(downloadTasks[index]) + DownloadTaskItemWidget(listDownloadTasks[index]) ), ), ); diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 13648a772..45e0166a5 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -440,7 +440,7 @@ class ThreadController extends BaseController with EmailActionController { void _getAllEmailSuccess(GetAllEmailSuccess success) { if (success.currentMailboxId != selectedMailboxId) { - log('ThreadController::_getAllEmailSuccess: GetAllForMailboxEd = ${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; } @@ -933,8 +933,6 @@ class ThreadController extends BaseController with EmailActionController { } } - bool isSelectionEnabled() => mailboxDashBoardController.isSelectionEnabled(); - void pressEmailSelectionAction(BuildContext context, EmailActionType actionType, List selectionEmail) { switch(actionType) { case EmailActionType.markAsRead: diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index f2c6b5190..e5192f4de 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -248,13 +248,21 @@ class ThreadView extends GetWidget Widget _buildListButtonSelectionForMobile(BuildContext context) { return Obx(() { - if ((PlatformInfo.isMobile || (PlatformInfo.isWeb && controller.isSelectionEnabled() - && controller.isSearchActive && !controller.responsiveUtils.isDesktop(context))) - && controller.mailboxDashBoardController.emailsInCurrentMailbox.listEmailSelected.isNotEmpty) { + final listEmailSelected = controller.mailboxDashBoardController.emailsInCurrentMailbox.listEmailSelected; + final currentSelectMode = controller.mailboxDashBoardController.currentSelectMode.value; + final isSearchEmailRunning = controller.searchController.simpleSearchIsActivated.isTrue + || controller.searchController.advancedSearchIsActivated.isTrue; + + if (_validateDisplayBottomBarSelection( + context: context, + listEmailSelected: listEmailSelected, + isSearchEmailRunning: isSearchEmailRunning, + currentSelectMode: currentSelectMode + )) { return BottomBarThreadSelectionWidget( controller.imagePaths, controller.responsiveUtils, - controller.mailboxDashBoardController.emailsInCurrentMailbox.listEmailSelected, + listEmailSelected, controller.mailboxDashBoardController.selectedMailbox.value, onPressEmailSelectionActionClick: (actionType, selectionEmail) => controller.pressEmailSelectionAction( @@ -269,6 +277,28 @@ class ThreadView extends GetWidget }); } + bool _validateDisplayBottomBarSelection({ + required BuildContext context, + required List listEmailSelected, + required bool isSearchEmailRunning, + required SelectMode currentSelectMode, + }) { + if (PlatformInfo.isMobile && listEmailSelected.isNotEmpty) { + return true; + } + + if (PlatformInfo.isWeb + && currentSelectMode == SelectMode.ACTIVE + && isSearchEmailRunning + && !controller.responsiveUtils.isDesktop(context) + && listEmailSelected.isNotEmpty + ) { + return true; + } + + return false; + } + Widget _buildFloatingButtonCompose(BuildContext context) { if (controller.responsiveUtils.isWebDesktop(context)) { return const SizedBox.shrink(); @@ -394,7 +424,7 @@ class ThreadView extends GetWidget if (index == listPresentationEmail.length + 1) { return _buildLoadMoreProgressBar(controller.loadingMoreStatus.value); } - return _buildEmailItem( + return _buildEmailItem( context, listPresentationEmail[index]); }), @@ -487,6 +517,7 @@ class ThreadView extends GetWidget final selectModeAll = controller.mailboxDashBoardController.currentSelectMode.value; return EmailTileBuilder( + key: Key('email_tile_builder_${presentationEmail.id?.asString}'), presentationEmail: presentationEmail, selectAllMode: selectModeAll, isShowingEmailContent: isShowingEmailContent, @@ -571,6 +602,7 @@ class ThreadView extends GetWidget : null, confirmDismiss: (direction) => controller.swipeEmailAction(context, presentationEmail, direction), child: EmailTileBuilder( + key: Key('email_tile_builder_${presentationEmail.id?.asString}'), presentationEmail: presentationEmail, selectAllMode: selectModeAll, isShowingEmailContent: isShowingEmailContent, @@ -656,24 +688,24 @@ class ThreadView extends GetWidget return Obx(() => controller.viewState.value.fold( (failure) => const SizedBox.shrink(), (success) { - if (success is! GetAllEmailLoading && success is! SearchingState) { - if (success is GetAllEmailSuccess - && success.currentMailboxId != controller.selectedMailboxId) { - return const SizedBox.shrink(); - } else { - return EmptyEmailsWidget( - key: const Key('empty_thread_view'), - title: _getMessageEmptyEmail(context), - iconSVG: controller.imagePaths.icEmptyEmail, - subTitle: _getSubMessageEmptyEmail(context), - onCreateFiltersActionCallback: controller.isNewFolderCreated - ? controller.goToCreateEmailRuleView - : null, - ); - } - } else { + if (success is GetAllEmailLoading || success is SearchingState) { return const SizedBox.shrink(); } + + if (success is GetAllEmailSuccess + && success.currentMailboxId != controller.selectedMailboxId) { + return const SizedBox.shrink(); + } else { + return EmptyEmailsWidget( + key: const Key('empty_thread_view'), + title: _getMessageEmptyEmail(context), + iconSVG: controller.imagePaths.icEmptyEmail, + subTitle: _getSubMessageEmptyEmail(context), + onCreateFiltersActionCallback: controller.isNewFolderCreated + ? controller.goToCreateEmailRuleView + : null, + ); + } }) ); } diff --git a/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_web_widget.dart b/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_web_widget.dart index a4e23f596..fdc42c4f8 100644 --- a/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_web_widget.dart +++ b/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_web_widget.dart @@ -2,6 +2,7 @@ import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/spam_banner/spam_report_banner_button_styles.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/spam_banner/spam_report_banner_label_styles.dart'; @@ -18,7 +19,8 @@ class SpamReportBannerWebWidget extends StatelessWidget { final spamReportController = Get.find(); final imagePaths = Get.find(); return Obx(() { - if (!spamReportController.enableSpamReport || spamReportController.notShowSpamReportBanner) { + if (spamReportController.spamReportState.value == SpamReportState.disabled + || spamReportController.presentationSpamMailbox.value == null) { return const SizedBox( height: 8, ); diff --git a/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_widget.dart b/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_widget.dart index 3ae1bc73b..0fab3f0aa 100644 --- a/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_widget.dart +++ b/lib/features/thread/presentation/widgets/spam_banner/spam_report_banner_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/spam_banner/spam_report_banner_button_styles.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/spam_banner/spam_report_banner_styles.dart'; @@ -19,9 +20,9 @@ class SpamReportBannerWidget extends StatelessWidget { @override Widget build(BuildContext context){ - return Obx(() { - if (!spamReportController.enableSpamReport || spamReportController.notShowSpamReportBanner) { + if (spamReportController.spamReportState.value == SpamReportState.disabled + || spamReportController.presentationSpamMailbox.value == null) { return const SizedBox.shrink(); } return Container( diff --git a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart new file mode 100644 index 000000000..7736eb9f1 --- /dev/null +++ b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart @@ -0,0 +1,586 @@ +import 'package:core/data/network/config/dynamic_url_interceptors.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/app_toast.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/utils/application_manager.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart' hide SearchController, State; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get/get.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:model/email/presentation_email.dart'; +import 'package:model/extensions/email_extension.dart'; +import 'package:model/extensions/email_id_extensions.dart'; +import 'package:model/extensions/mailbox_extension.dart'; +import 'package:rxdart/subjects.dart'; +import 'package:tmail_ui_user/features/caching/caching_manager.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.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/get_restored_deleted_message_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/domain/usecases/restore_deleted_message_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart'; +import 'package:tmail_ui_user/features/home/domain/usecases/get_session_interactor.dart'; +import 'package:tmail_ui_user/features/home/domain/usecases/store_session_interactor.dart'; +import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart'; +import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; +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/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'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_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/domain/usecases/move_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/rename_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart'; +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/mailbox_dashboard/domain/model/spam_report_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_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'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart'; +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/mailbox_dashboard/presentation/controller/spam_report_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; +import 'package:tmail_ui_user/features/quotas/domain/use_case/get_quotas_interactor.dart'; +import 'package:tmail_ui_user/features/quotas/presentation/quotas_controller.dart'; +import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_sending_email_interactor.dart'; +import 'package:tmail_ui_user/features/sending_queue/domain/usecases/get_all_sending_email_interactor.dart'; +import 'package:tmail_ui_user/features/sending_queue/domain/usecases/store_sending_email_interactor.dart'; +import 'package:tmail_ui_user/features/sending_queue/domain/usecases/update_sending_email_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/empty_spam_folder_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/empty_trash_folder_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/get_email_by_id_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/load_more_emails_in_mailbox_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/refresh_changes_emails_in_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_controller.dart'; +import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart'; +import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations_delegate.dart'; +import 'package:tmail_ui_user/main/localizations/localization_service.dart'; +import 'package:tmail_ui_user/main/utils/email_receive_manager.dart'; +import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart' + if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart'; +import 'package:uuid/uuid.dart'; + +import '../../../../fixtures/account_fixtures.dart'; +import '../../../../fixtures/email_fixtures.dart'; +import '../../../../fixtures/mailbox_fixtures.dart'; +import '../../../../fixtures/session_fixtures.dart'; +import 'mailbox_dashboard_view_widget_test.mocks.dart'; + +mockControllerCallback() => InternalFinalCallback(callback: () {}); +const fallbackGenerators = { + #onStart: mockControllerCallback, + #onDelete: mockControllerCallback, +}; + +@GenerateNiceMocks([ + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(fallbackGenerators: fallbackGenerators), + MockSpec(), + MockSpec(fallbackGenerators: fallbackGenerators), + MockSpec(fallbackGenerators: fallbackGenerators), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), +]) +void main() { + final moveToMailboxInteractor = MockMoveToMailboxInteractor(); + final deleteEmailPermanentlyInteractor = MockDeleteEmailPermanentlyInteractor(); + final markAsMailboxReadInteractor = MockMarkAsMailboxReadInteractor(); + final getEmailCacheOnWebInteractor = MockGetComposerCacheOnWebInteractor(); + final markAsEmailReadInteractor = MockMarkAsEmailReadInteractor(); + final markAsStarEmailInteractor = MockMarkAsStarEmailInteractor(); + final markAsMultipleEmailReadInteractor = MockMarkAsMultipleEmailReadInteractor(); + final markAsStarMultipleEmailInteractor = MockMarkAsStarMultipleEmailInteractor(); + final moveMultipleEmailToMailboxInteractor = MockMoveMultipleEmailToMailboxInteractor(); + final emptyTrashFolderInteractor = MockEmptyTrashFolderInteractor(); + final deleteMultipleEmailsPermanentlyInteractor = MockDeleteMultipleEmailsPermanentlyInteractor(); + final getEmailByIdInteractor = MockGetEmailByIdInteractor(); + final sendEmailInteractor = MockSendEmailInteractor(); + final storeSendingEmailInteractor = MockStoreSendingEmailInteractor(); + final updateSendingEmailInteractor = MockUpdateSendingEmailInteractor(); + final getAllSendingEmailInteractor = MockGetAllSendingEmailInteractor(); + final storeSessionInteractor = MockStoreSessionInteractor(); + final emptySpamFolderInteractor = MockEmptySpamFolderInteractor(); + final deleteSendingEmailInteractor = MockDeleteSendingEmailInteractor(); + final unsubscribeEmailInteractor = MockUnsubscribeEmailInteractor(); + final restoreDeletedMessageInteractor = MockRestoredDeletedMessageInteractor(); + final getRestoredDeletedMessageInteractor = MockGetRestoredDeletedMessageInterator(); + + final removeEmailDraftsInteractor = MockRemoveEmailDraftsInteractor(); + final emailReceiveManager = MockEmailReceiveManager(); + final downloadController = MockDownloadController(); + final appGridDashboardController = MockAppGridDashboardController(); + final spamReportController = MockSpamReportController(); + final networkConnectionController = MockNetworkConnectionController(); + + final quickSearchEmailInteractor = MockQuickSearchEmailInteractor(); + final saveRecentSearchInteractor = MockSaveRecentSearchInteractor(); + final getAllRecentSearchLatestInteractor = MockGetAllRecentSearchLatestInteractor(); + + final cachingManager = MockCachingManager(); + final languageCacheManager = MockLanguageCacheManager(); + final authorizationInterceptors = MockAuthorizationInterceptors(); + final dynamicUrlInterceptors = MockDynamicUrlInterceptors(); + final deleteCredentialInteractor = MockDeleteCredentialInteractor(); + final logoutOidcInteractor = MockLogoutOidcInteractor(); + final deleteAuthorityOidcInteractor = MockDeleteAuthorityOidcInteractor(); + final appToast = MockAppToast(); + final imagePaths = ImagePaths(); + final responsiveUtils = MockResponsiveUtils(); + final uuid = MockUuid(); + final applicationManager = MockApplicationManager(); + + final getSessionInteractor = MockGetSessionInteractor(); + final getAuthenticatedAccountInteractor = MockGetAuthenticatedAccountInteractor(); + final updateAccountCacheInteractor = MockUpdateAccountCacheInteractor(); + + final createNewMailboxInteractor = MockCreateNewMailboxInteractor(); + final deleteMultipleMailboxInteractor = MockDeleteMultipleMailboxInteractor(); + final renameMailboxInteractor = MockRenameMailboxInteractor(); + final moveMailboxInteractor = MockMoveMailboxInteractor(); + final subscribeMailboxInteractor = MockSubscribeMailboxInteractor(); + final subscribeMultipleMailboxInteractor = MockSubscribeMultipleMailboxInteractor(); + final createDefaultMailboxInteractor = MockCreateDefaultMailboxInteractor(); + final treeBuilder = MockTreeBuilder(); + final verifyNameInteractor = MockVerifyNameInteractor(); + final getAllMailboxInteractor = MockGetAllMailboxInteractor(); + final refreshAllMailboxInteractor = MockRefreshAllMailboxInteractor(); + final removeComposerCacheOnWebInteractor = MockRemoveComposerCacheOnWebInteractor(); + final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); + + final getEmailsInMailboxInteractor = MockGetEmailsInMailboxInteractor(); + final refreshChangesEmailsInMailboxInteractor = MockRefreshChangesEmailsInMailboxInteractor(); + final loadMoreEmailsInMailboxInteractor = MockLoadMoreEmailsInMailboxInteractor(); + final searchEmailInteractor = MockSearchEmailInteractor(); + final searchMoreEmailInteractor = MockSearchMoreEmailInteractor(); + + final getQuotasInteractor = MockGetQuotasInteractor(); + + late MailboxDashBoardController mailboxDashboardController; + late SearchController searchController; + late MailboxController mailboxController; + late ThreadController threadController; + late QuotasController quotasController; + + Widget makeTestableWidget({required Widget child}) { + return GetMaterialApp( + localizationsDelegates: const [ + AppLocalizationsDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: LocalizationService.supportedLocales, + locale: LocalizationService.defaultLocale, + home: Scaffold(body: child), + ); + } + + group('MailboxDashboardView::WidgetTest::OnWeb', () { + setUp(() { + Get.testMode = true; + + Get.put(removeEmailDraftsInteractor); + Get.put(emailReceiveManager); + Get.put(downloadController); + Get.put(appGridDashboardController); + Get.put(spamReportController); + Get.put(networkConnectionController); + Get.put(cachingManager); + Get.put(languageCacheManager); + Get.put(authorizationInterceptors); + Get.put( + authorizationInterceptors, + tag: BindingTag.isolateTag, + ); + Get.put(dynamicUrlInterceptors); + Get.put(deleteCredentialInteractor); + Get.put(logoutOidcInteractor); + Get.put(deleteAuthorityOidcInteractor); + Get.put(appToast); + Get.put(imagePaths); + Get.put(responsiveUtils); + Get.put(uuid); + Get.put(applicationManager); + Get.put(getSessionInteractor); + Get.put(getAuthenticatedAccountInteractor); + Get.put(updateAccountCacheInteractor); + Get.put(getAllIdentitiesInteractor); + Get.put(removeComposerCacheOnWebInteractor); + + when(emailReceiveManager.pendingEmailAddressInfo).thenAnswer((_) => BehaviorSubject.seeded(null)); + when(emailReceiveManager.pendingEmailContentInfo).thenAnswer((_) => BehaviorSubject.seeded(null)); + when(emailReceiveManager.pendingFileInfo).thenAnswer((_) => BehaviorSubject.seeded([])); + + searchController = SearchController( + quickSearchEmailInteractor, + saveRecentSearchInteractor, + getAllRecentSearchLatestInteractor + ); + Get.put(searchController); + + mailboxDashboardController = MailboxDashBoardController( + moveToMailboxInteractor, + deleteEmailPermanentlyInteractor, + markAsMailboxReadInteractor, + getEmailCacheOnWebInteractor, + markAsEmailReadInteractor, + markAsStarEmailInteractor, + markAsMultipleEmailReadInteractor, + markAsStarMultipleEmailInteractor, + moveMultipleEmailToMailboxInteractor, + emptyTrashFolderInteractor, + deleteMultipleEmailsPermanentlyInteractor, + getEmailByIdInteractor, + sendEmailInteractor, + storeSendingEmailInteractor, + updateSendingEmailInteractor, + getAllSendingEmailInteractor, + storeSessionInteractor, + emptySpamFolderInteractor, + deleteSendingEmailInteractor, + unsubscribeEmailInteractor, + restoreDeletedMessageInteractor, + getRestoredDeletedMessageInteractor, + removeComposerCacheOnWebInteractor, + getAllIdentitiesInteractor, + ); + Get.put(mailboxDashboardController); + mailboxDashboardController.onReady(); + + mailboxController = MailboxController( + createNewMailboxInteractor, + deleteMultipleMailboxInteractor, + renameMailboxInteractor, + moveMailboxInteractor, + subscribeMailboxInteractor, + subscribeMultipleMailboxInteractor, + createDefaultMailboxInteractor, + treeBuilder, + verifyNameInteractor, + getAllMailboxInteractor, + refreshAllMailboxInteractor + ); + mailboxController.onReady(); + + threadController = ThreadController( + getEmailsInMailboxInteractor, + refreshChangesEmailsInMailboxInteractor, + loadMoreEmailsInMailboxInteractor, + searchEmailInteractor, + searchMoreEmailInteractor, + getEmailByIdInteractor + ); + Get.put(threadController); + + quotasController = QuotasController(getQuotasInteractor); + Get.put(quotasController); + + mailboxDashboardController.sessionCurrent = SessionFixtures.aliceSession; + mailboxDashboardController.filterMessageOption.value = FilterMessageOption.all; + mailboxDashboardController.accountId.value = AccountFixtures.aliceAccountId; + }); + + group('ThreadView::test', () { + testWidgets( + 'WHEN switch from old mailbox to new mailbox\n' + 'AND old mailbox and new mailbox both have emails\n' + 'ThreadView SHOULD not load emails from the old mailbox', + (tester) async { + debugDefaultTargetPlatformOverride = TargetPlatform.macOS; + final dpi = tester.view.devicePixelRatio; + tester.view.physicalSize = Size(dpi * 1920 * 2, dpi * 1080 * 2); + + when(mailboxDashboardController.spamReportController.spamReportState).thenReturn(Rx(SpamReportState.disabled)); + when(mailboxDashboardController.spamReportController.presentationSpamMailbox).thenReturn(Rxn(null)); + when(mailboxDashboardController.downloadController.listDownloadTaskState).thenReturn(RxList([])); + + final widget = makeTestableWidget(child: MailboxDashBoardView()); + await tester.pumpWidget(widget); + + // Open mailbox Inbox + final listEmailsOfInbox = [ + EmailFixtures.email1.toPresentationEmail(), + EmailFixtures.email2.toPresentationEmail(), + EmailFixtures.email3.toPresentationEmail(), + ]; + mailboxDashboardController.setSelectedMailbox(MailboxFixtures.inboxMailbox.toPresentationMailbox()); + mailboxDashboardController.updateEmailList(listEmailsOfInbox); + + await tester.pump(); + + final threadViewFinder = find.byType(ThreadView); + expect(threadViewFinder, findsOneWidget); + + final emptyEmailWidgetFinder = find.byKey(const Key('empty_thread_view')); + expect(emptyEmailWidgetFinder, findsNothing); + + final listViewEmailWidgetFinder = find.byKey(const PageStorageKey('list_presentation_email_in_threads')); + expect(listViewEmailWidgetFinder, findsOneWidget); + + final listViewEmailWidget = tester.widget(listViewEmailWidgetFinder); + expect(listViewEmailWidget.semanticChildCount, equals(listEmailsOfInbox.length + 2)); + + final emailTile1Finder = find.byKey(Key('email_tile_builder_${EmailFixtures.email1.toPresentationEmail().id?.asString}'),); + expect(emailTile1Finder, findsOneWidget); + + final emailTile2Finder = find.byKey(Key('email_tile_builder_${EmailFixtures.email2.toPresentationEmail().id?.asString}'),); + expect(emailTile2Finder, findsOneWidget); + + final emailTile3Finder = find.byKey(Key('email_tile_builder_${EmailFixtures.email3.toPresentationEmail().id?.asString}'),); + expect(emailTile3Finder, findsOneWidget); + + // Switch to mailbox Folder 1 + final listEmailsOfFolder1 = [ + EmailFixtures.email4.toPresentationEmail(), + EmailFixtures.email5.toPresentationEmail(), + ]; + mailboxDashboardController.setSelectedMailbox(MailboxFixtures.folder1.toPresentationMailbox()); + mailboxDashboardController.updateEmailList(listEmailsOfFolder1); + + await tester.pump(); + + final folder1EmptyEmailWidgetFinder = find.byKey(const Key('empty_thread_view')); + expect(folder1EmptyEmailWidgetFinder, findsNothing); + + final folder1ListViewEmailWidgetFinder = find.byKey(const PageStorageKey('list_presentation_email_in_threads')); + expect(folder1ListViewEmailWidgetFinder, findsOneWidget); + + final folder1ListViewEmailWidget = tester.widget(folder1ListViewEmailWidgetFinder); + expect(folder1ListViewEmailWidget.semanticChildCount, equals(listEmailsOfFolder1.length + 2)); + + final emailTile4Finder = find.byKey(Key('email_tile_builder_${EmailFixtures.email4.toPresentationEmail().id?.asString}'),); + expect(emailTile4Finder, findsOneWidget); + + final emailTile5Finder = find.byKey(Key('email_tile_builder_${EmailFixtures.email5.toPresentationEmail().id?.asString}'),); + expect(emailTile5Finder, findsOneWidget); + + expect(emailTile1Finder, findsNothing); + expect(emailTile2Finder, findsNothing); + expect(emailTile3Finder, findsNothing); + + debugDefaultTargetPlatformOverride = null; + tester.view.reset(); + }); + + testWidgets( + 'WHEN switch new mailbox\n' + 'AND new mailbox has email\n' + 'ThreadView SHOULD not display empty view', + (tester) async { + debugDefaultTargetPlatformOverride = TargetPlatform.macOS; + final dpi = tester.view.devicePixelRatio; + tester.view.physicalSize = Size(dpi * 1920 * 2, dpi * 1080 * 2); + + when(mailboxDashboardController.spamReportController.spamReportState).thenReturn(Rx(SpamReportState.disabled)); + when(mailboxDashboardController.spamReportController.presentationSpamMailbox).thenReturn(Rxn(null)); + when(mailboxDashboardController.downloadController.listDownloadTaskState).thenReturn(RxList([])); + + final widget = makeTestableWidget(child: MailboxDashBoardView()); + await tester.pumpWidget(widget); + + // Open mailbox Inbox + final listEmailsOfInbox = []; + mailboxDashboardController.setSelectedMailbox(MailboxFixtures.inboxMailbox.toPresentationMailbox()); + mailboxDashboardController.updateEmailList(listEmailsOfInbox); + + threadController.consumeState( + Stream.value(Right(GetAllEmailSuccess( + emailList: listEmailsOfInbox, + currentMailboxId: MailboxFixtures.inboxMailbox.id + ))) + ); + + await tester.pump(); + + final emptyEmailWidgetFinder = find.byKey(const Key('empty_thread_view')); + expect(emptyEmailWidgetFinder, findsOneWidget); + + final listViewEmailWidgetFinder = find.byKey(const PageStorageKey('list_presentation_email_in_threads')); + expect(listViewEmailWidgetFinder, findsNothing); + + // Switch to mailbox Folder 1 + final listEmailsOfFolder1 = [ + EmailFixtures.email1.toPresentationEmail(), + EmailFixtures.email2.toPresentationEmail(), + ]; + mailboxDashboardController.setSelectedMailbox(MailboxFixtures.folder1.toPresentationMailbox()); + mailboxDashboardController.updateEmailList(listEmailsOfFolder1); + + await tester.pump(); + + final folder1EmptyEmailWidgetFinder = find.byKey(const Key('empty_thread_view')); + expect(folder1EmptyEmailWidgetFinder, findsNothing); + + final folder1ListViewEmailWidgetFinder = find.byKey(const PageStorageKey('list_presentation_email_in_threads')); + expect(folder1ListViewEmailWidgetFinder, findsOneWidget); + + final folder1ListViewEmailWidget = tester.widget(folder1ListViewEmailWidgetFinder); + expect(folder1ListViewEmailWidget.semanticChildCount, equals(listEmailsOfFolder1.length + 2)); + + final emailTile1Finder = find.byKey(Key('email_tile_builder_${EmailFixtures.email1.toPresentationEmail().id?.asString}'),); + expect(emailTile1Finder, findsOneWidget); + + final emailTile2Finder = find.byKey(Key('email_tile_builder_${EmailFixtures.email2.toPresentationEmail().id?.asString}'),); + expect(emailTile2Finder, findsOneWidget); + + debugDefaultTargetPlatformOverride = null; + tester.view.reset(); + }); + + testWidgets( + 'WHEN switch from old mailbox to new mailbox\n' + 'AND old mailbox has email, new mailbox has no email\n' + 'ThreadView SHOULD display empty view', + (tester) async { + debugDefaultTargetPlatformOverride = TargetPlatform.macOS; + final dpi = tester.view.devicePixelRatio; + tester.view.physicalSize = Size(dpi * 1920 * 2, dpi * 1080 * 2); + + when(mailboxDashboardController.spamReportController.spamReportState).thenReturn(Rx(SpamReportState.disabled)); + when(mailboxDashboardController.spamReportController.presentationSpamMailbox).thenReturn(Rxn(null)); + when(mailboxDashboardController.downloadController.listDownloadTaskState).thenReturn(RxList([])); + + final widget = makeTestableWidget(child: MailboxDashBoardView()); + await tester.pumpWidget(widget); + + // Open mailbox Inbox + final listEmailsOfInbox = [ + EmailFixtures.email1.toPresentationEmail(), + EmailFixtures.email2.toPresentationEmail(), + ]; + mailboxDashboardController.setSelectedMailbox(MailboxFixtures.inboxMailbox.toPresentationMailbox()); + mailboxDashboardController.updateEmailList(listEmailsOfInbox); + + threadController.consumeState( + Stream.value(Right(GetAllEmailSuccess( + emailList: listEmailsOfInbox, + currentMailboxId: MailboxFixtures.inboxMailbox.id + ))) + ); + + await tester.pump(); + + final emptyEmailWidgetFinder = find.byKey(const Key('empty_thread_view')); + expect(emptyEmailWidgetFinder, findsNothing); + + final listViewEmailWidgetFinder = find.byKey(const PageStorageKey('list_presentation_email_in_threads')); + final listViewEmailWidget = tester.widget(listViewEmailWidgetFinder); + expect(listViewEmailWidget.semanticChildCount, equals(listEmailsOfInbox.length + 2)); + + // Switch to mailbox Folder 1 + final listEmailsOfFolder1 = []; + mailboxDashboardController.setSelectedMailbox(MailboxFixtures.folder1.toPresentationMailbox()); + mailboxDashboardController.updateEmailList(listEmailsOfFolder1); + + threadController.consumeState( + Stream.value(Right(GetAllEmailSuccess( + emailList: listEmailsOfFolder1, + currentMailboxId: MailboxFixtures.folder1.id + ))) + ); + + await tester.pump(); + + final folder1EmptyEmailWidgetFinder = find.byKey(const Key('empty_thread_view')); + expect(folder1EmptyEmailWidgetFinder, findsOneWidget); + + final folder1ListViewEmailWidgetFinder = find.byKey(const PageStorageKey('list_presentation_email_in_threads')); + expect(folder1ListViewEmailWidgetFinder, findsNothing); + + debugDefaultTargetPlatformOverride = null; + tester.view.reset(); + }); + }); + + tearDown(Get.deleteAll); + }); +}