From 141fa2cc2ca43e2f4ba497184b94e501f77b33c1 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 3 Jul 2025 10:41:27 +0700 Subject: [PATCH] Apply new style left menu in Settings Signed-off-by: dab246 --- .../extensions/color_extension.dart | 3 + core/lib/presentation/utils/theme_utils.dart | 3 +- .../menu/manage_account_menu_view.dart | 304 ++++++++++-------- .../account_menu_item_tile_builder.dart | 56 ++-- lib/main.dart | 2 +- 5 files changed, 212 insertions(+), 156 deletions(-) diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 0a4df1a2f..1b219867c 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -243,6 +243,7 @@ extension AppColor on Color { static const steelGray600 = Color(0xFF4E5966); static const blue100 = Color(0xFFDFEEFF); static const blue400 = Color(0xFF80BDFF); + static const blue900 = Color(0xFF0F76E7); static const m3Tertiary = Color(0xFF8C9CAF); static const m3Neutral70 = Color(0xFFAEAAAE); static const m3Neutral90 = Color(0xFFE6E1E5); @@ -263,6 +264,8 @@ extension AppColor on Color { static const profileMenuDivider = Color(0xFF1D192B); static const popupMenuItemHovered = Color(0xFFF8F8F8); static const secondaryContrastText = Color(0xFFFFFFFF); + static const primaryLinShare = Color(0xFF007AFF); + static const lightGrayEAEDF2 = Color(0xFFEAEDF2); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/core/lib/presentation/utils/theme_utils.dart b/core/lib/presentation/utils/theme_utils.dart index c262334f6..ad95033ad 100644 --- a/core/lib/presentation/utils/theme_utils.dart +++ b/core/lib/presentation/utils/theme_utils.dart @@ -6,12 +6,13 @@ import 'package:flutter/services.dart'; class ThemeUtils { ThemeUtils._(); - static ThemeData get appTheme { + static ThemeData buildAppTheme(BuildContext context) { return ThemeData( scaffoldBackgroundColor: Colors.white, fontFamily: ConstantsUI.fontApp, appBarTheme: _appBarTheme, textTheme: _textTheme, + hoverColor: Theme.of(context).colorScheme.outline.withOpacity(0.08), textSelectionTheme: _textSelectionTheme, dividerTheme: _dividerTheme, visualDensity: VisualDensity.adaptivePlatformDensity, diff --git a/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart b/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart index 0f866b353..cbfe498ff 100644 --- a/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart +++ b/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart @@ -1,5 +1,6 @@ import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/utils/theme_utils.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; @@ -23,146 +24,179 @@ class ManageAccountMenuView extends GetWidget { backgroundColor: controller.responsiveUtils.isWebDesktop(context) ? AppColor.colorBgDesktop : Colors.white, - body: SafeArea(right: false, bottom: false, - child: Column( - children: [ - if (!controller.responsiveUtils.isWebDesktop(context)) - Padding( - padding: const EdgeInsetsDirectional.only(top: 16, bottom: 16, start: 16), - child: Row(children: [ - ApplicationLogoWidthTextWidget(), - const ApplicationVersionWidget( - padding: EdgeInsets.only(top: 8), - ), - ]) + body: SafeArea( + right: false, + bottom: false, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!controller.responsiveUtils.isWebDesktop(context)) + ...[ + Padding( + padding: const EdgeInsetsDirectional.only( + top: 16, + bottom: 16, + start: 16, ), - if (!controller.responsiveUtils.isWebDesktop(context)) - const Divider(color: AppColor.colorDividerMailbox, height: 1), - Expanded(child: Container( - color: controller.responsiveUtils.isWebDesktop(context) ? AppColor.colorBgDesktop : Colors.white, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Row( children: [ - Padding( - padding: const EdgeInsetsDirectional.only(start: 20, top: 24), - child: TMailButtonWidget( - key: const Key('back_to_dashboard_button'), - text: AppLocalizations.of(context).back, - icon: DirectionUtils.isDirectionRTLByLanguage(context) - ? controller.imagePaths.icArrowRight - : controller.imagePaths.icBack, - borderRadius: 10, - backgroundColor: AppColor.colorBgMailboxSelected, - iconColor: AppColor.colorTextButton, - maxWidth: 100, - padding: DirectionUtils.isDirectionRTLByLanguage(context) - ? const EdgeInsets.symmetric(vertical: 5) - : const EdgeInsets.symmetric(vertical: 10), - iconSize: DirectionUtils.isDirectionRTLByLanguage(context) ? null : 16, - textStyle: const TextStyle( - fontSize: 15, - color: AppColor.colorTextButton, - fontWeight: FontWeight.normal - ), - onTapActionCallback: () => controller.backToMailboxDashBoard(context), - ), + ApplicationLogoWidthTextWidget(), + const ApplicationVersionWidget( + padding: EdgeInsets.only(top: 8), ), - Padding( - padding: const EdgeInsetsDirectional.only(start: 32, top: 20), - child: Text( - AppLocalizations.of(context).manage_account, - style: const TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: 17 - ) - ) - ), - const SizedBox(height: 12), - Flexible( - child: Obx(() { - if (controller.listAccountMenuItem.isNotEmpty) { - return ListView.builder( - key: const Key('list_manage_account_menu_item'), - padding: const EdgeInsetsDirectional.only(start: 16, end: 8), - shrinkWrap: true, - itemCount: controller.listAccountMenuItem.length, - itemBuilder: (context, index) => Obx(() { - final menuItem = controller.listAccountMenuItem[index]; - return AccountMenuItemTileBuilder( - imagePaths: controller.imagePaths, - responsiveUtils: controller.responsiveUtils, - menuItem: menuItem, - menuItemSelected: controller.dashBoardController.accountMenuItemSelected.value, - onSelectAccountMenuItemAction: controller.selectAccountMenuItem - ); - }) - ); - } else { - return const SizedBox.shrink(); - } - }), - ), - const Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Divider()), - Obx(() { - final accountId = controller - .dashBoardController - .accountId - .value; - - if (accountId == null) return const SizedBox.shrink(); - - final contactSupportCapability = controller - .dashBoardController - .sessionCurrent - ?.getContactSupportCapability(accountId); - - if (contactSupportCapability?.isAvailable != true) return const SizedBox.shrink(); - - return AccountMenuItemTileBuilder( - imagePaths: controller.imagePaths, - responsiveUtils: controller.responsiveUtils, - menuItem: AccountMenuItem.contactSupport, - padding: const EdgeInsetsDirectional.only(start: 16, end: 8, bottom: 6), - onSelectAccountMenuItemAction: (_) { - controller.onGetHelpOrReportBug( - contactSupportCapability!, - route: AppRoutes.settings, - ); - }, - ); - }), - AccountMenuItemTileBuilder( - imagePaths: controller.imagePaths, - responsiveUtils: controller.responsiveUtils, - menuItem: AccountMenuItem.signOut, - padding: const EdgeInsetsDirectional.only(start: 16, end: 8), - onSelectAccountMenuItemAction: (_) { - controller.dashBoardController.logout( - context, - controller.dashBoardController.sessionCurrent, - controller.dashBoardController.accountId.value, - ); - } - ), - ] - ), - )), - Container( - color: AppColor.colorBgDesktop, - width: double.infinity, - alignment: controller.responsiveUtils.isDesktop(context) - ? AlignmentDirectional.centerStart - : AlignmentDirectional.center, - padding: const EdgeInsets.all(16), - child: ApplicationVersionWidget( - title: '${AppLocalizations.of(context).version.toLowerCase()} ', + ], ), ), - ] - ) + const Divider( + color: AppColor.colorDividerMailbox, + height: 1, + ), + ], + Expanded( + child: Padding( + padding: const EdgeInsetsDirectional.only( + start: 9, + end: 8, + top: 16, + bottom: 16, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8), + child: TMailButtonWidget( + key: const Key('back_to_dashboard_button'), + text: AppLocalizations.of(context).back, + icon: DirectionUtils.isDirectionRTLByLanguage(context) + ? controller.imagePaths.icArrowRight + : controller.imagePaths.icBack, + borderRadius: 8, + mainAxisSize: MainAxisSize.min, + backgroundColor: AppColor.lightGrayEAEDF2, + iconColor: AppColor.primaryLinShare, + minWidth: 79, + iconSize: + DirectionUtils.isDirectionRTLByLanguage(context) + ? null + : 9, + padding: const EdgeInsetsDirectional.only( + start: 19, + end: 12, + top: 8, + bottom: 8, + ), + textStyle: + Theme.of(context).textTheme.bodySmall?.copyWith( + color: AppColor.blue900, + ), + onTapActionCallback: () => + controller.backToMailboxDashBoard(context), + ), + ), + Padding( + padding: const EdgeInsets.all(8), + child: Text( + AppLocalizations.of(context).manage_account, + style: ThemeUtils.textStyleHeadingHeadingSmall( + fontWeight: FontWeight.bold, + ), + ) + ), + Flexible( + child: Obx(() { + if (controller.listAccountMenuItem.isNotEmpty) { + return ListView.builder( + key: const Key('list_manage_account_menu_item'), + padding: const EdgeInsetsDirectional.symmetric( + horizontal: 8, + ), + shrinkWrap: true, + itemCount: controller.listAccountMenuItem.length, + itemBuilder: (context, index) => Obx(() { + final menuItem = controller.listAccountMenuItem[index]; + return AccountMenuItemTileBuilder( + imagePaths: controller.imagePaths, + responsiveUtils: controller.responsiveUtils, + menuItem: menuItem, + menuItemSelected: controller.dashBoardController.accountMenuItemSelected.value, + onSelectAccountMenuItemAction: controller.selectAccountMenuItem + ); + }) + ); + } else { + return const SizedBox.shrink(); + } + }), + ), + const Padding( + padding: EdgeInsets.only(top: 20, bottom: 12), + child: Divider(color: Colors.black12), + ), + Obx(() { + final accountId = controller + .dashBoardController + .accountId + .value; + + if (accountId == null) return const SizedBox.shrink(); + + final contactSupportCapability = controller + .dashBoardController + .sessionCurrent + ?.getContactSupportCapability(accountId); + + if (contactSupportCapability?.isAvailable != true) return const SizedBox.shrink(); + + return AccountMenuItemTileBuilder( + imagePaths: controller.imagePaths, + responsiveUtils: controller.responsiveUtils, + menuItem: AccountMenuItem.contactSupport, + padding: const EdgeInsetsDirectional.symmetric( + horizontal: 8, + ), + onSelectAccountMenuItemAction: (_) { + controller.onGetHelpOrReportBug( + contactSupportCapability!, + route: AppRoutes.settings, + ); + }, + ); + }), + AccountMenuItemTileBuilder( + imagePaths: controller.imagePaths, + responsiveUtils: controller.responsiveUtils, + menuItem: AccountMenuItem.signOut, + padding: const EdgeInsetsDirectional.only( + start: 8, + end: 8, + top: 4, + ), + onSelectAccountMenuItemAction: (_) { + controller.dashBoardController.logout( + context, + controller.dashBoardController.sessionCurrent, + controller.dashBoardController.accountId.value, + ); + } + ), + ] + ), + ), + ), + Container( + color: AppColor.colorBgDesktop, + width: double.infinity, + alignment: controller.responsiveUtils.isDesktop(context) + ? AlignmentDirectional.centerStart + : AlignmentDirectional.center, + padding: const EdgeInsets.all(16), + child: ApplicationVersionWidget( + title: '${AppLocalizations.of(context).version.toLowerCase()} ', + ), + ), + ], + ), ), ); } diff --git a/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart b/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart index 968def08d..6f53481f9 100644 --- a/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart +++ b/lib/features/manage_account/presentation/menu/widgets/account_menu_item_tile_builder.dart @@ -32,36 +32,54 @@ class AccountMenuItemTileBuilder extends StatelessWidget { Widget build(BuildContext context) { return Padding( key: Key('${menuItem.getAliasBrowser()}_account_menu_item_tile'), - padding: padding ?? const EdgeInsets.only(top: 6), + padding: padding ?? const EdgeInsets.only(top: 4), child: Material( color: Colors.transparent, child: InkWell( onTap: () => onSelectAccountMenuItemAction.call(menuItem), - borderRadius: const BorderRadius.all(Radius.circular(10)), + borderRadius: const BorderRadius.all(Radius.circular(8)), child: Container( decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(10)), - color: menuItemSelected == menuItem - ? AppColor.colorBgMailboxSelected + borderRadius: const BorderRadius.all(Radius.circular(8)), + color: _isSelected + ? AppColor.lightGrayEAEDF2 : Colors.transparent, ), - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - child: Column(children: [ - Row(children: [ - SvgPicture.asset( - menuItem.getIcon(imagePaths), - width: 20, - height: 20, - fit: BoxFit.fill), - const SizedBox(width: 12), - Expanded(child: Text( - menuItem.getName(AppLocalizations.of(context)), - style: ThemeUtils.textStyleBodyBody3(color: Colors.black) - )) - ]), + padding: const EdgeInsets.all(8), + height: 36, + child: Row(children: [ + SvgPicture.asset( + menuItem.getIcon(imagePaths), + width: 20, + height: 20, + fit: BoxFit.fill, + colorFilter: AppColor.primaryLinShare.asFilter(), + ), + const SizedBox(width: 8), + Expanded(child: Text( + menuItem.getName(AppLocalizations.of(context)), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: _titleStyle, + )), ]) )), ), ); } + + bool get _isSelected => menuItemSelected == menuItem; + + TextStyle get _titleStyle { + if (_isSelected) { + return ThemeUtils.textStyleInter600().copyWith( + fontSize: 15, + height: 20 / 15, + letterSpacing: 0.0, + color: Colors.black, + ); + } else { + return ThemeUtils.textStyleBodyBody2(color: Colors.black); + } + } } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index ed342e4a1..5b389a68d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -71,7 +71,7 @@ class _TMailAppState extends State { Widget build(BuildContext context) { return GetMaterialApp( debugShowCheckedModeBanner: false, - theme: ThemeUtils.appTheme, + theme: ThemeUtils.buildAppTheme(context), supportedLocales: LocalizationService.supportedLocales, localizationsDelegates: const [ AppLocalizationsDelegate(),