From a57985a5ed85a00394746e42be7810df888a169c Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 7 Aug 2025 23:51:03 +0700 Subject: [PATCH] TF-3952 Change style for item in list recipients Signed-off-by: dab246 --- assets/images/ic_check.svg | 5 + .../extensions/color_extension.dart | 1 + .../presentation/resources/image_paths.dart | 3 +- core/lib/presentation/utils/theme_utils.dart | 9 + .../presentation/forward/forward_view.dart | 75 +++--- .../widgets/email_forward_item_widget.dart | 240 ++++++++++-------- .../widgets/keep_copy_in_inbox_widget.dart | 2 +- .../widgets/list_email_forward_widget.dart | 37 +-- 8 files changed, 213 insertions(+), 159 deletions(-) create mode 100644 assets/images/ic_check.svg diff --git a/assets/images/ic_check.svg b/assets/images/ic_check.svg new file mode 100644 index 000000000..8ecbebd2c --- /dev/null +++ b/assets/images/ic_check.svg @@ -0,0 +1,5 @@ + + + diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 69ee5d73f..b3659447f 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -271,6 +271,7 @@ extension AppColor on Color { static const m3Primary = Color(0xFF0A84FF); static const m3Primary95 = Color(0xFFE3F1FF); static const gray49454F = Color(0xFF49454F); + static const lightGrayF9FAFB = Color(0xFFF9FAFB); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index ff77f333f..cf39c7e4f 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -234,10 +234,9 @@ class ImagePaths { String get icArrowBack => _getImagePath('ic_arrow_back.svg'); String get icRadio => _getImagePath('ic_radio.svg'); String get icRadioSelected => _getImagePath('ic_radio_selected.svg'); - + String get icCheck => _getImagePath('ic_check.svg'); String get icFileDownload => _getImagePath('ic_file_download.svg'); String get icTwakeWorkplace => _getIconPath('icon_twp.png'); - String get animLottieTmail => _getAnimationPath('lottie-tmail.json'); String get icExpandArrows => _getImagePath('ic_expand_arrows.svg'); diff --git a/core/lib/presentation/utils/theme_utils.dart b/core/lib/presentation/utils/theme_utils.dart index db0b6bf7a..fb2d93337 100644 --- a/core/lib/presentation/utils/theme_utils.dart +++ b/core/lib/presentation/utils/theme_utils.dart @@ -245,6 +245,15 @@ class ThemeUtils { color: AppColor.m3Tertiary20, ); + static TextStyle get textStyleM3TitleMedium => defaultTextStyleInterFont.copyWith( + fontFamily: ConstantsUI.fontApp, + fontWeight: FontWeight.w500, + letterSpacing: 0.15, + fontSize: 16, + height: 24 / 16, + color: AppColor.secondaryContrastText, + ); + static TextStyle textStyleM3BodyMedium1 = defaultTextStyleInterFont.copyWith( fontWeight: FontWeight.w400, letterSpacing: -0.15, diff --git a/lib/features/manage_account/presentation/forward/forward_view.dart b/lib/features/manage_account/presentation/forward/forward_view.dart index 93b1f99a9..d3e95295d 100644 --- a/lib/features/manage_account/presentation/forward/forward_view.dart +++ b/lib/features/manage_account/presentation/forward/forward_view.dart @@ -51,7 +51,11 @@ class ForwardView extends GetWidget with AppLoaderMixin { ), width: double.infinity, padding: controller.responsiveUtils.isDesktop(context) - ? const EdgeInsets.symmetric(vertical: 30, horizontal: 22) + ? const EdgeInsetsDirectional.only( + start: 22, + end: 22, + top: 30, + ) : null, child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -62,7 +66,7 @@ class ForwardView extends GetWidget with AppLoaderMixin { textStyle: ThemeUtils.textStyleInter600().copyWith( color: Colors.black.withValues(alpha: 0.9), ), - padding: EdgeInsets.zero, + padding: const EdgeInsets.only(bottom: 16), ) else const SettingExplanationWidget( @@ -76,39 +80,42 @@ class ForwardView extends GetWidget with AppLoaderMixin { textAlign: TextAlign.center, ), Expanded( - child: Padding( - padding: isWebDesktop - ? EdgeInsets.zero - : const EdgeInsetsDirectional.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Obx(() => KeepCopyInInboxWidget( - imagePaths: controller.imagePaths, - recipientForwards: controller.listRecipientForward, - localCopyState: controller.currentForwardLocalCopyState, - onToggleLocalCopy: controller.handleEditLocalCopy, - )), - Obx( - () => NumberOfRecipientWidget( - numberOfRecipient: - controller.listRecipientForward.length, + child: SingleChildScrollView( + physics: const ClampingScrollPhysics(), + child: Padding( + padding: isWebDesktop + ? EdgeInsets.zero + : const EdgeInsetsDirectional.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Obx(() => KeepCopyInInboxWidget( + imagePaths: controller.imagePaths, + recipientForwards: controller.listRecipientForward, + localCopyState: controller.currentForwardLocalCopyState, + onToggleLocalCopy: controller.handleEditLocalCopy, + )), + Obx( + () => NumberOfRecipientWidget( + numberOfRecipient: + controller.listRecipientForward.length, + ), ), - ), - Obx( - () => controller.currentForward.value != null - ? _buildAddRecipientsFormWidget(context) - : const SizedBox.shrink(), - ), - _buildLoadingView(), - Obx(() { - if (controller.listRecipientForward.isNotEmpty) { - return const ListEmailForwardsWidget(); - } else { - return const SizedBox.shrink(); - } - }), - ], + Obx( + () => controller.currentForward.value != null + ? _buildAddRecipientsFormWidget(context) + : const SizedBox.shrink(), + ), + _buildLoadingView(), + Obx(() { + if (controller.listRecipientForward.isNotEmpty) { + return const ListEmailForwardsWidget(); + } else { + return const SizedBox.shrink(); + } + }), + ], + ), ), ), ), diff --git a/lib/features/manage_account/presentation/forward/widgets/email_forward_item_widget.dart b/lib/features/manage_account/presentation/forward/widgets/email_forward_item_widget.dart index 79a334541..ee478705b 100644 --- a/lib/features/manage_account/presentation/forward/widgets/email_forward_item_widget.dart +++ b/lib/features/manage_account/presentation/forward/widgets/email_forward_item_widget.dart @@ -1,15 +1,15 @@ +import 'dart:math'; + import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/string_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; -import 'package:core/presentation/utils/style_utils.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/utils/theme_utils.dart'; -import 'package:core/presentation/views/button/icon_button_web.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/presentation/views/image/avatar_builder.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:get/get.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:model/mailbox/select_mode.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; @@ -20,19 +20,22 @@ typedef OnSelectRecipientCallbackAction = Function(RecipientForward recipientFor typedef OnDeleteRecipientCallbackAction = Function(RecipientForward recipientForward); class EmailForwardItemWidget extends StatelessWidget { - + final ImagePaths imagePaths; + final ResponsiveUtils responsiveUtils; final RecipientForward recipientForward; final SelectMode selectionMode; final String internalDomain; + final double maxWidth; final OnSelectRecipientCallbackAction? onSelectRecipientCallback; final OnDeleteRecipientCallbackAction? onDeleteRecipientCallback; - final ImagePaths _imagePaths = Get.find(); - - EmailForwardItemWidget({ + const EmailForwardItemWidget({ Key? key, + required this.imagePaths, + required this.responsiveUtils, required this.recipientForward, required this.internalDomain, + required this.maxWidth, this.selectionMode = SelectMode.INACTIVE, this.onSelectRecipientCallback, this.onDeleteRecipientCallback, @@ -40,108 +43,132 @@ class EmailForwardItemWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Padding( + final isScreenWithShortestSide = responsiveUtils + .isScreenWithShortestSide(context); + + final isSameDomain = EmailUtils.isSameDomain( + emailAddress: recipientForward.emailAddress.emailAddress, + internalDomain: internalDomain, + ); + + final bodyWidget = Padding( padding: const EdgeInsets.only(top: 4), - child: Material( - color: Colors.transparent, - child: InkWell( - onLongPress: () { - if (PlatformInfo.isMobile) { - onSelectRecipientCallback?.call(recipientForward); - } - }, - customBorder: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(12))), - child: Container( - padding: const EdgeInsets.only(left: 12, bottom: 12, top: 12), - decoration: BoxDecoration( - color: _getBackgroundColor(), - borderRadius: BorderRadius.all(Radius.circular( - recipientForward.selectMode == SelectMode.ACTIVE ? 12 : 0)) - ), - child: Row(children: [ - _buildAvatarIcon(_imagePaths), - const SizedBox(width: 12), - Expanded(child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (EmailUtils.isSameDomain( - emailAddress: recipientForward.emailAddress.emailAddress, - internalDomain: internalDomain)) - Text( - recipientForward.emailAddress.asString(), - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: 1, - style: Theme.of(context).textTheme.labelSmall?.copyWith( - fontSize: 16, - fontWeight: FontWeight.normal, - color: Colors.black - ) - ) - else - Row( - children: [ - Flexible( - child: Text( - recipientForward.emailAddress.asString(), - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: 1, - style: Theme.of(context).textTheme.labelSmall?.copyWith( - fontSize: 16, - fontWeight: FontWeight.normal, - color: Colors.black - ) - ), - ), - TMailButtonWidget.fromIcon( - icon: _imagePaths.icInfoCircleOutline, - iconColor: AppColor.colorQuotaError, - iconSize: 20, - backgroundColor: Colors.transparent, - padding: const EdgeInsets.all(3), - tooltipMessage: AppLocalizations.of(context).externalDomain, - ) - ], - ), - if (recipientForward.emailAddress.displayName.isNotEmpty) + child: GestureDetector( + onLongPress: PlatformInfo.isMobile + ? () => onSelectRecipientCallback?.call(recipientForward) + : null, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: _getBackgroundColor(), + borderRadius: const BorderRadius.all(Radius.circular(10)), + ), + width: isScreenWithShortestSide + ? double.infinity + : min(maxWidth, 597), + height: 72, + child: Row( + children: [ + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - recipientForward.emailAddress.email ?? '', - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: 1, - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontSize: 14, - fontWeight: FontWeight.normal, - color: AppColor.colorContentEmail - ) + padding: const EdgeInsets.only(top: 3), + child: _buildAvatarIcon(imagePaths), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + recipientForward.emailAddress.asString(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: ThemeUtils.textStyleBodyBody2( + color: Colors.black, + ), + ), + ), + TMailButtonWidget.fromIcon( + icon: isSameDomain + ? imagePaths.icCheck + : imagePaths.icInfoCircleOutline, + iconColor: AppColor.primaryLinShare, + iconSize: 20, + margin: const EdgeInsetsDirectional.only( + start: 4, + ), + backgroundColor: Colors.transparent, + padding: const EdgeInsets.all(2), + tooltipMessage: isSameDomain + ? null + : AppLocalizations.of(context).externalDomain, + ) + ], + ), + if (recipientForward.emailAddress.displayName.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + recipientForward.emailAddress.email ?? '', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: ThemeUtils.textStyleBodyBody2( + color: AppColor.gray424244.withValues( + alpha: 0.64, + ), + ), + ), + ) + ], ), ) - ], - )), - const SizedBox(width: 12), + ], + ), + ), if (selectionMode == SelectMode.INACTIVE) - buildIconWeb( - iconSize: 30, - splashRadius: 20, - icon: SvgPicture.asset(_imagePaths.icDeleteRecipient), - onTap: () => onDeleteRecipientCallback?.call(recipientForward) - ) - ]), + TMailButtonWidget.fromIcon( + icon: imagePaths.icDeleteComposer, + iconSize: 20, + iconColor: AppColor.steelGrayA540, + backgroundColor: Colors.transparent, + margin: EdgeInsetsDirectional.only( + start: 12, + end: isScreenWithShortestSide ? 0 : 12, + ), + onTapActionCallback: () => + onDeleteRecipientCallback?.call(recipientForward), + ), + ], ), ), ), ); + + if (isScreenWithShortestSide) { + return bodyWidget; + } else { + return Row( + children: [ + bodyWidget, + const Spacer(), + ], + ); + } } Color _getBackgroundColor() { if (recipientForward.selectMode == SelectMode.ACTIVE) { return AppColor.colorItemRecipientSelected; } else { - return Colors.transparent; + return AppColor.lightGrayF9FAFB; } } @@ -151,29 +178,28 @@ class EmailForwardItemWidget extends StatelessWidget { customBorder: const CircleBorder(), onTap: () => onSelectRecipientCallback?.call(recipientForward), child: Container( - width: 40, - height: 40, + width: 32, + height: 32, color: Colors.transparent, alignment: Alignment.center, child: SvgPicture.asset( imagePaths.icSelectedRecipient, - width: 40, - height: 40, + width: 32, + height: 32, fit: BoxFit.fill, ), ), ); } else { return (AvatarBuilder() - ..text(recipientForward.emailAddress.asString().firstLetterToUpperCase) - ..size(40) - ..addTextStyle(ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 16, - color: Colors.white)) - ..avatarColor(recipientForward.emailAddress.avatarColors) - ..addOnTapActionClick(() => onSelectRecipientCallback?.call(recipientForward)) - ).build(); + ..text( + recipientForward.emailAddress.asString().firstLetterToUpperCase) + ..size(32) + ..addTextStyle(ThemeUtils.textStyleM3TitleMedium) + ..avatarColor(recipientForward.emailAddress.avatarColors) + ..addOnTapActionClick( + () => onSelectRecipientCallback?.call(recipientForward))) + .build(); } } } diff --git a/lib/features/manage_account/presentation/forward/widgets/keep_copy_in_inbox_widget.dart b/lib/features/manage_account/presentation/forward/widgets/keep_copy_in_inbox_widget.dart index d7610b4a2..94dad05f3 100644 --- a/lib/features/manage_account/presentation/forward/widgets/keep_copy_in_inbox_widget.dart +++ b/lib/features/manage_account/presentation/forward/widgets/keep_copy_in_inbox_widget.dart @@ -27,7 +27,7 @@ class KeepCopyInInboxWidget extends StatelessWidget { } return Padding( - padding: const EdgeInsets.only(top: 24), + padding: const EdgeInsets.only(top: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/features/manage_account/presentation/forward/widgets/list_email_forward_widget.dart b/lib/features/manage_account/presentation/forward/widgets/list_email_forward_widget.dart index 87195b59b..e3da1219e 100644 --- a/lib/features/manage_account/presentation/forward/widgets/list_email_forward_widget.dart +++ b/lib/features/manage_account/presentation/forward/widgets/list_email_forward_widget.dart @@ -26,22 +26,29 @@ class ListEmailForwardsWidget extends GetWidget { if (controller.listRecipientForward.isEmpty) { return const SizedBox.shrink(); } else { - return ListView.builder( - shrinkWrap: true, - primary: false, - itemCount: controller.listRecipientForward.length, - padding: EdgeInsets.zero, - itemBuilder: (context, index) { - return EmailForwardItemWidget( - recipientForward: controller.listRecipientForward[index], - internalDomain: controller.accountDashBoardController.sessionCurrent?.internalDomain ?? '', - selectionMode: controller.selectionMode.value, - onSelectRecipientCallback: controller.selectRecipientForward, - onDeleteRecipientCallback: (recipientForward) { - controller.deleteRecipients(context, recipientForward.emailAddress.emailAddress); - }, + return LayoutBuilder( + builder: (context, constraints) { + return ListView.builder( + shrinkWrap: true, + primary: false, + itemCount: controller.listRecipientForward.length, + padding: const EdgeInsets.only(bottom: 30), + itemBuilder: (context, index) { + return EmailForwardItemWidget( + imagePaths: controller.imagePaths, + responsiveUtils: controller.responsiveUtils, + recipientForward: controller.listRecipientForward[index], + internalDomain: controller.accountDashBoardController.sessionCurrent?.internalDomain ?? '', + selectionMode: controller.selectionMode.value, + maxWidth: constraints.maxWidth, + onSelectRecipientCallback: controller.selectRecipientForward, + onDeleteRecipientCallback: (recipientForward) { + controller.deleteRecipients(context, recipientForward.emailAddress.emailAddress); + }, + ); + } ); - } + }, ); } }),