From 49fe89a94926a6acb536f8772f69070a6d02a5eb Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 12 Feb 2025 02:30:21 +0700 Subject: [PATCH] TF-3478 Use ComposerManager to open & close single composer Signed-off-by: dab246 --- lib/features/base/base_controller.dart | 2 +- .../presentation/composer_bindings.dart | 17 +- .../presentation/composer_controller.dart | 19 +- .../presentation/composer_overlay_view.dart | 26 ++ .../manager/composer_manager.dart | 19 +- .../bindings/mailbox_dashboard_bindings.dart | 4 + .../mailbox_dashboard_controller.dart | 123 +++--- .../mailbox_dashboard_view_web.dart | 8 +- lib/main.dart | 3 - lib/main/utils/twake_app_manager.dart | 18 +- .../composer_controller_test.dart | 356 ++++++++++++++---- .../mailbox_dashboard_controller_test.dart | 5 + .../mailbox_dashboard_view_widget_test.dart | 5 + 13 files changed, 435 insertions(+), 170 deletions(-) create mode 100644 lib/features/composer/presentation/composer_overlay_view.dart diff --git a/lib/features/base/base_controller.dart b/lib/features/base/base_controller.dart index 68a413f34..78e93c64b 100644 --- a/lib/features/base/base_controller.dart +++ b/lib/features/base/base_controller.dart @@ -221,7 +221,7 @@ abstract class BaseController extends GetxController void _handleBadCredentialsException() { log('$runtimeType::_handleBadCredentialsException:'); - if (!twakeAppManager.isComposerOpened) { + if (!twakeAppManager.hasComposer) { _performReconnection(); return; } diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index b50df01b4..e105defb2 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -36,6 +36,7 @@ import 'package:tmail_ui_user/features/email/domain/repository/email_repository. import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/transform_html_email_content_interactor.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.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'; @@ -47,6 +48,9 @@ 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_dashboard/data/datasource/session_storage_composer_datasource.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; @@ -73,8 +77,9 @@ import 'package:uuid/uuid.dart'; class ComposerBindings extends BaseBindings { final String? composerId; + final ComposerArguments? composerArguments; - ComposerBindings({this.composerId}); + ComposerBindings({this.composerId, this.composerArguments}); @override void bindingsDataSourceImpl() { @@ -184,6 +189,10 @@ class ComposerBindings extends BaseBindings { Get.find(), Get.find(), ), tag: composerId); + Get.lazyPut( + () => ComposerCacheRepositoryImpl(Get.find(tag: composerId)), + tag: composerId, + ); Get.lazyPut( () => ContactRepositoryImpl(Get.find(tag: composerId)), tag: composerId, @@ -214,6 +223,10 @@ class ComposerBindings extends BaseBindings { () => Get.find(tag: composerId), tag: composerId, ); + Get.lazyPut( + () => Get.find(tag: composerId), + tag: composerId, + ); Get.lazyPut( () => Get.find(tag: composerId), tag: composerId, @@ -308,6 +321,8 @@ class ComposerBindings extends BaseBindings { Get.find(tag: composerId), Get.find(tag: composerId), Get.find(tag: composerId), + composerId: composerId, + composerArgs: composerArguments, ), tag: composerId); } diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 1ddb3c5cd..862803b63 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -155,6 +155,8 @@ class ComposerController extends BaseController final CreateNewAndSendEmailInteractor _createNewAndSendEmailInteractor; final CreateNewAndSaveEmailToDraftsInteractor _createNewAndSaveEmailToDraftsInteractor; final PrintEmailInteractor printEmailInteractor; + final String? composerId; + final ComposerArguments? composerArgs; GetAllAutoCompleteInteractor? _getAllAutoCompleteInteractor; GetAutoCompleteInteractor? _getAutoCompleteInteractor; @@ -222,7 +224,7 @@ class ComposerController extends BaseController int? _savedEmailDraftHash; bool _restoringSignatureButton = false; GlobalKey? responsiveContainerKey; - + @visibleForTesting bool get restoringSignatureButton => _restoringSignatureButton; @@ -247,6 +249,10 @@ class ComposerController extends BaseController this._createNewAndSendEmailInteractor, this._createNewAndSaveEmailToDraftsInteractor, this.printEmailInteractor, + { + this.composerId, + this.composerArgs, + } ); @override @@ -254,11 +260,11 @@ class ComposerController extends BaseController super.onInit(); if (PlatformInfo.isWeb) { responsiveContainerKey = GlobalKey(); - richTextWebController = getBinding(); + richTextWebController = getBinding(tag: composerId); responsiveContainerKey = GlobalKey(); menuMoreOptionController = CustomPopupMenuController(); } else { - richTextMobileTabletController = getBinding(); + richTextMobileTabletController = getBinding(tag: composerId); } createFocusNodeInput(); scrollControllerEmailAddress.addListener(_scrollControllerEmailAddressListener); @@ -609,7 +615,7 @@ class ComposerController extends BaseController void _initEmail() { _isEmailBodyLoaded = false; final arguments = PlatformInfo.isWeb - ? mailboxDashBoardController.composerArguments + ? composerArgs : Get.arguments; if (arguments is ComposerArguments) { composerArguments.value = arguments; @@ -1599,7 +1605,10 @@ class ComposerController extends BaseController if (closeOverlays) { popBack(); } - mailboxDashBoardController.closeComposerOverlay(result: result); + mailboxDashBoardController.closeComposerOnWeb( + composerId: composerId, + result: result, + ); } else { popBack(result: result, closeOverlays: closeOverlays); } diff --git a/lib/features/composer/presentation/composer_overlay_view.dart b/lib/features/composer/presentation/composer_overlay_view.dart new file mode 100644 index 000000000..8de5fe7a6 --- /dev/null +++ b/lib/features/composer/presentation/composer_overlay_view.dart @@ -0,0 +1,26 @@ + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; +import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart'; + +class ComposerOverlayView extends StatefulWidget { + const ComposerOverlayView({super.key}); + + @override + State createState() => _ComposerOverlayViewState(); +} + +class _ComposerOverlayViewState extends State { + + final ComposerManager _composerManager = Get.find(); + + @override + Widget build(BuildContext context) { + return Obx(() { + if (!_composerManager.hasComposer) return const SizedBox.shrink(); + + return ComposerView(composerId: _composerManager.singleComposerId); + }); + } +} diff --git a/lib/features/composer/presentation/manager/composer_manager.dart b/lib/features/composer/presentation/manager/composer_manager.dart index ab7137884..bb169f368 100644 --- a/lib/features/composer/presentation/manager/composer_manager.dart +++ b/lib/features/composer/presentation/manager/composer_manager.dart @@ -2,27 +2,34 @@ import 'package:core/utils/app_logger.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; class ComposerManager extends GetxController { final RxMap composers = {}.obs; - String addComposer() { + void addComposer(ComposerArguments composerArguments) { final String id = DateTime.now().millisecondsSinceEpoch.toString(); log('ComposerManager::addComposer:ID = $id'); - ComposerBindings(composerId: id).dependencies(); - final ComposerController controller = Get.find(tag: id); - composers[id] = controller; - return id; + ComposerBindings( + composerId: id, + composerArguments: composerArguments, + ).dependencies(); + composers[id] = Get.find(tag: id); + log('ComposerManager::addComposer:Success'); } void removeComposer(String id) { + log('ComposerManager::removeComposer:ID = $id'); if (composers.containsKey(id)) { ComposerBindings(composerId: id).dispose(); composers.remove(id); + log('ComposerManager::removeComposer:Success'); } } + bool get hasComposer => composers.isNotEmpty; + List get composerIds => composers.keys.toList(); - ComposerController? getComposer(String id) => composers[id]; + String get singleComposerId => composerIds.first; } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart index c5d8039bc..466a3083b 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -12,6 +12,7 @@ import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dar import 'package:tmail_ui_user/features/composer/data/repository/contact_repository_impl.dart'; import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart'; import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart'; import 'package:tmail_ui_user/features/email/data/datasource/print_file_datasource.dart'; @@ -167,6 +168,8 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find())); + Get.lazyPut(() => ComposerManager()); + Get.put(MailboxDashBoardController( Get.find(), Get.find(), @@ -193,6 +196,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); Get.put(AdvancedFilterController()); } diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 48766eec4..6adb2db63 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -44,6 +44,7 @@ import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.d import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/list_identities_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/compose_action_mode.dart'; import 'package:tmail_ui_user/features/contact/presentation/model/contact_arguments.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; @@ -106,7 +107,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/set_error_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/composer_overlay_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart'; @@ -216,6 +216,7 @@ class MailboxDashBoardController extends ReloadableController final GetRestoredDeletedMessageInterator _getRestoredDeletedMessageInteractor; final RemoveComposerCacheOnWebInteractor _removeComposerCacheOnWebInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; + final ComposerManager _composerManager; GetAllVacationInteractor? _getAllVacationInteractor; UpdateVacationInteractor? _updateVacationInteractor; @@ -238,7 +239,6 @@ class MailboxDashBoardController extends ReloadableController final currentSelectMode = SelectMode.INACTIVE.obs; final filterMessageOption = FilterMessageOption.all.obs; final listEmailSelected = [].obs; - final composerOverlayState = ComposerOverlayState.inActive.obs; final viewStateMailboxActionProgress = Rx>(Right(UIState.idle)); final vacationResponse = Rxn(); final routerParameters = Rxn>(); @@ -258,7 +258,6 @@ class MailboxDashBoardController extends ReloadableController final emailsInCurrentMailbox = [].obs; final listResultSearch = RxList(); PresentationMailbox? outboxMailbox; - ComposerArguments? composerArguments; List? _identities; jmap.State? _currentEmailState; ScrollController? listSearchFilterScrollController; @@ -309,6 +308,7 @@ class MailboxDashBoardController extends ReloadableController this._getRestoredDeletedMessageInteractor, this._removeComposerCacheOnWebInteractor, this._getAllIdentitiesInteractor, + this._composerManager, ); @override @@ -497,8 +497,7 @@ class MailboxDashBoardController extends ReloadableController @override Future onBeforeUnloadBrowserListener(html.Event event) async { - if (event is html.BeforeUnloadEvent - && composerOverlayState.value == ComposerOverlayState.active) { + if (event is html.BeforeUnloadEvent && twakeAppManager.hasComposer) { event.preventDefault(); } } @@ -1685,18 +1684,16 @@ class MailboxDashBoardController extends ReloadableController emailUIAction.value = newAction; } - void openComposerOverlay(ComposerArguments? arguments) { - composerArguments = arguments; - ComposerBindings().dependencies(); - composerOverlayState.value = ComposerOverlayState.active; - twakeAppManager.openComposerOnWeb(); - } - - void closeComposerOverlay({dynamic result}) async { - composerArguments = null; - ComposerBindings().dispose(); - composerOverlayState.value = ComposerOverlayState.inActive; - twakeAppManager.closeComposerOnWeb(); + Future closeComposerOnWeb({ + required String? composerId, + dynamic result, + }) async { + if (composerId != null) { + _composerManager.removeComposer(composerId); + } + if (!_composerManager.hasComposer) { + twakeAppManager.setHasComposer(false); + } if (result is SendingEmailArguments) { handleSendEmailAction(result); } else if (result is SendEmailSuccess || @@ -1824,55 +1821,64 @@ class MailboxDashBoardController extends ReloadableController } } - void goToComposer(ComposerArguments arguments) async { + void goToComposer(ComposerArguments arguments) { final argumentsWithIdentity = arguments.withIdentity( identities: List.from(_identities ?? []), selectedIdentityId: arguments.selectedIdentityId); if (PlatformInfo.isWeb) { - if (composerOverlayState.value == ComposerOverlayState.inActive) { - openComposerOverlay(argumentsWithIdentity); + _openComposerOnWeb(argumentsWithIdentity); + } else { + _openComposerOnMobile(argumentsWithIdentity); + } + } + + void _openComposerOnWeb(ComposerArguments composerArguments) { + if (_composerManager.composers.isNotEmpty) return; + + _composerManager.addComposer(composerArguments); + twakeAppManager.setHasComposer(true); + } + + Future _openComposerOnMobile(ComposerArguments arguments) async { + BackButtonInterceptor.removeByName(AppRoutes.dashboard); + + bool isTabletPlatform = currentContext != null + && !responsiveUtils.isScreenWithShortestSide(currentContext!); + dynamic result; + + if (isTabletPlatform) { + if (PlatformInfo.isIOS) { + dispatchEmailUIAction(HideEmailContentViewAction()); + } + + result = await Get.to( + () => const ComposerView(), + binding: ComposerBindings(), + opaque: false, + arguments: arguments, + ); + + if (PlatformInfo.isIOS) { + await Future.delayed( + const Duration(milliseconds: 200), + () => dispatchEmailUIAction(ShowEmailContentViewAction()), + ); } } else { - BackButtonInterceptor.removeByName(AppRoutes.dashboard); + result = await push(AppRoutes.composer, arguments: arguments); + } - bool isTabletPlatform = currentContext != null - && !responsiveUtils.isScreenWithShortestSide(currentContext!); - dynamic result; + BackButtonInterceptor.add(_onBackButtonInterceptor, name: AppRoutes.dashboard); - if (isTabletPlatform) { - if (PlatformInfo.isIOS) { - dispatchEmailUIAction(HideEmailContentViewAction()); - } - - result = await Get.to( - () => const ComposerView(), - binding: ComposerBindings(), - opaque: false, - arguments: argumentsWithIdentity); - - if (PlatformInfo.isIOS) { - await Future.delayed( - const Duration(milliseconds: 200), - () => dispatchEmailUIAction(ShowEmailContentViewAction())); - } - } else { - result = await push( - AppRoutes.composer, - arguments: argumentsWithIdentity); - } - - BackButtonInterceptor.add(_onBackButtonInterceptor, name: AppRoutes.dashboard); - - if (result is SendingEmailArguments) { - handleSendEmailAction(result); - } else if (result is SendEmailSuccess || - result is SaveEmailAsDraftsSuccess || - result is UpdateEmailDraftsSuccess) { - consumeState(Stream.value(Right(result))); - } else if (validateSendingEmailFailedWhenNetworkIsLostOnMobile(result)) { - _storeSendingEmailInCaseOfSendingFailureInMobile(result); - } + if (result is SendingEmailArguments) { + handleSendEmailAction(result); + } else if (result is SendEmailSuccess || + result is SaveEmailAsDraftsSuccess || + result is UpdateEmailDraftsSuccess) { + consumeState(Stream.value(Right(result))); + } else if (validateSendingEmailFailedWhenNetworkIsLostOnMobile(result)) { + _storeSendingEmailInCaseOfSendingFailureInMobile(result); } } @@ -3271,7 +3277,6 @@ class MailboxDashBoardController extends ReloadableController applicationManager.releaseUserAgent(); BackButtonInterceptor.removeByName(AppRoutes.dashboard); _identities = null; - composerArguments = null; outboxMailbox = null; sessionCurrent = null; mapMailboxById = {}; @@ -3279,7 +3284,7 @@ class MailboxDashBoardController extends ReloadableController WebSocketController.instance.onClose(); _currentEmailState = null; _isFirstSessionLoad = false; - twakeAppManager.closeComposerOnWeb(); + twakeAppManager.setHasComposer(false); super.onClose(); } } \ No newline at end of file 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 eb170c310..0c5cc54aa 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -8,14 +8,13 @@ import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/extensions/session_extension.dart'; import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart'; import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; -import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_overlay_view.dart'; import 'package:tmail_ui_user/features/email/presentation/email_view.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/base_mailbox_dashboard_view.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/composer_overlay_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; @@ -198,10 +197,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { } }), ), - Obx(() => controller.composerOverlayState.value == ComposerOverlayState.active - ? const ComposerView() - : const SizedBox.shrink() - ), + const ComposerOverlayView(), Obx(() => controller.searchMailboxActivated.value == true && !controller.responsiveUtils.isWebDesktop(context) ? const SearchMailboxView() : const SizedBox.shrink() diff --git a/lib/main.dart b/lib/main.dart index 8c8172352..af3d00786 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,7 +16,6 @@ import 'package:tmail_ui_user/main/pages/app_pages.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/utils/app_utils.dart'; -import 'package:tmail_ui_user/main/utils/twake_app_manager.dart'; import 'package:url_strategy/url_strategy.dart'; import 'package:worker_manager/worker_manager.dart'; @@ -53,7 +52,6 @@ class TMailApp extends StatefulWidget { class _TMailAppState extends State { DeepLinksManager? _deepLinksManager; - final TwakeAppManager _twakeAppManager = Get.find(); @override void initState() { @@ -107,7 +105,6 @@ class _TMailAppState extends State { if (PlatformInfo.isMobile) { _deepLinksManager?.dispose(); } - _twakeAppManager.dispose(); super.dispose(); } } \ No newline at end of file diff --git a/lib/main/utils/twake_app_manager.dart b/lib/main/utils/twake_app_manager.dart index 8c8c2fd97..d10cfc74c 100644 --- a/lib/main/utils/twake_app_manager.dart +++ b/lib/main/utils/twake_app_manager.dart @@ -1,20 +1,8 @@ -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/composer_overlay_state.dart'; class TwakeAppManager { - ComposerOverlayState? _composerOverlayState; + bool _hasComposer = false; - void openComposerOnWeb() => - _composerOverlayState = ComposerOverlayState.active; + void setHasComposer(bool value) => _hasComposer = value; - void closeComposerOnWeb() { - _composerOverlayState = ComposerOverlayState.inActive; - _composerOverlayState = null; - } - - bool get isComposerOpened => - _composerOverlayState == ComposerOverlayState.active; - - void dispose() { - _composerOverlayState = null; - } + bool get hasComposer => _hasComposer; } diff --git a/test/features/composer/presentation/composer_controller_test.dart b/test/features/composer/presentation/composer_controller_test.dart index 81019a94b..fa139621f 100644 --- a/test/features/composer/presentation/composer_controller_test.dart +++ b/test/features/composer/presentation/composer_controller_test.dart @@ -407,19 +407,36 @@ void main() { // arrange PlatformInfo.isTestingForWeb = true; + final selectedIdentity = Identity(id: IdentityId(Id('alice'))); + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( + selectedIdentityId: selectedIdentity.id, + identities: [selectedIdentity], + ), + ); + composerController?.onChangeTextEditorWeb(emailContent); composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; - final selectedIdentity = Identity(id: IdentityId(Id('alice'))); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); - - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( - selectedIdentityId: selectedIdentity.id, - identities: [selectedIdentity])); + final savedEmailDraft = SavedEmailDraft( content: emailContent, @@ -452,15 +469,30 @@ void main() { () async { // arrange PlatformInfo.isTestingForWeb = true; - + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments(identities: [identity]), + ); + composerController?.onChangeTextEditorWeb(emailContent); composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments(identities: [identity])); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); final savedEmailDraft = SavedEmailDraft( @@ -494,7 +526,29 @@ void main() { () async { // arrange PlatformInfo.isTestingForWeb = true; - + + final selectedIdentity = Identity( + id: IdentityId(Id('alice')), + mayDelete: true, + ); + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments(selectedIdentityId: selectedIdentity.id), + ); + composerController?.onChangeTextEditorWeb(emailContent); composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; @@ -503,11 +557,6 @@ void main() { composerController?.listReplyToEmailAddress = [replyToRecipient]; when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); - final selectedIdentity = Identity( - id: IdentityId(Id('alice')), - mayDelete: true); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments(selectedIdentityId: selectedIdentity.id)); when(mockGetAllIdentitiesInteractor.execute(any, any)).thenAnswer( (_) => Stream.value( Right(GetAllIdentitiesSuccess([selectedIdentity], null)))); @@ -543,7 +592,24 @@ void main() { () async { // arrange PlatformInfo.isTestingForWeb = true; - + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments(), + ); + composerController?.onChangeTextEditorWeb(emailContent); composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; @@ -555,8 +621,6 @@ void main() { final identity = Identity( id: IdentityId(Id('alice')), mayDelete: true); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments()); when(mockGetAllIdentitiesInteractor.execute(any, any)).thenAnswer( (_) => Stream.value( Right(GetAllIdentitiesSuccess([identity], null)))); @@ -828,27 +892,43 @@ void main() { () async { // arrange PlatformInfo.isTestingForWeb = true; - - composerController?.onChangeTextEditorWeb(emailContent); final selectedIdentity = Identity(id: IdentityId(Id('alice'))); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( - emailActionType: EmailActionType.editDraft, - emailContents: emailContent, - presentationEmail: PresentationEmail( - id: EmailId(Id('some-email-id')), - subject: emailSubject, - to: {toRecipient}, - cc: {ccRecipient}, - bcc: {bccRecipient}, - replyTo: {replyToRecipient}, - mailboxContain: PresentationMailbox( - MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)), - selectedIdentityId: selectedIdentity.id, - identities: [selectedIdentity])); + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( + emailActionType: EmailActionType.editDraft, + emailContents: emailContent, + presentationEmail: PresentationEmail( + id: EmailId(Id('some-email-id')), + subject: emailSubject, + to: {toRecipient}, + cc: {ccRecipient}, + bcc: {bccRecipient}, + mailboxContain: PresentationMailbox( + MailboxId(Id('some-mailbox-id')), + role: PresentationMailbox.roleJunk, + ), + ), + selectedIdentityId: selectedIdentity.id, + identities: [selectedIdentity], + ), + ); + + composerController?.onChangeTextEditorWeb(emailContent); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); @@ -883,13 +963,24 @@ void main() { () async { // arrange PlatformInfo.isTestingForWeb = true; - - composerController?.onChangeTextEditorWeb(emailContent); - + final identity = Identity(id: IdentityId(Id('alice'))); - - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( emailActionType: EmailActionType.editDraft, emailContents: emailContent, presentationEmail: PresentationEmail( @@ -901,8 +992,14 @@ void main() { replyTo: {replyToRecipient}, mailboxContain: PresentationMailbox( MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)), - identities: [identity])); + role: PresentationMailbox.roleJunk, + ), + ), + identities: [identity], + ), + ); + + composerController?.onChangeTextEditorWeb(emailContent); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); @@ -937,15 +1034,27 @@ void main() { () async { // arrange PlatformInfo.isTestingForWeb = true; - - composerController?.onChangeTextEditorWeb(emailContent); final selectedIdentity = Identity( id: IdentityId(Id('alice')), - mayDelete: true); + mayDelete: true, + ); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( emailActionType: EmailActionType.editDraft, emailContents: emailContent, presentationEmail: PresentationEmail( @@ -957,8 +1066,15 @@ void main() { replyTo: {replyToRecipient}, mailboxContain: PresentationMailbox( MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)), - selectedIdentityId: selectedIdentity.id)); + role: PresentationMailbox.roleJunk, + ), + ), + selectedIdentityId: selectedIdentity.id, + ), + ); + + composerController?.onChangeTextEditorWeb(emailContent); + when(mockGetAllIdentitiesInteractor.execute(any, any)).thenAnswer( (_) => Stream.value( Right(GetAllIdentitiesSuccess([selectedIdentity], null)))); @@ -996,15 +1112,27 @@ void main() { () async { // arrange PlatformInfo.isTestingForWeb = true; - - composerController?.onChangeTextEditorWeb(emailContent); - + final identity = Identity( id: IdentityId(Id('alice')), - mayDelete: true); - - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( + mayDelete: true, + ); + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( emailActionType: EmailActionType.editDraft, emailContents: emailContent, presentationEmail: PresentationEmail( @@ -1016,7 +1144,14 @@ void main() { replyTo: {replyToRecipient}, mailboxContain: PresentationMailbox( MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)),)); + role: PresentationMailbox.roleJunk, + ), + ), + ), + ); + + composerController?.onChangeTextEditorWeb(emailContent); + when(mockGetAllIdentitiesInteractor.execute(any, any)).thenAnswer( (_) => Stream.value( Right(GetAllIdentitiesSuccess([identity], null)))); @@ -1347,16 +1482,34 @@ void main() { PlatformInfo.isTestingForWeb = true; final selectedIdentity = Identity(id: IdentityId(Id('alice'))); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( emailActionType: EmailActionType.reply, emailContents: emailContent, presentationEmail: PresentationEmail( mailboxContain: PresentationMailbox( MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)), + role: PresentationMailbox.roleJunk, + ), + ), selectedIdentityId: selectedIdentity.id, - identities: [selectedIdentity])); + identities: [selectedIdentity], + ), + ); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); @@ -1381,15 +1534,33 @@ void main() { PlatformInfo.isTestingForWeb = true; final identity = Identity(id: IdentityId(Id('alice'))); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( emailActionType: EmailActionType.reply, emailContents: emailContent, presentationEmail: PresentationEmail( mailboxContain: PresentationMailbox( MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)), - identities: [identity])); + role: PresentationMailbox.roleJunk, + ), + ), + identities: [identity], + ), + ); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); @@ -1416,15 +1587,34 @@ void main() { final selectedIdentity = Identity( id: IdentityId(Id('alice')), mayDelete: true); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( + + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( emailActionType: EmailActionType.reply, emailContents: emailContent, presentationEmail: PresentationEmail( mailboxContain: PresentationMailbox( MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)), - selectedIdentityId: selectedIdentity.id)); + role: PresentationMailbox.roleJunk, + ), + ), + selectedIdentityId: selectedIdentity.id, + ), + ); + when(mockGetAllIdentitiesInteractor.execute(any, any)).thenAnswer( (_) => Stream.value( Right(GetAllIdentitiesSuccess([selectedIdentity], null)))); @@ -1455,14 +1645,32 @@ void main() { id: IdentityId(Id('alice')), mayDelete: true); - when(mockMailboxDashBoardController.composerArguments).thenReturn( - ComposerArguments( + composerController = ComposerController( + mockLocalFilePickerInteractor, + mockLocalImagePickerInteractor, + mockGetEmailContentInteractor, + mockGetAllIdentitiesInteractor, + mockUploadController, + mockRemoveComposerCacheOnWebInteractor, + mockSaveComposerCacheOnWebInteractor, + mockDownloadImageAsBase64Interactor, + mockTransformHtmlEmailContentInteractor, + mockGetAlwaysReadReceiptSettingInteractor, + mockCreateNewAndSendEmailInteractor, + mockCreateNewAndSaveEmailToDraftsInteractor, + mockPrintEmailInteractor, + composerArgs: ComposerArguments( emailActionType: EmailActionType.reply, emailContents: emailContent, presentationEmail: PresentationEmail( mailboxContain: PresentationMailbox( MailboxId(Id('some-mailbox-id')), - role: PresentationMailbox.roleJunk)),)); + role: PresentationMailbox.roleJunk, + ), + ), + ), + ); + when(mockGetAllIdentitiesInteractor.execute(any, any)).thenAnswer( (_) => Stream.value( Right(GetAllIdentitiesSuccess([identity], null)))); diff --git a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart index ae1465991..a0ad07df7 100644 --- a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart +++ b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart @@ -20,6 +20,7 @@ import 'package:model/mailbox/presentation_mailbox.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/composer/presentation/manager/composer_manager.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'; @@ -178,6 +179,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), + MockSpec(), ]) void main() { // mock mailbox dashboard controller direct dependencies @@ -263,6 +265,7 @@ void main() { final refreshAllMailboxInteractor = MockRefreshAllMailboxInteractor(); final removeComposerCacheOnWebInteractor = MockRemoveComposerCacheOnWebInteractor(); final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); + final composerManager = MockComposerManager(); late MailboxController mailboxController; // mock thread controller direct dependencies @@ -314,6 +317,7 @@ void main() { Get.put(updateAccountCacheInteractor); Get.put(getAllIdentitiesInteractor); Get.put(removeComposerCacheOnWebInteractor); + Get.put(composerManager); searchController = SearchController( quickSearchEmailInteractor, @@ -349,6 +353,7 @@ void main() { getRestoredDeletedMessageInteractor, removeComposerCacheOnWebInteractor, getAllIdentitiesInteractor, + composerManager, ); }); 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 index 3a69bf292..68dae1fde 100644 --- 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 @@ -20,6 +20,7 @@ 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/composer/presentation/manager/composer_manager.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'; @@ -180,6 +181,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), + MockSpec(), ]) void main() { final moveToMailboxInteractor = MockMoveToMailboxInteractor(); @@ -250,6 +252,7 @@ void main() { final refreshAllMailboxInteractor = MockRefreshAllMailboxInteractor(); final removeComposerCacheOnWebInteractor = MockRemoveComposerCacheOnWebInteractor(); final getAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); + final composerManager = MockComposerManager(); final getEmailsInMailboxInteractor = MockGetEmailsInMailboxInteractor(); final refreshChangesEmailsInMailboxInteractor = MockRefreshChangesEmailsInMailboxInteractor(); @@ -312,6 +315,7 @@ void main() { Get.put(updateAccountCacheInteractor); Get.put(getAllIdentitiesInteractor); Get.put(removeComposerCacheOnWebInteractor); + Get.put(composerManager); when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([])); @@ -348,6 +352,7 @@ void main() { getRestoredDeletedMessageInteractor, removeComposerCacheOnWebInteractor, getAllIdentitiesInteractor, + composerManager, ); Get.put(mailboxDashboardController); mailboxDashboardController.onReady();