From 9117b88c21fce7420fa3d098593b192758f2c370 Mon Sep 17 00:00:00 2001 From: hieubt Date: Fri, 3 Nov 2023 16:06:08 +0700 Subject: [PATCH] TF-2196 Add 'From' field dropdown (cherry picked from commit a798d4beb7734bb4ad5856bd6662276cde335a10) --- .../from_composer_drop_down_widget_style.dart | 99 +++++++++ .../web/from_composer_drop_down_widget.dart | 191 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 lib/features/composer/presentation/styles/web/from_composer_drop_down_widget_style.dart create mode 100644 lib/features/composer/presentation/widgets/web/from_composer_drop_down_widget.dart diff --git a/lib/features/composer/presentation/styles/web/from_composer_drop_down_widget_style.dart b/lib/features/composer/presentation/styles/web/from_composer_drop_down_widget_style.dart new file mode 100644 index 000000000..8f76bd34e --- /dev/null +++ b/lib/features/composer/presentation/styles/web/from_composer_drop_down_widget_style.dart @@ -0,0 +1,99 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; + +class FromComposerDropDownWidgetStyle { + static const double space = 8.0; + static const double dropdownItemSpace = 12.0; + static const double avatarSize = 48.0; + static const double avatarBorderWidth = 0.5; + static const double dropdownTopBarHeight = 32.0; + static const double buttonHeight = 32.0; + static const double buttonWidth = 411.0; + + static const EdgeInsetsGeometry prefixPadding = EdgeInsetsDirectional.only(top: 16.0); + static const EdgeInsetsGeometry editIdentityIconPadding = EdgeInsets.all(5.0); + static const EdgeInsetsGeometry dropdownButtonPadding = EdgeInsets.symmetric(vertical: 8.0); + static const EdgeInsetsGeometry dropdownItemPadding = EdgeInsets.symmetric(vertical: 12.0); + static const EdgeInsetsGeometry dropdownTopBarPadding = EdgeInsets.only( + top: 12.0, + left: 20.0, + right: 20.0, + ); + static const EdgeInsetsGeometry buttonPadding = EdgeInsets.only( + top: 4.0, + bottom: 4.0, + right: 4.0, + left: 8.0, + ); + + static const editIdentityIconBorderRadius = BorderRadius.all(Radius.circular(12.0)); + + static const BoxDecoration buttonDecoration = BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + color: AppColor.colorComposerAppBar, + ); + + static const ButtonStyleData buttonStyleData = ButtonStyleData( + width: buttonWidth, + height: buttonHeight, + padding: buttonPadding, + decoration: buttonDecoration, + ); + static DropdownStyleData dropdownStyleData = DropdownStyleData( + maxHeight: 272.0, + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + color: Colors.white, + ), + width: 381.0, + elevation: 4, + offset: const Offset(0.0, -8.0), + scrollbarTheme: ScrollbarThemeData( + radius: const Radius.circular(40.0), + thickness: MaterialStateProperty.all(6.0), + thumbVisibility: MaterialStateProperty.all(true), + ) + ); + static MenuItemStyleData menuIemStyleData = MenuItemStyleData( + padding: const EdgeInsets.symmetric(horizontal: 12), + height: 72, + overlayColor: MaterialStateProperty.resolveWith((Set states) => Colors.white) + ); + + static const TextStyle prefixTextStyle = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: AppColor.colorLabelComposer, + ); + static const TextStyle avatarTextStyle = TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.black, + ); + static const TextStyle dropdownItemTitleTextStyle = TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: AppColor.colorDropDownItemTitleComposer, + ); + static const TextStyle dropdownItemSubTitleTextStyle = TextStyle( + fontSize: 13, + fontWeight: FontWeight.w400, + color: AppColor.colorLabelQuotas + ); + static const TextStyle dropdownTitleTextStyle = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: AppColor.colorDropDownTitleComposer, + ); + static const TextStyle dropdownButtonTitleTextStyle = TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: AppColor.colorCalendarEventUnread + ); + static const TextStyle dropdownButtonSubTitleTextStyle = TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: AppColor.colorLabelComposer + ); +} \ No newline at end of file diff --git a/lib/features/composer/presentation/widgets/web/from_composer_drop_down_widget.dart b/lib/features/composer/presentation/widgets/web/from_composer_drop_down_widget.dart new file mode 100644 index 000000000..4dbec500b --- /dev/null +++ b/lib/features/composer/presentation/widgets/web/from_composer_drop_down_widget.dart @@ -0,0 +1,191 @@ +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:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:jmap_dart_client/jmap/identities/identity.dart'; +import 'package:model/model.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart'; +import 'package:tmail_ui_user/features/composer/presentation/styles/web/from_composer_drop_down_widget_style.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +typedef OnChangeIdentity = void Function(Identity? identity); + +class FromComposerDropDownWidget extends StatelessWidget { + + final List items; + final GlobalKey? dropdownKey; + final Identity? itemSelected; + final EdgeInsetsGeometry? padding; + final EdgeInsetsGeometry? margin; + final OnChangeIdentity? onChangeIdentity; + final ImagePaths imagePaths; + + const FromComposerDropDownWidget({ + super.key, + required this.items, + required this.dropdownKey, + required this.imagePaths, + this.itemSelected, + this.padding, + this.margin, + this.onChangeIdentity, + }); + + @override + Widget build(BuildContext context) { + return Container( + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: AppColor.colorLineComposer, + width: 1, + ) + ) + ), + padding: padding, + margin: margin, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: FromComposerDropDownWidgetStyle.prefixPadding, + child: Text( + '${PrefixEmailAddress.from.asName(context)}:', + style: FromComposerDropDownWidgetStyle.prefixTextStyle, + ), + ), + const SizedBox(width: FromComposerDropDownWidgetStyle.space), + Padding( + padding: FromComposerDropDownWidgetStyle.dropdownButtonPadding, + child: DropdownButtonHideUnderline( + child: PointerInterceptor( + child: DropdownButton2( + key: dropdownKey, + isExpanded: false, + items: items.map((item) => DropdownMenuItem( + value: item, + child: PointerInterceptor( + child: Container( + color: Colors.transparent, + padding: FromComposerDropDownWidgetStyle.dropdownItemPadding, + child: Row( + children: [ + Container( + width: FromComposerDropDownWidgetStyle.avatarSize, + height: FromComposerDropDownWidgetStyle.avatarSize, + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColor.avatarColor, + border: Border.all( + color: AppColor.colorShadowBgContentEmail, + width: FromComposerDropDownWidgetStyle.avatarBorderWidth + ) + ), + child: Text( + item.name!.isNotEmpty + ? item.name!.firstLetterToUpperCase + : item.email!.firstLetterToUpperCase, + style: FromComposerDropDownWidgetStyle.avatarTextStyle, + ), + ), + const SizedBox(width: FromComposerDropDownWidgetStyle.dropdownItemSpace), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (item.name!.isNotEmpty) + Text( + item.name!, + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + style: FromComposerDropDownWidgetStyle.dropdownItemTitleTextStyle, + ), + if (item.email!.isNotEmpty) + Text( + item.email!, + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + style: FromComposerDropDownWidgetStyle.dropdownItemSubTitleTextStyle, + ) + ], + ), + ) + ], + ), + ), + ), + )).toList(), + value: itemSelected, + buttonStyleData: FromComposerDropDownWidgetStyle.buttonStyleData, + dropdownSearchData: DropdownSearchData( + searchInnerWidget: Container( + padding: FromComposerDropDownWidgetStyle.dropdownTopBarPadding, + child: Text( + AppLocalizations.of(context).yourIdentities, + style: FromComposerDropDownWidgetStyle.dropdownTitleTextStyle, + ), + ), + searchInnerWidgetHeight: FromComposerDropDownWidgetStyle.dropdownTopBarHeight, + ), + dropdownStyleData: FromComposerDropDownWidgetStyle.dropdownStyleData, + iconStyleData: IconStyleData( + icon: SvgPicture.asset(imagePaths.icDropDown), + ), + menuItemStyleData: FromComposerDropDownWidgetStyle.menuIemStyleData, + customButton: Tooltip( + message: itemSelected != null ? itemSelected!.email : '', + child: Container( + height: FromComposerDropDownWidgetStyle.buttonHeight, + width: FromComposerDropDownWidgetStyle.buttonWidth, + padding: FromComposerDropDownWidgetStyle.buttonPadding, + decoration: FromComposerDropDownWidgetStyle.buttonDecoration, + child: Row( + children: [ + if (itemSelected != null) + Expanded( + child: RichText( + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + text: TextSpan( + children: [ + if (itemSelected!.name!.isNotEmpty) + TextSpan( + text: '${itemSelected!.name} ', + style: FromComposerDropDownWidgetStyle.dropdownButtonTitleTextStyle, + ), + TextSpan( + text: '(${itemSelected!.email})', + style: itemSelected!.name!.isNotEmpty + ? FromComposerDropDownWidgetStyle.dropdownButtonSubTitleTextStyle + : FromComposerDropDownWidgetStyle.dropdownButtonTitleTextStyle + ) + ] + ), + ) + ) + else + const SizedBox.shrink(), + SvgPicture.asset(imagePaths.icDropDown) + ], + ), + ), + ), + onChanged: onChangeIdentity, + ), + ), + ), + ), + ], + ), + ); + } +} \ No newline at end of file