TF-3766 Change context menu style for other widgets on mobile

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-06-13 01:14:16 +07:00
committed by Dat H. Pham
parent 3dce663b98
commit 2d175633e7
36 changed files with 759 additions and 612 deletions
+2 -11
View File
@@ -234,24 +234,15 @@ class ThemeUtils {
color: Colors.black, color: Colors.black,
); );
static TextStyle textStyleInter400() => const TextStyle( static const TextStyle textStyleInter400 = TextStyle(
fontFamily: ConstantsUI.fontApp, fontFamily: ConstantsUI.fontApp,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
letterSpacing: 0.01, letterSpacing: -0.13,
fontSize: 13, fontSize: 13,
height: 16 / 13, height: 16 / 13,
color: Colors.black, color: Colors.black,
); );
static final TextStyle textStyleInter400 = TextStyle(
fontFamily: ConstantsUI.fontApp,
fontWeight: FontWeight.w400,
letterSpacing: -0.15,
fontSize: 16,
height: 21.01 / 16,
color: AppColor.gray424244.withOpacity(0.9),
);
static TextStyle textStyleM3LabelLarge({Color? color}) => TextStyle( static TextStyle textStyleM3LabelLarge({Color? color}) => TextStyle(
fontFamily: ConstantsUI.fontApp, fontFamily: ConstantsUI.fontApp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@@ -11,51 +11,49 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart';
mixin PopupContextMenuActionMixin { mixin PopupContextMenuActionMixin {
Future<void> openContextMenuAction(
void openContextMenuAction(
BuildContext context, BuildContext context,
List<Widget> actionTiles, List<Widget> actionTiles,
{
Widget? cancelButton,
Key? key,
List<ContextMenuItemAction>? itemActions,
OnContextMenuActionClick? onContextMenuActionClick,
}
) async { ) async {
if (actionTiles.isNotEmpty) { await (CupertinoActionSheetBuilder(context)
await (CupertinoActionSheetBuilder(context, key: key) ..addTiles(actionTiles)
..addTiles(actionTiles) ..addCancelButton(buildCancelButton(context)))
..addCancelButton(cancelButton ?? buildCancelButton(context))) .show();
.show(); }
} else {
await showModalBottomSheet( Future<void> openBottomSheetContextMenuAction({
context: context, required BuildContext context,
showDragHandle: true, required List<ContextMenuItemAction> itemActions,
useSafeArea: true, required OnContextMenuActionClick onContextMenuActionClick,
isScrollControlled: true, Key? key,
shape: const RoundedRectangleBorder( }) async {
borderRadius: BorderRadius.only( await showModalBottomSheet(
topLeft: Radius.circular(16.0), context: context,
topRight: Radius.circular(16.0), 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), backgroundColor: Colors.white,
builder: (_) { barrierColor: Colors.black.withOpacity(0.2),
return PointerInterceptor( builder: (_) {
child: Container( return PointerInterceptor(
color: Colors.white, child: Container(
padding: const EdgeInsetsDirectional.only(bottom: 24), key: key,
child: ContextMenuDialogView( color: Colors.white,
actions: itemActions ?? [], padding: const EdgeInsetsDirectional.only(bottom: 24),
onContextMenuActionClick: (menuAction) => child: ContextMenuDialogView(
onContextMenuActionClick?.call(menuAction), actions: itemActions,
), onContextMenuActionClick: onContextMenuActionClick,
), ),
); ),
}, );
); },
} );
} }
void openPopupMenuAction( void openPopupMenuAction(
@@ -1,4 +1,3 @@
import 'package:core/presentation/extensions/color_extension.dart'; 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';
@@ -17,6 +16,76 @@ class ContextMenuDialogItem extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SvgPicture? icon;
SvgPicture? selectedIcon;
bool isSelected = false;
if (menuAction is ContextMenuItemActionRequiredIcon) {
final specificMenuAction =
menuAction as ContextMenuItemActionRequiredIcon;
icon = SvgPicture.asset(
specificMenuAction.actionIcon,
width: 20,
height: 20,
colorFilter: specificMenuAction.actionIconColor.asFilter(),
fit: BoxFit.fill,
);
} else if (menuAction is ContextMenuItemActionRequiredSelectedIcon) {
final specificMenuAction =
menuAction as ContextMenuItemActionRequiredSelectedIcon;
selectedIcon = SvgPicture.asset(
specificMenuAction.selectedIcon,
width: 20,
height: 20,
colorFilter: specificMenuAction.selectedIconColor.asFilter(),
fit: BoxFit.fill,
);
isSelected = specificMenuAction.selectedAction == menuAction.action;
} else if (menuAction is ContextMenuItemActionRequiredFull) {
final specificMenuAction =
menuAction as ContextMenuItemActionRequiredFull;
icon = SvgPicture.asset(
specificMenuAction.actionIcon,
width: 20,
height: 20,
colorFilter: specificMenuAction.actionIconColor.asFilter(),
fit: BoxFit.fill,
);
selectedIcon = SvgPicture.asset(
specificMenuAction.selectedIcon,
width: 20,
height: 20,
colorFilter: specificMenuAction.selectedIconColor.asFilter(),
fit: BoxFit.fill,
);
isSelected = specificMenuAction.selectedAction == menuAction.action;
}
Widget? iconWidget = icon != null
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Container(
height: 32,
width: 32,
alignment: Alignment.center,
child: icon,
),
)
: null;
Widget? selectedIconWidget = selectedIcon != null
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Container(
height: 32,
width: 32,
alignment: Alignment.center,
child: selectedIcon,
),
)
: null;
return Material( return Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: InkWell( child: InkWell(
@@ -25,31 +94,24 @@ class ContextMenuDialogItem extends StatelessWidget {
height: 48, height: 48,
child: Row( child: Row(
children: [ children: [
Padding( if (iconWidget != null) iconWidget else const SizedBox(width: 24),
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Container(
height: 32,
width: 32,
alignment: Alignment.center,
child: SvgPicture.asset(
menuAction.actionIcon,
width: 20,
height: 20,
colorFilter: menuAction.actionIconColor.asFilter(),
fit: BoxFit.fill,
),
),
),
Expanded( Expanded(
child: Text( child: Text(
menuAction.actionName, menuAction.actionName,
style: ThemeUtils.textStyleInter400.copyWith( style: ThemeUtils.textStyleInter400.copyWith(
color: menuAction.actionNameColor, color: menuAction.actionNameColor,
letterSpacing: -0.15,
fontSize: 16,
height: 21.01 / 16,
), ),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
if (isSelected && selectedIconWidget != null)
selectedIconWidget
else
const SizedBox(width: 24),
], ],
), ),
), ),
@@ -12,13 +12,41 @@ abstract class ContextMenuItemAction<T> with EquatableMixin {
@override @override
List<Object?> get props => [action]; List<Object?> get props => [action];
String get actionIcon;
Color get actionIconColor => AppColor.gray424244.withOpacity(0.72);
String get actionName; String get actionName;
Color get actionNameColor => AppColor.gray424244.withOpacity(0.9); Color get actionNameColor => AppColor.gray424244.withOpacity(0.9);
void onClick(OnContextMenuActionClick callback) => callback(this); void onClick(OnContextMenuActionClick callback) => callback(this);
} }
mixin OptionalIcon {
String get actionIcon;
Color get actionIconColor => AppColor.gray424244.withOpacity(0.72);
}
mixin OptionalSelectedIcon<T> {
String get selectedIcon;
Color get selectedIconColor => AppColor.primaryMain;
}
abstract class ContextMenuItemActionRequiredIcon<T>
extends ContextMenuItemAction<T> with OptionalIcon {
ContextMenuItemActionRequiredIcon(super.action);
}
abstract class ContextMenuItemActionRequiredSelectedIcon<T>
extends ContextMenuItemAction<T> with OptionalSelectedIcon<T> {
final T? selectedAction;
ContextMenuItemActionRequiredSelectedIcon(super.action, this.selectedAction);
}
abstract class ContextMenuItemActionRequiredFull<T>
extends ContextMenuItemAction<T> with OptionalIcon, OptionalSelectedIcon<T> {
final T selectedAction;
ContextMenuItemActionRequiredFull(super.action, this.selectedAction);
}
@@ -14,6 +14,7 @@ import 'package:rule_filter/rule_filter/rule_condition_group.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class DropDownButtonWidget<T> extends StatelessWidget { class DropDownButtonWidget<T> extends StatelessWidget {
@@ -173,6 +174,8 @@ class DropDownButtonWidget<T> extends StatelessWidget {
} }
String _getTextItemDropdown(BuildContext context, {required T? item}) { String _getTextItemDropdown(BuildContext context, {required T? item}) {
final appLocalizations = AppLocalizations.of(context);
if (item is Identity) { if (item is Identity) {
return item.name ?? ''; return item.name ?? '';
} }
@@ -183,16 +186,16 @@ class DropDownButtonWidget<T> extends StatelessWidget {
return item.name; return item.name;
} }
if (item is rule_condition.Field) { if (item is rule_condition.Field) {
return item.getTitle(context); return item.getTitle(appLocalizations);
} }
if (item is rule_condition.Comparator) { if (item is rule_condition.Comparator) {
return item.getTitle(context); return item.getTitle(appLocalizations);
} }
if (item is EmailRuleFilterAction) { if (item is EmailRuleFilterAction) {
return item.getTitle(context); return item.getTitle(appLocalizations);
} }
if (item is ConditionCombiner) { if (item is ConditionCombiner) {
return item.getTitle(context); return item.getTitle(appLocalizations);
} }
return hintText ?? ''; return hintText ?? '';
} }
@@ -556,9 +556,8 @@ class EmailView extends GetWidget<SingleEmailController> {
.toList(); .toList();
if (position == null) { if (position == null) {
controller.openContextMenuAction( controller.openBottomSheetContextMenuAction(
context, context: context,
[],
itemActions: contextMenuActions, itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) { onContextMenuActionClick: (menuAction) {
popBack(); popBack();
@@ -5,7 +5,7 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/email_ac
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemEmailAction class ContextItemEmailAction
extends ContextMenuItemAction<EmailActionType> { extends ContextMenuItemActionRequiredIcon<EmailActionType> {
final AppLocalizations appLocalizations; final AppLocalizations appLocalizations;
final ImagePaths imagePaths; final ImagePaths imagePaths;
@@ -7,6 +7,7 @@ import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension HandleMailboxActionExtension on MailboxController { extension HandleMailboxActionExtension on MailboxController {
@@ -25,20 +26,21 @@ extension HandleMailboxActionExtension on MailboxController {
mailboxDashBoardController.enableSpamReport, mailboxDashBoardController.enableSpamReport,
deletedMessageVaultSupported, deletedMessageVaultSupported,
isSubAddressingSupported, isSubAddressingSupported,
imagePaths,
AppLocalizations.of(context),
); );
if (contextMenuActions.isEmpty) { if (contextMenuActions.isEmpty) {
return; return;
} }
openContextMenuAction( openBottomSheetContextMenuAction(
context, context: context,
contextMenuMailboxActionTiles( itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) => handleMailboxAction(
context, context,
imagePaths, menuAction.action,
mailbox, mailbox,
contextMenuActions,
handleMailboxAction: handleMailboxAction,
), ),
); );
} }
@@ -76,6 +78,8 @@ extension HandleMailboxActionExtension on MailboxController {
mailboxDashBoardController.enableSpamReport, mailboxDashBoardController.enableSpamReport,
deletedMessageVaultSupported, deletedMessageVaultSupported,
isSubAddressingSupported, isSubAddressingSupported,
imagePaths,
AppLocalizations.of(context),
); );
if (contextMenuActions.isEmpty) { if (contextMenuActions.isEmpty) {
@@ -83,15 +87,14 @@ extension HandleMailboxActionExtension on MailboxController {
} }
if (responsiveUtils.isScreenWithShortestSide(context)) { if (responsiveUtils.isScreenWithShortestSide(context)) {
openContextMenuAction( openBottomSheetContextMenuAction(
context, context: context,
contextMenuMailboxActionTiles( itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) => handleMailboxAction(
context, context,
imagePaths, menuAction.action,
mailbox, mailbox,
contextMenuActions, ),
handleMailboxAction: handleMailboxAction,
)
); );
} else { } else {
openPopupMenuAction( openPopupMenuAction(
@@ -1,19 +1,12 @@
import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/utils/platform_info.dart'; import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/mailbox/mailbox_constants.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart'; import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/context_item_mailbox_action.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/context_item_mailbox_action.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.dart';
import 'package:tmail_ui_user/main/error/capability_validator.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
mixin MailboxWidgetMixin { mixin MailboxWidgetMixin {
@@ -97,65 +90,35 @@ mixin MailboxWidgetMixin {
PresentationMailbox mailbox, PresentationMailbox mailbox,
bool spamReportEnabled, bool spamReportEnabled,
bool deletedMessageVaultSupported, bool deletedMessageVaultSupported,
bool subaddressingSupported, bool isSubAddressingSupported,
) { ) {
if (mailbox.isDefault) { if (mailbox.isDefault) {
return _listActionForDefaultMailbox(mailbox, spamReportEnabled, deletedMessageVaultSupported); return _listActionForDefaultMailbox(
mailbox,
spamReportEnabled,
deletedMessageVaultSupported,
);
} else if (mailbox.isPersonal) { } else if (mailbox.isPersonal) {
return _listActionForPersonalMailbox(mailbox, subaddressingSupported); return _listActionForPersonalMailbox(mailbox, isSubAddressingSupported);
} else { } else {
return _listActionForTeamMailbox(mailbox); return _listActionForTeamMailbox(mailbox);
} }
} }
void openMailboxMenuActionOnMobile(
BuildContext context,
ImagePaths imagePaths,
PresentationMailbox mailbox,
MailboxController controller
) {
final bool deletedMessageVaultSupported = MailboxUtils.isDeletedMessageVaultSupported(
controller.mailboxDashBoardController.sessionCurrent,
controller.mailboxDashBoardController.accountId.value);
final bool subaddressingSupported = isSubaddressingSupported(
controller.mailboxDashBoardController.sessionCurrent,
controller.mailboxDashBoardController.accountId.value);
final contextMenuActions = listContextMenuItemAction(
mailbox,
controller.mailboxDashBoardController.enableSpamReport,
deletedMessageVaultSupported,
subaddressingSupported,
imagePaths,
AppLocalizations.of(context),
);
if (contextMenuActions.isEmpty) {
return;
}
controller.openContextMenuAction(
context,
[],
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) => controller.handleMailboxAction(
context,
menuAction.action,
mailbox,
),
);
}
List<ContextMenuItemMailboxAction> listContextMenuItemAction( List<ContextMenuItemMailboxAction> listContextMenuItemAction(
PresentationMailbox mailbox, PresentationMailbox mailbox,
bool spamReportEnabled, bool spamReportEnabled,
bool deletedMessageVaultSupported, bool deletedMessageVaultSupported,
bool subaddressingSupported, bool isSubAddressingSupported,
ImagePaths imagePaths, ImagePaths imagePaths,
AppLocalizations appLocalizations, AppLocalizations appLocalizations,
) { ) {
final mailboxActionsSupported = _listActionForAllMailboxType(mailbox, spamReportEnabled, deletedMessageVaultSupported, subaddressingSupported); final mailboxActionsSupported = _listActionForAllMailboxType(
mailbox,
spamReportEnabled,
deletedMessageVaultSupported,
isSubAddressingSupported,
);
final listContextMenuItemAction = mailboxActionsSupported final listContextMenuItemAction = mailboxActionsSupported
.map((action) => ContextMenuItemMailboxAction( .map((action) => ContextMenuItemMailboxAction(
@@ -168,61 +131,6 @@ mixin MailboxWidgetMixin {
return listContextMenuItemAction; return listContextMenuItemAction;
} }
void openMailboxMenuActionOnWeb(
BuildContext context,
ImagePaths imagePaths,
ResponsiveUtils responsiveUtils,
RelativeRect position,
PresentationMailbox mailbox,
MailboxController controller
) {
final bool deletedMessageVaultSupported = MailboxUtils.isDeletedMessageVaultSupported(
controller.mailboxDashBoardController.sessionCurrent,
controller.mailboxDashBoardController.accountId.value);
final bool subaddressingSupported = isSubaddressingSupported(
controller.mailboxDashBoardController.sessionCurrent,
controller.mailboxDashBoardController.accountId.value);
final contextMenuActions = listContextMenuItemAction(
mailbox,
controller.mailboxDashBoardController.enableSpamReport,
deletedMessageVaultSupported,
subaddressingSupported,
imagePaths,
AppLocalizations.of(context),
);
if (contextMenuActions.isEmpty) {
return;
}
if (responsiveUtils.isScreenWithShortestSide(context)) {
controller.openContextMenuAction(
context,
[],
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) => controller.handleMailboxAction(
context,
menuAction.action,
mailbox,
),
);
} else {
controller.openPopupMenuAction(
context,
position,
popupMenuMailboxActionTiles(
context,
imagePaths,
mailbox,
contextMenuActions,
handleMailboxAction: controller.handleMailboxAction
)
);
}
}
List<PopupMenuEntry> popupMenuMailboxActionTiles( List<PopupMenuEntry> popupMenuMailboxActionTiles(
BuildContext context, BuildContext context,
ImagePaths imagePaths, ImagePaths imagePaths,
@@ -243,20 +151,6 @@ mixin MailboxWidgetMixin {
.toList(); .toList();
} }
static bool isSubaddressingSupported(Session? session, AccountId? accountId) {
if (session == null || accountId == null) {
return false;
}
if (!CapabilityIdentifier.jmapTeamMailboxes.isSupported(session, accountId)) {
return false;
}
return (session.getCapabilityProperties(accountId, CapabilityIdentifier.jmapTeamMailboxes)
?.props[0] as Map<String, dynamic>?)
?[subaddressingSupported]
?? false;
}
PopupMenuItem _buildPopupMenuItem( PopupMenuItem _buildPopupMenuItem(
BuildContext context, BuildContext context,
ImagePaths imagePaths, ImagePaths imagePaths,
@@ -5,7 +5,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_action
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextMenuItemMailboxAction class ContextMenuItemMailboxAction
extends ContextMenuItemAction<MailboxActions> { extends ContextMenuItemActionRequiredIcon<MailboxActions> {
final AppLocalizations appLocalizations; final AppLocalizations appLocalizations;
final ImagePaths imagePaths; final ImagePaths imagePaths;
@@ -16,7 +16,7 @@ class CountOfEmailsWidget extends StatelessWidget {
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: PlatformInfo.isMobile style: PlatformInfo.isMobile
? ThemeUtils.textStyleInter400() ? ThemeUtils.textStyleInter400
: Theme.of(context).textTheme.bodySmall?.copyWith( : Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.black, color: Colors.black,
), ),
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
mixin FilterEmailPopupMenuMixin { mixin FilterEmailPopupMenuMixin {
final _imagePaths = Get.find<ImagePaths>(); final _imagePaths = Get.find<ImagePaths>();
@@ -68,7 +69,7 @@ mixin FilterEmailPopupMenuMixin {
: null), : null),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded(child: Text( Expanded(child: Text(
option.getName(context), option.getName(AppLocalizations.of(context)),
style: const TextStyle( style: const TextStyle(
fontSize: 15, fontSize: 15,
color: Colors.black, color: Colors.black,
@@ -5,7 +5,6 @@ import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:core/utils/platform_info.dart'; import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart';
@@ -22,8 +21,9 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new
import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_email_rule_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_email_rule_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_email_rule_filter_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_email_rule_filter_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_rules_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_rules_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/widgets/email_rule_bottom_sheet_action_tile_builder.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/context_item_email_rule_type_action.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/email_rule_action_type.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/creator_action_type.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/creator_action_type.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
@@ -241,45 +241,41 @@ class EmailRulesController extends BaseController {
} }
void openEditRuleMenuAction(BuildContext context, TMailRule rule) { void openEditRuleMenuAction(BuildContext context, TMailRule rule) {
openContextMenuAction( final contextMenuActions = [
context, EmailRuleActionType.edit,
[ EmailRuleActionType.delete,
_editEmailRuleActionTile(context, rule), ].map((filter) {
_deleteEmailRuleActionTile(context, rule), return ContextItemEmailRuleTypeAction(
], filter,
AppLocalizations.of(context),
imagePaths,
);
}).toList();
openBottomSheetContextMenuAction(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (action) {
popBack();
_handleRuleFilterActionType(context, rule, action.action);
},
); );
} }
Widget _deleteEmailRuleActionTile(BuildContext context, TMailRule rule) { void _handleRuleFilterActionType(
return (EmailRuleBottomSheetActionTileBuilder( BuildContext context,
const Key('delete_emailRule_action'), TMailRule rule,
SvgPicture.asset( EmailRuleActionType actionType,
imagePaths.icDeleteComposer, ) {
colorFilter: AppColor.colorActionDeleteConfirmDialog.asFilter()), switch (actionType) {
AppLocalizations.of(context).deleteRule, case EmailRuleActionType.edit:
rule,
iconLeftPadding: const EdgeInsets.only(left: 12, right: 16),
iconRightPadding: const EdgeInsets.only(right: 12),
textStyleAction: const TextStyle(
fontSize: 17, color: AppColor.colorActionDeleteConfirmDialog),
)..onActionClick((rule) {
popBack();
deleteEmailRule(context, rule);
})).build();
}
Widget _editEmailRuleActionTile(BuildContext context, TMailRule rule) {
return (EmailRuleBottomSheetActionTileBuilder(
const Key('edit_emailRule_action'),
SvgPicture.asset(imagePaths.icEdit),
AppLocalizations.of(context).editRule,
rule,
iconLeftPadding: const EdgeInsets.only(left: 12, right: 16),
iconRightPadding: const EdgeInsets.only(right: 12))
..onActionClick((rule) {
popBack();
editEmailRule(context, rule); editEmailRule(context, rule);
})) break;
.build(); case EmailRuleActionType.delete:
deleteEmailRule(context, rule);
break;
case EmailRuleActionType.add:
break;
}
} }
} }
@@ -0,0 +1,29 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/email_rule_action_type.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemEmailRuleTypeAction
extends ContextMenuItemActionRequiredIcon<EmailRuleActionType> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemEmailRuleTypeAction(
super.action,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionIcon => action.getIcon(imagePaths);
@override
String get actionName => action.getName(appLocalizations);
@override
Color get actionIconColor => action.getIconColor();
@override
Color get actionNameColor => action.getNameColor();
}
@@ -0,0 +1,49 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum EmailRuleActionType {
add,
edit,
delete;
String getName(AppLocalizations appLocalizations) {
switch(this) {
case EmailRuleActionType.add:
return appLocalizations.addNewRule;
case EmailRuleActionType.edit:
return appLocalizations.editRule;
case EmailRuleActionType.delete:
return appLocalizations.deleteRule;
}
}
String getIcon(ImagePaths imagePaths) {
switch(this) {
case EmailRuleActionType.add:
return imagePaths.icAddNewFolder;
case EmailRuleActionType.edit:
return imagePaths.icEdit;
case EmailRuleActionType.delete:
return imagePaths.icDeleteComposer;
}
}
Color getIconColor() {
if (this == EmailRuleActionType.delete) {
return AppColor.redFF3347;
} else {
return AppColor.gray424244.withOpacity(0.72);
}
}
Color getNameColor() {
if (this == EmailRuleActionType.delete) {
return AppColor.redFF3347;
} else {
return AppColor.gray424244.withOpacity(0.79);
}
}
}
@@ -1,51 +1,50 @@
import 'package:flutter/cupertino.dart';
import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition;
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:rule_filter/rule_filter/rule_condition_group.dart' as rule_combiner; import 'package:rule_filter/rule_filter/rule_condition_group.dart' as rule_combiner;
extension RuleConditionFieldExtension on rule_condition.Field { extension RuleConditionFieldExtension on rule_condition.Field {
String getTitle(BuildContext context) { String getTitle(AppLocalizations appLocalizations) {
switch(this) { switch(this) {
case rule_condition.Field.from: case rule_condition.Field.from:
return AppLocalizations.of(context).ruleFilterAddressFromField; return appLocalizations.ruleFilterAddressFromField;
case rule_condition.Field.to: case rule_condition.Field.to:
return AppLocalizations.of(context).ruleFilterAddressToField; return appLocalizations.ruleFilterAddressToField;
case rule_condition.Field.cc: case rule_condition.Field.cc:
return AppLocalizations.of(context).ruleFilterAddressCcField; return appLocalizations.ruleFilterAddressCcField;
case rule_condition.Field.recipient: case rule_condition.Field.recipient:
return AppLocalizations.of(context).recipient; return appLocalizations.recipient;
case rule_condition.Field.subject: case rule_condition.Field.subject:
return AppLocalizations.of(context).subject; return appLocalizations.subject;
} }
} }
} }
extension RuleConditionComparatorExtension on rule_condition.Comparator { extension RuleConditionComparatorExtension on rule_condition.Comparator {
String getTitle(BuildContext context) { String getTitle(AppLocalizations appLocalizations) {
switch(this) { switch(this) {
case rule_condition.Comparator.contains: case rule_condition.Comparator.contains:
return AppLocalizations.of(context).contains; return appLocalizations.contains;
case rule_condition.Comparator.notContains: case rule_condition.Comparator.notContains:
return AppLocalizations.of(context).notContains; return appLocalizations.notContains;
case rule_condition.Comparator.exactlyEquals: case rule_condition.Comparator.exactlyEquals:
return AppLocalizations.of(context).exactlyEquals; return appLocalizations.exactlyEquals;
case rule_condition.Comparator.notExactlyEquals: case rule_condition.Comparator.notExactlyEquals:
return AppLocalizations.of(context).notExactlyEquals; return appLocalizations.notExactlyEquals;
} }
} }
} }
extension RuleConditionCombinerExtension on rule_combiner.ConditionCombiner { extension RuleConditionCombinerExtension on rule_combiner.ConditionCombiner {
String getTitle(BuildContext context) { String getTitle(AppLocalizations appLocalizations) {
switch(this) { switch(this) {
case rule_combiner.ConditionCombiner.AND: case rule_combiner.ConditionCombiner.AND:
return AppLocalizations.of(context).all; return appLocalizations.all;
case rule_combiner.ConditionCombiner.OR: case rule_combiner.ConditionCombiner.OR:
return AppLocalizations.of(context).any; return appLocalizations.any;
} }
} }
} }
@@ -0,0 +1,144 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:rule_filter/rule_filter/rule_condition.dart';
import 'package:rule_filter/rule_filter/rule_condition_group.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/context_menu/context_item_condition_combiner_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/context_menu/context_item_rule_condition_comparator_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/context_menu/context_item_rule_condition_field_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/context_menu/context_item_rule_filter_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.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';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension SelectRuleActionFieldExtension on RulesFilterCreatorController {
void unFocusAllInputField() {
inputRuleNameFocusNode.unfocus();
FocusManager.instance.primaryFocus?.unfocus();
}
void selectRuleConditionCombinerAction(
BuildContext context,
ConditionCombiner conditionCombiner,
) {
unFocusAllInputField();
final contextMenuActions = ConditionCombiner.values.map((filter) {
return ContextItemConditionCombinerAction(
filter,
conditionCombiner,
AppLocalizations.of(context),
imagePaths,
);
}).toList();
openBottomSheetContextMenuAction(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
popBack();
selectConditionCombiner(menuAction.action);
},
);
}
void selectRuleConditionFieldAction(
BuildContext context,
Field? currentField,
Field selectedField,
RuleFilterConditionScreenType screenType,
int index,
) {
if (screenType == RuleFilterConditionScreenType.mobile) {
unFocusAllInputField();
final contextMenuActions = Field.values.map((field) {
return ContextItemRuleConditionFieldAction(
field,
selectedField,
AppLocalizations.of(context),
imagePaths,
);
}).toList();
openBottomSheetContextMenuAction(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
popBack();
updateRuleConditionField(menuAction.action, index);
},
);
} else {
updateRuleConditionField(currentField, index);
}
}
void selectRuleConditionComparatorAction(
BuildContext context,
Comparator? currentComparator,
Comparator selectedComparator,
RuleFilterConditionScreenType screenType,
int index,
) {
if (screenType == RuleFilterConditionScreenType.mobile) {
unFocusAllInputField();
final contextMenuActions = Comparator.values.map((comparator) {
return ContextItemRuleConditionComparatorAction(
comparator,
selectedComparator,
AppLocalizations.of(context),
imagePaths,
);
}).toList();
openBottomSheetContextMenuAction(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
popBack();
updateRuleConditionComparator(menuAction.action, index);
},
);
} else {
updateRuleConditionComparator(currentComparator, index);
}
}
void selectRuleFilterAction(
BuildContext context,
EmailRuleFilterAction? selectedFilterAction,
int index,
) {
final contextMenuActions = EmailRuleFilterAction.values.map((filterAction) {
if (filterAction.isSupported) {
return ContextItemRuleFilterAction(
filterAction,
selectedFilterAction,
AppLocalizations.of(context),
imagePaths,
);
} else {
return null;
}
}).whereNotNull().toList();
if (contextMenuActions.isEmpty) return;
unFocusAllInputField();
openBottomSheetContextMenuAction(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
popBack();
if (menuAction.action !=
listEmailRuleFilterActionSelected[index].action) {
updateEmailRuleFilterAction(context, menuAction.action, index);
}
},
);
}
}
@@ -0,0 +1,24 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:rule_filter/rule_filter/rule_condition_group.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemConditionCombinerAction
extends ContextMenuItemActionRequiredSelectedIcon<ConditionCombiner> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemConditionCombinerAction(
super.action,
super.selectedAction,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionName => action.getTitle(appLocalizations);
@override
String get selectedIcon => imagePaths.icFilterSelected;
}
@@ -0,0 +1,24 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:rule_filter/rule_filter/rule_condition.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemRuleConditionComparatorAction
extends ContextMenuItemActionRequiredSelectedIcon<Comparator> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemRuleConditionComparatorAction(
super.action,
super.selectedAction,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionName => action.getTitle(appLocalizations);
@override
String get selectedIcon => imagePaths.icFilterSelected;
}
@@ -0,0 +1,24 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:rule_filter/rule_filter/rule_condition.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemRuleConditionFieldAction
extends ContextMenuItemActionRequiredSelectedIcon<Field> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemRuleConditionFieldAction(
super.action,
super.selectedAction,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionName => action.getTitle(appLocalizations);
@override
String get selectedIcon => imagePaths.icFilterSelected;
}
@@ -0,0 +1,23 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemRuleFilterAction
extends ContextMenuItemActionRequiredSelectedIcon<EmailRuleFilterAction> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemRuleFilterAction(
super.action,
super.selectedAction,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionName => action.getTitle(appLocalizations);
@override
String get selectedIcon => imagePaths.icFilterSelected;
}
@@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum EmailRuleFilterAction { enum EmailRuleFilterAction {
@@ -9,24 +8,22 @@ enum EmailRuleFilterAction {
markAsSpam, markAsSpam,
forwardTo; forwardTo;
String getTitle(BuildContext context) { String getTitle(AppLocalizations appLocalizations) {
switch(this) { switch(this) {
case EmailRuleFilterAction.moveMessage: case EmailRuleFilterAction.moveMessage:
return AppLocalizations.of(context).moveMessage; return appLocalizations.moveMessage;
case EmailRuleFilterAction.maskAsSeen: case EmailRuleFilterAction.maskAsSeen:
return AppLocalizations.of(context).maskAsSeen; return appLocalizations.maskAsSeen;
case EmailRuleFilterAction.starIt: case EmailRuleFilterAction.starIt:
return AppLocalizations.of(context).starIt; return appLocalizations.starIt;
case EmailRuleFilterAction.rejectIt: case EmailRuleFilterAction.rejectIt:
return AppLocalizations.of(context).rejectIt; return appLocalizations.rejectIt;
case EmailRuleFilterAction.markAsSpam: case EmailRuleFilterAction.markAsSpam:
return AppLocalizations.of(context).markAsSpam; return appLocalizations.markAsSpam;
case EmailRuleFilterAction.forwardTo: case EmailRuleFilterAction.forwardTo:
return AppLocalizations.of(context).forwardTo; return appLocalizations.forwardTo;
} }
} }
bool getSupported() { bool get isSupported => this != EmailRuleFilterAction.forwardTo;
return this != EmailRuleFilterAction.forwardTo;
}
} }
@@ -66,7 +66,7 @@ class RulesFilterCreatorController extends BaseMailboxController {
final TextEditingController forwardEmailController = TextEditingController(); final TextEditingController forwardEmailController = TextEditingController();
final FocusNode forwardEmailFocusNode = FocusNode(); final FocusNode forwardEmailFocusNode = FocusNode();
final listEmailRuleFilterActionSelected = RxList<RuleFilterActionArguments>(); final listEmailRuleFilterActionSelected = RxList<RuleFilterActionArguments>();
int maxCountAction = EmailRuleFilterAction.values.where((action) => action.getSupported() == true).length - 1; int maxCountAction = EmailRuleFilterAction.values.where((action) => action.isSupported).length - 1;
final isShowAddAction = Rxn<bool>(); final isShowAddAction = Rxn<bool>();
String? _newRuleName; String? _newRuleName;
@@ -330,7 +330,7 @@ class RulesFilterCreatorController extends BaseMailboxController {
); );
} }
void selectRuleConditionField(rule_condition.Field? newField, int? ruleConditionIndex) { void updateRuleConditionField(rule_condition.Field? newField, int? ruleConditionIndex) {
if (newField != null && ruleConditionIndex != null) { if (newField != null && ruleConditionIndex != null) {
RuleCondition newRuleCondition = RuleCondition( RuleCondition newRuleCondition = RuleCondition(
field: newField, field: newField,
@@ -342,7 +342,7 @@ class RulesFilterCreatorController extends BaseMailboxController {
} }
} }
void selectRuleConditionComparator(rule_condition.Comparator? newComparator, int? ruleConditionIndex) { void updateRuleConditionComparator(rule_condition.Comparator? newComparator, int? ruleConditionIndex) {
if (newComparator != null && ruleConditionIndex != null) { if (newComparator != null && ruleConditionIndex != null) {
RuleCondition newRuleCondition = RuleCondition( RuleCondition newRuleCondition = RuleCondition(
field: listRuleCondition[ruleConditionIndex].field, field: listRuleCondition[ruleConditionIndex].field,
@@ -354,7 +354,7 @@ class RulesFilterCreatorController extends BaseMailboxController {
} }
} }
void selectEmailRuleFilterAction( void updateEmailRuleFilterAction(
BuildContext context, BuildContext context,
EmailRuleFilterAction? newAction, EmailRuleFilterAction? newAction,
int ruleFilterActionIndex int ruleFilterActionIndex
@@ -3,24 +3,16 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition;
import 'package:rule_filter/rule_filter/rule_condition_group.dart'; import 'package:rule_filter/rule_filter/rule_condition_group.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.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/email_rule_filter_action.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'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_action_bottom_sheet_action_tile_builder.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_condition_combiner_bottomsheet_action_tile_builder.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_condition_comparator_bottom_sheet_action_tile_builder.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_condition_field_bottom_sheet_action_tile_builder.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_list.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_list.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_title_builder.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_title_builder.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_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';
import 'model/rule_filter_condition_type.dart';
class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> { class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> {
@@ -183,7 +175,7 @@ class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> {
responsiveUtils: controller.responsiveUtils, responsiveUtils: controller.responsiveUtils,
actionList: controller.listEmailRuleFilterActionSelected, actionList: controller.listEmailRuleFilterActionSelected,
onActionChanged: (newAction, index) { onActionChanged: (newAction, index) {
controller.selectEmailRuleFilterAction(context, newAction, index); controller.updateEmailRuleFilterAction(context, newAction, index);
}, },
forwardEmailEditingController: controller.forwardEmailController, forwardEmailEditingController: controller.forwardEmailController,
forwardEmailFocusNode: controller.forwardEmailFocusNode, forwardEmailFocusNode: controller.forwardEmailFocusNode,
@@ -344,7 +336,7 @@ class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> {
responsiveUtils: controller.responsiveUtils, responsiveUtils: controller.responsiveUtils,
actionList: controller.listEmailRuleFilterActionSelected, actionList: controller.listEmailRuleFilterActionSelected,
onActionChanged: (newAction, index) { onActionChanged: (newAction, index) {
controller.selectEmailRuleFilterAction(context, newAction, index); controller.updateEmailRuleFilterAction(context, newAction, index);
}, },
forwardEmailEditingController: controller.forwardEmailController, forwardEmailEditingController: controller.forwardEmailController,
forwardEmailFocusNode: controller.forwardEmailFocusNode, forwardEmailFocusNode: controller.forwardEmailFocusNode,
@@ -463,14 +455,12 @@ class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> {
Obx(() => RuleFilterTitle( Obx(() => RuleFilterTitle(
conditionCombinerType: controller.conditionCombinerType.value, conditionCombinerType: controller.conditionCombinerType.value,
ruleFilterConditionScreenType: RuleFilterConditionScreenType.mobile, ruleFilterConditionScreenType: RuleFilterConditionScreenType.mobile,
tapActionCallback: (value) => { tapActionCallback: (_) {
controller.openContextMenuAction( controller.selectRuleConditionCombinerAction(
context, context,
_bottomSheetRuleConditionCombinerActionTiles( controller.conditionCombinerType.value
context, ?? ConditionCombiner.AND,
controller.conditionCombinerType.value, );
)
),
}, },
)), )),
const SizedBox(height: 24), const SizedBox(height: 24),
@@ -519,14 +509,10 @@ class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> {
responsiveUtils: controller.responsiveUtils, responsiveUtils: controller.responsiveUtils,
actionList: controller.listEmailRuleFilterActionSelected, actionList: controller.listEmailRuleFilterActionSelected,
onActionChangeMobile: (currentAction, index) { onActionChangeMobile: (currentAction, index) {
KeyboardUtils.hideKeyboard(context); controller.selectRuleFilterAction(
controller.openContextMenuAction(
context, context,
_bottomSheetActionRuleFilterActionTiles( currentAction,
context, index
currentAction,
index
)
); );
}, },
forwardEmailEditingController: controller.forwardEmailController, forwardEmailEditingController: controller.forwardEmailController,
@@ -631,34 +617,22 @@ class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> {
conditionValueErrorText: controller.listRuleConditionValueArguments[index].errorText, conditionValueErrorText: controller.listRuleConditionValueArguments[index].errorText,
conditionValueFocusNode: controller.listRuleConditionValueArguments[index].focusNode, conditionValueFocusNode: controller.listRuleConditionValueArguments[index].focusNode,
conditionValueEditingController: controller.listRuleConditionValueArguments[index].controller, conditionValueEditingController: controller.listRuleConditionValueArguments[index].controller,
tapRuleConditionFieldCallback: (value) => { tapRuleConditionFieldCallback: (value) =>
if (ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile) { controller.selectRuleConditionFieldAction(
controller.openContextMenuAction(
context, context,
_bottomSheetRuleConditionFieldActionTiles( value,
context, controller.listRuleCondition[index].field,
controller.listRuleCondition[index].field, ruleFilterConditionScreenType,
index, index,
)
), ),
} else { tapRuleConditionComparatorCallback: (value) =>
controller.selectRuleConditionField(value, index) controller.selectRuleConditionComparatorAction(
}
},
tapRuleConditionComparatorCallback: (value) => {
if (ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile) {
controller.openContextMenuAction(
context, context,
_bottomSheetRuleConditionComparatorActionTiles( value,
context, controller.listRuleCondition[index].comparator,
controller.listRuleCondition[index].comparator, ruleFilterConditionScreenType,
index, index,
)
), ),
} else {
controller.selectRuleConditionComparator(value, index),
}
},
conditionValueOnChangeAction: (value) => conditionValueOnChangeAction: (value) =>
controller.updateConditionValue(context, value, index), controller.updateConditionValue(context, value, index),
tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index),
@@ -670,147 +644,4 @@ class RuleFilterCreatorView extends GetWidget<RulesFilterCreatorController> {
); );
}); });
} }
List<Widget> _bottomSheetRuleConditionFieldActionTiles(
BuildContext context,
rule_condition.Field? fieldSelected,
int? ruleConditionIndex,
) {
return rule_condition.Field.values
.map((field) =>
_buildRuleConditionFieldWidget(context, field, fieldSelected, ruleConditionIndex))
.toList();
}
Widget _buildRuleConditionFieldWidget(
BuildContext context,
rule_condition.Field field,
rule_condition.Field? fieldSelected,
int? ruleConditionIndex,
) {
return (RuleConditionFieldSheetActionTileBuilder(
field.getTitle(context),
fieldSelected,
field,
iconLeftPadding: const EdgeInsets.only(left: 12, right: 16),
iconRightPadding: const EdgeInsets.only(right: 12),
actionSelected: SvgPicture.asset(
controller.imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill))
..onActionClick((field) {
controller.selectRuleConditionField(field, ruleConditionIndex);
popBack();
}))
.build();
}
List<Widget> _bottomSheetRuleConditionComparatorActionTiles(
BuildContext context,
rule_condition.Comparator? comparatorSelected,
int? ruleConditionIndex,
) {
return rule_condition.Comparator.values
.map((comparator) =>
_buildRuleConditionComparatorWidget(context, comparator, comparatorSelected, ruleConditionIndex))
.toList();
}
Widget _buildRuleConditionComparatorWidget(
BuildContext context,
rule_condition.Comparator comparator,
rule_condition.Comparator? comparatorSelected,
int? ruleConditionIndex,
) {
return (RuleConditionComparatorSheetActionTileBuilder(
comparator.getTitle(context),
comparatorSelected,
comparator,
iconLeftPadding: const EdgeInsets.only(left: 12, right: 16),
iconRightPadding: const EdgeInsets.only(right: 12),
actionSelected: SvgPicture.asset(
controller.imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill))
..onActionClick((comparator) {
controller.selectRuleConditionComparator(comparator, ruleConditionIndex);
popBack();
}))
.build();
}
List<Widget> _bottomSheetRuleConditionCombinerActionTiles(
BuildContext context,
ConditionCombiner? combinerSelected,
) {
return ConditionCombiner.values
.map((combiner) =>
_buildRuleConditionCombinerWidget(context, combiner, combinerSelected))
.toList();
}
Widget _buildRuleConditionCombinerWidget(
BuildContext context,
ConditionCombiner combiner,
ConditionCombiner? combinerSelected,
) {
return (RuleConditionCombinerSheetActionTileBuilder(
combiner.getTitle(context),
combiner,
combinerSelected,
iconLeftPadding: const EdgeInsets.only(left: 12, right: 16),
iconRightPadding: const EdgeInsets.only(right: 12),
actionSelected: SvgPicture.asset(
controller.imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill))
..onActionClick((combiner) {
controller.selectConditionCombiner(combiner);
popBack();
}))
.build();
}
List<Widget> _bottomSheetActionRuleFilterActionTiles(
BuildContext context,
EmailRuleFilterAction? ruleActionSelected,
int ruleActionIndex,
) {
final supportedAction = EmailRuleFilterAction.values
.where((ruleAction) => ruleAction.getSupported() == true)
.toList();
return supportedAction
.map((ruleAction) =>
_buildRuleActionWidget(context, ruleAction, ruleActionSelected, ruleActionIndex))
.toList();
}
Widget _buildRuleActionWidget(
BuildContext context,
EmailRuleFilterAction ruleAction,
EmailRuleFilterAction? ruleActionSelected,
int ruleActionIndex,
) {
return (RuleActionSheetActionTileBuilder(
ruleAction.getTitle(context),
ruleActionSelected,
ruleAction,
iconLeftPadding: const EdgeInsets.only(left: 12, right: 16),
iconRightPadding: const EdgeInsets.only(right: 12),
actionSelected: SvgPicture.asset(
controller.imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill))
..onActionClick((ruleAction) {
if (ruleAction != controller.listEmailRuleFilterActionSelected[ruleActionIndex].action) {
controller.selectEmailRuleFilterAction(context, ruleAction, ruleActionIndex);
}
popBack();
}))
.build();
}
} }
@@ -40,7 +40,7 @@ class RuleFilterActionRow extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final supportedAction = actionList.where((action) => action.getSupported() == true).toList(); final supportedAction = actionList.where((action) => action.isSupported).toList();
return Row( return Row(
crossAxisAlignment: actionSelected == EmailRuleFilterAction.moveMessage ? CrossAxisAlignment.center : CrossAxisAlignment.start, crossAxisAlignment: actionSelected == EmailRuleFilterAction.moveMessage ? CrossAxisAlignment.center : CrossAxisAlignment.start,
children: [ children: [
@@ -11,6 +11,7 @@ import 'package:rule_filter/rule_filter/rule_condition_group.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnTapActionCallback<T> = Function(T? value); typedef OnTapActionCallback<T> = Function(T? value);
@@ -63,20 +64,22 @@ class RuleFilterButtonField<T> extends StatelessWidget {
} }
String _getName(BuildContext context, T? value) { String _getName(BuildContext context, T? value) {
final appLocalizations = AppLocalizations.of(context);
if (value is PresentationMailbox) { if (value is PresentationMailbox) {
return value.getDisplayName(context); return value.getDisplayName(context);
} }
if (value is rule_condition.Field) { if (value is rule_condition.Field) {
return value.getTitle(context); return value.getTitle(appLocalizations);
} }
if (value is rule_condition.Comparator) { if (value is rule_condition.Comparator) {
return value.getTitle(context); return value.getTitle(appLocalizations);
} }
if (value is EmailRuleFilterAction) { if (value is EmailRuleFilterAction) {
return value.getTitle(context); return value.getTitle(appLocalizations);
} }
if (value is ConditionCombiner) { if (value is ConditionCombiner) {
return value.getTitle(context); return value.getTitle(appLocalizations);
} }
return hintText ?? ''; return hintText ?? '';
} }
@@ -36,9 +36,8 @@ extension HandleEmailMoreActionExtension on SearchEmailController {
)) ))
.toList(); .toList();
openContextMenuAction( openBottomSheetContextMenuAction(
context, context: context,
[],
itemActions: contextMenuActions, itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) { onContextMenuActionClick: (menuAction) {
pressEmailAction( pressEmailAction(
@@ -0,0 +1,23 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemReceiveTimeTypeAction
extends ContextMenuItemActionRequiredSelectedIcon<EmailReceiveTimeType> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemReceiveTimeTypeAction(
super.action,
super.selectedAction,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionName => action.getTitleByAppLocalizations(appLocalizations);
@override
String get selectedIcon => imagePaths.icFilterSelected;
}
@@ -0,0 +1,23 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemSortOrderTypeAction
extends ContextMenuItemActionRequiredSelectedIcon<EmailSortOrderType> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemSortOrderTypeAction(
super.action,
super.selectedAction,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionName => action.getTitleByAppLocalizations(appLocalizations);
@override
String get selectedIcon => imagePaths.icFilterSelected;
}
@@ -22,15 +22,15 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/qu
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/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/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/extension/handle_email_more_action_extension.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/context_item_receive_time_type_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/context_item_sort_order_type_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/search_more_state.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/search_email_controller.dart';
import 'package:tmail_ui_user/features/search/email/presentation/styles/search_email_view_style.dart'; import 'package:tmail_ui_user/features/search/email/presentation/styles/search_email_view_style.dart';
import 'package:tmail_ui_user/features/search/email/presentation/utils/search_email_utils.dart'; import 'package:tmail_ui_user/features/search/email/presentation/utils/search_email_utils.dart';
import 'package:tmail_ui_user/features/search/email/presentation/widgets/app_bar_selection_mode.dart'; import 'package:tmail_ui_user/features/search/email/presentation/widgets/app_bar_selection_mode.dart';
import 'package:tmail_ui_user/features/search/email/presentation/widgets/email_receive_time_action_tile_widget.dart'; import 'package:tmail_ui_user/features/search/email/presentation/widgets/email_receive_time_action_tile_widget.dart';
import 'package:tmail_ui_user/features/search/email/presentation/widgets/email_receive_time_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/search/email/presentation/widgets/email_sort_by_action_tile_widget.dart'; import 'package:tmail_ui_user/features/search/email/presentation/widgets/email_sort_by_action_tile_widget.dart';
import 'package:tmail_ui_user/features/search/email/presentation/widgets/email_sort_by_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/search/email/presentation/widgets/empty_search_email_widget.dart'; import 'package:tmail_ui_user/features/search/email/presentation/widgets/empty_search_email_widget.dart';
import 'package:tmail_ui_user/features/search/email/presentation/widgets/search_email_loading_bar_widget.dart'; import 'package:tmail_ui_user/features/search/email/presentation/widgets/search_email_loading_bar_widget.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
@@ -352,17 +352,25 @@ class SearchEmailView extends GetWidget<SearchEmailController>
} }
void _openContextMenuDateFilter(BuildContext context) { void _openContextMenuDateFilter(BuildContext context) {
controller.openContextMenuAction( final contextMenuActions = EmailReceiveTimeType.values.map((timeType) {
context, return ContextItemReceiveTimeTypeAction(
_emailReceiveTimeCupertinoActionTile( timeType,
context,
controller.emailReceiveTimeType.value, controller.emailReceiveTimeType.value,
(receiveTime) => controller.selectReceiveTimeQuickSearchFilter( AppLocalizations.of(context),
context, controller.imagePaths,
receiveTime );
) }).toList();
),
controller.openBottomSheetContextMenuAction(
key: const Key('date_time_filter_context_menu'), key: const Key('date_time_filter_context_menu'),
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
controller.selectReceiveTimeQuickSearchFilter(
context,
menuAction.action,
);
},
); );
} }
@@ -379,14 +387,25 @@ class SearchEmailView extends GetWidget<SearchEmailController>
} }
void _openContextMenuSortFilter(BuildContext context) { void _openContextMenuSortFilter(BuildContext context) {
controller.openContextMenuAction( final contextMenuActions = EmailSortOrderType.values.map((orderType) {
context, return ContextItemSortOrderTypeAction(
_emailSortOrderCupertinoActionTitle( orderType,
context,
controller.emailSortOrderType.value, controller.emailSortOrderType.value,
controller.selectSortOrderQuickSearchFilter AppLocalizations.of(context),
), controller.imagePaths,
key: const Key('sort_filter_context_menu') );
}).toList();
controller.openBottomSheetContextMenuAction(
key: const Key('sort_filter_context_menu'),
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
controller.selectSortOrderQuickSearchFilter(
context,
menuAction.action,
);
},
); );
} }
@@ -406,32 +425,6 @@ class SearchEmailView extends GetWidget<SearchEmailController>
.toList(); .toList();
} }
List<Widget> _emailReceiveTimeCupertinoActionTile(
BuildContext context,
EmailReceiveTimeType? receiveTimeSelected,
Function(EmailReceiveTimeType)? onCallBack
) {
return EmailReceiveTimeType.values
.map((timeType) => (EmailReceiveTimeCupertinoActionSheetActionBuilder(
timeType.getTitle(context),
timeType,
timeTypeCurrent: receiveTimeSelected,
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(end: 12)
: EdgeInsets.zero,
actionSelected: SvgPicture.asset(
controller.imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill))
..onActionClick((timeType) => onCallBack?.call(timeType)))
.build())
.toList();
}
List<PopupMenuEntry> _popupMenuEmailSortOrderType( List<PopupMenuEntry> _popupMenuEmailSortOrderType(
BuildContext context, BuildContext context,
EmailSortOrderType? sortTypeSelected, EmailSortOrderType? sortTypeSelected,
@@ -449,36 +442,6 @@ class SearchEmailView extends GetWidget<SearchEmailController>
)).toList(); )).toList();
} }
List<Widget> _emailSortOrderCupertinoActionTitle(
BuildContext context,
EmailSortOrderType? sortOrderSelected,
Function(BuildContext context, EmailSortOrderType)? onCallBack,
) {
return EmailSortOrderType.values
.map(
(sortType) => (
EmailSortByCupertinoActionSheetActionBuilder(
sortType.getTitle(context),
sortType,
sortTypeCurrent: sortOrderSelected,
iconLeftPadding: controller.responsiveUtils.isMobile(context)
? const EdgeInsetsDirectional.only(start: 12, end: 16)
: const EdgeInsetsDirectional.only(start: 12),
iconRightPadding: controller.responsiveUtils.isMobile(context)
? const EdgeInsetsDirectional.only(end: 12)
: EdgeInsetsDirectional.zero,
actionSelected: SvgPicture.asset(
controller.imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill
)
)
..onActionClick((sortType) => onCallBack?.call(context, sortType))
).build()
).toList();
}
Widget _buildShowAllResultSearchButton(BuildContext context, String textSearch) { Widget _buildShowAllResultSearchButton(BuildContext context, String textSearch) {
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
@@ -283,9 +283,8 @@ class SearchMailboxView extends GetWidget<SearchMailboxController>
} }
if (controller.responsiveUtils.isScreenWithShortestSide(context) || position == null) { if (controller.responsiveUtils.isScreenWithShortestSide(context) || position == null) {
controller.openContextMenuAction( controller.openBottomSheetContextMenuAction(
context, context: context,
[],
itemActions: contextMenuActions, itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) => controller.handleMailboxAction( onContextMenuActionClick: (menuAction) => controller.handleMailboxAction(
context, context,
@@ -79,16 +79,16 @@ extension FilterMessageOptionExtension on FilterMessageOption {
} }
} }
String getName(BuildContext context) { String getName(AppLocalizations appLocalizations) {
switch(this) { switch(this) {
case FilterMessageOption.all: case FilterMessageOption.all:
return ''; return '';
case FilterMessageOption.unread: case FilterMessageOption.unread:
return AppLocalizations.of(context).unread; return appLocalizations.unread;
case FilterMessageOption.attachments: case FilterMessageOption.attachments:
return AppLocalizations.of(context).with_attachments; return appLocalizations.with_attachments;
case FilterMessageOption.starred: case FilterMessageOption.starred:
return AppLocalizations.of(context).starred; return appLocalizations.starred;
} }
} }
@@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/context_item_filter_message_option_action.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension HandleSelectMessageFilterExtension on ThreadController {
void handleSelectMessageFilter(
BuildContext context,
FilterMessageOption selectedOption,
) {
final contextMenuActions = [
FilterMessageOption.attachments,
FilterMessageOption.unread,
FilterMessageOption.starred,
].map((filter) {
return ContextItemFilterMessageOptionAction(
filter,
selectedOption,
AppLocalizations.of(context),
imagePaths,
);
}).toList();
openBottomSheetContextMenuAction(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (action) => filterMessagesAction(action.action),
);
}
}
@@ -0,0 +1,26 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ContextItemFilterMessageOptionAction
extends ContextMenuItemActionRequiredFull<FilterMessageOption> {
final AppLocalizations appLocalizations;
final ImagePaths imagePaths;
ContextItemFilterMessageOptionAction(
super.action,
super.selectedAction,
this.appLocalizations,
this.imagePaths,
);
@override
String get actionIcon => action.getContextMenuIcon(imagePaths);
@override
String get actionName => action.getName(appLocalizations);
@override
String get selectedIcon => imagePaths.icFilterSelected;
}
@@ -28,6 +28,7 @@ import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_st
import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/handle_pull_to_refresh_list_email_extension.dart'; import 'package:tmail_ui_user/features/thread/presentation/extensions/handle_pull_to_refresh_list_email_extension.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/handle_select_message_filter_extension.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/loading_more_status.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/loading_more_status.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_tile_styles.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_tile_styles.dart';
@@ -39,7 +40,6 @@ import 'package:tmail_ui_user/features/thread/presentation/widgets/bottom_bar_th
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart' 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'; if (dart.library.html) 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_web_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/empty_emails_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/empty_emails_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/filter_message_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/scroll_to_top_button_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/scroll_to_top_button_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/spam_banner/spam_report_banner_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/spam_banner/spam_report_banner_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/thread_view_loading_bar_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/thread_view_loading_bar_widget.dart';
@@ -84,10 +84,7 @@ class ThreadView extends GetWidget<ThreadController>
cancelEditThreadAction: controller.cancelSelectEmail, cancelEditThreadAction: controller.cancelSelectEmail,
emailSelectionAction: controller.pressEmailSelectionAction, emailSelectionAction: controller.pressEmailSelectionAction,
onContextMenuFilterEmailAction: controller.responsiveUtils.isScreenWithShortestSide(context) onContextMenuFilterEmailAction: controller.responsiveUtils.isScreenWithShortestSide(context)
? (filterOption) => controller.openContextMenuAction( ? (filterOption) => controller.handleSelectMessageFilter(context, filterOption)
context,
_filterMessagesCupertinoActionTile(context, filterOption)
)
: null, : null,
onPopupMenuFilterEmailAction: !controller.responsiveUtils.isScreenWithShortestSide(context) onPopupMenuFilterEmailAction: !controller.responsiveUtils.isScreenWithShortestSide(context)
? (filterOption, position) => controller.openPopupMenuAction( ? (filterOption, position) => controller.openPopupMenuAction(
@@ -342,41 +339,6 @@ class ThreadView extends GetWidget<ThreadController>
}); });
} }
List<Widget> _filterMessagesCupertinoActionTile(BuildContext context, FilterMessageOption optionCurrent) {
final listFilter = [
FilterMessageOption.attachments,
FilterMessageOption.unread,
FilterMessageOption.starred,
];
return listFilter.map((filter) => (FilterMessageCupertinoActionSheetActionBuilder(
Key('filter_email_${filter.name}'),
SvgPicture.asset(
filter.getContextMenuIcon(controller.imagePaths),
width: 20,
height: 20,
fit: BoxFit.fill,
colorFilter: filter == FilterMessageOption.attachments
? AppColor.colorTextButton.asFilter()
: null),
filter.getName(context),
filter,
optionCurrent: optionCurrent,
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,
actionSelected: SvgPicture.asset(
controller.imagePaths.icFilterSelected,
width: 20,
height: 20,
fit: BoxFit.fill))
..onActionClick(controller.filterMessagesAction))
.build()).toList();
}
Widget _buildResultListEmail(BuildContext context, List<PresentationEmail> listPresentationEmail) { Widget _buildResultListEmail(BuildContext context, List<PresentationEmail> listPresentationEmail) {
return listPresentationEmail.isNotEmpty return listPresentationEmail.isNotEmpty
? _buildListEmailBody(context, listPresentationEmail) ? _buildListEmailBody(context, listPresentationEmail)
@@ -685,9 +647,8 @@ class ThreadView extends GetWidget<ThreadController>
)) ))
.toList(); .toList();
controller.openContextMenuAction( controller.openBottomSheetContextMenuAction(
context, context: context,
[],
itemActions: contextMenuActions, itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) { onContextMenuActionClick: (menuAction) {
controller.handleEmailActionType( controller.handleEmailActionType(
@@ -52,7 +52,7 @@ class EmptyEmailsWidget extends StatelessWidget {
Text( Text(
key: const Key('empty_email_sub_message'), key: const Key('empty_email_sub_message'),
AppLocalizations.of(context).startToComposeEmails, AppLocalizations.of(context).startToComposeEmails,
style: ThemeUtils.textStyleInter400().copyWith( style: ThemeUtils.textStyleInter400.copyWith(
letterSpacing: -0.15, letterSpacing: -0.15,
fontSize: 16, fontSize: 16,
height: 21.01 / 16, height: 21.01 / 16,