From 9e7298bc7684604cf678ebe075833a8727b0b1e0 Mon Sep 17 00:00:00 2001 From: DatDang Date: Thu, 7 Aug 2025 14:14:50 +0700 Subject: [PATCH] TF-3953 Close several modals when click outside --- lib/features/base/base_controller.dart | 5 +- .../base/base_mailbox_controller.dart | 32 +-- .../handle_mailbox_action_type_extension.dart | 52 ++-- .../base/mixin/date_range_picker_mixin.dart | 3 + lib/features/base/mixin/logout_mixin.dart | 6 +- .../mixin/mailbox_action_handler_mixin.dart | 103 ++++---- ...art => message_dialog_action_manager.dart} | 232 ++++++++++-------- .../base/widget/pop_back_barrier_widget.dart | 17 ++ .../presentation/composer_controller.dart | 19 +- .../presentation/composer_view_web.dart | 19 ++ .../controller/single_email_controller.dart | 4 +- .../email/presentation/email_view.dart | 6 +- .../email_action_reactor.dart | 97 ++++---- .../email_recovery_form_desktop_builder.dart | 15 +- .../presentation/identity_creator_view.dart | 26 +- ...identity_creator_form_desktop_builder.dart | 17 +- .../presentation/mailbox_controller.dart | 25 +- .../mailbox_dashboard_controller.dart | 87 +++---- .../email_rules/email_rules_controller.dart | 27 +- .../export_trace_log_extension.dart | 3 +- .../forward/forward_controller.dart | 5 +- ...complete_contact_text_field_with_tags.dart | 6 +- .../identities/identities_controller.dart | 42 ++-- .../delete_identity_dialog_builder.dart | 67 ----- .../identities/widgets/signature_builder.dart | 26 +- .../rules_filter_creator_view.dart | 138 ++++++----- .../sending_queue_controller.dart | 6 +- .../mixin/email_action_controller.dart | 27 +- .../controller/upload_controller.dart | 5 +- lib/main/deep_links/deep_links_manager.dart | 3 +- .../open_app_deep_link_handler_mixin.dart | 6 +- lib/main/routes/dialog_router.dart | 13 +- pubspec.lock | 4 +- .../composer_controller_test.dart | 12 + 34 files changed, 575 insertions(+), 580 deletions(-) rename lib/features/base/mixin/{message_dialog_action_mixin.dart => message_dialog_action_manager.dart} (55%) create mode 100644 lib/features/base/widget/pop_back_barrier_widget.dart delete mode 100644 lib/features/manage_account/presentation/identities/widgets/delete_identity_dialog_builder.dart diff --git a/lib/features/base/base_controller.dart b/lib/features/base/base_controller.dart index ea648780d..b80459a9f 100644 --- a/lib/features/base/base_controller.dart +++ b/lib/features/base/base_controller.dart @@ -17,7 +17,6 @@ import 'package:model/model.dart'; import 'package:rule_filter/rule_filter/capability_rule_filter.dart'; import 'package:tmail_ui_user/features/base/before_reconnect_manager.dart'; import 'package:tmail_ui_user/features/base/mixin/logout_mixin.dart'; -import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; import 'package:tmail_ui_user/features/email/presentation/bindings/mdn_interactor_bindings.dart'; @@ -64,9 +63,7 @@ import 'package:tmail_ui_user/main/utils/twake_app_manager.dart'; import 'package:uuid/uuid.dart'; abstract class BaseController extends GetxController - with MessageDialogActionMixin, - PopupContextMenuActionMixin, - LogoutMixin { + with PopupContextMenuActionMixin, LogoutMixin { final CachingManager cachingManager = Get.find(); final LanguageCacheManager languageCacheManager = Get.find(); diff --git a/lib/features/base/base_mailbox_controller.dart b/lib/features/base/base_mailbox_controller.dart index 8c99219c1..6146d1e9b 100644 --- a/lib/features/base/base_mailbox_controller.dart +++ b/lib/features/base/base_mailbox_controller.dart @@ -1,8 +1,6 @@ -import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:core/presentation/views/modal_sheets/edit_text_modal_sheet_builder.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; @@ -17,11 +15,11 @@ import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/mailbox/expand_mode.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/select_mode.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/action/update_mailbox_properties_action/update_mailbox_name_action.dart'; import 'package:tmail_ui_user/features/base/action/update_mailbox_properties_action/update_mailbox_total_emails_count_action.dart'; import 'package:tmail_ui_user/features/base/action/update_mailbox_properties_action/update_mailbox_unread_count_action.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_action_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_state.dart'; @@ -378,9 +376,10 @@ abstract class BaseMailboxController extends BaseController { ))) ).show(context); } else { - showInputDialogAction( + MessageDialogActionManager().showInputDialogAction( key: const Key('rename_mailbox_dialog'), context: context, + outsideDismissible: true, title: AppLocalizations.of(context).renameFolder, value: presentationMailbox.name?.name ?? '', negativeText: AppLocalizations.of(context).cancel, @@ -449,21 +448,16 @@ abstract class BaseMailboxController extends BaseController { ..onConfirmAction(AppLocalizations.of(context).delete, () => onDeleteMailboxAction(presentationMailbox)) ).show(); } else { - Get.dialog( - PointerInterceptor( - child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_delete_mailbox'), - imagePath: imagePaths, - title: AppLocalizations.of(context).deleteFolders, - textContent: AppLocalizations.of(context).message_confirmation_dialog_delete_folder(presentationMailbox.getDisplayName(context)), - confirmText: AppLocalizations.of(context).delete, - cancelText: AppLocalizations.of(context).cancel, - onConfirmButtonAction: () => onDeleteMailboxAction(presentationMailbox), - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - ), - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + context, + AppLocalizations.of(context).message_confirmation_dialog_delete_folder(presentationMailbox.getDisplayName(context)), + AppLocalizations.of(context).delete, + key: const Key('confirm_dialog_delete_mailbox'), + title: AppLocalizations.of(context).deleteFolders, + cancelTitle: AppLocalizations.of(context).cancel, + onConfirmAction: () => onDeleteMailboxAction(presentationMailbox), + onCancelAction: popBack, + onCloseButtonAction: popBack, ); } } diff --git a/lib/features/base/extensions/handle_mailbox_action_type_extension.dart b/lib/features/base/extensions/handle_mailbox_action_type_extension.dart index fdf8ab440..22552d588 100644 --- a/lib/features/base/extensions/handle_mailbox_action_type_extension.dart +++ b/lib/features/base/extensions/handle_mailbox_action_type_extension.dart @@ -1,12 +1,9 @@ -import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.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/model/mailbox_subaddressing_action.dart'; @@ -67,34 +64,29 @@ extension HandleMailboxActionTypeExtension on BaseMailboxController { )) ).show(); } else { - Get.dialog( - PointerInterceptor( - child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_subAddressing'), - imagePath: imagePaths, - title: AppLocalizations.of(context).allowSubaddressing, - textContent: AppLocalizations.of(context) - .message_confirmation_dialog_allow_subaddressing(mailboxName), - confirmText: AppLocalizations.of(context).allow, - cancelText: AppLocalizations.of(context).cancel, - additionalWidgetContent: CopySubaddressWidget( - imagePath: imagePaths, - subaddress: subAddress, - onCopyButtonAction: () => copySubAddressAction( - context, - subAddress, - ), - ), - onConfirmButtonAction: () => onAllowSubAddressingAction( - mailboxId, - currentRights, - MailboxActions.allowSubaddressing, - ), - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, + MessageDialogActionManager().showConfirmDialogAction( + context, + AppLocalizations.of(context) + .message_confirmation_dialog_allow_subaddressing(mailboxName), + AppLocalizations.of(context).allow, + key: const Key('confirm_dialog_subAddressing'), + title: AppLocalizations.of(context).allowSubaddressing, + cancelTitle: AppLocalizations.of(context).cancel, + additionalWidgetContent: CopySubaddressWidget( + imagePath: imagePaths, + subaddress: subAddress, + onCopyButtonAction: () => copySubAddressAction( + context, + subAddress, ), ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + onConfirmAction: () => onAllowSubAddressingAction( + mailboxId, + currentRights, + MailboxActions.allowSubaddressing, + ), + onCancelAction: popBack, + onCloseButtonAction: popBack, ); } } diff --git a/lib/features/base/mixin/date_range_picker_mixin.dart b/lib/features/base/mixin/date_range_picker_mixin.dart index 70ad1744f..e12692b84 100644 --- a/lib/features/base/mixin/date_range_picker_mixin.dart +++ b/lib/features/base/mixin/date_range_picker_mixin.dart @@ -26,6 +26,9 @@ mixin DateRangePickerMixin { initStartDate: initStartDate, initEndDate: initEndDate, autoClose: false, + barrierDismissible: true, + barrierLabel: 'Multiple view date range picker', + usePointerInterceptor: false, selectDateRangeActionCallback: (startDate, endDate) { _handleSelectDateRangeResult( context, diff --git a/lib/features/base/mixin/logout_mixin.dart b/lib/features/base/mixin/logout_mixin.dart index 7eb3be050..a0468db95 100644 --- a/lib/features/base/mixin/logout_mixin.dart +++ b/lib/features/base/mixin/logout_mixin.dart @@ -1,9 +1,9 @@ import 'package:core/presentation/utils/theme_utils.dart'; import 'package:flutter/material.dart'; -import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -mixin LogoutMixin implements MessageDialogActionMixin { +mixin LogoutMixin { void showLogoutConfirmDialog({ required BuildContext context, required String userAddress, @@ -11,7 +11,7 @@ mixin LogoutMixin implements MessageDialogActionMixin { }) { final appLocalizations = AppLocalizations.of(context); - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, '', appLocalizations.yesLogout, diff --git a/lib/features/base/mixin/mailbox_action_handler_mixin.dart b/lib/features/base/mixin/mailbox_action_handler_mixin.dart index babaed8f0..141d5135f 100644 --- a/lib/features/base/mixin/mailbox_action_handler_mixin.dart +++ b/lib/features/base/mixin/mailbox_action_handler_mixin.dart @@ -1,15 +1,12 @@ -import 'package:core/presentation/extensions/color_extension.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/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.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'; @@ -53,7 +50,6 @@ mixin MailboxActionHandlerMixin { MailboxDashBoardController dashboardController ) { final responsiveUtils = Get.find(); - final imagePaths = Get.find(); final appToast = Get.find(); if (responsiveUtils.isScreenWithShortestSide(context)) { @@ -76,34 +72,29 @@ mixin MailboxActionHandlerMixin { })) .show(); } else { - Get.dialog( - PointerInterceptor( - child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_empty_trash'), - imagePath: imagePaths, - title: AppLocalizations.of(context).emptyTrash, - textContent: AppLocalizations.of(context).empty_trash_dialog_message, - cancelText: AppLocalizations.of(context).cancel, - confirmText: AppLocalizations.of(context).delete, - onCloseButtonAction: popBack, - onConfirmButtonAction: () { - popBack(); - if (mailbox.countTotalEmails > 0) { - dashboardController.emptyTrashFolderAction( - trashFolderId: mailbox.id, - totalEmails: mailbox.countTotalEmails - ); - } else { - appToast.showToastWarningMessage( - context, - AppLocalizations.of(context).noEmailInYourCurrentFolder - ); - } - }, - onCancelButtonAction: popBack, - ), - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + key: const Key('confirm_dialog_empty_trash'), + context, + title: AppLocalizations.of(context).emptyTrash, + AppLocalizations.of(context).empty_trash_dialog_message, + cancelTitle: AppLocalizations.of(context).cancel, + AppLocalizations.of(context).delete, + onCloseButtonAction: popBack, + onConfirmAction: () { + popBack(); + if (mailbox.countTotalEmails > 0) { + dashboardController.emptyTrashFolderAction( + trashFolderId: mailbox.id, + totalEmails: mailbox.countTotalEmails + ); + } else { + appToast.showToastWarningMessage( + context, + AppLocalizations.of(context).noEmailInYourCurrentFolder + ); + } + }, + onCancelAction: popBack, ); } } @@ -118,7 +109,6 @@ mixin MailboxActionHandlerMixin { } final responsiveUtils = Get.find(); - final imagePaths = Get.find(); final appToast = Get.find(); if (responsiveUtils.isScreenWithShortestSide(context)) { @@ -138,31 +128,26 @@ mixin MailboxActionHandlerMixin { })) .show(); } else { - Get.dialog( - PointerInterceptor( - child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_empty_spam'), - imagePath: imagePaths, - title: AppLocalizations.of(context).emptySpamFolder, - textContent: AppLocalizations.of(context).emptySpamMessageDialog, - cancelText: AppLocalizations.of(context).cancel, - confirmText: AppLocalizations.of(context).delete_all, - onCloseButtonAction: popBack, - onConfirmButtonAction: () { - popBack(); - if (mailbox.countTotalEmails > 0) { - dashboardController.emptySpamFolderAction(spamFolderId: mailbox.id, totalEmails: mailbox.countTotalEmails); - } else { - appToast.showToastWarningMessage( - context, - AppLocalizations.of(context).noEmailInYourCurrentFolder - ); - } - }, - onCancelButtonAction: popBack, - ), - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + key: const Key('confirm_dialog_empty_spam'), + context, + title: AppLocalizations.of(context).emptySpamFolder, + AppLocalizations.of(context).emptySpamMessageDialog, + cancelTitle: AppLocalizations.of(context).cancel, + AppLocalizations.of(context).delete_all, + onCloseButtonAction: popBack, + onConfirmAction: () { + popBack(); + if (mailbox.countTotalEmails > 0) { + dashboardController.emptySpamFolderAction(spamFolderId: mailbox.id, totalEmails: mailbox.countTotalEmails); + } else { + appToast.showToastWarningMessage( + context, + AppLocalizations.of(context).noEmailInYourCurrentFolder + ); + } + }, + onCancelAction: popBack ); } } diff --git a/lib/features/base/mixin/message_dialog_action_mixin.dart b/lib/features/base/mixin/message_dialog_action_manager.dart similarity index 55% rename from lib/features/base/mixin/message_dialog_action_mixin.dart rename to lib/features/base/mixin/message_dialog_action_manager.dart index 882a14a16..cb850359e 100644 --- a/lib/features/base/mixin/message_dialog_action_mixin.dart +++ b/lib/features/base/mixin/message_dialog_action_manager.dart @@ -8,13 +8,21 @@ import 'package:core/presentation/views/dialog/edit_text_dialog_builder.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; -mixin MessageDialogActionMixin { +class MessageDialogActionManager { + static final _instance = MessageDialogActionManager._(); - Future showConfirmDialogAction( + factory MessageDialogActionManager() => _instance; + + MessageDialogActionManager._(); + + final _isConfirmDialogOpened = RxBool(false); + final _isInputDialogOpened = RxBool(false); + bool get isDialogOpened => _isConfirmDialogOpened.value || _isInputDialogOpened.value; + + Future showConfirmDialogAction( BuildContext context, String message, String actionName, @@ -33,6 +41,7 @@ mixin MessageDialogActionMixin { bool usePopScope = false, List? listTextSpan, Widget? icon, + Widget? additionalWidgetContent, Color? actionButtonColor, Color? cancelButtonColor, Color? cancelLabelButtonColor, @@ -45,31 +54,82 @@ mixin MessageDialogActionMixin { EdgeInsets? outsideDialogPadding, } ) async { + if (PlatformInfo.isWeb) { + _isConfirmDialogOpened.value = true; + } + final responsiveUtils = Get.find(); final imagePaths = Get.find(); if (alignCenter) { - final childWidget = PointerInterceptor( - child: ConfirmationDialogBuilder( + final childWidget = ConfirmationDialogBuilder( + key: key, + imagePath: imagePaths, + listTextSpan: listTextSpan, + isArrangeActionButtonsVertical: isArrangeActionButtonsVertical, + useIconAsBasicLogo: useIconAsBasicLogo, + isScrollContentEnabled: isScrollContentEnabled, + title: title ?? '', + textContent: message, + confirmText: actionName, + cancelText: hasCancelButton ? cancelTitle ?? AppLocalizations.of(context).cancel : '', + iconWidget: icon, + outsideDialogPadding: outsideDialogPadding ?? + (responsiveUtils.isScreenWithShortestSide(context) + ? const EdgeInsets.all(16) + : null), + additionalWidgetContent: additionalWidgetContent, + cancelBackgroundButtonColor: cancelButtonColor, + confirmBackgroundButtonColor: actionButtonColor, + cancelLabelButtonColor: cancelLabelButtonColor, + confirmLabelButtonColor: confirmLabelButtonColor, + onConfirmButtonAction: () { + if (autoPerformPopBack) { + popBack(); + } + onConfirmAction?.call(); + }, + onCancelButtonAction: () { + if (autoPerformPopBack) { + popBack(); + } + onCancelAction?.call(); + }, + onCloseButtonAction: onCloseButtonAction, + ); + await Get.dialog( + usePopScope && PlatformInfo.isMobile + ? PopScope(onPopInvokedWithResult: onPopInvoked, canPop: false, child: childWidget) + : childWidget, + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + barrierDismissible: outsideDismissible + ); + } else { + if (responsiveUtils.isMobile(context)) { + final childWidget = ConfirmationDialogBuilder( key: key, imagePath: imagePaths, + showAsBottomSheet: true, listTextSpan: listTextSpan, + maxWidth: responsiveUtils.getSizeScreenShortestSide(context) - 16, isArrangeActionButtonsVertical: isArrangeActionButtonsVertical, - useIconAsBasicLogo: useIconAsBasicLogo, - isScrollContentEnabled: isScrollContentEnabled, - title: title ?? '', textContent: message, - confirmText: actionName, - cancelText: hasCancelButton ? cancelTitle ?? AppLocalizations.of(context).cancel : '', + title: title ?? '', iconWidget: icon, outsideDialogPadding: outsideDialogPadding ?? (responsiveUtils.isScreenWithShortestSide(context) ? const EdgeInsets.all(16) : null), - cancelBackgroundButtonColor: cancelButtonColor, + additionalWidgetContent: additionalWidgetContent, + margin: dialogMargin, confirmBackgroundButtonColor: actionButtonColor, + cancelBackgroundButtonColor: cancelButtonColor, cancelLabelButtonColor: cancelLabelButtonColor, confirmLabelButtonColor: confirmLabelButtonColor, + confirmText: actionName, + cancelText: hasCancelButton ? cancelTitle ?? AppLocalizations.of(context).cancel : '', + useIconAsBasicLogo: useIconAsBasicLogo, + isScrollContentEnabled: isScrollContentEnabled, onConfirmButtonAction: () { if (autoPerformPopBack) { popBack(); @@ -82,55 +142,10 @@ mixin MessageDialogActionMixin { } onCancelAction?.call(); }, - onCloseButtonAction: onCloseButtonAction, - ), - ); - return await Get.dialog( - usePopScope && PlatformInfo.isMobile - ? PopScope(onPopInvokedWithResult: onPopInvoked, canPop: false, child: childWidget) - : childWidget, - barrierColor: AppColor.colorDefaultCupertinoActionSheet, - barrierDismissible: outsideDismissible - ); - } else { - if (responsiveUtils.isMobile(context)) { - final childWidget = PointerInterceptor( - child: ConfirmationDialogBuilder( - key: key, - imagePath: imagePaths, - showAsBottomSheet: true, - listTextSpan: listTextSpan, - maxWidth: responsiveUtils.getSizeScreenShortestSide(context) - 16, - isArrangeActionButtonsVertical: isArrangeActionButtonsVertical, - textContent: message, - title: title ?? '', - iconWidget: icon, - margin: dialogMargin, - confirmBackgroundButtonColor: actionButtonColor, - cancelBackgroundButtonColor: cancelButtonColor, - cancelLabelButtonColor: cancelLabelButtonColor, - confirmLabelButtonColor: confirmLabelButtonColor, - confirmText: actionName, - cancelText: hasCancelButton ? cancelTitle ?? AppLocalizations.of(context).cancel : '', - useIconAsBasicLogo: useIconAsBasicLogo, - isScrollContentEnabled: isScrollContentEnabled, - onConfirmButtonAction: () { - if (autoPerformPopBack) { - popBack(); - } - onConfirmAction?.call(); - }, - onCancelButtonAction: () { - if (autoPerformPopBack) { - popBack(); - } - onCancelAction?.call(); - }, - onCloseButtonAction: onCloseButtonAction ?? popBack - ), + onCloseButtonAction: onCloseButtonAction ?? popBack, ); if (showAsBottomSheet) { - return await Get.bottomSheet( + await Get.bottomSheet( usePopScope && PlatformInfo.isMobile ? PopScope(onPopInvokedWithResult: onPopInvoked, canPop: false, child: childWidget) : childWidget, @@ -143,7 +158,7 @@ mixin MessageDialogActionMixin { shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(18))), ); } else { - return (ConfirmationDialogActionSheetBuilder(context, listTextSpan: listTextSpan) + await (ConfirmationDialogActionSheetBuilder(context, listTextSpan: listTextSpan) ..messageText(message) ..onCancelAction( cancelTitle ?? AppLocalizations.of(context).cancel, @@ -162,39 +177,39 @@ mixin MessageDialogActionMixin { })).show(); } } else { - final childWidget = PointerInterceptor( - child: ConfirmationDialogBuilder( - key: key, - imagePath: imagePaths, - listTextSpan: listTextSpan, - isArrangeActionButtonsVertical: isArrangeActionButtonsVertical, - useIconAsBasicLogo: useIconAsBasicLogo, - isScrollContentEnabled: isScrollContentEnabled, - title: title ?? '', - textContent: message, - iconWidget: icon, - confirmBackgroundButtonColor: actionButtonColor, - cancelBackgroundButtonColor: cancelButtonColor, - cancelLabelButtonColor: cancelLabelButtonColor, - confirmLabelButtonColor: confirmLabelButtonColor, - confirmText: actionName, - cancelText: hasCancelButton ? cancelTitle ?? AppLocalizations.of(context).cancel : '', - onConfirmButtonAction: () { - if (autoPerformPopBack) { - popBack(); - } - onConfirmAction?.call(); - }, - onCancelButtonAction: () { - if (autoPerformPopBack) { - popBack(); - } - onCancelAction?.call(); - }, - onCloseButtonAction: onCloseButtonAction ?? popBack, - ), + final childWidget = ConfirmationDialogBuilder( + key: key, + imagePath: imagePaths, + listTextSpan: listTextSpan, + isArrangeActionButtonsVertical: isArrangeActionButtonsVertical, + useIconAsBasicLogo: useIconAsBasicLogo, + isScrollContentEnabled: isScrollContentEnabled, + title: title ?? '', + textContent: message, + iconWidget: icon, + additionalWidgetContent: additionalWidgetContent, + confirmBackgroundButtonColor: actionButtonColor, + cancelBackgroundButtonColor: cancelButtonColor, + cancelLabelButtonColor: cancelLabelButtonColor, + confirmLabelButtonColor: confirmLabelButtonColor, + confirmText: actionName, + cancelText: hasCancelButton ? cancelTitle ?? AppLocalizations.of(context).cancel : '', + onConfirmButtonAction: () { + if (autoPerformPopBack) { + popBack(); + } + onConfirmAction?.call(); + }, + onCancelButtonAction: () { + if (autoPerformPopBack) { + popBack(); + } + onCancelAction?.call(); + }, + onCloseButtonAction: onCloseButtonAction ?? popBack, + outsideDialogPadding: outsideDialogPadding, ); - return await Get.dialog( + await Get.dialog( usePopScope && PlatformInfo.isMobile ? PopScope(onPopInvokedWithResult: onPopInvoked, canPop: false, child: childWidget) : childWidget, @@ -203,9 +218,10 @@ mixin MessageDialogActionMixin { ); } } + _isConfirmDialogOpened.value = false; } - Future showInputDialogAction({ + Future showInputDialogAction({ required BuildContext context, required String title, required String value, @@ -216,23 +232,27 @@ mixin MessageDialogActionMixin { String? closeIcon, OnInputDialogNegativeButtonAction? onNegativeButtonAction, OnInputDialogInputErrorChangedAction? onInputErrorChanged, + bool outsideDismissible = false, }) async { - return await Get.dialog( - PointerInterceptor( - child: EditTextDialogBuilder( - key: key, - title: AppLocalizations.of(context).renameFolder, - value: value, - positiveText: positiveText, - negativeText: negativeText, - closeIcon: closeIcon, - onInputErrorChanged: onInputErrorChanged, - onPositiveButtonAction: onPositiveButtonAction, - onNegativeButtonAction: onNegativeButtonAction, - onCloseButtonAction: closeIcon != null ? popBack : null, - ), + _isInputDialogOpened.value = true; + + await Get.dialog( + EditTextDialogBuilder( + key: key, + title: AppLocalizations.of(context).renameFolder, + value: value, + positiveText: positiveText, + negativeText: negativeText, + closeIcon: closeIcon, + onInputErrorChanged: onInputErrorChanged, + onPositiveButtonAction: onPositiveButtonAction, + onNegativeButtonAction: onNegativeButtonAction, + onCloseButtonAction: closeIcon != null ? popBack : null, ), barrierColor: AppColor.colorDefaultCupertinoActionSheet, + barrierDismissible: outsideDismissible, ); + _isInputDialogOpened.value = false; + } } \ No newline at end of file diff --git a/lib/features/base/widget/pop_back_barrier_widget.dart b/lib/features/base/widget/pop_back_barrier_widget.dart new file mode 100644 index 000000000..266999471 --- /dev/null +++ b/lib/features/base/widget/pop_back_barrier_widget.dart @@ -0,0 +1,17 @@ +import 'package:flutter/widgets.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; + +class PopBackBarrierWidget extends StatelessWidget { + const PopBackBarrierWidget({super.key, required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: popBack, + child: child, + ); + } +} \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 4aa5999ec..9171ef812 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -31,6 +31,7 @@ import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/before_reconnect_handler.dart'; import 'package:tmail_ui_user/features/base/before_reconnect_manager.dart'; import 'package:tmail_ui_user/features/base/mixin/auto_complete_result_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/state/base_ui_state.dart'; import 'package:tmail_ui_user/features/base/state/button_state.dart'; import 'package:tmail_ui_user/features/composer/domain/exceptions/compose_email_exception.dart'; @@ -781,7 +782,7 @@ class ComposerController extends BaseController } if (!isEnableEmailSendButton.value) { - showConfirmDialogAction(context, + MessageDialogActionManager().showConfirmDialogAction(context, AppLocalizations.of(context).message_dialog_send_email_without_recipient, AppLocalizations.of(context).add_recipients, title: AppLocalizations.of(context).sending_failed, @@ -797,7 +798,7 @@ class ComposerController extends BaseController .where((emailAddress) => !EmailUtils.isEmailAddressValid(emailAddress.emailAddress)) .toList(); if (listEmailAddressInvalid.isNotEmpty) { - showConfirmDialogAction(context, + MessageDialogActionManager().showConfirmDialogAction(context, AppLocalizations.of(context).message_dialog_send_email_with_email_address_invalid, AppLocalizations.of(context).fix_email_addresses, onConfirmAction: () { @@ -815,7 +816,7 @@ class ComposerController extends BaseController } if (subjectEmail.value == null || subjectEmail.isEmpty == true) { - showConfirmDialogAction(context, + MessageDialogActionManager().showConfirmDialogAction(context, AppLocalizations.of(context).message_dialog_send_email_without_a_subject, AppLocalizations.of(context).cancel, cancelTitle: AppLocalizations.of(context).send_anyway, @@ -830,7 +831,7 @@ class ComposerController extends BaseController } if (!uploadController.allUploadAttachmentsCompleted) { - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, AppLocalizations.of(context).messageDialogSendEmailUploadingAttachment, AppLocalizations.of(context).got_it, @@ -843,7 +844,7 @@ class ComposerController extends BaseController } if (uploadController.isExceededMaxSizeAttachmentsPerEmail()) { - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, AppLocalizations.of(context).message_dialog_send_email_exceeds_maximum_size( filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)), @@ -985,7 +986,7 @@ class ComposerController extends BaseController appLocalizations: AppLocalizations.of(context), exception: failure.exception, ); - await showConfirmDialogAction( + await MessageDialogActionManager().showConfirmDialogAction( context, title: '', errorMessage, @@ -1956,14 +1957,13 @@ class ComposerController extends BaseController } Future _showConfirmDialogSaveMessage(BuildContext context) async { - await showConfirmDialogAction( + await MessageDialogActionManager().showConfirmDialogAction( context, title: AppLocalizations.of(context).saveMessage.capitalizeFirstEach, AppLocalizations.of(context).warningMessageWhenClickCloseComposer, AppLocalizations.of(context).save, cancelTitle: AppLocalizations.of(context).discardChanges, alignCenter: true, - outsideDismissible: false, autoPerformPopBack: false, isArrangeActionButtonsVertical: true, isScrollContentEnabled: responsiveUtils.isLandscapeMobile(context), @@ -1987,6 +1987,7 @@ class ComposerController extends BaseController } }, ); + _closeComposerButtonState = ButtonState.enabled; } void handleOnDragEnterHtmlEditorWeb(List? types) { @@ -2212,7 +2213,7 @@ class ComposerController extends BaseController exception: failure.exception, isDraft: true, ); - await showConfirmDialogAction( + await MessageDialogActionManager().showConfirmDialogAction( context, title: '', errorMessage, diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 3bd42ddad..1137e74c3 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:model/email/prefix_email_address.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/composer_print_draft_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_edit_recipient_extension.dart'; @@ -27,6 +28,7 @@ import 'package:tmail_ui_user/features/composer/presentation/widgets/web/from_co import 'package:tmail_ui_user/features/composer/presentation/widgets/web/local_file_drop_zone_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/web/toolbar_rich_text_widget.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/verify_display_overlay_view_on_iframe_extension.dart'; class ComposerView extends GetWidget { @@ -39,6 +41,20 @@ class ComposerView extends GetWidget { @override Widget build(BuildContext context) { + final iframeOverlay = Obx(() { + if (controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame || + MessageDialogActionManager().isDialogOpened) { + return Positioned.fill( + key: const ValueKey('tap-to-close'), + child: PointerInterceptor( + child: const SizedBox.expand(), + ), + ); + } else { + return const SizedBox.shrink(); + } + }); + return ResponsiveWidget( responsiveUtils: controller.responsiveUtils, mobile: MobileResponsiveContainerView( @@ -329,6 +345,7 @@ class ComposerView extends GetWidget { return const SizedBox.shrink(); } }), + iframeOverlay, ], ); } @@ -647,6 +664,7 @@ class ComposerView extends GetWidget { return const SizedBox.shrink(); } }), + iframeOverlay, ], ); } @@ -967,6 +985,7 @@ class ComposerView extends GetWidget { return const SizedBox.shrink(); } }), + iframeOverlay, ], ); }, diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 8dbcfd481..5a05875ac 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -10,7 +10,6 @@ import 'package:core/utils/html/html_utils.dart'; import 'package:core/presentation/utils/html_transformer/dom/sanitize_hyper_link_tag_in_html_transformers.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_file_dialog/flutter_file_dialog.dart'; @@ -40,6 +39,7 @@ import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:share_plus/share_plus.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/state/button_state.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart'; import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart'; @@ -772,7 +772,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void _handleReadReceipt() { if (currentContext != null) { - showConfirmDialogAction(currentContext!, + MessageDialogActionManager().showConfirmDialogAction(currentContext!, AppLocalizations.of(currentContext!).subTitleReadReceiptRequestNotificationMessage, AppLocalizations.of(currentContext!).yes, onConfirmAction: () => _handleSendReceiptToSenderAction(currentContext!), diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 2060a86df..d462a06ec 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -13,11 +13,13 @@ import 'package:model/extensions/list_email_address_extension.dart'; import 'package:model/extensions/presentation_email_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/widget/optional_expanded.dart'; import 'package:tmail_ui_user/features/base/widget/optional_scroll.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_event_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/styles/email_view_styles.dart'; +import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_action_banner_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_information_widget.dart'; @@ -529,7 +531,9 @@ class EmailView extends GetWidget { ), ), Obx(() { - if (controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame) { + if (controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame || + MessageDialogActionManager().isDialogOpened || + EmailActionReactor.isDialogOpened) { return Positioned.fill( child: PointerInterceptor( child: const SizedBox.expand(), diff --git a/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart b/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart index e6b5e39d3..d2d18d70f 100644 --- a/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart +++ b/lib/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart @@ -11,7 +11,6 @@ import 'package:core/presentation/utils/html_transformer/transform_configuration import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/utils/theme_utils.dart'; import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; import 'package:dartz/dartz.dart'; @@ -36,8 +35,7 @@ import 'package:model/extensions/presentation_email_extension.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/extensions/session_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; -import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart'; import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; @@ -88,8 +86,8 @@ typedef OpenPopUpContextMenuAction = Future Function( List popupMenuItems, ); -class EmailActionReactor with MessageDialogActionMixin { - const EmailActionReactor( +class EmailActionReactor { + EmailActionReactor( this._markAsEmailReadInteractor, this._markAsStarEmailInteractor, this._createNewEmailRuleFilterInteractor, @@ -105,6 +103,9 @@ class EmailActionReactor with MessageDialogActionMixin { final GetEmailContentInteractor _getEmailContentInteractor; final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor; + static final _isEmailAddressDialogOpened = false.obs; + static bool get isDialogOpened => _isEmailAddressDialogOpened.value; + Stream> markAsEmailRead( Session session, AccountId accountId, @@ -210,19 +211,16 @@ class EmailActionReactor with MessageDialogActionMixin { ) ).show(); } else { - await Get.dialog( - PointerInterceptor(child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_delete_email_permanently'), - imagePath: imagePaths, - title: DeleteActionType.single.getTitleDialog(currentContext!), - textContent: DeleteActionType.single.getContentDialog(currentContext!), - cancelText: DeleteActionType.single.getConfirmActionName(currentContext!), - confirmText: AppLocalizations.of(currentContext!).cancel, - onCancelButtonAction: () => onDeleteEmailRequest.call(presentationEmail), - onConfirmButtonAction: popBack, - onCloseButtonAction: popBack, - )), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + await MessageDialogActionManager().showConfirmDialogAction( + key: const Key('confirm_dialog_delete_email_permanently'), + currentContext!, + title: DeleteActionType.single.getTitleDialog(currentContext!), + DeleteActionType.single.getContentDialog(currentContext!), + cancelTitle: DeleteActionType.single.getConfirmActionName(currentContext!), + AppLocalizations.of(currentContext!).cancel, + onCancelAction: () => onDeleteEmailRequest.call(presentationEmail), + onConfirmAction: popBack, + onCloseButtonAction: popBack, ); } } @@ -331,7 +329,7 @@ class EmailActionReactor with MessageDialogActionMixin { }) async { if (currentContext == null || !currentContext!.mounted) return; - await showConfirmDialogAction( + await MessageDialogActionManager().showConfirmDialogAction( currentContext!, '', AppLocalizations.of(currentContext!).unsubscribe, @@ -656,7 +654,7 @@ class EmailActionReactor with MessageDialogActionMixin { }).toList(); } - void openEmailAddressDialog( + Future openEmailAddressDialog( Session session, AccountId accountId, { required EmailAddress emailAddress, @@ -665,24 +663,25 @@ class EmailActionReactor with MessageDialogActionMixin { required AppToast appToast, required void Function(EmailAddress emailAddress) onComposeEmailFromEmailAddressRequest, required void Function(Stream> quickCreateRuleStream) onQuickCreateRuleRequest, - }) { + }) async { if (currentContext?.mounted != true) return; + if (PlatformInfo.isWeb) { + _isEmailAddressDialogOpened.value = true; + } if (responsiveUtils.isScreenWithShortestSide(currentContext!)) { - Get.bottomSheet( - PointerInterceptor( - child: EmailAddressBottomSheetBuilder( - imagePaths: imagePaths, - emailAddress: emailAddress, - onCloseDialogAction: popBack, - onCopyEmailAddressAction: (emailAddress) => - _copyEmailAddress(currentContext!, emailAddress, appToast), - onComposeEmailAction: (emailAddress) => - onComposeEmailFromEmailAddressRequest(emailAddress), - onQuickCreatingRuleEmailDialogAction: (emailAddress) => - onQuickCreateRuleRequest( - quickCreateRule(session, accountId, emailAddress: emailAddress), - ), + await Get.bottomSheet( + EmailAddressBottomSheetBuilder( + imagePaths: imagePaths, + emailAddress: emailAddress, + onCloseDialogAction: popBack, + onCopyEmailAddressAction: (emailAddress) => + _copyEmailAddress(currentContext!, emailAddress, appToast), + onComposeEmailAction: (emailAddress) => + onComposeEmailFromEmailAddressRequest(emailAddress), + onQuickCreatingRuleEmailDialogAction: (emailAddress) => + onQuickCreateRuleRequest( + quickCreateRule(session, accountId, emailAddress: emailAddress), ), ), useRootNavigator: true, @@ -697,25 +696,25 @@ class EmailActionReactor with MessageDialogActionMixin { backgroundColor: Colors.transparent, ); } else { - Get.dialog( - PointerInterceptor( - child: EmailAddressDialogBuilder( - imagePaths: imagePaths, - emailAddress: emailAddress, - onCloseDialogAction: popBack, - onCopyEmailAddressAction: (emailAddress) => - _copyEmailAddress(currentContext!, emailAddress, appToast), - onComposeEmailAction: (emailAddress) => - onComposeEmailFromEmailAddressRequest(emailAddress), - onQuickCreatingRuleEmailDialogAction: (emailAddress) => - onQuickCreateRuleRequest( - quickCreateRule(session, accountId, emailAddress: emailAddress), - ), + await Get.dialog( + EmailAddressDialogBuilder( + imagePaths: imagePaths, + emailAddress: emailAddress, + onCloseDialogAction: popBack, + onCopyEmailAddressAction: (emailAddress) => + _copyEmailAddress(currentContext!, emailAddress, appToast), + onComposeEmailAction: (emailAddress) => + onComposeEmailFromEmailAddressRequest(emailAddress), + onQuickCreatingRuleEmailDialogAction: (emailAddress) => + onQuickCreateRuleRequest( + quickCreateRule(session, accountId, emailAddress: emailAddress), ), ), barrierColor: AppColor.colorDefaultCupertinoActionSheet, ); } + + _isEmailAddressDialogOpened.value = false; } void _copyEmailAddress( diff --git a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart index abc8eff08..7081451d1 100644 --- a/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart +++ b/lib/features/email_recovery/presentation/widgets/email_recovery_form/email_recovery_form_desktop_builder.dart @@ -10,6 +10,7 @@ import 'package:tmail_ui_user/features/base/widget/default_field/default_close_b import 'package:tmail_ui_user/features/base/widget/default_field/default_date_drop_down_field_widget.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_input_field_with_tab_key_widget.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_label_field_widget.dart'; +import 'package:tmail_ui_user/features/base/widget/pop_back_barrier_widget.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/email_recovery_controller.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/extension/handle_drag_email_tag_between_field_extension.dart'; import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/limits_banner.dart'; @@ -26,11 +27,10 @@ class EmailRecoveryFormDesktopBuilder extends StatelessWidget { Widget build(BuildContext context) { final appLocalizations = AppLocalizations.of(context); - return Scaffold( - backgroundColor: Colors.black.withValues(alpha: 0.20), - body: GestureDetector( - onTap: FocusScope.of(context).unfocus, - child: Center( + final child = PopBackBarrierWidget( + child: Center( + child: GestureDetector( + onTap: FocusScope.of(context).unfocus, child: Card( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), @@ -264,5 +264,10 @@ class EmailRecoveryFormDesktopBuilder extends StatelessWidget { ), ), ); + + return Scaffold( + backgroundColor: Colors.black.withValues(alpha: 0.20), + body: child, + ); } } \ No newline at end of file diff --git a/lib/features/identity_creator/presentation/identity_creator_view.dart b/lib/features/identity_creator/presentation/identity_creator_view.dart index 96c8d68ec..2315a96bc 100644 --- a/lib/features/identity_creator/presentation/identity_creator_view.dart +++ b/lib/features/identity_creator/presentation/identity_creator_view.dart @@ -8,11 +8,9 @@ import 'package:core/presentation/views/text/type_ahead_form_field_builder.dart' import 'package:core/utils/direction_utils.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_portal/flutter_portal.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/extensions/email_address_extension.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_email_address_drop_down_button.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_horizontal_field_widget.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_label_field_widget.dart'; @@ -313,20 +311,16 @@ class IdentityCreatorView extends GetWidget { ); } - return PointerInterceptor( - child: ResponsiveWidget( - responsiveUtils: controller.responsiveUtils, - mobile: IdentityCreatorFormMobileBuilder( - controller: controller, - formView: bodyCreatorView, - enableRichTextKeyboard: PlatformInfo.isMobile, - ), - tablet: Portal( - child: IdentityCreatorFormDesktopBuilder( - controller: controller, - formView: bodyCreatorView, - ), - ), + return ResponsiveWidget( + responsiveUtils: controller.responsiveUtils, + mobile: IdentityCreatorFormMobileBuilder( + controller: controller, + formView: bodyCreatorView, + enableRichTextKeyboard: PlatformInfo.isMobile, + ), + tablet: IdentityCreatorFormDesktopBuilder( + controller: controller, + formView: bodyCreatorView, ), ); } diff --git a/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart b/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart index f69c6e026..a2fb027a0 100644 --- a/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart +++ b/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart @@ -7,6 +7,7 @@ import 'package:get/get.dart'; import 'package:rich_text_composer/views/keyboard_rich_text.dart'; import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_close_button_widget.dart'; +import 'package:tmail_ui_user/features/base/widget/pop_back_barrier_widget.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_controller.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/widgets/identity_creator_form_title_widget.dart'; @@ -34,12 +35,12 @@ class IdentityCreatorFormDesktopBuilder extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(16)), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.08), + color: Colors.black.withValues(alpha: 0.08), blurRadius: 24, offset: const Offset(0, 2), ), BoxShadow( - color: Colors.black.withOpacity(0.08), + color: Colors.black.withValues(alpha: 0.08), blurRadius: 2, ), ], @@ -101,10 +102,14 @@ class IdentityCreatorFormDesktopBuilder extends StatelessWidget { } return Scaffold( - backgroundColor: Colors.black.withOpacity(0.2), - body: GestureDetector( - onTap: () => controller.clearFocusEditor(context), - child: Center(child: bodyWidget), + backgroundColor: Colors.black.withValues(alpha: 0.2), + body: PopBackBarrierWidget( + child: Center( + child: GestureDetector( + onTap: () => controller.clearFocusEditor(context), + child: bodyWidget, + ), + ), ), ); } diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index fbbe63967..ddf1bae6e 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -15,13 +15,13 @@ import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:rxdart/transformers.dart'; import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:tmail_ui_user/features/base/extensions/handle_mailbox_action_type_extension.dart'; import 'package:tmail_ui_user/features/base/mixin/contact_support_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/launcher_application_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/mailbox_action_handler_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_email_permanently_state.dart'; @@ -1056,19 +1056,16 @@ class MailboxController extends BaseMailboxController _deleteMultipleMailboxAction(selectedMailboxList))) .show(); } else { - Get.dialog( - PointerInterceptor(child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_delete_multiple_mailbox'), - imagePath: imagePaths, - title: AppLocalizations.of(context).deleteFolders, - textContent: AppLocalizations.of(context).messageConfirmationDialogDeleteMultipleFolder(selectedMailboxList.length), - cancelText: AppLocalizations.of(context).cancel, - confirmText: AppLocalizations.of(context).delete, - onConfirmButtonAction: () => _deleteMultipleMailboxAction(selectedMailboxList), - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - )), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + key: const Key('confirm_dialog_delete_multiple_mailbox'), + context, + title: AppLocalizations.of(context).deleteFolders, + AppLocalizations.of(context).messageConfirmationDialogDeleteMultipleFolder(selectedMailboxList.length), + cancelTitle: AppLocalizations.of(context).cancel, + AppLocalizations.of(context).delete, + onCancelAction: popBack, + onConfirmAction: () => _deleteMultipleMailboxAction(selectedMailboxList), + onCloseButtonAction: popBack, ); } } 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 40d73cd68..bd0e99f70 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -26,11 +26,11 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/vacation/vacation_response.dart'; import 'package:model/model.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:rxdart/transformers.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart'; import 'package:tmail_ui_user/features/base/mixin/contact_support_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart'; import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart'; import 'package:tmail_ui_user/features/composer/domain/extensions/email_request_extension.dart'; @@ -1669,30 +1669,27 @@ class MailboxDashBoardController extends ReloadableController })) .show(); } else { - Get.dialog( - PointerInterceptor(child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_delete_emails_permanently'), - imagePath: imagePaths, - title: actionType.getTitleDialog(context), - textContent: actionType.getContentDialog( - context, - count: listEmails?.length, - mailboxName: mailboxCurrent?.getDisplayName(context), - ), - confirmText: actionType.getConfirmActionName(context), - cancelText: AppLocalizations.of(context).cancel, - onConfirmButtonAction: () { + MessageDialogActionManager().showConfirmDialogAction( + key: const Key('confirm_dialog_delete_emails_permanently'), + context, + title: actionType.getTitleDialog(context), + actionType.getContentDialog( + context, + count: listEmails?.length, + mailboxName: mailboxCurrent?.getDisplayName(context), + ), + actionType.getConfirmActionName(context), + cancelTitle: AppLocalizations.of(context).cancel, + onConfirmAction: () { onConfirm?.call(); _deleteSelectionEmailsPermanentlyAction( - actionType, - listEmails: listEmails, - onCancelSelectionEmail: onCancelSelectionEmail, - ); + actionType, + listEmails: listEmails, + onCancelSelectionEmail: onCancelSelectionEmail, + ); }, - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - )), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + onCancelAction: popBack, + onCloseButtonAction: popBack, ); } } @@ -2730,32 +2727,26 @@ class MailboxDashBoardController extends ReloadableController })) .show(); } else { - Get.dialog( - PointerInterceptor(child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_empty_spam'), - imagePath: imagePaths, - title: AppLocalizations.of(context).emptySpamFolder, - textContent: AppLocalizations.of(context).emptySpamMessageDialog, - confirmText: AppLocalizations.of(context).delete_all, - cancelText: AppLocalizations.of(context).cancel, - onConfirmButtonAction: () { - popBack(); - if (spamMailbox.countTotalEmails > 0) { - emptySpamFolderAction( - spamFolderId: spamMailbox.id, - totalEmails: spamMailbox.countTotalEmails, - ); - } else { - appToast.showToastWarningMessage( - context, - AppLocalizations.of(context).noEmailInYourCurrentFolder, - ); - } - }, - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - )), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + key: const Key('confirm_dialog_empty_spam'), + context, + title: AppLocalizations.of(context).emptySpamFolder, + AppLocalizations.of(context).emptySpamMessageDialog, + AppLocalizations.of(context).delete_all, + cancelTitle: AppLocalizations.of(context).cancel, + onConfirmAction: () { + popBack(); + if (spamMailbox.countTotalEmails > 0) { + emptySpamFolderAction(spamFolderId: spamMailbox.id, totalEmails: spamMailbox.countTotalEmails); + } else { + appToast.showToastWarningMessage( + context, + AppLocalizations.of(context).noEmailInYourCurrentFolder + ); + } + }, + onCancelAction: popBack, + onCloseButtonAction: popBack, ); } } diff --git a/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart b/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart index a03bbaf6b..abba90144 100644 --- a/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart +++ b/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart @@ -1,15 +1,13 @@ -import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:rule_filter/rule_filter/tmail_rule.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_email_rule_filter_request.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/delete_email_rule_request.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/edit_email_rule_filter_request.dart'; @@ -166,20 +164,15 @@ class EmailRulesController extends BaseController { })) .show(); } else { - Get.dialog( - PointerInterceptor( - child: ConfirmationDialogBuilder( - imagePath: imagePaths, - title: AppLocalizations.of(context).deleteEmailRule, - textContent: AppLocalizations.of(context).messageConfirmationDialogDeleteEmailRule(emailRule.name), - confirmText: AppLocalizations.of(context).delete, - cancelText: AppLocalizations.of(context).cancel, - onConfirmButtonAction: () => _handleDeleteEmailRuleAction(emailRule), - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - ), - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + context, + title: AppLocalizations.of(context).deleteEmailRule, + AppLocalizations.of(context).messageConfirmationDialogDeleteEmailRule(emailRule.name), + AppLocalizations.of(context).delete, + cancelTitle: AppLocalizations.of(context).cancel, + onConfirmAction: () => _handleDeleteEmailRuleAction(emailRule), + onCancelAction: popBack, + onCloseButtonAction: popBack, ); } } diff --git a/lib/features/manage_account/presentation/extensions/export_trace_log_extension.dart b/lib/features/manage_account/presentation/extensions/export_trace_log_extension.dart index 5925413d7..16376a937 100644 --- a/lib/features/manage_account/presentation/extensions/export_trace_log_extension.dart +++ b/lib/features/manage_account/presentation/extensions/export_trace_log_extension.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/export_trace_log_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/export_trace_log_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; @@ -18,7 +19,7 @@ extension ExportTraceLogExtension on ManageAccountDashBoardController { } Future showExportTraceLogConfirmDialog(BuildContext context) async { - await showConfirmDialogAction( + await MessageDialogActionManager().showConfirmDialogAction( context, AppLocalizations.of(context).messageExportTraceLogDialog, AppLocalizations.of(context).yes, diff --git a/lib/features/manage_account/presentation/forward/forward_controller.dart b/lib/features/manage_account/presentation/forward/forward_controller.dart index 7e4277ae1..60f97cb57 100644 --- a/lib/features/manage_account/presentation/forward/forward_controller.dart +++ b/lib/features/manage_account/presentation/forward/forward_controller.dart @@ -10,6 +10,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:model/mailbox/select_mode.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/state/banner_state.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; @@ -121,7 +122,7 @@ class ForwardController extends BaseController { void deleteRecipients(BuildContext context, String emailAddress) { clearInputFocus(); - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, title: AppLocalizations.of(context).deleteRecipient, AppLocalizations.of(context).messageConfirmationDialogDeleteRecipientForward(emailAddress), @@ -210,7 +211,7 @@ class ForwardController extends BaseController { void deleteMultipleRecipients(BuildContext context, Set listEmailAddress) { clearInputFocus(); - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, title: AppLocalizations.of(context).deleteRecipient, AppLocalizations.of(context).messageConfirmationDialogDeleteAllRecipientForward, diff --git a/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart b/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart index 7323543a6..733a2f3b3 100644 --- a/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart +++ b/lib/features/manage_account/presentation/forward/widgets/autocomplete_contact_text_field_with_tags.dart @@ -15,7 +15,7 @@ import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/model.dart'; import 'package:super_tag_editor/tag_editor.dart'; -import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; import 'package:tmail_ui_user/features/contact/presentation/widgets/contact_input_tag_item.dart'; @@ -58,7 +58,7 @@ class AutocompleteContactTextFieldWithTags extends StatefulWidget { State createState() => _AutocompleteContactTextFieldWithTagsState(); } -class _AutocompleteContactTextFieldWithTagsState extends State with MessageDialogActionMixin { +class _AutocompleteContactTextFieldWithTagsState extends State { final _responsiveUtils = Get.find(); final _imagePaths = Get.find(); @@ -461,7 +461,7 @@ class _AutocompleteContactTextFieldWithTagsState extends State _dereferencePublicAssets(identity), - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + final appLocalizations = AppLocalizations.of(context); + MessageDialogActionManager().showConfirmDialogAction( + context, + appLocalizations.message_confirmation_dialog_delete_identity, + appLocalizations.delete, + key: const Key('confirm_dialog_delete_identity'), + showAsBottomSheet: responsiveUtils.isMobile(context), + outsideDialogPadding: EdgeInsets.only(bottom: PlatformInfo.isWeb ? 42 : 16), + title: appLocalizations.delete_identity, + cancelTitle: appLocalizations.cancel, + onCancelAction: popBack, + onCloseButtonAction: popBack, + onConfirmAction: () => _dereferencePublicAssets(identity), ); } @@ -358,16 +362,14 @@ class IdentitiesController extends ReloadableController implements BeforeReconne void _deleteIdentityFailure(DeleteIdentityFailure failure) { if (currentContext != null) { - Get.dialog( - ConfirmationDialogBuilder( - key: const Key('dialog_message_delete_identity_failed'), - imagePath: imagePaths, - title: AppLocalizations.of(currentContext!).delete_failed, - confirmText: '${AppLocalizations.of(currentContext!).got_it}!', - onConfirmButtonAction: popBack, - onCloseButtonAction: popBack, - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + key: const Key('dialog_message_delete_identity_failed'), + currentContext!, + title: AppLocalizations.of(currentContext!).delete_failed, + '', + '${AppLocalizations.of(currentContext!).got_it}!', + onConfirmAction: popBack, + onCloseButtonAction: popBack, ); } } diff --git a/lib/features/manage_account/presentation/identities/widgets/delete_identity_dialog_builder.dart b/lib/features/manage_account/presentation/identities/widgets/delete_identity_dialog_builder.dart deleted file mode 100644 index 652f4f32f..000000000 --- a/lib/features/manage_account/presentation/identities/widgets/delete_identity_dialog_builder.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:core/presentation/resources/image_paths.dart'; -import 'package:core/presentation/utils/responsive_utils.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; -import 'package:core/presentation/views/responsive/responsive_widget.dart'; -import 'package:core/utils/platform_info.dart'; -import 'package:flutter/material.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; -import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -import 'package:tmail_ui_user/main/routes/route_navigation.dart'; - -typedef OnDeleteIdentityAction = void Function(); - -class DeleteIdentityDialogBuilder extends StatelessWidget { - - final ResponsiveUtils responsiveUtils; - final ImagePaths imagePaths; - final OnDeleteIdentityAction onDeleteIdentityAction; - - const DeleteIdentityDialogBuilder({ - Key? key, - required this.responsiveUtils, - required this.imagePaths, - required this.onDeleteIdentityAction - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final appLocalizations = AppLocalizations.of(context); - final deleteDialogBuilder = ResponsiveWidget( - responsiveUtils: responsiveUtils, - mobile: _buildDeleteDialog( - appLocalizations: appLocalizations, - alignment: Alignment.bottomCenter, - outsideDialogPadding: EdgeInsets.only(bottom: PlatformInfo.isWeb ? 42 : 16), - ), - landscapeMobile: _buildDeleteDialog(appLocalizations: appLocalizations), - tablet: _buildDeleteDialog(appLocalizations: appLocalizations), - tabletLarge: _buildDeleteDialog(appLocalizations: appLocalizations), - landscapeTablet: _buildDeleteDialog(appLocalizations: appLocalizations), - desktop: _buildDeleteDialog(appLocalizations: appLocalizations), - ); - - return PlatformInfo.isWeb - ? PointerInterceptor(child: deleteDialogBuilder) - : deleteDialogBuilder; - } - - ConfirmationDialogBuilder _buildDeleteDialog({ - required AppLocalizations appLocalizations, - Alignment? alignment, - EdgeInsets? outsideDialogPadding, - }) { - return ConfirmationDialogBuilder( - key: const Key('confirm_dialog_delete_identity'), - imagePath: imagePaths, - title: appLocalizations.delete_identity, - textContent: appLocalizations.message_confirmation_dialog_delete_identity, - confirmText: appLocalizations.delete, - cancelText: appLocalizations.cancel, - alignment: alignment, - outsideDialogPadding: outsideDialogPadding, - onConfirmButtonAction: onDeleteIdentityAction, - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - ); - } -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/identities/widgets/signature_builder.dart b/lib/features/manage_account/presentation/identities/widgets/signature_builder.dart index 5e4e3f542..a17048892 100644 --- a/lib/features/manage_account/presentation/identities/widgets/signature_builder.dart +++ b/lib/features/manage_account/presentation/identities/widgets/signature_builder.dart @@ -2,6 +2,10 @@ import 'package:core/presentation/views/html_viewer/html_content_viewer_on_web_w import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; +import 'package:get/state_manager.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; +import 'package:tmail_ui_user/main/routes/dialog_router.dart'; import 'package:tmail_ui_user/main/utils/app_utils.dart'; class SignatureBuilder extends StatelessWidget { @@ -22,7 +26,20 @@ class SignatureBuilder extends StatelessWidget { @override Widget build(BuildContext context) { if (PlatformInfo.isWeb) { - return HtmlContentViewerOnWeb( + final iframeOverlay = Obx(() { + if (MessageDialogActionManager().isDialogOpened || + DialogRouter.isDialogOpened) { + return Positioned.fill( + child: PointerInterceptor( + child: const SizedBox.expand(), + ), + ); + } else { + return const SizedBox.shrink(); + } + }); + + final htmlView = HtmlContentViewerOnWeb( contentHtml: value, widthContent: width, heightContent: height, @@ -38,6 +55,13 @@ class SignatureBuilder extends StatelessWidget { disableScrolling: true, autoAdjustHeight: true, ); + + return Stack( + children: [ + htmlView, + iframeOverlay, + ], + ); } else { return HtmlContentViewer( contentHtml: value, diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart index ca866e525..a95a9ee46 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart @@ -4,6 +4,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:rule_filter/rule_filter/rule_condition_group.dart'; +import 'package:tmail_ui_user/features/base/widget/pop_back_barrier_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/select_rule_action_field_extension.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart'; @@ -23,80 +24,81 @@ class RuleFilterCreatorView extends GetWidget { @override Widget build(BuildContext context) { + final responsiveUtil = controller.responsiveUtils; + final focusScope = FocusScope.of(context); + return PointerInterceptor( child: ResponsiveWidget( - responsiveUtils: controller.responsiveUtils, - mobile: Scaffold( - backgroundColor: PlatformInfo.isWeb - ? Colors.black.withAlpha(24) - : Colors.black38, - body: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: SafeArea( - bottom: false, - left: false, - right: false, - child: Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16)), - color: Colors.white), - margin: EdgeInsets.only(top: PlatformInfo.isWeb ? 70 : 0), - child: ClipRRect( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16)), - child: SafeArea(child: _buildRulesFilterFormOnMobile(context)) - ) + responsiveUtils: responsiveUtil, + mobile: Scaffold( + backgroundColor: + PlatformInfo.isWeb ? Colors.black.withAlpha(24) : Colors.black38, + body: PopBackBarrierWidget( + child: SafeArea( + bottom: false, + left: false, + right: false, + child: GestureDetector( + onTap: focusScope.unfocus, + child: Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.vertical( + top: Radius.circular(16), + ), + color: Colors.white, + ), + margin: EdgeInsets.only(top: PlatformInfo.isWeb ? 70 : 0), + child: SafeArea( + child: _buildRulesFilterFormOnMobile(context), ), ), - ) + ), + ), ), - tablet: Scaffold( - backgroundColor: Colors.black.withAlpha(24), - body: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: Align(alignment: Alignment.bottomCenter, child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - )), - width: double.infinity, - height: controller.responsiveUtils.getSizeScreenHeight(context) * 0.7, - child: ClipRRect( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16)), - child: _buildRulesFilterFormOnTablet(context) - ) - )), - ) + ), + tablet: Scaffold( + backgroundColor: Colors.black.withAlpha(24), + body: PopBackBarrierWidget( + child: Align( + alignment: Alignment.bottomCenter, + child: GestureDetector( + onTap: focusScope.unfocus, + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.vertical( + top: Radius.circular(16), + ), + ), + height: responsiveUtil.getSizeScreenHeight(context) * 0.7, + child: _buildRulesFilterFormOnTablet(context), + ), + ), + ), ), - desktop: Scaffold( - backgroundColor: Colors.black.withAlpha(24), - body: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: Center(child: Card( - color: Colors.transparent, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(16))), - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(16))), - width: controller.responsiveUtils.getSizeScreenWidth(context) * 0.6, - height: controller.responsiveUtils.getSizeScreenHeight(context) * 0.7, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(16)), - child: _buildRulesFilterFormOnDesktop(context) - ) - ) - )), - ) - ) + ), + desktop: Scaffold( + backgroundColor: Colors.black.withAlpha(24), + body: PopBackBarrierWidget( + child: Center( + child: GestureDetector( + onTap: focusScope.unfocus, + child: Card( + color: Colors.white, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16)), + ), + clipBehavior: Clip.hardEdge, + child: SizedBox( + width: responsiveUtil.getSizeScreenWidth(context) * 0.6, + height: responsiveUtil.getSizeScreenHeight(context) * 0.7, + child: _buildRulesFilterFormOnDesktop(context), + ), + ), + ), + ), + ), + ), ), ); } diff --git a/lib/features/sending_queue/presentation/sending_queue_controller.dart b/lib/features/sending_queue/presentation/sending_queue_controller.dart index a78fb193f..dc96629b3 100644 --- a/lib/features/sending_queue/presentation/sending_queue_controller.dart +++ b/lib/features/sending_queue/presentation/sending_queue_controller.dart @@ -9,7 +9,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/mailbox/select_mode.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; -import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_sending_email_state.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; @@ -35,7 +35,7 @@ import 'package:tmail_ui_user/features/sending_queue/presentation/utils/sending_ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; -class SendingQueueController extends BaseController with MessageDialogActionMixin { +class SendingQueueController extends BaseController { final DeleteMultipleSendingEmailInteractor _deleteMultipleSendingEmailInteractor; final UpdateSendingEmailInteractor _updateSendingEmailInteractor; @@ -191,7 +191,7 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi } void _deleteListSendingEmailAction(BuildContext context, List listSendingEmails) { - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, AppLocalizations.of(context).messageDialogDeleteSendingEmail, AppLocalizations.of(context).cancel, diff --git a/lib/features/thread/presentation/mixin/email_action_controller.dart b/lib/features/thread/presentation/mixin/email_action_controller.dart index 6ce185aaa..3c6a1c663 100644 --- a/lib/features/thread/presentation/mixin/email_action_controller.dart +++ b/lib/features/thread/presentation/mixin/email_action_controller.dart @@ -1,9 +1,7 @@ -import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; -import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; @@ -17,7 +15,7 @@ import 'package:model/email/presentation_email.dart'; import 'package:model/email/read_actions.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; @@ -244,19 +242,16 @@ mixin EmailActionController { () => _deleteEmailPermanentlyAction(context, email))) .show(); } else { - Get.dialog( - PointerInterceptor(child: ConfirmationDialogBuilder( - key: const Key('confirm_dialog_delete_email_permanently'), - imagePath: imagePaths, - title: DeleteActionType.single.getTitleDialog(context), - textContent: DeleteActionType.single.getContentDialog(context), - confirmText: DeleteActionType.single.getConfirmActionName(context), - cancelText: AppLocalizations.of(context).cancel, - onConfirmButtonAction: () => _deleteEmailPermanentlyAction(context, email), - onCancelButtonAction: popBack, - onCloseButtonAction: popBack, - )), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, + MessageDialogActionManager().showConfirmDialogAction( + key: const Key('confirm_dialog_delete_email_permanently'), + context, + title: DeleteActionType.single.getTitleDialog(context), + DeleteActionType.single.getContentDialog(context), + DeleteActionType.single.getConfirmActionName(context), + cancelTitle: AppLocalizations.of(context).cancel, + onConfirmAction: () => _deleteEmailPermanentlyAction(context, email), + onCancelAction: popBack, + onCloseButtonAction: popBack, ); } } diff --git a/lib/features/upload/presentation/controller/upload_controller.dart b/lib/features/upload/presentation/controller/upload_controller.dart index 1100a2649..c8cc09fb6 100644 --- a/lib/features/upload/presentation/controller/upload_controller.dart +++ b/lib/features/upload/presentation/controller/upload_controller.dart @@ -15,6 +15,7 @@ import 'package:model/email/attachment.dart'; import 'package:model/extensions/attachment_extension.dart'; import 'package:model/upload/file_info.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/state/base_ui_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_state.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart'; @@ -369,7 +370,7 @@ class UploadController extends BaseController { void _showConfirmDialogWhenExceededMaxSizeAttachmentsPerEmail({required BuildContext context}) { final maxSizeAttachmentsPerEmail = filesize(_mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0); - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, AppLocalizations.of(context).message_dialog_upload_attachments_exceeds_maximum_size(maxSizeAttachmentsPerEmail), AppLocalizations.of(context).got_it, @@ -381,7 +382,7 @@ class UploadController extends BaseController { required BuildContext context, VoidCallback? confirmAction, }) { - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, title: '', AppLocalizations.of(context).warningMessageWhenExceedGenerallySizeInComposer, diff --git a/lib/main/deep_links/deep_links_manager.dart b/lib/main/deep_links/deep_links_manager.dart index 3016a8f4a..37e6325e1 100644 --- a/lib/main/deep_links/deep_links_manager.dart +++ b/lib/main/deep_links/deep_links_manager.dart @@ -3,13 +3,12 @@ import 'dart:async'; import 'package:app_links/app_links.dart'; import 'package:core/utils/app_logger.dart'; import 'package:rxdart/subjects.dart'; -import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; import 'package:tmail_ui_user/main/deep_links/deep_link_action_type.dart'; import 'package:tmail_ui_user/main/deep_links/deep_link_callback_action_define.dart'; import 'package:tmail_ui_user/main/deep_links/deep_link_data.dart'; import 'package:tmail_ui_user/main/deep_links/open_app_deep_link_handler_mixin.dart'; -class DeepLinksManager with MessageDialogActionMixin, OpenAppDeepLinkHandlerMixin { +class DeepLinksManager with OpenAppDeepLinkHandlerMixin { BehaviorSubject _pendingDeepLinkData = BehaviorSubject.seeded(null); diff --git a/lib/main/deep_links/open_app_deep_link_handler_mixin.dart b/lib/main/deep_links/open_app_deep_link_handler_mixin.dart index 27fbda449..e3bb71ff4 100644 --- a/lib/main/deep_links/open_app_deep_link_handler_mixin.dart +++ b/lib/main/deep_links/open_app_deep_link_handler_mixin.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:rich_text_composer/views/commons/logger.dart'; -import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; +import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/home/domain/state/auto_sign_in_via_deep_link_state.dart'; import 'package:tmail_ui_user/features/home/domain/usecases/auto_sign_in_via_deep_link_interactor.dart'; import 'package:tmail_ui_user/main/deep_links/deep_link_callback_action_define.dart'; @@ -13,7 +13,7 @@ import 'package:tmail_ui_user/main/deep_links/open_app_deep_link_data.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; -mixin OpenAppDeepLinkHandlerMixin on MessageDialogActionMixin { +mixin OpenAppDeepLinkHandlerMixin { OpenAppDeepLinkData? parseOpenAppDeepLink(Uri uri) { try { final accessToken = uri.queryParameters['access_token'] ?? ''; @@ -120,7 +120,7 @@ mixin OpenAppDeepLinkHandlerMixin on MessageDialogActionMixin { }) { final appLocalizations = AppLocalizations.of(context); - showConfirmDialogAction( + MessageDialogActionManager().showConfirmDialogAction( context, '', appLocalizations.yes, diff --git a/lib/main/routes/dialog_router.dart b/lib/main/routes/dialog_router.dart index 76bf5f2e2..f1f2c83f4 100644 --- a/lib/main/routes/dialog_router.dart +++ b/lib/main/routes/dialog_router.dart @@ -21,15 +21,24 @@ class DialogRouter { static Future pushGeneralDialog({ required String routeName, required Object? arguments - }) { + }) async { + _isDialogOpened.value = true; _bindingDI(routeName); - return Get.generalDialog( + final returnedValue = await Get.generalDialog( + barrierDismissible: true, + barrierLabel: routeName, routeSettings: RouteSettings(arguments: arguments), pageBuilder: (_, __, ___) => _generateView(routeName: routeName, arguments: arguments) ); + + _isDialogOpened.value = false; + return returnedValue; } + static final RxBool _isDialogOpened = false.obs; + static bool get isDialogOpened => _isDialogOpened.value; + static void _bindingDI(String routeName) { log('DialogRouter::_bindingDI():routeName: $routeName'); switch(routeName) { diff --git a/pubspec.lock b/pubspec.lock index 452e129f9..ba227c40f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -771,10 +771,10 @@ packages: description: path: "." ref: main - resolved-ref: "66e3713f0e7a22da911b360cef4d219fc30cee77" + resolved-ref: "6c929093a154a2d16fa414f7d9a907e13f15b0ea" url: "https://github.com/linagora/flutter-date-range-picker.git" source: git - version: "2.0.0" + version: "2.0.1" flutter_dotenv: dependency: "direct main" description: diff --git a/test/features/composer/presentation/composer_controller_test.dart b/test/features/composer/presentation/composer_controller_test.dart index e4360540b..b56cb6637 100644 --- a/test/features/composer/presentation/composer_controller_test.dart +++ b/test/features/composer/presentation/composer_controller_test.dart @@ -127,6 +127,18 @@ class MockMailboxDashBoardController extends Mock implements MailboxDashBoardCon @override Map get mapMailboxById => {}; + + @override + RxBool get isAppGridDialogDisplayed => false.obs; + + @override + RxBool get isDrawerOpened => false.obs; + + @override + RxBool get isContextMenuOpened => false.obs; + + @override + RxBool get isPopupMenuOpened => false.obs; } @GenerateNiceMocks([