TF-3911 Add Keyboard shortcuts dictionary in Setting

This commit is contained in:
dab246
2025-10-02 13:25:29 +07:00
committed by Dat H. Pham
parent 846c9c6583
commit 0bd60ea83d
26 changed files with 991 additions and 147 deletions
@@ -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<KeyboardShortcutsView> createState() => _KeyboardShortcutsViewState();
}
class _KeyboardShortcutsViewState extends State<KeyboardShortcutsView> {
static const double _desktopTabViewMaxWidth = 618;
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
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,
);
},
),
),
),
],
),
),
),
],
),
),
);
}
}
@@ -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<KeyboardShortcut> 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);
},
);
}
}
@@ -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),
),
),
);
}
}
@@ -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(),
),
],
),
);
}
}
@@ -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,
);
}
},
),
);
}
}