TF-733 Apply change text color to body composer on web
This commit is contained in:
@@ -158,4 +158,40 @@ Widget buildButtonWrapText(String name, {
|
||||
color: Colors.white)),
|
||||
),
|
||||
);
|
||||
}
|
||||
Widget buildButtonWrapText(String name, {
|
||||
TextStyle? textStyle,
|
||||
Color? bgColor,
|
||||
Color? borderColor,
|
||||
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<Color>(
|
||||
(Set<MaterialState> states) => bgColor ?? AppColor.colorTextButton),
|
||||
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radius ?? 8),
|
||||
side: BorderSide(
|
||||
width: borderColor != null ? 1 : 0,
|
||||
color: borderColor ?? bgColor ?? AppColor.colorTextButton))),
|
||||
padding: MaterialStateProperty.resolveWith<EdgeInsets>(
|
||||
(Set<MaterialState> states) => const EdgeInsets.symmetric(horizontal: 16)),
|
||||
elevation: MaterialStateProperty.resolveWith<double>(
|
||||
(Set<MaterialState> states) => 0)),
|
||||
child: Text(name,
|
||||
textAlign: TextAlign.center,
|
||||
style: textStyle ??
|
||||
const TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
Expanded(child: Column(
|
||||
children: [
|
||||
_buildAttachmentsWidget(context),
|
||||
_buildToolbarRichTextWidget(),
|
||||
_buildToolbarRichTextWidget(context),
|
||||
_buildInlineLoadingView(),
|
||||
_buildEditorForm(context)
|
||||
]
|
||||
@@ -299,7 +299,7 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
child: Column(
|
||||
children: [
|
||||
_buildAttachmentsWidget(context),
|
||||
_buildToolbarRichTextWidget(),
|
||||
_buildToolbarRichTextWidget(context),
|
||||
_buildInlineLoadingView(),
|
||||
_buildEditorForm(context)
|
||||
]
|
||||
@@ -734,15 +734,25 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildToolbarRichTextWidget() {
|
||||
Widget _buildToolbarRichTextWidget(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 20, top: 4, bottom: 8),
|
||||
child: Row(
|
||||
children: RichTextStyleType.values.map((textType) => Obx(() {
|
||||
return buildIconStyleText(
|
||||
path: textType.getIcon(imagePaths),
|
||||
isSelected: controller.richTextWebController.isTextStyleTypeSelected(textType),
|
||||
onTap: () => controller.richTextWebController.applyRichTextStyle(textType));
|
||||
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));
|
||||
default:
|
||||
return buildIconStyleText(
|
||||
path: textType.getIcon(imagePaths),
|
||||
isSelected: controller.richTextWebController.isTextStyleTypeSelected(textType),
|
||||
tooltip: textType.getTooltipButton(context),
|
||||
onTap: () => controller.richTextWebController.applyRichTextStyle(context, textType));
|
||||
}
|
||||
})).toList()
|
||||
),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
import 'package:core/presentation/views/dialog/color_picker_dialog_builder.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
abstract class BaseRichTextController extends GetxController {
|
||||
|
||||
void openMenuSelectColor(
|
||||
BuildContext context,
|
||||
Color currentColor,
|
||||
{Function(Color?)? onSelectColor}
|
||||
) async {
|
||||
await ColorPickerDialogBuilder(
|
||||
context,
|
||||
currentColor,
|
||||
title: AppLocalizations.of(context).chooseAColor,
|
||||
textActionSetColor: AppLocalizations.of(context).setColor,
|
||||
textActionResetDefault: AppLocalizations.of(context).resetToDefault,
|
||||
textActionCancel: AppLocalizations.of(context).cancel,
|
||||
cancelActionCallback: () => popBack(),
|
||||
setColorActionCallback: (selectedColor) {
|
||||
onSelectColor?.call(selectedColor);
|
||||
popBack();
|
||||
}
|
||||
).show();
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,22 @@ import 'package:dartz/dartz.dart';
|
||||
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/rich_text_style_type.dart';
|
||||
|
||||
class RichTextWebController extends GetxController {
|
||||
class RichTextWebController extends BaseRichTextController {
|
||||
|
||||
final editorController = HtmlEditorController(processNewLineAsBr: true);
|
||||
|
||||
final listTextStyleApply = RxList<RichTextStyleType>();
|
||||
final selectedTextColor = Colors.black.obs;
|
||||
|
||||
void onEditorSettingsChange(EditorSettings settings) {
|
||||
log('RichTextWebController::onEditorSettingsChange():');
|
||||
@@ -37,9 +41,32 @@ class RichTextWebController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
void applyRichTextStyle(RichTextStyleType textStyleType) {
|
||||
editorController.execCommand(textStyleType.commandAction);
|
||||
_selectTextStyleType(textStyleType);
|
||||
void applyRichTextStyle(BuildContext context, RichTextStyleType textStyleType) {
|
||||
switch(textStyleType) {
|
||||
case RichTextStyleType.textColor:
|
||||
openMenuSelectColor(
|
||||
context,
|
||||
selectedTextColor.value,
|
||||
onSelectColor: (selectedColor) {
|
||||
final newColor = selectedColor ?? Colors.black;
|
||||
final colorAsString = (newColor.value & 0xFFFFFF)
|
||||
.toRadixString(16)
|
||||
.padLeft(6, '0')
|
||||
.toUpperCase();
|
||||
log('RichTextWebController::applyRichTextStyle(): color: $newColor');
|
||||
log('RichTextWebController::applyRichTextStyle(): colorAsString: $colorAsString');
|
||||
selectedTextColor.value = newColor;
|
||||
editorController.execCommand(
|
||||
textStyleType.commandAction,
|
||||
argument: colorAsString);
|
||||
}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
editorController.execCommand(textStyleType.commandAction);
|
||||
_selectTextStyleType(textStyleType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _selectTextStyleType(RichTextStyleType textStyleType) {
|
||||
|
||||
@@ -10,6 +10,7 @@ mixin RichTextButtonMixin {
|
||||
required String path,
|
||||
required bool? isSelected,
|
||||
required VoidCallback onTap,
|
||||
String? tooltip
|
||||
}){
|
||||
return buildIconWeb(
|
||||
icon: SvgPicture.asset(
|
||||
@@ -21,6 +22,23 @@ mixin RichTextButtonMixin {
|
||||
iconPadding: const EdgeInsets.all(4),
|
||||
colorFocus: Colors.white,
|
||||
minSize: 26,
|
||||
tooltip: tooltip,
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildIconColorText({
|
||||
required IconData? iconData,
|
||||
required Color? colorSelected,
|
||||
required VoidCallback onTap,
|
||||
String? tooltip
|
||||
}){
|
||||
return buildIconWeb(
|
||||
icon: Icon(iconData, color: colorSelected ?? Colors.black, size: 20),
|
||||
iconPadding: const EdgeInsets.all(4),
|
||||
colorFocus: Colors.white,
|
||||
minSize: 20,
|
||||
tooltip: tooltip,
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
enum RichTextStyleType {
|
||||
bold,
|
||||
italic,
|
||||
underline,
|
||||
strikeThrough;
|
||||
strikeThrough,
|
||||
textColor;
|
||||
|
||||
String get commandAction {
|
||||
switch (this) {
|
||||
@@ -17,6 +20,8 @@ enum RichTextStyleType {
|
||||
return 'underline';
|
||||
case strikeThrough:
|
||||
return 'strikeThrough';
|
||||
case textColor:
|
||||
return 'foreColor';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
@@ -36,4 +41,30 @@ enum RichTextStyleType {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
IconData? getIconData() {
|
||||
switch (this) {
|
||||
case textColor:
|
||||
return Icons.format_color_text;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String getTooltipButton(BuildContext context) {
|
||||
switch (this) {
|
||||
case bold:
|
||||
return AppLocalizations.of(context).formatBold;
|
||||
case italic:
|
||||
return AppLocalizations.of(context).formatItalic;
|
||||
case underline:
|
||||
return AppLocalizations.of(context).formatUnderline;
|
||||
case strikeThrough:
|
||||
return AppLocalizations.of(context).formatStrikethrough;
|
||||
case textColor:
|
||||
return AppLocalizations.of(context).formatTextColor;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2022-07-18T16:31:40.598846",
|
||||
"@@last_modified": "2022-07-21T13:16:06.832687",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -1615,5 +1615,53 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"chooseAColor": "Choose a color",
|
||||
"@chooseAColor": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"resetToDefault": "Reset to default",
|
||||
"@resetToDefault": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"setColor": "Set color",
|
||||
"@setColor": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"formatBold": "Bold",
|
||||
"@formatBold": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"formatItalic": "Italic",
|
||||
"@formatItalic": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"formatUnderline": "Underline",
|
||||
"@formatUnderline": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"formatStrikethrough": "Strikethrough",
|
||||
"@formatStrikethrough": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"formatTextColor": "Text Color",
|
||||
"@formatTextColor": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -1659,4 +1659,52 @@ class AppLocalizations {
|
||||
'Please input either an image or an image URL, not both',
|
||||
name: 'insertImageErrorDuplicate');
|
||||
}
|
||||
|
||||
String get chooseAColor {
|
||||
return Intl.message(
|
||||
'Choose a color',
|
||||
name: 'chooseAColor');
|
||||
}
|
||||
|
||||
String get resetToDefault {
|
||||
return Intl.message(
|
||||
'Reset to default',
|
||||
name: 'resetToDefault');
|
||||
}
|
||||
|
||||
String get setColor {
|
||||
return Intl.message(
|
||||
'Set color',
|
||||
name: 'setColor');
|
||||
}
|
||||
|
||||
String get formatBold {
|
||||
return Intl.message(
|
||||
'Bold',
|
||||
name: 'formatBold');
|
||||
}
|
||||
|
||||
String get formatItalic {
|
||||
return Intl.message(
|
||||
'Italic',
|
||||
name: 'formatItalic');
|
||||
}
|
||||
|
||||
String get formatUnderline {
|
||||
return Intl.message(
|
||||
'Underline',
|
||||
name: 'formatUnderline');
|
||||
}
|
||||
|
||||
String get formatStrikethrough {
|
||||
return Intl.message(
|
||||
'Strikethrough',
|
||||
name: 'formatStrikethrough');
|
||||
}
|
||||
|
||||
String get formatTextColor {
|
||||
return Intl.message(
|
||||
'Text Color',
|
||||
name: 'formatTextColor');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user