From 95d9ddc9ad98f8a2577eeda8a38b709733f53286 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 12 Jun 2025 14:14:06 +0700 Subject: [PATCH] TF-3766 Change context menu style for search email view on mobile Signed-off-by: dab246 --- .../popup_context_menu_action_mixin.dart | 54 +++++---- .../handle_email_more_action_extension.dart | 97 +++++++++++++++ .../presentation/search_email_controller.dart | 4 + .../email/presentation/search_email_view.dart | 114 ++---------------- 4 files changed, 141 insertions(+), 128 deletions(-) create mode 100644 lib/features/search/email/presentation/extension/handle_email_more_action_extension.dart diff --git a/lib/features/base/mixin/popup_context_menu_action_mixin.dart b/lib/features/base/mixin/popup_context_menu_action_mixin.dart index 178f690b0..f8e00e9de 100644 --- a/lib/features/base/mixin/popup_context_menu_action_mixin.dart +++ b/lib/features/base/mixin/popup_context_menu_action_mixin.dart @@ -1,5 +1,6 @@ import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/views/bottom_popup/cupertino_action_sheet_builder.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -20,30 +21,37 @@ mixin PopupContextMenuActionMixin { OnContextMenuActionClick? onContextMenuActionClick, } ) async { - await showModalBottomSheet( - context: context, - showDragHandle: true, - useSafeArea: true, - isScrollControlled: true, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - ), - backgroundColor: Colors.white, - barrierColor: Colors.black.withOpacity(0.2), - builder: (_) { - return ColoredBox( - color: Colors.white, - child: ContextMenuDialogView( - actions: itemActions ?? [], - onContextMenuActionClick: (menuAction) => - onContextMenuActionClick?.call(menuAction), + if (actionTiles.isNotEmpty) { + await (CupertinoActionSheetBuilder(context, key: key) + ..addTiles(actionTiles) + ..addCancelButton(cancelButton ?? buildCancelButton(context))) + .show(); + } else { + await showModalBottomSheet( + context: context, + showDragHandle: true, + useSafeArea: true, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), ), - ); - }, - ); + ), + backgroundColor: Colors.white, + barrierColor: Colors.black.withOpacity(0.2), + builder: (_) { + return ColoredBox( + color: Colors.white, + child: ContextMenuDialogView( + actions: itemActions ?? [], + onContextMenuActionClick: (menuAction) => + onContextMenuActionClick?.call(menuAction), + ), + ); + }, + ); + } } void openPopupMenuAction( diff --git a/lib/features/search/email/presentation/extension/handle_email_more_action_extension.dart b/lib/features/search/email/presentation/extension/handle_email_more_action_extension.dart new file mode 100644 index 000000000..0501fe635 --- /dev/null +++ b/lib/features/search/email/presentation/extension/handle_email_more_action_extension.dart @@ -0,0 +1,97 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:model/email/email_action_type.dart'; +import 'package:model/email/presentation_email.dart'; +import 'package:model/extensions/presentation_mailbox_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/context_item_email_action.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart'; +import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +extension HandleEmailMoreActionExtension on SearchEmailController { + void handleEmailMoreAction( + BuildContext context, + PresentationEmail presentationEmail, + RelativeRect? position, + ) { + final mailboxContain = presentationEmail.mailboxContain; + + final listEmailActions = [ + mailboxContain?.isSpam == true + ? EmailActionType.unSpam + : EmailActionType.moveToSpam, + if (mailboxContain?.isDrafts == false) EmailActionType.editAsNewEmail, + ]; + + if (listEmailActions.isEmpty) return; + + if (responsiveUtils.isScreenWithShortestSide(context)) { + final contextMenuActions = listEmailActions + .map((action) => ContextItemEmailAction( + action, + AppLocalizations.of(context), + imagePaths, + )) + .toList(); + + openContextMenuAction( + context, + [], + itemActions: contextMenuActions, + onContextMenuActionClick: (menuAction) { + pressEmailAction( + context, + menuAction.action, + presentationEmail, + ); + }, + ); + } else { + final popupMenuEntries = listEmailActions + .map((actionType) => PopupMenuItem( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: _buildPopupMenuAction( + context, + presentationEmail, + actionType, + ), + )) + .toList(); + openPopupMenuAction( + context, + position, + popupMenuEntries, + ); + } + } + + Widget _buildPopupMenuAction( + BuildContext context, + PresentationEmail presentationEmail, + EmailActionType emailActionType, + ) { + return (EmailActionCupertinoActionSheetActionBuilder( + Key(emailActionType.name), + SvgPicture.asset(emailActionType.getIcon(imagePaths), + width: 28, + height: 28, + fit: BoxFit.fill, + colorFilter: AppColor.colorTextButton.asFilter()), + emailActionType.getTitle(AppLocalizations.of(context)), + presentationEmail, + iconLeftPadding: responsiveUtils.isMobile(context) + ? const EdgeInsetsDirectional.only(start: 12, end: 16) + : const EdgeInsetsDirectional.only(end: 12), + iconRightPadding: responsiveUtils.isMobile(context) + ? const EdgeInsetsDirectional.only(end: 12) + : EdgeInsets.zero, + )..onActionClick((email) => pressEmailAction( + context, + emailActionType, + email, + ))) + .build(); + } +} diff --git a/lib/features/search/email/presentation/search_email_controller.dart b/lib/features/search/email/presentation/search_email_controller.dart index 141268c35..111b08c0e 100644 --- a/lib/features/search/email/presentation/search_email_controller.dart +++ b/lib/features/search/email/presentation/search_email_controller.dart @@ -888,6 +888,10 @@ class SearchEmailController extends BaseController popBack(); unSpam(selectedEmail); break; + case EmailActionType.editAsNewEmail: + popBack(); + editAsNewEmail(selectedEmail); + break; default: break; } diff --git a/lib/features/search/email/presentation/search_email_view.dart b/lib/features/search/email/presentation/search_email_view.dart index 509928ad7..82d594b3e 100644 --- a/lib/features/search/email/presentation/search_email_view.dart +++ b/lib/features/search/email/presentation/search_email_view.dart @@ -13,7 +13,6 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; -import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.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'; @@ -22,6 +21,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/qu import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/quick_search/email_quick_search_item_tile_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/quick_search/recent_search_item_tile_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart'; +import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_email_more_action_extension.dart'; import 'package:tmail_ui_user/features/search/email/presentation/model/search_more_state.dart'; import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart'; import 'package:tmail_ui_user/features/search/email/presentation/styles/search_email_view_style.dart'; @@ -39,7 +39,6 @@ import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_til import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart' if (dart.library.html) 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_web_builder.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class SearchEmailView extends GetWidget with AppLoaderMixin { @@ -667,20 +666,12 @@ class SearchEmailView extends GetWidget mailboxContain: currentPresentationEmail.mailboxContain ); }, - onMoreActionClick: (email, position) { - if (controller.responsiveUtils.isScreenWithShortestSide(context)) { - controller.openContextMenuAction( - context, - _contextMenuActionTile(context, email) - ); - } else { - controller.openPopupMenuAction( + onMoreActionClick: (email, position) => + controller.handleEmailMoreAction( context, + email, position, - _popupMenuActionTile(context, email) - ); - } - }, + ), )); }, separatorBuilder: (BuildContext context, int index) { @@ -720,21 +711,12 @@ class SearchEmailView extends GetWidget mailboxContain: currentPresentationEmail.mailboxContain ); }, - onMoreActionClick: (email, position) { - if (controller.responsiveUtils.isScreenWithShortestSide(context)) { - controller.openContextMenuAction( - context, - _contextMenuActionTile(context, email) - ); - } else { - controller.openPopupMenuAction( + onMoreActionClick: (email, position) => + controller.handleEmailMoreAction( context, + email, position, - _popupMenuActionTile(context, email) - ); - } - }, - + ), )); }, separatorBuilder: (context, index) { @@ -752,84 +734,6 @@ class SearchEmailView extends GetWidget ); } - List _contextMenuActionTile(BuildContext context, PresentationEmail email) { - return [ - _markAsEmailSpamOrUnSpamAction(context, email), - if (email.mailboxContain?.isDrafts == false) - _editAsNewEmailContextMenuItemAction(context, email), - ]; - } - - Widget _markAsEmailSpamOrUnSpamAction(BuildContext context, PresentationEmail email) { - final mailboxContain = email.mailboxContain; - - return (EmailActionCupertinoActionSheetActionBuilder( - const Key('mark_as_spam_or_un_spam_action'), - SvgPicture.asset( - mailboxContain?.isSpam == true ? controller.imagePaths.icNotSpam : controller.imagePaths.icSpam, - width: 28, - height: 28, - fit: BoxFit.fill, - colorFilter: AppColor.colorTextButton.asFilter()), - mailboxContain?.isSpam == true - ? AppLocalizations.of(context).remove_from_spam - : AppLocalizations.of(context).mark_as_spam, - email, - iconLeftPadding: controller.responsiveUtils.isMobile(context) - ? const EdgeInsets.only(left: 12, right: 16) - : const EdgeInsets.only(right: 12), - iconRightPadding: controller.responsiveUtils.isMobile(context) - ? const EdgeInsets.only(right: 12) - : EdgeInsets.zero) - ..onActionClick((email) => controller.pressEmailAction(context, - mailboxContain?.isSpam == true - ? EmailActionType.unSpam - : EmailActionType.moveToSpam, - email))) - .build(); - } - - Widget _editAsNewEmailContextMenuItemAction( - BuildContext context, - PresentationEmail email, - ) { - return ( - EmailActionCupertinoActionSheetActionBuilder( - const Key('edit_as_new_email_action'), - SvgPicture.asset( - controller.imagePaths.icEdit, - width: 24, - height: 24, - fit: BoxFit.fill, - colorFilter: AppColor.colorTextButton.asFilter() - ), - AppLocalizations.of(context).editAsNewEmail, - email, - iconLeftPadding: controller.responsiveUtils.isMobile(context) - ? const EdgeInsetsDirectional.only(start: 12, end: 16) - : const EdgeInsetsDirectional.only(end: 12), - iconRightPadding: controller.responsiveUtils.isMobile(context) - ? const EdgeInsetsDirectional.only(start: 12) - : EdgeInsets.zero) - ..onActionClick((email) { - popBack(); - controller.editAsNewEmail(email); - }) - ).build(); - } - - List _popupMenuActionTile(BuildContext context, PresentationEmail email) { - return [ - PopupMenuItem( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: _markAsEmailSpamOrUnSpamAction(context, email)), - if (email.mailboxContain?.isDrafts == false) - PopupMenuItem( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: _editAsNewEmailContextMenuItemAction(context, email)), - ]; - } - Widget _buildLoadingViewLoadMore() { return Obx(() => controller.viewState.value.fold( (failure) => const SizedBox.shrink(),