diff --git a/assets/images/ic_style_arrow_down.svg b/assets/images/ic_style_arrow_down.svg new file mode 100644 index 000000000..12ed951e2 --- /dev/null +++ b/assets/images/ic_style_arrow_down.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_style_color.svg b/assets/images/ic_style_color.svg new file mode 100644 index 000000000..01ac8ed33 --- /dev/null +++ b/assets/images/ic_style_color.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/assets/images/ic_style_header.svg b/assets/images/ic_style_header.svg index be41d43bb..30781b17b 100644 --- a/assets/images/ic_style_header.svg +++ b/assets/images/ic_style_header.svg @@ -1,3 +1,3 @@ - - \ No newline at end of file + + diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 0a0bde5b4..3855834a3 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -126,6 +126,8 @@ extension AppColor on Color { static const colorStyleBlockQuote = Color(0xFFEEEEEE); static const colorBorderStyleCode = Color(0xFFCCCCCC); static const colorBackgroundStyleCode = Color(0xFFF5F5F5); + static const colorBorderWrapIconStyleCode = Color(0xFFE4E4E4); + static const colorBackgroundWrapIconStyleCode = Color(0xFFF2F3F5); 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 c5e0fbe19..6bc09bbda 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -135,6 +135,8 @@ class ImagePaths { String get icStyleStrikeThrough => _getImagePath('ic_style_strikethrough.svg'); String get icStyleCodeView => _getImagePath('ic_style_code_view.svg'); String get icStyleHeader => _getImagePath('ic_style_header.svg'); + String get icStyleColor => _getImagePath('ic_style_color.svg'); + String get icStyleArrowDown => _getImagePath('ic_style_arrow_down.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 16bb2b3f6..c158ad3ae 100644 --- a/lib/features/base/widget/drop_down_button_widget.dart +++ b/lib/features/base/widget/drop_down_button_widget.dart @@ -23,6 +23,8 @@ class DropDownButtonWidget extends StatelessWidget { final double sizeIconChecked; final double radiusButton; final double opacity; + final Widget? iconArrowDown; + final Color? colorButton; const DropDownButtonWidget({ Key? key, @@ -36,6 +38,8 @@ class DropDownButtonWidget extends StatelessWidget { this.sizeIconChecked = 20, this.radiusButton = 10, this.opacity = 1.0, + this.iconArrowDown, + this.colorButton, }) : super(key: key); @override @@ -94,7 +98,7 @@ class DropDownButtonWidget extends StatelessWidget { color: AppColor.colorInputBorderCreateMailbox, width: 0.5, ), - color: AppColor.colorInputBackgroundCreateMailbox, + color: colorButton ?? AppColor.colorInputBackgroundCreateMailbox, ), padding: const EdgeInsets.only(left: 12, right: 10), child: Row(children: [ @@ -106,12 +110,12 @@ class DropDownButtonWidget extends StatelessWidget { maxLines: 1, overflow: CommonTextStyle.defaultTextOverFlow, )), - SvgPicture.asset(_imagePaths.icDropDown) + iconArrowDown ?? SvgPicture.asset(_imagePaths.icDropDown) ]), ) : null, onChanged: onChanged, - icon: SvgPicture.asset(_imagePaths.icDropDown), + icon: iconArrowDown ?? SvgPicture.asset(_imagePaths.icDropDown), buttonPadding: const EdgeInsets.symmetric(horizontal: 12), buttonDecoration: BoxDecoration( borderRadius: BorderRadius.circular(radiusButton), @@ -119,7 +123,7 @@ class DropDownButtonWidget extends StatelessWidget { color: AppColor.colorInputBorderCreateMailbox, width: 0.5, ), - color: AppColor.colorInputBackgroundCreateMailbox, + color: colorButton ?? AppColor.colorInputBackgroundCreateMailbox, ), itemHeight: heightItem, buttonHeight: heightItem, diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index c7dcf611a..7256c4759 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -757,117 +757,144 @@ class ComposerView extends GetWidget } Widget _buildToolbarRichTextWidget(BuildContext context) { - return Container( - padding: const EdgeInsets.only(left: 20, top: 8, bottom: 8), - alignment: Alignment.centerLeft, - child: Wrap( - alignment: WrapAlignment.start, - crossAxisAlignment: WrapCrossAlignment.center, - children: RichTextStyleType.values.map((textType) => Obx(() { - final opacity = controller.richTextWebController.codeViewEnabled ? 0.5 : 1.0; - switch(textType) { - case RichTextStyleType.textColor: - 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: 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 AbsorbPointer( - absorbing: controller.richTextWebController.codeViewEnabled, + return Obx(() { + final richTextController = controller.richTextWebController; + final codeViewEnabled = richTextController.codeViewEnabled; + final opacity = codeViewEnabled ? 0.5 : 1.0; + + return Container( + padding: const EdgeInsets.only(left: 20, top: 8, bottom: 8), + alignment: Alignment.centerLeft, + child: Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + AbsorbPointer( + absorbing: codeViewEnabled, + child: DropDownMenuHeaderStyleWidget( + icon: buildWrapIconStyleText( + icon: Tooltip( + message: RichTextStyleType.headerStyle.getTooltipButton(context), + child: SvgPicture.asset(RichTextStyleType.headerStyle.getIcon(imagePaths), + color: AppColor.colorDefaultRichTextButton.withOpacity(opacity), + fit: BoxFit.fill), + ) + ), + items: HeaderStyleType.values, + onMenuStateChange: (isOpen) { + log('ComposerView::_buildToolbarRichTextWidget(): MenuHeaderStyleStatus: $isOpen'); + final newStatus = isOpen + ? DropdownMenuFontStatus.open + : DropdownMenuFontStatus.closed; + richTextController.menuHeaderStyleStatus = newStatus; + }, + onChanged: (newStyle) => richTextController.applyHeaderStyle(newStyle)), + ), + AbsorbPointer( + absorbing: 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.toggleCodeView()); - case RichTextStyleType.headerStyle: - return AbsorbPointer( - absorbing: controller.richTextWebController.codeViewEnabled, - child: Container( - width: 50, - height: 35, - alignment: Alignment.center, - padding: const EdgeInsets.only(right: 2), - child: DropDownMenuHeaderStyleWidget( - icon: Material( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(5), - side: const BorderSide( - color: AppColor.colorInputBorderCreateMailbox, - width: 0.5)), - color: AppColor.colorInputBackgroundCreateMailbox, - child: Tooltip( - message: textType.getTooltipButton(context), - child: Padding( - padding: const EdgeInsets.only(left: 10, top: 10), - child: SvgPicture.asset(textType.getIcon(imagePaths), - color: AppColor.colorDefaultRichTextButton.withOpacity(opacity), - fit: BoxFit.fill), - ), - ), - ), - items: HeaderStyleType.values, + width: 200, + padding: const EdgeInsets.only(left: 8, right: 8), + child: DropDownButtonWidget( + items: FontNameType.values, + itemSelected: richTextController.selectedFontName.value, + onChanged: (newFont) => richTextController.applyNewFontStyle(newFont), onMenuStateChange: (isOpen) { - log('ComposerView::_buildToolbarRichTextWidget(): MenuHeaderStyleStatus: $isOpen'); + log('ComposerView::_buildToolbarRichTextWidget(): MenuFontStatus: $isOpen'); final newStatus = isOpen ? DropdownMenuFontStatus.open : DropdownMenuFontStatus.closed; - controller.richTextWebController.menuHeaderStyleStatus = newStatus; + richTextController.menuFontStatus = newStatus; }, - onChanged: (newStyle) => controller.richTextWebController.applyHeaderStyle(newStyle))), - ); - 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() - ), - ); + heightItem: 38, + sizeIconChecked: 16, + radiusButton: 5, + opacity: opacity, + colorButton: Colors.white, + iconArrowDown: SvgPicture.asset(imagePaths.icStyleArrowDown), + supportSelectionIcon: true)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildWrapIconStyleText( + icon: buildIconWithTooltip( + path: RichTextStyleType.textColor.getIcon(imagePaths), + color: richTextController.selectedTextColor.value, + tooltip: RichTextStyleType.textColor.getTooltipButton(context), + opacity: opacity), + onTap: () => richTextController.applyRichTextStyle(context, RichTextStyleType.textColor)), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: AbsorbPointer( + absorbing: codeViewEnabled, + child: buildWrapIconStyleText( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5), + icon: buildIconColorBackgroundText( + iconData: RichTextStyleType.textBackgroundColor.getIconData(), + colorSelected: richTextController.selectedTextBackgroundColor.value, + tooltip: RichTextStyleType.textBackgroundColor.getTooltipButton(context), + opacity: opacity), + onTap: () => richTextController.applyRichTextStyle(context, RichTextStyleType.textBackgroundColor)), + ), + ), + buildWrapIconStyleText( + hasDropdown: false, + padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 5), + icon: Wrap(children: [ + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.bold.getIcon(imagePaths), + isSelected: richTextController.isTextStyleTypeSelected(RichTextStyleType.bold), + tooltip: RichTextStyleType.bold.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextController.applyRichTextStyle(context, RichTextStyleType.bold)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.italic.getIcon(imagePaths), + isSelected: richTextController.isTextStyleTypeSelected(RichTextStyleType.italic), + tooltip: RichTextStyleType.italic.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextController.applyRichTextStyle(context, RichTextStyleType.italic)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.underline.getIcon(imagePaths), + isSelected: richTextController.isTextStyleTypeSelected(RichTextStyleType.underline), + tooltip: RichTextStyleType.underline.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextController.applyRichTextStyle(context, RichTextStyleType.underline)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.strikeThrough.getIcon(imagePaths), + isSelected: richTextController.isTextStyleTypeSelected( + RichTextStyleType.strikeThrough), + tooltip: RichTextStyleType.strikeThrough.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextController.applyRichTextStyle(context, RichTextStyleType.strikeThrough)), + ) + ])), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: buildWrapIconStyleText( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 5), + isSelected: richTextController.isTextStyleTypeSelected(RichTextStyleType.codeView), + icon: buildIconWithTooltip( + path: RichTextStyleType.codeView.getIcon(imagePaths), + color: AppColor.colorDefaultRichTextButton.withOpacity(opacity), + tooltip: RichTextStyleType.codeView.getTooltipButton(context)), + onTap: () => richTextController.toggleCodeView()), + ) + ] + ), + ); + }); } Widget _buildInlineLoadingView() { 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 3a4574f9f..8da428480 100644 --- a/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart +++ b/lib/features/composer/presentation/mixin/rich_text_button_mixin.dart @@ -1,11 +1,45 @@ -import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:core/presentation/views/button/icon_button_web.dart'; +import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; mixin RichTextButtonMixin { + final _imagePaths = Get.find(); + + Widget buildWrapIconStyleText({ + required Widget icon, + VoidCallback? onTap, + bool isSelected = false, + bool hasDropdown = true, + double opacity = 1.0, + EdgeInsets? padding, + }){ + return InkWell( + onTap: onTap, + child: Container( + padding: padding ?? const EdgeInsets.symmetric(horizontal: 5, vertical: 5), + decoration: BoxDecoration( + color: isSelected == true + ? AppColor.colorBackgroundWrapIconStyleCode.withOpacity(opacity) + : Colors.white.withOpacity(opacity), + border: Border.all( + color: AppColor.colorBorderWrapIconStyleCode, + width: 0.5), + borderRadius: BorderRadius.circular(8)), + child: hasDropdown + ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + icon, + SvgPicture.asset(_imagePaths.icStyleArrowDown) + ]) + : icon, + ), + ); + } + Widget buildIconStyleText({ required String path, required bool? isSelected, @@ -28,50 +62,38 @@ mixin RichTextButtonMixin { ); } - Widget buildIconColorText({ - required IconData? iconData, - required Color? colorSelected, - required VoidCallback onTap, + Widget buildIconWithTooltip({ + required String path, + Color? color, String? tooltip, double opacity = 1.0, }){ - return buildIconWeb( - icon: Icon(iconData, - color: (colorSelected ?? Colors.black).withOpacity(opacity), - size: 20), - iconPadding: const EdgeInsets.all(4), - colorSelected: colorSelected == Colors.white - ? AppColor.colorFocusRichTextButton - : Colors.transparent, - colorFocus: Colors.white, - minSize: 20, - tooltip: tooltip, - onTap: onTap, + final newColor = color == Colors.white + ? AppColor.colorDefaultRichTextButton + : color; + + return Tooltip( + child: SvgPicture.asset(path, + color: newColor?.withOpacity(opacity), + fit: BoxFit.fill), + message: tooltip, ); } Widget buildIconColorBackgroundText({ required IconData? iconData, required Color? colorSelected, - required VoidCallback onTap, String? tooltip, double opacity = 1.0, }){ final newColor = colorSelected == Colors.white ? AppColor.colorDefaultRichTextButton : colorSelected; - return buildIconWeb( - icon: Icon(iconData, + return Tooltip( + child: Icon(iconData, color: (newColor ?? AppColor.colorDefaultRichTextButton).withOpacity(opacity), size: 20), - iconPadding: const EdgeInsets.all(4), - colorSelected: newColor == Colors.white - ? AppColor.colorFocusRichTextButton - : Colors.transparent, - colorFocus: Colors.white, - minSize: 20, - tooltip: tooltip, - onTap: onTap, + message: tooltip, ); } } \ 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 850a962f9..297b820a9 100644 --- a/lib/features/composer/presentation/model/rich_text_style_type.dart +++ b/lib/features/composer/presentation/model/rich_text_style_type.dart @@ -51,6 +51,9 @@ enum RichTextStyleType { return imagePaths.icStyleCodeView; case headerStyle: return imagePaths.icStyleHeader; + case textColor: + case textBackgroundColor: + return imagePaths.icStyleColor; default: return ''; }