TF-3766 Change context menu style for search email view on mobile

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-06-12 14:14:06 +07:00
committed by Dat H. Pham
parent 075243a54b
commit 95d9ddc9ad
4 changed files with 141 additions and 128 deletions
@@ -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(
@@ -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();
}
}
@@ -888,6 +888,10 @@ class SearchEmailController extends BaseController
popBack();
unSpam(selectedEmail);
break;
case EmailActionType.editAsNewEmail:
popBack();
editAsNewEmail(selectedEmail);
break;
default:
break;
}
@@ -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<SearchEmailController>
with AppLoaderMixin {
@@ -667,20 +666,12 @@ class SearchEmailView extends GetWidget<SearchEmailController>
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<SearchEmailController>
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<SearchEmailController>
);
}
List<Widget> _contextMenuActionTile(BuildContext context, PresentationEmail email) {
return <Widget>[
_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<PopupMenuEntry> _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(),