From 0bd60ea83d0f7fd6eba3264151de6e4287670b5f Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 2 Oct 2025 13:25:29 +0700 Subject: [PATCH] TF-3911 Add Keyboard shortcuts dictionary in Setting --- assets/images/ic_keyboard.svg | 3 + assets/images/ic_message.svg | 5 + assets/images/ic_navigation.svg | 5 + assets/images/ic_reading.svg | 5 + .../extensions/color_extension.dart | 1 + .../presentation/resources/image_paths.dart | 4 + .../keyboard_shortcut_extension.dart | 66 ++++++ .../keyboard_shortcuts_view.dart | 190 +++++++++++++++ .../shortcut_category_list_widget.dart | 24 ++ .../widgets/shortcut_key_widget.dart | 30 +++ .../widgets/shortcut_row_widget.dart | 47 ++++ .../widgets/shortcut_tab_bar_widget.dart | 79 +++++++ .../manage_account_dashboard_view.dart | 3 + .../menu/manage_account_menu_controller.dart | 6 +- .../menu/settings/settings_controller.dart | 13 +- .../settings/settings_first_level_view.dart | 223 +++++++----------- .../menu/settings/settings_view.dart | 3 + .../presentation/menu/settings_utils.dart | 13 + .../setting_first_level_tile_builder.dart | 8 +- .../presentation/model/account_menu_item.dart | 11 + .../keyboard_shortcuts/keyboard_shortcut.dart | 38 +++ .../keyboard_shortcuts_manager.dart | 96 ++++++++ lib/l10n/intl_messages.arb | 122 +++++++++- lib/main/localizations/app_localizations.dart | 133 +++++++++++ pubspec.lock | 8 + pubspec.yaml | 2 + 26 files changed, 991 insertions(+), 147 deletions(-) create mode 100644 assets/images/ic_keyboard.svg create mode 100644 assets/images/ic_message.svg create mode 100644 assets/images/ic_navigation.svg create mode 100644 assets/images/ic_reading.svg create mode 100644 lib/features/manage_account/presentation/extensions/keyboard_shortcut_extension.dart create mode 100644 lib/features/manage_account/presentation/keyboard_shortcuts/keyboard_shortcuts_view.dart create mode 100644 lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_category_list_widget.dart create mode 100644 lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_key_widget.dart create mode 100644 lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_row_widget.dart create mode 100644 lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_tab_bar_widget.dart create mode 100644 lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart create mode 100644 lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcuts_manager.dart diff --git a/assets/images/ic_keyboard.svg b/assets/images/ic_keyboard.svg new file mode 100644 index 000000000..ae335c58b --- /dev/null +++ b/assets/images/ic_keyboard.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_message.svg b/assets/images/ic_message.svg new file mode 100644 index 000000000..55504f9ec --- /dev/null +++ b/assets/images/ic_message.svg @@ -0,0 +1,5 @@ + + + diff --git a/assets/images/ic_navigation.svg b/assets/images/ic_navigation.svg new file mode 100644 index 000000000..82b8c5908 --- /dev/null +++ b/assets/images/ic_navigation.svg @@ -0,0 +1,5 @@ + + + diff --git a/assets/images/ic_reading.svg b/assets/images/ic_reading.svg new file mode 100644 index 000000000..8e7e76b50 --- /dev/null +++ b/assets/images/ic_reading.svg @@ -0,0 +1,5 @@ + + + diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 9304e58e9..93557e81e 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -255,6 +255,7 @@ extension AppColor on Color { static const iconFolder = Color(0xFF297EF2); static const folderDivider = Color(0xFFE4E8EC); static const gray424244 = Color(0xFF424244); + static const gray200 = Color(0xFFCCCCCC); static const lightGrayF4F4F4 = Color(0xFFF4F4F4); static const gray959DAD = Color(0xFF959DAD); static const gray9AA7B6 = Color(0xFF9AA7B6); diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index edf946446..2a5d2cb7e 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -251,6 +251,10 @@ class ImagePaths { String get icNoRules => _getImagePath('ic_no_rules.svg'); String get icStorage => _getImagePath('ic_storage.svg'); String get icWarning => _getImagePath('ic_warning.svg'); + String get icKeyboard => _getImagePath('ic_keyboard.svg'); + String get icMessage => _getImagePath('ic_message.svg'); + String get icNavigation => _getImagePath('ic_navigation.svg'); + String get icReading => _getImagePath('ic_reading.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/manage_account/presentation/extensions/keyboard_shortcut_extension.dart b/lib/features/manage_account/presentation/extensions/keyboard_shortcut_extension.dart new file mode 100644 index 000000000..c1dfff28c --- /dev/null +++ b/lib/features/manage_account/presentation/extensions/keyboard_shortcut_extension.dart @@ -0,0 +1,66 @@ +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +extension ShortcutContextText on ShortcutContext { + String getDisplayName(AppLocalizations appLocalizations) { + switch (this) { + case ShortcutContext.mailComposer: + return appLocalizations.mailComposer; + case ShortcutContext.focusOnSearch: + return appLocalizations.focusOnSearch; + case ShortcutContext.openedModal: + return appLocalizations.openedModal; + case ShortcutContext.mailboxList: + return appLocalizations.mailboxList; + case ShortcutContext.openedMailView: + return appLocalizations.openedMailView; + case ShortcutContext.mailboxListWithSelectedEmail: + return appLocalizations.mailboxListWithSelectedMail; + } + } +} + +extension ShortcutCategoryText on ShortcutCategory { + String getDisplayName( + AppLocalizations appLocalizations, { + bool isDesktop = false, + }) { + switch (this) { + case ShortcutCategory.navigationAndClosing: + return !isDesktop + ? appLocalizations.navigation + : appLocalizations.navigationAndClosing; + case ShortcutCategory.readingAndReplying: + return !isDesktop + ? appLocalizations.reading + : appLocalizations.readingAndReplying; + case ShortcutCategory.messageManagementAndSelection: + return !isDesktop + ? appLocalizations.message + : appLocalizations.messageManagementAndSelection; + } + } + + String getIcon(ImagePaths imagePaths) { + switch (this) { + case ShortcutCategory.navigationAndClosing: + return imagePaths.icNavigation; + case ShortcutCategory.readingAndReplying: + return imagePaths.icReading; + case ShortcutCategory.messageManagementAndSelection: + return imagePaths.icMessage; + } + } + + double getTabWidth() { + switch (this) { + case ShortcutCategory.navigationAndClosing: + return 174; + case ShortcutCategory.readingAndReplying: + return 164; + case ShortcutCategory.messageManagementAndSelection: + return 280; + } + } +} diff --git a/lib/features/manage_account/presentation/keyboard_shortcuts/keyboard_shortcuts_view.dart b/lib/features/manage_account/presentation/keyboard_shortcuts/keyboard_shortcuts_view.dart new file mode 100644 index 000000000..ff9520b20 --- /dev/null +++ b/lib/features/manage_account/presentation/keyboard_shortcuts/keyboard_shortcuts_view.dart @@ -0,0 +1,190 @@ +import 'package:core/presentation/extensions/color_extension.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:flutter/material.dart'; +import 'package:flutter_custom_tab_bar/custom_tab_bar.dart'; +import 'package:flutter_custom_tab_bar/indicator/custom_indicator.dart'; +import 'package:flutter_custom_tab_bar/indicator/linear_indicator.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/base/setting_detail_view_builder.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/extensions/keyboard_shortcut_extension.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_category_list_widget.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_tab_bar_widget.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcuts_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/widgets/setting_explanation_widget.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/widgets/setting_header_widget.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class KeyboardShortcutsView extends StatefulWidget { + const KeyboardShortcutsView({Key? key}) : super(key: key); + + @override + State createState() => _KeyboardShortcutsViewState(); +} + +class _KeyboardShortcutsViewState extends State { + static const double _desktopTabViewMaxWidth = 618; + + final _responsiveUtils = Get.find(); + final _imagePaths = Get.find(); + final _categories = ShortcutCategory.values; + + late final CustomTabBarController _tabBarController; + late final PageController _pageController; + + @override + void initState() { + super.initState(); + _tabBarController = CustomTabBarController(); + _pageController = PageController(); + } + + @override + void dispose() { + _pageController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final appLocalizations = AppLocalizations.of(context); + final allShortcuts = KeyboardShortcutsManager.generateKeyboardShortcuts( + appLocalizations, + ); + final isDesktop = _responsiveUtils.isDesktop(context); + double tabBarMaxHeight = isDesktop ? 52 : 82; + + return SettingDetailViewBuilder( + responsiveUtils: _responsiveUtils, + child: Container( + color: SettingsUtils.getContentBackgroundColor( + context, + _responsiveUtils, + ), + decoration: SettingsUtils.getBoxDecorationForContent( + context, + _responsiveUtils, + ), + width: double.infinity, + padding: isDesktop + ? const EdgeInsets.symmetric(vertical: 30, horizontal: 22) + : null, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_responsiveUtils.isWebDesktop(context)) + SettingHeaderWidget( + menuItem: AccountMenuItem.keyboardShortcuts, + textStyle: ThemeUtils.textStyleInter600().copyWith( + color: Colors.black.withValues(alpha: 0.9), + ), + padding: EdgeInsets.zero, + ) + else + const SettingExplanationWidget( + menuItem: AccountMenuItem.keyboardShortcuts, + padding: EdgeInsetsDirectional.only( + start: 16, + end: 16, + bottom: 16, + ), + isCenter: true, + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: SettingsUtils.getBodyPadding( + context, + _responsiveUtils, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LayoutBuilder( + builder: (context, constraints) { + final maxWidth = constraints.maxWidth; + final countCategories = _categories.length; + + return Stack( + children: [ + CustomTabBar( + tabBarController: _tabBarController, + height: tabBarMaxHeight, + width: isDesktop + ? _desktopTabViewMaxWidth + : maxWidth, + itemCount: countCategories, + builder: (_, index) { + final category = _categories[index]; + return ShortcutTabBarWidget( + index: index, + label: category.getDisplayName( + appLocalizations, + isDesktop: isDesktop, + ), + icon: isDesktop + ? null + : category.getIcon(_imagePaths), + width: isDesktop + ? category.getTabWidth() + : maxWidth / countCategories, + height: tabBarMaxHeight, + ); + }, + indicator: LinearIndicator( + color: AppColor.primaryLinShare, + height: 1, + bottom: 0, + ), + pageController: _pageController, + ), + PositionedDirectional( + bottom: 0, + start: 0, + end: 0, + child: Divider( + color: Colors.black.withValues(alpha: 0.12), + ), + ), + ], + ); + } + ), + Expanded( + child: SizedBox( + width: isDesktop + ? _desktopTabViewMaxWidth + : double.infinity, + child: PageView.builder( + controller: _pageController, + itemCount: _categories.length, + physics: PlatformInfo.isMobile + ? const PageScrollPhysics() + : const NeverScrollableScrollPhysics(), + itemBuilder: (_, index) { + final category = _categories[index]; + final shortcutsByCategory = allShortcuts + .where((shortcut) => shortcut.category == category) + .toList(); + return ShortcutCategoryList( + shortcutsByCategory: shortcutsByCategory, + ); + }, + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_category_list_widget.dart b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_category_list_widget.dart new file mode 100644 index 000000000..61510d38c --- /dev/null +++ b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_category_list_widget.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_row_widget.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart'; + +class ShortcutCategoryList extends StatelessWidget { + final List shortcutsByCategory; + + const ShortcutCategoryList({ + super.key, + required this.shortcutsByCategory, + }); + + @override + Widget build(BuildContext context) { + return ListView.builder( + padding: const EdgeInsets.only(top: 40), + itemCount: shortcutsByCategory.length, + itemBuilder: (_, index) { + final item = shortcutsByCategory[index]; + return ShortcutRow(item: item); + }, + ); + } +} diff --git a/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_key_widget.dart b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_key_widget.dart new file mode 100644 index 000000000..2e2c921fb --- /dev/null +++ b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_key_widget.dart @@ -0,0 +1,30 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; + +class ShortcutKeyWidget extends StatelessWidget { + final String label; + + const ShortcutKeyWidget({super.key, required this.label}); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsetsDirectional.only(end: 4), + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: AppColor.blue100, + borderRadius: const BorderRadius.all(Radius.circular(2)), + border: Border.all( + width: 1, + color: AppColor.gray200, + ), + ), + child: Text( + label, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Colors.black.withValues(alpha: 0.88), + ), + ), + ); + } +} diff --git a/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_row_widget.dart b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_row_widget.dart new file mode 100644 index 000000000..74e692b78 --- /dev/null +++ b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_row_widget.dart @@ -0,0 +1,47 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/utils/theme_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/extensions/keyboard_shortcut_extension.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_key_widget.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class ShortcutRow extends StatelessWidget { + final KeyboardShortcut item; + + const ShortcutRow({super.key, required this.item}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsetsDirectional.only( + top: 5, + bottom: 21, + ), + child: Wrap( + spacing: 27, + runSpacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text( + item.label, + style: ThemeUtils.textStyleBodyBody3( + color: Colors.black, + ), + ), + Text( + item.context.getDisplayName(AppLocalizations.of(context)), + style: ThemeUtils.textStyleBodyBody3( + color: AppColor.gray424244.withValues(alpha: 0.64), + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: + item.keys.map((key) => ShortcutKeyWidget(label: key)).toList(), + ), + ], + ), + ); + } +} diff --git a/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_tab_bar_widget.dart b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_tab_bar_widget.dart new file mode 100644 index 000000000..d46220ea7 --- /dev/null +++ b/lib/features/manage_account/presentation/keyboard_shortcuts/widgets/shortcut_tab_bar_widget.dart @@ -0,0 +1,79 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/utils/theme_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_custom_tab_bar/library.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class ShortcutTabBarWidget extends StatelessWidget { + final int index; + final String label; + final String? icon; + final double? height; + final double? width; + + const ShortcutTabBarWidget({ + super.key, + required this.index, + required this.label, + this.icon, + this.height, + this.width, + }); + + @override + Widget build(BuildContext context) { + final labelWidget = Text( + label, + style: ThemeUtils.textStyleInter400.copyWith( + fontSize: 14, + height: 20 / 14, + letterSpacing: 0.25, + color: AppColor.gray424244, + ), + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ); + + return TabBarItem( + index: index, + transform: ColorsTransform( + highlightColor: AppColor.gray424244, + normalColor: AppColor.gray424244, + builder: (context, _) { + if (icon != null) { + return Container( + height: height, + width: width, + alignment: Alignment.center, + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset( + icon!, + width: 20, + height: 20, + colorFilter: AppColor.gray686E76.asFilter(), + fit: BoxFit.fill, + ), + const SizedBox(height: 10), + labelWidget, + ], + ), + ); + } else { + return Container( + height: height, + width: width, + alignment: Alignment.center, + margin: EdgeInsets.zero, + padding: const EdgeInsets.symmetric(horizontal: 16), + child: labelWidget, + ); + } + }, + ), + ); + } +} diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_view.dart b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart index 5fc4864f0..5a6ca415c 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_view.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart @@ -14,6 +14,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/extensions/va import 'package:tmail_ui_user/features/manage_account/presentation/extensions/validate_setting_capability_supported_extension.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/forward/forward_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/identities/identities_view.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/keyboard_shortcuts/keyboard_shortcuts_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/mailbox_visibility/mailbox_visibility_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; @@ -175,6 +176,8 @@ class ManageAccountDashBoardView extends GetWidget([ AccountMenuItem.profiles, AccountMenuItem.mailboxVisibility, - AccountMenuItem.languageAndRegion, + if (PlatformInfo.isWeb) + AccountMenuItem.keyboardShortcuts, ]); late Worker _quotaRxWorker; @@ -58,6 +60,8 @@ class ManageAccountMenuController extends GetxController with ContactSupportMixi AccountMenuItem.mailboxVisibility, if (dashBoardController.isLanguageSettingDisplayed) AccountMenuItem.languageAndRegion, + if (PlatformInfo.isWeb) + AccountMenuItem.keyboardShortcuts, ]; listAccountMenuItem.value = newListMenuSetting; diff --git a/lib/features/manage_account/presentation/menu/settings/settings_controller.dart b/lib/features/manage_account/presentation/menu/settings/settings_controller.dart index e467bac82..6cf0d6922 100644 --- a/lib/features/manage_account/presentation/menu/settings/settings_controller.dart +++ b/lib/features/manage_account/presentation/menu/settings/settings_controller.dart @@ -3,7 +3,9 @@ import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/mixin/contact_support_mixin.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/profile_setting/profile_setting_action_type.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/export_trace_log_extension.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/extensions/handle_profile_setting_action_type_click_extension.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/account_menu_item.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/settings_page_level.dart'; @@ -13,7 +15,16 @@ class SettingsController extends GetxController with ContactSupportMixin { final responsiveUtils = Get.find(); final imagePaths = Get.find(); - void selectSettings(AccountMenuItem accountMenuItem) => manageAccountDashboardController.selectSettings(accountMenuItem); + void selectSettings(BuildContext context, AccountMenuItem accountMenuItem) { + if (accountMenuItem == AccountMenuItem.signOut) { + manageAccountDashboardController.handleProfileSettingActionTypeClick( + context: context, + actionType: ProfileSettingActionType.signOut, + ); + } else { + manageAccountDashboardController.selectSettings(accountMenuItem); + } + } void backToUniversalSettings() => manageAccountDashboardController.backToUniversalSettings(); diff --git a/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart b/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart index 2d71e7ac6..461bcd321 100644 --- a/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart +++ b/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart @@ -5,8 +5,6 @@ import 'package:get/get.dart'; import 'package:model/extensions/session_extension.dart'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/user_information_widget.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/profile_setting/profile_setting_action_type.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/extensions/handle_profile_setting_action_type_click_extension.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings/settings_controller.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/widgets/setting_first_level_tile_builder.dart'; @@ -19,6 +17,20 @@ class SettingsFirstLevelView extends GetWidget { @override Widget build(BuildContext context) { + final indent = SettingsUtils.getHorizontalPadding( + context, + controller.responsiveUtils, + ); + + final appLocalizations = AppLocalizations.of(context); + + final divider = Divider( + color: AppColor.colorDividerHorizontal, + height: 1, + indent: indent, + endIndent: indent, + ); + return SingleChildScrollView( key: const Key('setting_menu'), child: Column(children: [ @@ -43,40 +55,23 @@ class SettingsFirstLevelView extends GetWidget { titlePadding: const EdgeInsetsDirectional.only(start: 16), ); }), - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) - ), - SettingFirstLevelTileBuilder( + divider, + _buildSettingItem( key: const Key('setting_profiles'), - AppLocalizations.of(context).profiles, - AccountMenuItem.profiles.getIcon(controller.imagePaths), - subtitle: AppLocalizations.of(context).profilesSettingExplanation, - () => controller.selectSettings(AccountMenuItem.profiles) - ), - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) + context: context, + menuItem: AccountMenuItem.profiles, + appLocalizations: appLocalizations, ), + divider, Obx(() { if (controller.manageAccountDashboardController.isRuleFilterCapabilitySupported) { return Column(children: [ - SettingFirstLevelTileBuilder( - AccountMenuItem.emailRules.getName(AppLocalizations.of(context)), - AccountMenuItem.emailRules.getIcon(controller.imagePaths), - subtitle: AppLocalizations.of(context).emailRuleSettingExplanation, - () => controller.selectSettings(AccountMenuItem.emailRules) - ), - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) + _buildSettingItem( + context: context, + menuItem: AccountMenuItem.emailRules, + appLocalizations: appLocalizations, ), + divider, ]); } else { return const SizedBox.shrink(); @@ -85,19 +80,13 @@ class SettingsFirstLevelView extends GetWidget { Obx(() { if (controller.manageAccountDashboardController.isServerSettingsCapabilitySupported) { return Column(children: [ - SettingFirstLevelTileBuilder( + _buildSettingItem( key: const ValueKey('setting_preferences'), - AccountMenuItem.preferences.getName(AppLocalizations.of(context)), - AccountMenuItem.preferences.getIcon(controller.imagePaths), - subtitle: AppLocalizations.of(context).emailReadReceiptsSettingExplanation, - () => controller.selectSettings(AccountMenuItem.preferences) - ), - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) + context: context, + menuItem: AccountMenuItem.preferences, + appLocalizations: appLocalizations, ), + divider, ]); } else { return const SizedBox.shrink(); @@ -106,18 +95,12 @@ class SettingsFirstLevelView extends GetWidget { Obx(() { if (controller.manageAccountDashboardController.isForwardCapabilitySupported) { return Column(children: [ - SettingFirstLevelTileBuilder( - AccountMenuItem.forward.getName(AppLocalizations.of(context)), - AccountMenuItem.forward.getIcon(controller.imagePaths), - subtitle: AppLocalizations.of(context).forwardingSettingExplanation, - () => controller.selectSettings(AccountMenuItem.forward) - ), - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) + _buildSettingItem( + context: context, + menuItem: AccountMenuItem.forward, + appLocalizations: appLocalizations, ), + divider, ]); } else { return const SizedBox.shrink(); @@ -126,28 +109,21 @@ class SettingsFirstLevelView extends GetWidget { Obx(() { if (controller.manageAccountDashboardController.isVacationCapabilitySupported) { return Column(children: [ - SettingFirstLevelTileBuilder( - AccountMenuItem.vacation.getName(AppLocalizations.of(context)), - AccountMenuItem.vacation.getIcon(controller.imagePaths), - subtitle: AppLocalizations.of(context).vacationSettingExplanation, - () => controller.selectSettings(AccountMenuItem.vacation) - ), - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) + _buildSettingItem( + context: context, + menuItem: AccountMenuItem.vacation, + appLocalizations: appLocalizations, ), + divider, ]); } else { return const SizedBox.shrink(); } }), - SettingFirstLevelTileBuilder( - AccountMenuItem.mailboxVisibility.getName(AppLocalizations.of(context)), - AccountMenuItem.mailboxVisibility.getIcon(controller.imagePaths), - subtitle: AppLocalizations.of(context).folderVisibilitySubtitle, - () => controller.selectSettings(AccountMenuItem.mailboxVisibility) + _buildSettingItem( + context: context, + menuItem: AccountMenuItem.mailboxVisibility, + appLocalizations: appLocalizations, ), Obx(() { if (!controller.manageAccountDashboardController.isLanguageSettingDisplayed) { @@ -155,41 +131,24 @@ class SettingsFirstLevelView extends GetWidget { } return Column(children: [ - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) - ), - SettingFirstLevelTileBuilder( + divider, + _buildSettingItem( key: const Key('setting_language_region'), - AccountMenuItem.languageAndRegion.getName(AppLocalizations.of(context)), - AccountMenuItem.languageAndRegion.getIcon(controller.imagePaths), - () => controller.selectSettings(AccountMenuItem.languageAndRegion) + context: context, + menuItem: AccountMenuItem.languageAndRegion, + appLocalizations: appLocalizations, ), ]); }), Obx(() { if (controller.manageAccountDashboardController.octetsQuota.value != null) { return Column(children: [ - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding( - context, - controller.responsiveUtils, - ), - endIndent: SettingsUtils.getHorizontalPadding( - context, - controller.responsiveUtils, - ), - ), - SettingFirstLevelTileBuilder( + divider, + _buildSettingItem( key: const ValueKey('setting_storage'), - AccountMenuItem.storage.getName(AppLocalizations.of(context)), - AccountMenuItem.storage.getIcon(controller.imagePaths), - subtitle: AppLocalizations.of(context).storageSettingExplanation, - () => controller.selectSettings(AccountMenuItem.storage), + context: context, + menuItem: AccountMenuItem.keyboardShortcuts, + appLocalizations: appLocalizations, ), ]); } else { @@ -199,18 +158,12 @@ class SettingsFirstLevelView extends GetWidget { Obx(() { if (controller.manageAccountDashboardController.isFcmCapabilitySupported && PlatformInfo.isMobile) { return Column(children: [ - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) + divider, + _buildSettingItem( + context: context, + menuItem: AccountMenuItem.notification, + appLocalizations: appLocalizations, ), - SettingFirstLevelTileBuilder( - AppLocalizations.of(context).notification, - controller.imagePaths.icNotification, - () => controller.selectSettings(AccountMenuItem.notification), - subtitle: AppLocalizations.of(context).allowsTwakeMailToNotifyYouWhenANewMessageArrivesOnYourPhone, - ) ]); } else { return const SizedBox.shrink(); @@ -232,45 +185,41 @@ class SettingsFirstLevelView extends GetWidget { if (contactSupportCapability?.isAvailable != true) return const SizedBox.shrink(); return Column(children: [ - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding( - context, - controller.responsiveUtils, - ), - endIndent: SettingsUtils.getHorizontalPadding( - context, - controller.responsiveUtils, - ), - ), - SettingFirstLevelTileBuilder( - AccountMenuItem.contactSupport.getName(AppLocalizations.of(context)), - AccountMenuItem.contactSupport.getIcon(controller.imagePaths), - () => controller.onGetHelpOrReportBug( + divider, + _buildSettingItem( + context: context, + menuItem: AccountMenuItem.contactSupport, + appLocalizations: appLocalizations, + onActionCallback: () => controller.onGetHelpOrReportBug( contactSupportCapability!, route: AppRoutes.settings, ), ), ]); }), - Divider( - color: AppColor.colorDividerHorizontal, - height: 1, - indent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils), - endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) - ), - SettingFirstLevelTileBuilder( - AppLocalizations.of(context).sign_out, - controller.imagePaths.icSignOut, - () => controller - .manageAccountDashboardController - .handleProfileSettingActionTypeClick( - context: context, - actionType: ProfileSettingActionType.signOut, - ) + divider, + _buildSettingItem( + context: context, + menuItem: AccountMenuItem.signOut, + appLocalizations: appLocalizations, ), ]), ); } + + Widget _buildSettingItem({ + required BuildContext context, + required AccountMenuItem menuItem, + required AppLocalizations appLocalizations, + Key? key, + VoidCallback? onActionCallback, + }) { + return SettingFirstLevelTileBuilder( + key: key, + menuItem.getName(appLocalizations), + menuItem.getIcon(controller.imagePaths), + subtitle: menuItem.getExplanation(appLocalizations), + onActionCallback ?? () => controller.selectSettings(context, menuItem), + ); + } } diff --git a/lib/features/manage_account/presentation/menu/settings/settings_view.dart b/lib/features/manage_account/presentation/menu/settings/settings_view.dart index 2ffddefed..78845f1c2 100644 --- a/lib/features/manage_account/presentation/menu/settings/settings_view.dart +++ b/lib/features/manage_account/presentation/menu/settings/settings_view.dart @@ -5,6 +5,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/extensions/va import 'package:tmail_ui_user/features/manage_account/presentation/extensions/validate_setting_capability_supported_extension.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/forward/forward_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/identities/identities_view.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/keyboard_shortcuts/keyboard_shortcuts_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/language_and_region_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/mailbox_visibility/mailbox_visibility_view.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings/setting_app_bar.dart'; @@ -145,6 +146,8 @@ class SettingsView extends GetWidget { } else { return const SizedBox.shrink(); } + case AccountMenuItem.keyboardShortcuts: + return const KeyboardShortcutsView(); default: return const SizedBox.shrink(); } diff --git a/lib/features/manage_account/presentation/menu/settings_utils.dart b/lib/features/manage_account/presentation/menu/settings_utils.dart index 237ca2e7a..17b43795e 100644 --- a/lib/features/manage_account/presentation/menu/settings_utils.dart +++ b/lib/features/manage_account/presentation/menu/settings_utils.dart @@ -149,4 +149,17 @@ class SettingsUtils { return const EdgeInsetsDirectional.symmetric(vertical: 8); } } + + static EdgeInsetsGeometry getBodyPadding( + BuildContext context, + ResponsiveUtils responsiveUtils, + ) { + if (responsiveUtils.isMobile(context)) { + return const EdgeInsetsDirectional.only(top: 16, start: 24, end: 24); + } else if (responsiveUtils.isDesktop(context)) { + return const EdgeInsetsDirectional.only(top: 36); + } else { + return const EdgeInsetsDirectional.only(top: 16, start: 44, end: 44); + } + } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/menu/widgets/setting_first_level_tile_builder.dart b/lib/features/manage_account/presentation/menu/widgets/setting_first_level_tile_builder.dart index 5beeb5792..4263cf73d 100644 --- a/lib/features/manage_account/presentation/menu/widgets/setting_first_level_tile_builder.dart +++ b/lib/features/manage_account/presentation/menu/widgets/setting_first_level_tile_builder.dart @@ -20,7 +20,7 @@ class SettingFirstLevelTileBuilder extends StatelessWidget { this.clickAction, { Key? key, - this.subtitle + this.subtitle = '', } ) : super(key: key); @@ -29,7 +29,7 @@ class SettingFirstLevelTileBuilder extends StatelessWidget { final String settingIcon; final String title; - final String? subtitle; + final String subtitle; final SettingFirstLevelTileClickAction clickAction; @override @@ -70,7 +70,7 @@ class SettingFirstLevelTileBuilder extends StatelessWidget { )) ], ), - subtitle != null + subtitle.isNotEmpty ? Padding( padding: EdgeInsets.only( left: AppUtils.isDirectionRTL(context) ? 12 : _getSubtitleLeftPadding(context), @@ -78,7 +78,7 @@ class SettingFirstLevelTileBuilder extends StatelessWidget { top: 12 ), child: Text( - subtitle!, + subtitle, style: ThemeUtils.defaultTextStyleInterFont.copyWith( fontSize: 13, color: AppColor.colorContentEmail, diff --git a/lib/features/manage_account/presentation/model/account_menu_item.dart b/lib/features/manage_account/presentation/model/account_menu_item.dart index 9ef9bd47f..5a22f7cd1 100644 --- a/lib/features/manage_account/presentation/model/account_menu_item.dart +++ b/lib/features/manage_account/presentation/model/account_menu_item.dart @@ -13,6 +13,7 @@ enum AccountMenuItem { notification, contactSupport, storage, + keyboardShortcuts, signOut, none; @@ -38,6 +39,8 @@ enum AccountMenuItem { return imagePaths.icHelp; case AccountMenuItem.storage: return imagePaths.icStorage; + case AccountMenuItem.keyboardShortcuts: + return imagePaths.icKeyboard; case AccountMenuItem.signOut: return imagePaths.icSignOut; case AccountMenuItem.none: @@ -67,6 +70,8 @@ enum AccountMenuItem { return appLocalizations.contactSupport; case AccountMenuItem.storage: return appLocalizations.storageQuotas; + case AccountMenuItem.keyboardShortcuts: + return appLocalizations.keyboardShortcuts; case AccountMenuItem.signOut: return appLocalizations.sign_out; case AccountMenuItem.none: @@ -90,6 +95,10 @@ enum AccountMenuItem { return appLocalizations.folderVisibilitySubtitle; case AccountMenuItem.storage: return appLocalizations.storageSettingExplanation; + case AccountMenuItem.notification: + return appLocalizations.allowsTwakeMailToNotifyYouWhenANewMessageArrivesOnYourPhone; + case AccountMenuItem.keyboardShortcuts: + return appLocalizations.keyboardShortcutsSettingExplanation; default: return ''; } @@ -117,6 +126,8 @@ enum AccountMenuItem { return 'contact-support'; case AccountMenuItem.storage: return 'storage'; + case AccountMenuItem.keyboardShortcuts: + return 'keyboard-shortcuts'; case AccountMenuItem.signOut: return 'sign-out'; case AccountMenuItem.none: diff --git a/lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart b/lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart new file mode 100644 index 000000000..8c3c073ba --- /dev/null +++ b/lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart @@ -0,0 +1,38 @@ +import 'package:equatable/equatable.dart'; + +enum ShortcutCategory { + navigationAndClosing, + readingAndReplying, + messageManagementAndSelection, +} + +enum ShortcutContext { + mailComposer, + focusOnSearch, + openedModal, + mailboxList, + mailboxListWithSelectedEmail, + openedMailView, +} + +class KeyboardShortcut with EquatableMixin { + final String label; + final ShortcutCategory category; + final ShortcutContext context; + final List keys; + + const KeyboardShortcut({ + required this.label, + required this.category, + required this.context, + required this.keys, + }); + + @override + List get props => [ + label, + category, + context, + keys, + ]; +} diff --git a/lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcuts_manager.dart b/lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcuts_manager.dart new file mode 100644 index 000000000..75fe55b1d --- /dev/null +++ b/lib/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcuts_manager.dart @@ -0,0 +1,96 @@ +import 'package:tmail_ui_user/features/manage_account/presentation/model/keyboard_shortcuts/keyboard_shortcut.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class KeyboardShortcutsManager { + KeyboardShortcutsManager._(); + + static List generateKeyboardShortcuts( + AppLocalizations appLocalizations, + ) { + return [ + // Navigation & Closing + KeyboardShortcut( + label: appLocalizations.closeMailComposer, + category: ShortcutCategory.navigationAndClosing, + context: ShortcutContext.mailComposer, + keys: ['ESC'], + ), + KeyboardShortcut( + label: appLocalizations.removeFocusFromSearch, + category: ShortcutCategory.navigationAndClosing, + context: ShortcutContext.focusOnSearch, + keys: ['ESC'], + ), + KeyboardShortcut( + label: appLocalizations.closeModalWindow, + category: ShortcutCategory.navigationAndClosing, + context: ShortcutContext.openedModal, + keys: ['ESC'], + ), + KeyboardShortcut( + label: appLocalizations.openNewMessage, + category: ShortcutCategory.navigationAndClosing, + context: ShortcutContext.mailboxList, + keys: ['N'], + ), + + // Reading & Replying + KeyboardShortcut( + label: appLocalizations.reply, + category: ShortcutCategory.readingAndReplying, + context: ShortcutContext.openedMailView, + keys: ['R'], + ), + KeyboardShortcut( + label: appLocalizations.replyToAll, + category: ShortcutCategory.readingAndReplying, + context: ShortcutContext.openedMailView, + keys: ['Shift', 'R'], + ), + KeyboardShortcut( + label: appLocalizations.forward, + category: ShortcutCategory.readingAndReplying, + context: ShortcutContext.openedMailView, + keys: ['F'], + ), + KeyboardShortcut( + label: appLocalizations.mark_as_read, + category: ShortcutCategory.readingAndReplying, + context: ShortcutContext.openedMailView, + keys: ['Q'], + ), + KeyboardShortcut( + label: appLocalizations.mark_as_unread, + category: ShortcutCategory.readingAndReplying, + context: ShortcutContext.openedMailView, + keys: ['U'], + ), + + // Message Management & Selection + KeyboardShortcut( + label: appLocalizations.deleteMessage, + category: ShortcutCategory.messageManagementAndSelection, + context: ShortcutContext.openedMailView, + keys: ['Delete'], + ), + KeyboardShortcut( + label: appLocalizations.deleteMessage, + category: ShortcutCategory.messageManagementAndSelection, + context: ShortcutContext.mailboxListWithSelectedEmail, + keys: ['Delete'], + ), + KeyboardShortcut( + label: appLocalizations.mark_as_read, + category: ShortcutCategory.messageManagementAndSelection, + context: ShortcutContext.mailboxListWithSelectedEmail, + keys: ['Q'], + ), + KeyboardShortcut( + label: appLocalizations.mark_as_unread, + category: ShortcutCategory.messageManagementAndSelection, + context: ShortcutContext.mailboxListWithSelectedEmail, + keys: ['U'], + ), + ]; + } +} diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index ff052807e..ec8801bf9 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2025-10-17T09:52:08.303266", + "@@last_modified": "2025-10-29T10:59:38.089168", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2688,13 +2688,13 @@ "placeholders_order": [], "placeholders": {} }, - "noEmailInYourCurrentFolder": "There are no emails in your current folder", + "noEmailInYourCurrentFolder": "We're sorry, there are no emails in your current folder", "@noEmailInYourCurrentFolder": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "noEmailMatchYourCurrentFilter": "There are no emails that match your current filter.", + "noEmailMatchYourCurrentFilter": "We're sorry, there are no emails that match your current filter.", "@noEmailMatchYourCurrentFilter": { "type": "text", "placeholders_order": [], @@ -4937,5 +4937,119 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "keyboardShortcuts": "Keyboard shortcuts", + "@keyboardShortcuts": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "keyboardShortcutsSettingExplanation": "Mailbox & email actions", + "@keyboardShortcutsSettingExplanation": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "navigationAndClosing": "Navigation & Closing", + "@navigationAndClosing": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "readingAndReplying": "Reading & Replying", + "@readingAndReplying": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "messageManagementAndSelection": "Message Management & Selection", + "@messageManagementAndSelection": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "navigation": "Navigation", + "@navigation": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "reading": "Reading", + "@reading": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "closeMailComposer": "Close mail composer", + "@closeMailComposer": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "removeFocusFromSearch": "Remove focus from search", + "@removeFocusFromSearch": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "closeModalWindow": "Close modal window", + "@closeModalWindow": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "openNewMessage": "Open new message", + "@openNewMessage": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "mailComposer": "Mail composer", + "@mailComposer": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "focusOnSearch": "Focus on search", + "@focusOnSearch": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "openedModal": "Opened modal", + "@openedModal": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "mailboxList": "Mailbox list", + "@mailboxList": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "openedMailView": "Opened mail view", + "@openedMailView": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "mailboxListWithSelectedMail": "Mailbox list (selected mail)", + "@mailboxListWithSelectedMail": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "replyToAll": "Reply to all", + "@replyToAll": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "deleteMessage": "Delete message", + "@deleteMessage": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } -} +} \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 3a0dd6ec4..33def3be6 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5212,4 +5212,137 @@ class AppLocalizations { name: 'mailHasBeenUnstarred', ); } + + String get keyboardShortcuts { + return Intl.message( + 'Keyboard shortcuts', + name: 'keyboardShortcuts', + ); + } + + String get keyboardShortcutsSettingExplanation { + return Intl.message( + 'Mailbox & email actions', + name: 'keyboardShortcutsSettingExplanation', + ); + } + + String get navigationAndClosing { + return Intl.message( + 'Navigation & Closing', + name: 'navigationAndClosing', + ); + } + + String get readingAndReplying { + return Intl.message( + 'Reading & Replying', + name: 'readingAndReplying', + ); + } + + String get messageManagementAndSelection { + return Intl.message( + 'Message Management & Selection', + name: 'messageManagementAndSelection', + ); + } + + String get navigation { + return Intl.message( + 'Navigation', + name: 'navigation', + ); + } + + String get reading { + return Intl.message( + 'Reading', + name: 'reading', + ); + } + + String get closeMailComposer { + return Intl.message( + 'Close mail composer', + name: 'closeMailComposer', + ); + } + + String get removeFocusFromSearch { + return Intl.message( + 'Remove focus from search', + name: 'removeFocusFromSearch', + ); + } + + String get closeModalWindow { + return Intl.message( + 'Close modal window', + name: 'closeModalWindow', + ); + } + + String get openNewMessage { + return Intl.message( + 'Open new message', + name: 'openNewMessage', + ); + } + + String get mailComposer { + return Intl.message( + 'Mail composer', + name: 'mailComposer', + ); + } + + String get focusOnSearch { + return Intl.message( + 'Focus on search', + name: 'focusOnSearch', + ); + } + + String get openedModal { + return Intl.message( + 'Opened modal', + name: 'openedModal', + ); + } + + String get mailboxList { + return Intl.message( + 'Mailbox list', + name: 'mailboxList', + ); + } + + String get openedMailView { + return Intl.message( + 'Opened mail view', + name: 'openedMailView', + ); + } + + String get mailboxListWithSelectedMail { + return Intl.message( + 'Mailbox list (selected mail)', + name: 'mailboxListWithSelectedMail', + ); + } + + String get replyToAll { + return Intl.message( + 'Reply to all', + name: 'replyToAll', + ); + } + + String get deleteMessage { + return Intl.message( + 'Delete message', + name: 'deleteMessage', + ); + } } diff --git a/pubspec.lock b/pubspec.lock index 1d5213b2e..4fb694a5a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -757,6 +757,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + flutter_custom_tab_bar: + dependency: "direct main" + description: + name: flutter_custom_tab_bar + sha256: "5f550d5343ebf778ae73d1de775c8d38e4a2312146cd77845472dd7ed04aafca" + url: "https://pub.dev" + source: hosted + version: "1.2.1" flutter_date_range_picker: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index c354eee28..9c1951332 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -265,6 +265,8 @@ dependencies: lottie_native: 0.1.2 + flutter_custom_tab_bar: 1.2.1 + dev_dependencies: flutter_test: sdk: flutter