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