diff --git a/assets/images/ic_style_strike_through.svg b/assets/images/ic_style_strike_through.svg deleted file mode 100644 index f980e2bbe..000000000 --- a/assets/images/ic_style_strike_through.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/ic_style_strikethroughs.svg b/assets/images/ic_style_strikethrough.svg similarity index 100% rename from assets/images/ic_style_strikethroughs.svg rename to assets/images/ic_style_strikethrough.svg diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 9490acc52..2c652ade5 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -132,7 +132,7 @@ class ImagePaths { String get icStyleItalic => _getImagePath('ic_style_italic.svg'); String get icStyleUnderline => _getImagePath('ic_style_underline.svg'); String get icInsertImage => _getImagePath('ic_insert_image.svg'); - String get icStyleStrikeThrough => _getImagePath('ic_style_strikethroughs.svg'); + String get icStyleStrikeThrough => _getImagePath('ic_style_strikethrough.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/core/lib/presentation/views/button/icon_button_web.dart b/core/lib/presentation/views/button/icon_button_web.dart index 9c01146b8..4867e85ce 100644 --- a/core/lib/presentation/views/button/icon_button_web.dart +++ b/core/lib/presentation/views/button/icon_button_web.dart @@ -126,39 +126,6 @@ Widget buildTextButton(String text, { ); } -Widget buildButtonWrapText(String name, { - TextStyle? textStyle, - Color? bgColor, - double? radius, - double? height, - EdgeInsets? padding, - IconWebCallback? onTap -}) { - return Container( - height: height ?? 40, - padding: padding, - child: ElevatedButton( - onPressed: () => onTap?.call(), - style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) => bgColor ?? AppColor.colorTextButton), - shape: MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(radius ?? 8), - side: BorderSide(width: 0, color: bgColor ?? AppColor.colorTextButton))), - padding: MaterialStateProperty.resolveWith( - (Set states) => const EdgeInsets.symmetric(horizontal: 16)), - elevation: MaterialStateProperty.resolveWith( - (Set states) => 0)), - child: Text(name, - textAlign: TextAlign.center, - style: textStyle ?? - const TextStyle( - fontSize: 17, - fontWeight: FontWeight.w500, - color: Colors.white)), - ), - ); -} Widget buildButtonWrapText(String name, { TextStyle? textStyle, Color? bgColor, diff --git a/lib/features/base/widget/drop_down_button_widget.dart b/lib/features/base/widget/drop_down_button_widget.dart index bdf199188..a4b92c775 100644 --- a/lib/features/base/widget/drop_down_button_widget.dart +++ b/lib/features/base/widget/drop_down_button_widget.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/language_and_region/extensions/locale_extension.dart'; class DropDownButtonWidget extends StatelessWidget { @@ -16,6 +18,9 @@ class DropDownButtonWidget extends StatelessWidget { final Function(T?)? onChanged; final bool supportHint; final bool supportSelectionIcon; + final double heightItem; + final double sizeIconChecked; + final double radiusButton; const DropDownButtonWidget({ Key? key, @@ -23,7 +28,10 @@ class DropDownButtonWidget extends StatelessWidget { required this.itemSelected, this.onChanged, this.supportHint = false, - this.supportSelectionIcon = false + this.supportSelectionIcon = false, + this.heightItem = 44, + this.sizeIconChecked = 20, + this.radiusButton = 10, }) : super(key: key); @override @@ -31,92 +39,99 @@ class DropDownButtonWidget extends StatelessWidget { final _imagePaths = Get.find(); return DropdownButtonHideUnderline( - child: DropdownButton2( - isExpanded: true, - hint: supportHint - ? Row(children: [ - Expanded(child: Text( - _getTextItemDropdown(context, item: itemSelected), - style: const TextStyle(fontSize: 16, - fontWeight: FontWeight.normal, - color: Colors.black), - maxLines: 1, - overflow: CommonTextStyle.defaultTextOverFlow, - )), - ]) - : null, - items: items - .map((item) => DropdownMenuItem( - value: item, - child: Row(children: [ - Expanded(child: Text(_getTextItemDropdown(context, item: item), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.normal, - color: Colors.black), - maxLines: 1, - overflow: CommonTextStyle.defaultTextOverFlow, - )), - if (supportSelectionIcon && item == itemSelected) - SvgPicture.asset(_imagePaths.icChecked, - width: 20, - height: 20, - fit: BoxFit.fill) - ]), - )) - .toList(), - value: itemSelected, - customButton: supportSelectionIcon - ? Container( - height: 44, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: AppColor.colorInputBorderCreateMailbox, - width: 0.5, + child: PointerInterceptor( + child: DropdownButton2( + isExpanded: true, + hint: supportHint + ? Row(children: [ + Expanded(child: Text( + _getTextItemDropdown(context, item: itemSelected), + style: const TextStyle(fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black), + maxLines: 1, + overflow: CommonTextStyle.defaultTextOverFlow, + )), + ]) + : null, + items: items + .map((item) => DropdownMenuItem( + value: item, + child: PointerInterceptor( + child: SizedBox( + height: heightItem, + child: Row(children: [ + Expanded(child: Text(_getTextItemDropdown(context, item: item), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black), + maxLines: 1, + overflow: CommonTextStyle.defaultTextOverFlow, + )), + if (supportSelectionIcon && item == itemSelected) + SvgPicture.asset(_imagePaths.icChecked, + width: sizeIconChecked, + height: sizeIconChecked, + fit: BoxFit.fill) + ]), + ), + ), + )) + .toList(), + value: itemSelected, + customButton: supportSelectionIcon + ? Container( + height: heightItem, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(radiusButton), + border: Border.all( + color: AppColor.colorInputBorderCreateMailbox, + width: 0.5, + ), + color: AppColor.colorInputBackgroundCreateMailbox, ), - color: AppColor.colorInputBackgroundCreateMailbox, - ), - padding: const EdgeInsets.only(left: 12, right: 10), - child: Row(children: [ - Expanded(child: Text( - _getTextItemDropdown(context, item: itemSelected), - style: const TextStyle(fontSize: 16, - fontWeight: FontWeight.normal, - color: Colors.black), - maxLines: 1, - overflow: CommonTextStyle.defaultTextOverFlow, - )), - SvgPicture.asset(_imagePaths.icDropDown) - ]), - ) - : null, - onChanged: onChanged, - icon: SvgPicture.asset(_imagePaths.icDropDown), - buttonPadding: const EdgeInsets.symmetric(horizontal: 12), - buttonDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: AppColor.colorInputBorderCreateMailbox, - width: 0.5, + padding: const EdgeInsets.only(left: 12, right: 10), + child: Row(children: [ + Expanded(child: Text( + _getTextItemDropdown(context, item: itemSelected), + style: const TextStyle(fontSize: 16, + fontWeight: FontWeight.normal, + color: Colors.black), + maxLines: 1, + overflow: CommonTextStyle.defaultTextOverFlow, + )), + SvgPicture.asset(_imagePaths.icDropDown) + ]), + ) + : null, + onChanged: onChanged, + icon: SvgPicture.asset(_imagePaths.icDropDown), + buttonPadding: const EdgeInsets.symmetric(horizontal: 12), + buttonDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(radiusButton), + border: Border.all( + color: AppColor.colorInputBorderCreateMailbox, + width: 0.5, + ), + color: AppColor.colorInputBackgroundCreateMailbox, ), - color: AppColor.colorInputBackgroundCreateMailbox, + itemHeight: heightItem, + buttonHeight: heightItem, + selectedItemHighlightColor: supportSelectionIcon + ? Colors.white + : Colors.black12, + itemPadding: const EdgeInsets.symmetric(horizontal: 12), + dropdownMaxHeight: 200, + dropdownDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(radiusButton), + color: Colors.white, + ), + offset: const Offset(0.0, -8.0), + dropdownElevation: 4, + scrollbarRadius: const Radius.circular(40), + scrollbarThickness: 6, ), - itemHeight: 44, - buttonHeight: 44, - selectedItemHighlightColor: supportSelectionIcon - ? Colors.white - : Colors.black12, - itemPadding: const EdgeInsets.symmetric(horizontal: 12), - dropdownMaxHeight: 200, - dropdownDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.white, - ), - offset: const Offset(0.0, -8.0), - dropdownElevation: 4, - scrollbarRadius: const Radius.circular(40), - scrollbarThickness: 6, ), ); } @@ -128,6 +143,9 @@ class DropDownButtonWidget extends StatelessWidget { if (item is Locale) { return item.getLanguageName(context); } + if (item is FontNameType) { + return item.fontFamily; + } return ''; } } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 331a34df1..487cdfcf3 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -11,8 +11,10 @@ import 'package:model/model.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_base64_state.dart'; +import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/mixin/rich_text_button_mixin.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart'; @@ -736,9 +738,11 @@ class ComposerView extends GetWidget Widget _buildToolbarRichTextWidget(BuildContext context) { return Container( - padding: const EdgeInsets.only(left: 20, top: 4, bottom: 8), + padding: const EdgeInsets.only(left: 20, top: 8, bottom: 8), alignment: Alignment.centerLeft, child: Wrap( + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, children: RichTextStyleType.values.map((textType) => Obx(() { switch(textType) { case RichTextStyleType.textColor: @@ -750,12 +754,24 @@ class ComposerView extends GetWidget case RichTextStyleType.textBackgroundColor: return Padding( padding: const EdgeInsets.symmetric(horizontal: 2), - child: buildIconColorText( + child: buildIconColorBackgroundText( iconData: textType.getIconData(), colorSelected: controller.richTextWebController.selectedTextBackgroundColor.value, tooltip: textType.getTooltipButton(context), onTap: () => controller.richTextWebController.applyRichTextStyle(context, textType)), ); + case RichTextStyleType.fontName: + return Container( + width: 200, + padding: const EdgeInsets.only(right: 2), + child: DropDownButtonWidget( + items: FontNameType.values, + itemSelected: controller.richTextWebController.selectedFontName.value, + onChanged: (newFont) => controller.richTextWebController.applyNewFontStyle(newFont), + heightItem: 35, + sizeIconChecked: 16, + radiusButton: 5, + supportSelectionIcon: true)); default: return buildIconStyleText( path: textType.getIcon(imagePaths), diff --git a/lib/features/composer/presentation/controller/rich_text_web_controller.dart b/lib/features/composer/presentation/controller/rich_text_web_controller.dart index 302125c96..fd4e8bb0b 100644 --- a/lib/features/composer/presentation/controller/rich_text_web_controller.dart +++ b/lib/features/composer/presentation/controller/rich_text_web_controller.dart @@ -5,13 +5,13 @@ import 'package:html/parser.dart' show parse; import 'package:core/utils/app_logger.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:html_editor_enhanced/html_editor.dart'; import 'package:model/email/attachment.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/image_source.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/base_rich_text_controller.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart'; class RichTextWebController extends BaseRichTextController { @@ -20,7 +20,8 @@ class RichTextWebController extends BaseRichTextController { final listTextStyleApply = RxList(); final selectedTextColor = Colors.black.obs; - final selectedTextBackgroundColor = Colors.transparent.obs; + final selectedTextBackgroundColor = Colors.white.obs; + final selectedFontName = FontNameType.sansSerif.obs; void onEditorSettingsChange(EditorSettings settings) { log('RichTextWebController::onEditorSettingsChange():'); @@ -77,17 +78,18 @@ class RichTextWebController extends BaseRichTextController { context, selectedTextBackgroundColor.value, onResetToDefault: () { - final colorAsString = (Colors.transparent.value & 0xFFFFFF) + final colorAsString = (Colors.white.value & 0xFFFFFF) .toRadixString(16) .padLeft(6, '0') .toUpperCase(); - selectedTextBackgroundColor.value = Colors.transparent; + log('RichTextWebController::applyRichTextStyle():onResetToDefault: colorAsString: $colorAsString'); + selectedTextBackgroundColor.value = Colors.white; editorController.execCommand( textStyleType.commandAction, argument: colorAsString); }, onSelectColor: (selectedColor) { - final newColor = selectedColor ?? Colors.transparent; + final newColor = selectedColor ?? Colors.white; final colorAsString = (newColor.value & 0xFFFFFF) .toRadixString(16) .padLeft(6, '0') @@ -155,4 +157,12 @@ class RichTextWebController extends BaseRichTextController { log('RichTextWebController::refactorContentHasInlineImage(): listInlineAttachment: $listInlineAttachment'); return Tuple2(newContent, listInlineAttachment); } + + void applyNewFontStyle(FontNameType? newFont) { + final fontSelected = newFont ?? FontNameType.sansSerif; + selectedFontName.value = fontSelected; + editorController.execCommand( + RichTextStyleType.fontName.commandAction, + argument: fontSelected.fontFamily); + } } \ No newline at end of file diff --git a/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart b/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart index d9cfa3f20..8787ee03d 100644 --- a/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart +++ b/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart @@ -33,13 +33,10 @@ mixin RichTextButtonMixin { required VoidCallback onTap, String? tooltip }){ - final newColor = colorSelected == Colors.transparent - ? AppColor.colorDefaultRichTextButton - : colorSelected; return buildIconWeb( - icon: Icon(iconData, color: newColor ?? Colors.black, size: 20), + icon: Icon(iconData, color: colorSelected ?? Colors.black, size: 20), iconPadding: const EdgeInsets.all(4), - colorSelected: newColor == Colors.white + colorSelected: colorSelected == Colors.white ? AppColor.colorFocusRichTextButton : Colors.transparent, colorFocus: Colors.white, @@ -48,4 +45,26 @@ mixin RichTextButtonMixin { onTap: onTap, ); } + + Widget buildIconColorBackgroundText({ + required IconData? iconData, + required Color? colorSelected, + required VoidCallback onTap, + String? tooltip + }){ + final newColor = colorSelected == Colors.white + ? AppColor.colorDefaultRichTextButton + : colorSelected; + return buildIconWeb( + icon: Icon(iconData, color: newColor ?? AppColor.colorDefaultRichTextButton, size: 20), + iconPadding: const EdgeInsets.all(4), + colorSelected: newColor == Colors.white + ? AppColor.colorFocusRichTextButton + : Colors.transparent, + colorFocus: Colors.white, + minSize: 20, + tooltip: tooltip, + onTap: onTap, + ); + } } \ No newline at end of file diff --git a/lib/features/composer/presentation/model/font_name_type.dart b/lib/features/composer/presentation/model/font_name_type.dart new file mode 100644 index 000000000..25788be6d --- /dev/null +++ b/lib/features/composer/presentation/model/font_name_type.dart @@ -0,0 +1,50 @@ + +enum FontNameType { + arial, + arialBlack, + brushScriptMT, + comicSansMS, + courierNew, + helveticaNeue, + helvetica, + impact, + lucidaGrande, + tahoma, + timesNewRoman, + trebuchetMS, + sansSerif, + verdana; + + String get fontFamily { + switch(this) { + case FontNameType.arial: + return 'Arial'; + case FontNameType.arialBlack: + return 'Arial Black'; + case FontNameType.brushScriptMT: + return 'Brush Script MT'; + case FontNameType.comicSansMS: + return 'Comic Sans MS'; + case FontNameType.courierNew: + return 'Courier New'; + case FontNameType.helveticaNeue: + return 'Helvetica Neue'; + case FontNameType.helvetica: + return 'Helvetica'; + case FontNameType.impact: + return 'Impact'; + case FontNameType.lucidaGrande: + return 'Lucida Grande'; + case FontNameType.tahoma: + return 'Tahoma'; + case FontNameType.timesNewRoman: + return 'Times New Roman'; + case FontNameType.trebuchetMS: + return 'Trebuchet MS'; + case FontNameType.sansSerif: + return 'Sans Serif'; + case FontNameType.verdana: + return 'Verdana'; + } + } +} \ No newline at end of file diff --git a/lib/features/composer/presentation/model/rich_text_style_type.dart b/lib/features/composer/presentation/model/rich_text_style_type.dart index 5eb001896..dadb7a89c 100644 --- a/lib/features/composer/presentation/model/rich_text_style_type.dart +++ b/lib/features/composer/presentation/model/rich_text_style_type.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; enum RichTextStyleType { + fontName, bold, italic, underline, @@ -13,6 +14,8 @@ enum RichTextStyleType { String get commandAction { switch (this) { + case fontName: + return 'fontName'; case bold: return 'bold'; case italic: