TF-3759 Update style popup context menu for search email view

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-06-13 16:02:01 +07:00
committed by Dat H. Pham
parent 0fb7437a08
commit 3e4ff52cd3
9 changed files with 108 additions and 90 deletions
@@ -79,7 +79,7 @@ mixin PopupContextMenuActionMixin {
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6)),
),
constraints: const BoxConstraints(maxWidth: 220),
constraints: const BoxConstraints(maxWidth: 300),
items: popupMenuItems,
);
}
@@ -14,11 +14,6 @@ abstract class PopupMenuItemAction<T> with EquatableMixin {
String get actionName;
String getActionNameWithLimitation({int limitCharacters = 22}) =>
actionName.length > limitCharacters
? '${actionName.substring(0, limitCharacters)}...'
: actionName;
Color get actionNameColor => Colors.black;
void onClick(OnPopupMenuActionClick callback) => callback(this);
@@ -2,6 +2,7 @@ import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:tmail_ui_user/features/base/model/popup_menu_item_action.dart';
class PopupMenuItemActionWidget extends StatelessWidget {
@@ -32,27 +33,30 @@ class PopupMenuItemActionWidget extends StatelessWidget {
);
}
return Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () => menuAction.onClick(menuActionClick),
child: Container(
height: 48,
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
if (iconWidget != null) iconWidget,
Expanded(
child: Text(
menuAction.getActionNameWithLimitation(),
style: ThemeUtils.textStyleBodyBody3(
color: menuAction.actionNameColor,
return PointerInterceptor(
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () => menuAction.onClick(menuActionClick),
child: Container(
height: 48,
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
if (iconWidget != null) iconWidget,
Expanded(
child: Text(
menuAction.actionName,
style: ThemeUtils.textStyleBodyBody3(
color: menuAction.actionNameColor,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
),
],
],
),
),
),
),
@@ -1,14 +1,13 @@
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/base/widget/popup_menu/popup_menu_item_action_widget.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/email/presentation/model/popup_menu_item_email_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension HandleEmailMoreActionExtension on SearchEmailController {
void handleEmailMoreAction(
@@ -17,17 +16,17 @@ extension HandleEmailMoreActionExtension on SearchEmailController {
RelativeRect? position,
) {
final mailboxContain = presentationEmail.mailboxContain;
final isDrafts = mailboxContain?.isDrafts ?? false;
final isSpam = mailboxContain?.isSpam ?? false;
final listEmailActions = [
mailboxContain?.isSpam == true
? EmailActionType.unSpam
: EmailActionType.moveToSpam,
if (mailboxContain?.isDrafts == false) EmailActionType.editAsNewEmail,
isSpam ? EmailActionType.unSpam : EmailActionType.moveToSpam,
if (!isDrafts) EmailActionType.editAsNewEmail,
];
if (listEmailActions.isEmpty) return;
if (responsiveUtils.isScreenWithShortestSide(context)) {
if (position == null) {
final contextMenuActions = listEmailActions
.map((action) => ContextItemEmailAction(
action,
@@ -44,53 +43,34 @@ extension HandleEmailMoreActionExtension on SearchEmailController {
context,
menuAction.action,
presentationEmail,
mailboxContain: mailboxContain,
);
},
);
} else {
final popupMenuEntries = listEmailActions
.map((actionType) => PopupMenuItem(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: _buildPopupMenuAction(
context,
presentationEmail,
actionType,
),
))
.toList();
openPopupMenuAction(
context,
position,
popupMenuEntries,
);
final popupMenuItems = listEmailActions.map((actionType) {
return PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
menuAction: PopupMenuItemEmailAction(
actionType,
AppLocalizations.of(context),
imagePaths,
),
menuActionClick: (menuAction) {
popBack();
pressEmailAction(
context,
menuAction.action,
presentationEmail,
mailboxContain: mailboxContain,
);
},
),
);
}).toList();
openPopupMenuAction(context, position, popupMenuItems);
}
}
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();
}
}
@@ -0,0 +1,48 @@
import 'package:flutter/material.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/base/widget/popup_menu/popup_menu_item_action_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/model/popup_menu_item_email_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension HandleEmailActionExtension on SearchEmailController {
void handleEmailMoreActionClick(
BuildContext context,
RelativeRect position,
PresentationEmail presentationEmail,
) {
final mailboxContain = presentationEmail.mailboxContain;
final isDrafts = mailboxContain?.isDrafts ?? false;
final isSpam = mailboxContain?.isSpam ?? false;
final popupMenuItems = [
isSpam ? EmailActionType.unSpam : EmailActionType.moveToSpam,
if (isDrafts == false) EmailActionType.editAsNewEmail,
].map((actionType) {
return PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
menuAction: PopupMenuItemEmailAction(
actionType,
AppLocalizations.of(context),
imagePaths,
),
menuActionClick: (menuAction) {
popBack();
pressEmailAction(
context,
menuAction.action,
presentationEmail,
mailboxContain: mailboxContain,
);
},
),
);
}).toList();
openPopupMenuAction(context, position, popupMenuItems);
}
}
@@ -846,7 +846,7 @@ class SearchEmailController extends BaseController
BuildContext context,
EmailActionType actionType,
PresentationEmail selectedEmail,
{PresentationMailbox? mailboxContain}
{required PresentationMailbox? mailboxContain}
) {
switch(actionType) {
case EmailActionType.preview:
@@ -881,15 +881,12 @@ class SearchEmailController extends BaseController
deleteEmailPermanently(context, selectedEmail);
break;
case EmailActionType.moveToSpam:
popBack();
moveToSpam(selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.unSpam:
popBack();
unSpam(selectedEmail);
break;
case EmailActionType.editAsNewEmail:
popBack();
editAsNewEmail(selectedEmail);
break;
default:
@@ -273,12 +273,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
BuildContext context,
MailboxActions actions,
PresentationMailbox mailbox,
{bool isFocusedMenu = false}
) {
if (!isFocusedMenu) {
popBack();
}
switch(actions) {
case MailboxActions.openInNewTab:
openMailboxInNewTabAction(mailbox);
@@ -22,6 +22,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.
import 'package:tmail_ui_user/features/search/mailbox/presentation/search_mailbox_controller.dart';
import 'package:tmail_ui_user/features/search/mailbox/presentation/widgets/mailbox_searched_item_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class SearchMailboxView extends GetWidget<SearchMailboxController>
with AppLoaderMixin,
@@ -231,7 +232,6 @@ class SearchMailboxView extends GetWidget<SearchMailboxController>
context,
contextMenuItem.action,
mailbox,
isFocusedMenu: true
),
title: Expanded(
child: Row(children: [
@@ -309,6 +309,7 @@ class SearchMailboxView extends GetWidget<SearchMailboxController>
child: PopupMenuItemActionWidget(
menuAction: menuAction,
menuActionClick: (menuAction) {
popBack();
controller.handleMailboxAction(
context,
menuAction.action,
@@ -1158,7 +1158,7 @@ class ThreadController extends BaseController with EmailActionController {
EmailActionType actionType,
PresentationEmail selectedEmail,
{
PresentationMailbox? mailboxContain,
required PresentationMailbox? mailboxContain,
}
) {
switch(actionType) {
@@ -1198,11 +1198,9 @@ class ThreadController extends BaseController with EmailActionController {
}
break;
case EmailActionType.moveToSpam:
popBack();
moveToSpam(selectedEmail, mailboxContain: mailboxContain);
break;
case EmailActionType.unSpam:
popBack();
unSpam(selectedEmail);
break;
case EmailActionType.openInNewTab: