From dd7793a56962b6b41ef6b0317e875d21cf8a41d4 Mon Sep 17 00:00:00 2001 From: DatDang Date: Mon, 16 Sep 2024 16:30:19 +0700 Subject: [PATCH] Add semantics for text formatting --- .../base/key_values/composer_key_values.dart | 11 + .../web/toolbar_rich_text_builder.dart | 315 ++++++++++-------- 2 files changed, 191 insertions(+), 135 deletions(-) diff --git a/lib/features/base/key_values/composer_key_values.dart b/lib/features/base/key_values/composer_key_values.dart index 4f056abf65..bfdb88214f 100644 --- a/lib/features/base/key_values/composer_key_values.dart +++ b/lib/features/base/key_values/composer_key_values.dart @@ -22,4 +22,15 @@ class ComposerKeyValues { static const String toggleReadRecipientsButton = 'tmail_composer_toggle_read_recipients_button'; static const String saveAsDraftButton = 'tmail_composer_save_as_draft_button'; static const String openMobileMoreOptionsButton = 'tmail_composer_open_mobile_more_options_button'; + static const String richtextHeaderStyleButton = 'tmail_composer_richtext_header_style_button'; + static const String richtextFontSizeButton = 'tmail_composer_richtext_font_size_button'; + static const String richtextFontNameButton = 'tmail_composer_richtext_font_name_button'; + static const String richtextTextColorButton = 'tmail_composer_richtext_text_color_button'; + static const String richtextBackgroundColorButton = 'tmail_composer_richtext_background_color_button'; + static const String richtextBoldToggle = 'tmail_composer_richtext_bold_toggle'; + static const String richtextItalicToggle = 'tmail_composer_richtext_italic_toggle'; + static const String richtextUnderlineToggle = 'tmail_composer_richtext_underline_toggle'; + static const String richtextStrikethroughToggle = 'tmail_composer_richtext_strikethrough_toggle'; + static const String richtextAlignParagraphButton = 'tmail_composer_richtext_align_paragraph_button'; + static const String richtextListStyleButton = 'tmail_composer_richtext_list_style_button'; } \ No newline at end of file diff --git a/lib/features/composer/presentation/widgets/web/toolbar_rich_text_builder.dart b/lib/features/composer/presentation/widgets/web/toolbar_rich_text_builder.dart index 8e98cb961a..513252d711 100644 --- a/lib/features/composer/presentation/widgets/web/toolbar_rich_text_builder.dart +++ b/lib/features/composer/presentation/widgets/web/toolbar_rich_text_builder.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart'; @@ -56,92 +57,112 @@ class ToolbarRichTextWebBuilder extends StatelessWidget with RichTextButtonMixin ...extendedOption!, AbsorbPointer( absorbing: codeViewEnabled, - child: DropDownMenuHeaderStyleWidget( - icon: buildWrapIconStyleText( - isSelected: richTextWebController.isMenuHeaderStyleOpen, - icon: SvgPicture.asset( - RichTextStyleType.headerStyle.getIcon(_imagePaths), - colorFilter: AppColor.colorDefaultRichTextButton.withOpacity(opacity).asFilter(), - fit: BoxFit.fill + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextHeaderStyleButton, + child: DropDownMenuHeaderStyleWidget( + icon: buildWrapIconStyleText( + isSelected: richTextWebController.isMenuHeaderStyleOpen, + icon: SvgPicture.asset( + RichTextStyleType.headerStyle.getIcon(_imagePaths), + colorFilter: AppColor.colorDefaultRichTextButton.withOpacity(opacity).asFilter(), + fit: BoxFit.fill + ), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), + tooltip: RichTextStyleType.headerStyle.getTooltipButton(context) ), - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), - tooltip: RichTextStyleType.headerStyle.getTooltipButton(context) + items: HeaderStyleType.values, + onMenuStateChange: (isOpen) { + final newStatus = isOpen + ? DropdownMenuFontStatus.open + : DropdownMenuFontStatus.closed; + richTextWebController.menuHeaderStyleStatus.value = newStatus; + }, + onChanged: richTextWebController.applyHeaderStyle ), - items: HeaderStyleType.values, - onMenuStateChange: (isOpen) { - final newStatus = isOpen - ? DropdownMenuFontStatus.open - : DropdownMenuFontStatus.closed; - richTextWebController.menuHeaderStyleStatus.value = newStatus; - }, - onChanged: richTextWebController.applyHeaderStyle ), ), AbsorbPointer( absorbing: codeViewEnabled, - child: DropdownMenuFontSizeWidget( - onChanged: richTextWebController.applyNewFontSize, - selectedFontSize: richTextWebController.selectedFontSize.value + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextFontSizeButton, + child: DropdownMenuFontSizeWidget( + onChanged: richTextWebController.applyNewFontSize, + selectedFontSize: richTextWebController.selectedFontSize.value + ), ), ), AbsorbPointer( absorbing: codeViewEnabled, child: SizedBox( width: 130, - child: DropDownButtonWidget( - items: FontNameType.values, - itemSelected: richTextWebController.selectedFontName.value, - onChanged: (newFont) => richTextWebController.applyNewFontStyle(newFont), - onMenuStateChange: (isOpen) { - final newStatus = isOpen - ? DropdownMenuFontStatus.open - : DropdownMenuFontStatus.closed; - richTextWebController.menuFontStatus.value = newStatus; - }, - heightItem: 40, - sizeIconChecked: 16, - radiusButton: 8, - opacity: opacity, - dropdownWidth: 200, - colorButton: richTextWebController.isMenuFontOpen - ? AppColor.colorBackgroundWrapIconStyleCode - : Colors.white, - iconArrowDown: SvgPicture.asset(_imagePaths.icStyleArrowDown), - tooltip: RichTextStyleType.fontName.getTooltipButton(context), - supportSelectionIcon: true + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextFontNameButton, + child: DropDownButtonWidget( + items: FontNameType.values, + itemSelected: richTextWebController.selectedFontName.value, + onChanged: (newFont) => richTextWebController.applyNewFontStyle(newFont), + onMenuStateChange: (isOpen) { + final newStatus = isOpen + ? DropdownMenuFontStatus.open + : DropdownMenuFontStatus.closed; + richTextWebController.menuFontStatus.value = newStatus; + }, + heightItem: 40, + sizeIconChecked: 16, + radiusButton: 8, + opacity: opacity, + dropdownWidth: 200, + colorButton: richTextWebController.isMenuFontOpen + ? AppColor.colorBackgroundWrapIconStyleCode + : Colors.white, + iconArrowDown: SvgPicture.asset(_imagePaths.icStyleArrowDown), + tooltip: RichTextStyleType.fontName.getTooltipButton(context), + supportSelectionIcon: true + ), ) ), ), AbsorbPointer( absorbing: codeViewEnabled, - child: buildWrapIconStyleText( - icon: buildIconWithTooltip( - path: RichTextStyleType.textColor.getIcon(_imagePaths), - color: richTextWebController.selectedTextColor.value, - tooltip: RichTextStyleType.textColor.getTooltipButton(context), - opacity: opacity + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextTextColorButton, + child: buildWrapIconStyleText( + icon: buildIconWithTooltip( + path: RichTextStyleType.textColor.getIcon(_imagePaths), + color: richTextWebController.selectedTextColor.value, + tooltip: RichTextStyleType.textColor.getTooltipButton(context), + opacity: opacity + ), + onTap: () => richTextWebController.applyRichTextStyle( + context, + RichTextStyleType.textColor + ) ), - onTap: () => richTextWebController.applyRichTextStyle( - context, - RichTextStyleType.textColor - ) ), ), AbsorbPointer( absorbing: codeViewEnabled, - child: buildWrapIconStyleText( - padding: const EdgeInsets.symmetric(vertical: 9, horizontal: 7), - spacing: 3, - icon: buildIconColorBackgroundText( - iconData: RichTextStyleType.textBackgroundColor.getIconData(), - colorSelected: richTextWebController.selectedTextBackgroundColor.value, - tooltip: RichTextStyleType.textBackgroundColor.getTooltipButton(context), - opacity: opacity + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextBackgroundColorButton, + child: buildWrapIconStyleText( + padding: const EdgeInsets.symmetric(vertical: 9, horizontal: 7), + spacing: 3, + icon: buildIconColorBackgroundText( + iconData: RichTextStyleType.textBackgroundColor.getIconData(), + colorSelected: richTextWebController.selectedTextBackgroundColor.value, + tooltip: RichTextStyleType.textBackgroundColor.getTooltipButton(context), + opacity: opacity + ), + onTap: () => richTextWebController.applyRichTextStyle( + context, + RichTextStyleType.textBackgroundColor + ) ), - onTap: () => richTextWebController.applyRichTextStyle( - context, - RichTextStyleType.textBackgroundColor - ) ), ), buildWrapIconStyleText( @@ -150,101 +171,125 @@ class ToolbarRichTextWebBuilder extends StatelessWidget with RichTextButtonMixin icon: Wrap(children: [ AbsorbPointer( absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.bold.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.bold), - tooltip: RichTextStyleType.bold.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle( - context, - RichTextStyleType.bold - ) + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextBoldToggle, + child: buildIconStyleText( + path: RichTextStyleType.bold.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.bold), + tooltip: RichTextStyleType.bold.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle( + context, + RichTextStyleType.bold + ) + ), ), ), AbsorbPointer( absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.italic.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.italic), - tooltip: RichTextStyleType.italic.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle( - context, - RichTextStyleType.italic - ) + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextItalicToggle, + child: buildIconStyleText( + path: RichTextStyleType.italic.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.italic), + tooltip: RichTextStyleType.italic.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle( + context, + RichTextStyleType.italic + ) + ), ), ), AbsorbPointer( absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.underline.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.underline), - tooltip: RichTextStyleType.underline.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle( - context, - RichTextStyleType.underline - ) + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextUnderlineToggle, + child: buildIconStyleText( + path: RichTextStyleType.underline.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.underline), + tooltip: RichTextStyleType.underline.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle( + context, + RichTextStyleType.underline + ) + ), ), ), AbsorbPointer( absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.strikeThrough.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.strikeThrough), - tooltip: RichTextStyleType.strikeThrough.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle( - context, - RichTextStyleType.strikeThrough - ) + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextStrikethroughToggle, + child: buildIconStyleText( + path: RichTextStyleType.strikeThrough.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.strikeThrough), + tooltip: RichTextStyleType.strikeThrough.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle( + context, + RichTextStyleType.strikeThrough + ) + ), ), ) ]) ), AbsorbPointer( absorbing: codeViewEnabled, - child: PopupMenuOverlayWidget( - controller: richTextWebController.menuParagraphController, - listButtonAction: ParagraphType.values - .map((paragraph) => paragraph.buildButtonWidget( - context, - _imagePaths, - (paragraph) => richTextWebController.applyParagraphType(paragraph))) - .toList(), - iconButton: buildWrapIconStyleText( - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), - spacing: 3, - isSelected: richTextWebController.focusMenuParagraph.value, - icon: buildIconWithTooltip( - path: richTextWebController.selectedParagraph.value.getIcon(_imagePaths), - color: AppColor.colorDefaultRichTextButton, - opacity: opacity, - tooltip: RichTextStyleType.paragraph.getTooltipButton(context) - ) + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextAlignParagraphButton, + child: PopupMenuOverlayWidget( + controller: richTextWebController.menuParagraphController, + listButtonAction: ParagraphType.values + .map((paragraph) => paragraph.buildButtonWidget( + context, + _imagePaths, + (paragraph) => richTextWebController.applyParagraphType(paragraph))) + .toList(), + iconButton: buildWrapIconStyleText( + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), + spacing: 3, + isSelected: richTextWebController.focusMenuParagraph.value, + icon: buildIconWithTooltip( + path: richTextWebController.selectedParagraph.value.getIcon(_imagePaths), + color: AppColor.colorDefaultRichTextButton, + opacity: opacity, + tooltip: RichTextStyleType.paragraph.getTooltipButton(context) + ) + ), ), ), ), AbsorbPointer( absorbing: codeViewEnabled, - child: PopupMenuOverlayWidget( - controller: richTextWebController.menuOrderListController, - listButtonAction: OrderListType.values - .map((orderType) => orderType.buildButtonWidget( - context, - _imagePaths, - (orderType) => richTextWebController.applyOrderListType(orderType))) - .toList(), - iconButton: buildWrapIconStyleText( - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), - spacing: 3, - isSelected: richTextWebController.focusMenuOrderList.value, - icon: buildIconWithTooltip( - path: richTextWebController.selectedOrderList.value.getIcon(_imagePaths), - color: AppColor.colorDefaultRichTextButton, - opacity: opacity, - tooltip: RichTextStyleType.orderList.getTooltipButton(context) - ) + child: Semantics( + excludeSemantics: true, + identifier: ComposerKeyValues.richtextListStyleButton, + child: PopupMenuOverlayWidget( + controller: richTextWebController.menuOrderListController, + listButtonAction: OrderListType.values + .map((orderType) => orderType.buildButtonWidget( + context, + _imagePaths, + (orderType) => richTextWebController.applyOrderListType(orderType))) + .toList(), + iconButton: buildWrapIconStyleText( + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), + spacing: 3, + isSelected: richTextWebController.focusMenuOrderList.value, + icon: buildIconWithTooltip( + path: richTextWebController.selectedOrderList.value.getIcon(_imagePaths), + color: AppColor.colorDefaultRichTextButton, + opacity: opacity, + tooltip: RichTextStyleType.orderList.getTooltipButton(context) + ) + ), ), ), )