From 429d882b7d52d515bb7d0b94c922a15575d2b494 Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 22 Jul 2022 14:24:43 +0700 Subject: [PATCH] TF-735 Display button code view in composer web --- assets/images/ic_style_code_view.svg | 3 + .../presentation/resources/image_paths.dart | 1 + .../base/widget/drop_down_button_widget.dart | 13 +- .../presentation/composer_controller.dart | 4 - .../presentation/composer_view_web.dart | 117 ++++++++++++------ .../mixin/rich_text_button_mixin.dart | 21 ++-- lib/l10n/intl_messages.arb | 8 +- lib/main/localizations/app_localizations.dart | 6 + 8 files changed, 121 insertions(+), 52 deletions(-) create mode 100644 assets/images/ic_style_code_view.svg diff --git a/assets/images/ic_style_code_view.svg b/assets/images/ic_style_code_view.svg new file mode 100644 index 000000000..5afd5da90 --- /dev/null +++ b/assets/images/ic_style_code_view.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 2c652ade5..854b9e078 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -133,6 +133,7 @@ class ImagePaths { String get icStyleUnderline => _getImagePath('ic_style_underline.svg'); String get icInsertImage => _getImagePath('ic_insert_image.svg'); String get icStyleStrikeThrough => _getImagePath('ic_style_strikethrough.svg'); + String get icStyleCodeView => _getImagePath('ic_style_code_view.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/base/widget/drop_down_button_widget.dart b/lib/features/base/widget/drop_down_button_widget.dart index a4b92c775..4e5b468f4 100644 --- a/lib/features/base/widget/drop_down_button_widget.dart +++ b/lib/features/base/widget/drop_down_button_widget.dart @@ -16,22 +16,26 @@ class DropDownButtonWidget extends StatelessWidget { final List items; final T? itemSelected; final Function(T?)? onChanged; + final Function(bool)? onMenuStateChange; final bool supportHint; final bool supportSelectionIcon; final double heightItem; final double sizeIconChecked; final double radiusButton; + final double opacity; const DropDownButtonWidget({ Key? key, required this.items, required this.itemSelected, this.onChanged, + this.onMenuStateChange, this.supportHint = false, this.supportSelectionIcon = false, this.heightItem = 44, this.sizeIconChecked = 20, this.radiusButton = 10, + this.opacity = 1.0, }) : super(key: key); @override @@ -46,9 +50,9 @@ class DropDownButtonWidget extends StatelessWidget { ? Row(children: [ Expanded(child: Text( _getTextItemDropdown(context, item: itemSelected), - style: const TextStyle(fontSize: 16, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.normal, - color: Colors.black), + color: Colors.black.withOpacity(opacity)), maxLines: 1, overflow: CommonTextStyle.defaultTextOverFlow, )), @@ -95,9 +99,9 @@ class DropDownButtonWidget extends StatelessWidget { child: Row(children: [ Expanded(child: Text( _getTextItemDropdown(context, item: itemSelected), - style: const TextStyle(fontSize: 16, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.normal, - color: Colors.black), + color: Colors.black.withOpacity(opacity)), maxLines: 1, overflow: CommonTextStyle.defaultTextOverFlow, )), @@ -131,6 +135,7 @@ class DropDownButtonWidget extends StatelessWidget { dropdownElevation: 4, scrollbarRadius: const Radius.circular(40), scrollbarThickness: 6, + onMenuStateChange: onMenuStateChange, ), ), ); diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index adec96dc7..2461e156c 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -355,10 +355,6 @@ class ComposerController extends BaseController { return ''; } - void setFullScreenEditor() { - richTextWebController.editorController.setFullScreen(); - } - String? _getHeaderEmailQuoted(BuildContext context, ComposerArguments arguments) { final presentationEmail = arguments.presentationEmail; if (presentationEmail != null) { diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 487cdfcf3..4b02efe66 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -14,6 +14,7 @@ import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_b 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/dropdown_menu_font_status.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'; @@ -508,16 +509,22 @@ class ComposerView extends GetWidget tooltip: AppLocalizations.of(context).attach_file, onTap: () => controller.openFilePickerByType(context, FileType.any)), const SizedBox(width: 4), - buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset(imagePaths.icInsertImage, - color: AppColor.colorTextButton, - fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).insertImage, - onTap: () => controller.insertImage( - context, - maxWithEditor: constraints.maxWidth - 120)), + Obx(() { + final opacity = controller.richTextWebController.codeViewEnabled ? 0.5 : 1.0; + return AbsorbPointer( + absorbing: controller.richTextWebController.codeViewEnabled, + child: buildIconWeb( + minSize: 40, + iconPadding: EdgeInsets.zero, + icon: SvgPicture.asset(imagePaths.icInsertImage, + color: AppColor.colorTextButton.withOpacity(opacity), + fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).insertImage, + onTap: () => controller.insertImage( + context, + maxWithEditor: constraints.maxWidth - 120)), + ); + }), ]) ) ); @@ -598,27 +605,35 @@ class ComposerView extends GetWidget toolbarType: ToolbarType.hide, defaultToolbarButtons: []), otherOptions: const OtherOptions(height: 550), - callbacks: Callbacks(onBeforeCommand: (String? currentHtml) { + callbacks: Callbacks(onBeforeCommand: (currentHtml) { log('ComposerView::_buildHtmlEditor(): onBeforeCommand : $currentHtml'); controller.setTextEditorWeb(currentHtml); - }, onChangeContent: (String? changed) { + }, onChangeContent: (changed) { log('ComposerView::_buildHtmlEditor(): onChangeContent : $changed'); controller.setTextEditorWeb(changed); }, onInit: () { log('ComposerView::_buildHtmlEditor(): onInit'); controller.setTextEditorWeb(initContent); - controller.setFullScreenEditor(); + controller.richTextWebController.setFullScreenEditor(); + controller.richTextWebController.setEnableCodeView(); }, onFocus: () { + log('ComposerView::_buildHtmlEditor(): onFocus'); FocusManager.instance.primaryFocus?.unfocus(); Future.delayed(const Duration(milliseconds: 500), () { controller.richTextWebController.editorController.setFocus(); }); + if (controller.richTextWebController.isMenuFontOpen) { + controller.richTextWebController.closeDropdownMenuFont(); + } }, onBlur: () { controller.onEditorFocusChange(false); }, onMouseDown: () { controller.onEditorFocusChange(true); }, onChangeSelection: (settings) { controller.richTextWebController.onEditorSettingsChange(settings); + }, onChangeCodeview: (contentChanged) { + log('ComposerView::_buildHtmlEditor(): onChangeCodeView : $contentChanged'); + controller.setTextEditorWeb(contentChanged); }), ) ) @@ -744,40 +759,70 @@ class ComposerView extends GetWidget alignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, children: RichTextStyleType.values.map((textType) => Obx(() { + final opacity = controller.richTextWebController.codeViewEnabled ? 0.5 : 1.0; switch(textType) { case RichTextStyleType.textColor: - return buildIconColorText( - iconData: textType.getIconData(), - colorSelected: controller.richTextWebController.selectedTextColor.value, - tooltip: textType.getTooltipButton(context), - onTap: () => controller.richTextWebController.applyRichTextStyle(context, textType)); + return AbsorbPointer( + absorbing: controller.richTextWebController.codeViewEnabled, + child: buildIconColorText( + iconData: textType.getIconData(), + colorSelected: controller.richTextWebController.selectedTextColor.value, + tooltip: textType.getTooltipButton(context), + opacity: opacity, + onTap: () => controller.richTextWebController.applyRichTextStyle(context, textType)), + ); case RichTextStyleType.textBackgroundColor: return Padding( padding: const EdgeInsets.symmetric(horizontal: 2), - child: buildIconColorBackgroundText( - iconData: textType.getIconData(), - colorSelected: controller.richTextWebController.selectedTextBackgroundColor.value, - tooltip: textType.getTooltipButton(context), - onTap: () => controller.richTextWebController.applyRichTextStyle(context, textType)), + child: AbsorbPointer( + absorbing: controller.richTextWebController.codeViewEnabled, + child: buildIconColorBackgroundText( + iconData: textType.getIconData(), + colorSelected: controller.richTextWebController.selectedTextBackgroundColor.value, + tooltip: textType.getTooltipButton(context), + opacity: opacity, + 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 AbsorbPointer( + absorbing: controller.richTextWebController.codeViewEnabled, + child: 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), + onMenuStateChange: (isOpen) { + log('ComposerView::_buildToolbarRichTextWidget(): MenuFontStatus: $isOpen'); + final newStatus = isOpen + ? DropdownMenuFontStatus.open + : DropdownMenuFontStatus.closed; + controller.richTextWebController.menuFontStatus = newStatus; + }, + heightItem: 35, + sizeIconChecked: 16, + radiusButton: 5, + opacity: opacity, + supportSelectionIcon: true)), + ); + case RichTextStyleType.codeView: return buildIconStyleText( path: textType.getIcon(imagePaths), isSelected: controller.richTextWebController.isTextStyleTypeSelected(textType), tooltip: textType.getTooltipButton(context), - onTap: () => controller.richTextWebController.applyRichTextStyle(context, textType)); + onTap: () => controller.richTextWebController.toggleCodeView()); + default: + return AbsorbPointer( + absorbing: controller.richTextWebController.codeViewEnabled, + child: buildIconStyleText( + path: textType.getIcon(imagePaths), + isSelected: controller.richTextWebController.isTextStyleTypeSelected(textType), + tooltip: textType.getTooltipButton(context), + opacity: opacity, + onTap: () => controller.richTextWebController.applyRichTextStyle(context, textType)), + ); } })).toList() ), 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 8787ee03d..3a4574f9f 100644 --- a/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart +++ b/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart @@ -10,14 +10,15 @@ mixin RichTextButtonMixin { required String path, required bool? isSelected, required VoidCallback onTap, - String? tooltip + String? tooltip, + double opacity = 1.0, }){ return buildIconWeb( icon: SvgPicture.asset( path, color: isSelected == true - ? Colors.black - : AppColor.colorDefaultRichTextButton, + ? Colors.black.withOpacity(opacity) + : AppColor.colorDefaultRichTextButton.withOpacity(opacity), fit: BoxFit.fill), iconPadding: const EdgeInsets.all(4), colorFocus: Colors.white, @@ -31,10 +32,13 @@ mixin RichTextButtonMixin { required IconData? iconData, required Color? colorSelected, required VoidCallback onTap, - String? tooltip + String? tooltip, + double opacity = 1.0, }){ return buildIconWeb( - icon: Icon(iconData, color: colorSelected ?? Colors.black, size: 20), + icon: Icon(iconData, + color: (colorSelected ?? Colors.black).withOpacity(opacity), + size: 20), iconPadding: const EdgeInsets.all(4), colorSelected: colorSelected == Colors.white ? AppColor.colorFocusRichTextButton @@ -50,13 +54,16 @@ mixin RichTextButtonMixin { required IconData? iconData, required Color? colorSelected, required VoidCallback onTap, - String? tooltip + String? tooltip, + double opacity = 1.0, }){ final newColor = colorSelected == Colors.white ? AppColor.colorDefaultRichTextButton : colorSelected; return buildIconWeb( - icon: Icon(iconData, color: newColor ?? AppColor.colorDefaultRichTextButton, size: 20), + icon: Icon(iconData, + color: (newColor ?? AppColor.colorDefaultRichTextButton).withOpacity(opacity), + size: 20), iconPadding: const EdgeInsets.all(4), colorSelected: newColor == Colors.white ? AppColor.colorFocusRichTextButton diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 4479c2ec0..e47c7bd3c 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-07-21T14:49:43.482260", + "@@last_modified": "2022-07-22T14:15:06.629292", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1669,5 +1669,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "codeView": "Code view", + "@codeView": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index b1882d2cb..60a93c9b4 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1713,4 +1713,10 @@ class AppLocalizations { 'Text Background Color', name: 'formatTextBackgroundColor'); } + + String get codeView { + return Intl.message( + 'Code view', + name: 'codeView'); + } } \ No newline at end of file