TF-733 Apply change font to body composer on web
This commit is contained in:
@@ -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<T> extends StatelessWidget {
|
||||
@@ -16,6 +18,9 @@ class DropDownButtonWidget<T> 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<T> 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<T> extends StatelessWidget {
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
return DropdownButtonHideUnderline(
|
||||
child: DropdownButton2<T>(
|
||||
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<T>(
|
||||
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<T>(
|
||||
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<T>(
|
||||
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<T> extends StatelessWidget {
|
||||
if (item is Locale) {
|
||||
return item.getLanguageName(context);
|
||||
}
|
||||
if (item is FontNameType) {
|
||||
return item.fontFamily;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -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<ComposerController>
|
||||
|
||||
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<ComposerController>
|
||||
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<FontNameType>(
|
||||
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),
|
||||
|
||||
@@ -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<RichTextStyleType>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user