TF-1034: Apply new rich text toolbox for Tablet
This commit is contained in:
@@ -12,17 +12,10 @@ import 'package:model/model.dart';
|
|||||||
import 'package:rich_text_composer/rich_text_composer.dart' as rich_text_composer;
|
import 'package:rich_text_composer/rich_text_composer.dart' as rich_text_composer;
|
||||||
import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart';
|
import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart';
|
||||||
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.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/composer_controller.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/mixin/composer_loading_mixin.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/mixin/composer_loading_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/mixin/rich_text_button_mixin.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/mixin/rich_text_button_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/header_style_type.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/order_list_type.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/paragraph_type.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/drop_down_menu_header_style_widget.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/upload/presentation/extensions/list_upload_file_state_extension.dart';
|
import 'package:tmail_ui_user/features/upload/presentation/extensions/list_upload_file_state_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||||
@@ -90,19 +83,33 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Colors.black38,
|
backgroundColor: Colors.black38,
|
||||||
body: Align(alignment: Alignment.center, child: Card(
|
body: LayoutBuilder(builder: (context, constraints) {
|
||||||
color: Colors.transparent,
|
return rich_text_composer.KeyboardRichText(
|
||||||
elevation: 20,
|
richTextController: controller.keyboardRichTextController,
|
||||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))),
|
keyBroadToolbar: RichTextKeyboardToolBar(
|
||||||
shadowColor: Colors.transparent,
|
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
||||||
child: Container(
|
insertAttachment: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context)),
|
||||||
decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(24))),
|
insertImage: () => controller.insertImage(context, constraints.maxWidth),
|
||||||
width: responsiveUtils.getSizeScreenWidth(context) * 0.9,
|
richTextController: controller.keyboardRichTextController,
|
||||||
height: responsiveUtils.getSizeScreenHeight(context) * 0.9,
|
titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles,
|
||||||
child: ClipRRect(
|
titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(24)),
|
titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground,
|
||||||
child: SafeArea(
|
titleFormatBottomSheet: AppLocalizations.of(context).titleFormat,
|
||||||
child: Column(children: [
|
titleBack: AppLocalizations.of(context).format,
|
||||||
|
),
|
||||||
|
child: Align(alignment: Alignment.center, child: Card(
|
||||||
|
color: Colors.transparent,
|
||||||
|
elevation: 20,
|
||||||
|
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||||
|
width: responsiveUtils.getSizeScreenWidth(context) * 0.9,
|
||||||
|
height: responsiveUtils.getSizeScreenHeight(context) * 0.9,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(24)),
|
||||||
|
child: SafeArea(
|
||||||
|
child: Column(children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: _buildAppBar(context, controller.isEnableEmailSendButton.value)),
|
child: _buildAppBar(context, controller.isEnableEmailSendButton.value)),
|
||||||
@@ -110,11 +117,13 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
Expanded(child: _buildBodyTablet(context)),
|
Expanded(child: _buildBodyTablet(context)),
|
||||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||||
Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)),
|
Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)),
|
||||||
]),
|
]),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)),
|
||||||
))
|
);
|
||||||
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -415,8 +424,8 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
])
|
])
|
||||||
),
|
),
|
||||||
richTextController: controller.keyboardRichTextController,
|
richTextController: controller.keyboardRichTextController,
|
||||||
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
|
||||||
keyBroadToolbar: RichTextKeyboardToolBar(
|
keyBroadToolbar: RichTextKeyboardToolBar(
|
||||||
|
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
||||||
isLandScapeMode: responsiveUtils.isLandscapeMobile(context),
|
isLandScapeMode: responsiveUtils.isLandscapeMobile(context),
|
||||||
insertAttachment: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context)),
|
insertAttachment: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context)),
|
||||||
insertImage: () => controller.insertImage(context, maxWidth),
|
insertImage: () => controller.insertImage(context, maxWidth),
|
||||||
@@ -425,50 +434,51 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground,
|
titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground,
|
||||||
titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground,
|
titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground,
|
||||||
titleFormatBottomSheet: AppLocalizations.of(context).titleFormat,
|
titleFormatBottomSheet: AppLocalizations.of(context).titleFormat,
|
||||||
|
titleBack: AppLocalizations.of(context).format,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBodyTablet(BuildContext context) {
|
Widget _buildBodyTablet(BuildContext context) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
physics: const ClampingScrollPhysics(),
|
controller: controller.scrollController,
|
||||||
child: Column(children: [
|
physics: const ClampingScrollPhysics(),
|
||||||
Padding(
|
child: Column(children: [
|
||||||
padding: const EdgeInsets.only(left: 16),
|
Padding(
|
||||||
child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
padding: const EdgeInsets.only(left: 16),
|
||||||
Padding(padding: const EdgeInsets.only(top: 20),
|
child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
child: (AvatarBuilder()
|
Padding(padding: const EdgeInsets.only(top: 20),
|
||||||
..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '')
|
child: (AvatarBuilder()
|
||||||
..size(56)
|
..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '')
|
||||||
..addTextStyle(const TextStyle(fontWeight: FontWeight.w600, fontSize: 28, color: Colors.white))
|
..size(56)
|
||||||
..backgroundColor(AppColor.colorAvatar))
|
..addTextStyle(const TextStyle(fontWeight: FontWeight.w600, fontSize: 28, color: Colors.white))
|
||||||
.build()),
|
..backgroundColor(AppColor.colorAvatar))
|
||||||
Expanded(child: Padding(
|
.build()),
|
||||||
padding: const EdgeInsets.only(left: 16),
|
Expanded(child: Padding(
|
||||||
child: Column(children: [
|
padding: const EdgeInsets.only(left: 16),
|
||||||
Obx(() => controller.identitySelected.value != null
|
child: Column(children: [
|
||||||
? _buildFromEmailAddress(context)
|
Obx(() => controller.identitySelected.value != null
|
||||||
: const SizedBox.shrink()),
|
? _buildFromEmailAddress(context)
|
||||||
Obx(() => controller.identitySelected.value != null
|
: const SizedBox.shrink()),
|
||||||
? const Divider(color: AppColor.colorDividerComposer, height: 1)
|
Obx(() => controller.identitySelected.value != null
|
||||||
: const SizedBox.shrink()),
|
? const Divider(color: AppColor.colorDividerComposer, height: 1)
|
||||||
_buildEmailAddress(context),
|
: const SizedBox.shrink()),
|
||||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
_buildEmailAddress(context),
|
||||||
Padding(padding: const EdgeInsets.only(right: 16), child: _buildSubjectEmail(context)),
|
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||||
]),
|
Padding(padding: const EdgeInsets.only(right: 16), child: _buildSubjectEmail(context)),
|
||||||
))
|
]),
|
||||||
])),
|
))
|
||||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
])),
|
||||||
Padding(
|
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||||
padding: const EdgeInsets.only(left: 60, right: 25),
|
Padding(
|
||||||
child: Column(children: [
|
padding: const EdgeInsets.only(left: 60, right: 25),
|
||||||
_buildToolbarRichTextWidget(context),
|
child: Column(children: [
|
||||||
_buildAttachmentsWidget(context),
|
_buildAttachmentsWidget(context),
|
||||||
buildInlineLoadingView(controller),
|
buildInlineLoadingView(controller),
|
||||||
_buildComposerEditor(context),
|
_buildComposerEditor(context),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,128 +504,6 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildToolbarRichTextWidget(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
final richTextMobileTabletController = controller.richTextMobileTabletController;
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(left: 20, top: 8, bottom: 8),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Wrap(
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
|
||||||
DropDownMenuHeaderStyleWidget(
|
|
||||||
icon: buildWrapIconStyleText(
|
|
||||||
isSelected: richTextMobileTabletController.isMenuHeaderStyleOpen,
|
|
||||||
icon: SvgPicture.asset(RichTextStyleType.headerStyle.getIcon(imagePaths),
|
|
||||||
color: AppColor.colorDefaultRichTextButton,
|
|
||||||
fit: BoxFit.fill),
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
|
||||||
),
|
|
||||||
items: HeaderStyleType.values,
|
|
||||||
onChanged: (newStyle) => richTextMobileTabletController.applyHeaderStyle(newStyle)),
|
|
||||||
Container(
|
|
||||||
width: 120,
|
|
||||||
padding: const EdgeInsets.only(right: 2, left: 8),
|
|
||||||
child: DropDownButtonWidget<SafeFont>(
|
|
||||||
items: SafeFont.values,
|
|
||||||
itemSelected: richTextMobileTabletController.selectedFontName.value,
|
|
||||||
onChanged: (newFont) => richTextMobileTabletController.applyNewFontStyle(newFont),
|
|
||||||
heightItem: 38,
|
|
||||||
sizeIconChecked: 16,
|
|
||||||
dropdownWidth: 200,
|
|
||||||
radiusButton: 5,
|
|
||||||
colorButton: Colors.white,
|
|
||||||
supportSelectionIcon: true)),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8),
|
|
||||||
child: buildWrapIconStyleText(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5),
|
|
||||||
icon: buildIconColorBackgroundTextWithoutTooltip(
|
|
||||||
iconData: RichTextStyleType.textColor.getIconData(),
|
|
||||||
colorSelected: richTextMobileTabletController.selectedTextColor.value,
|
|
||||||
),
|
|
||||||
onTap: () => richTextMobileTabletController.applyRichTextStyle(context, RichTextStyleType.textColor)),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: buildWrapIconStyleText(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5),
|
|
||||||
icon: buildIconColorBackgroundTextWithoutTooltip(
|
|
||||||
iconData: RichTextStyleType.textBackgroundColor.getIconData(),
|
|
||||||
colorSelected: richTextMobileTabletController.selectedTextBackgroundColor.value,
|
|
||||||
),
|
|
||||||
onTap: () => richTextMobileTabletController.applyRichTextStyle(context, RichTextStyleType.textBackgroundColor)),
|
|
||||||
),
|
|
||||||
buildWrapIconStyleText(
|
|
||||||
hasDropdown: false,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 5),
|
|
||||||
icon: Wrap(children: [
|
|
||||||
buildIconStyleText(
|
|
||||||
path: RichTextStyleType.bold.getIcon(imagePaths),
|
|
||||||
isSelected: richTextMobileTabletController.isTextStyleTypeSelected(RichTextStyleType.bold),
|
|
||||||
onTap: () => richTextMobileTabletController.applyRichTextStyle(context, RichTextStyleType.bold)),
|
|
||||||
buildIconStyleText(
|
|
||||||
path: RichTextStyleType.italic.getIcon(imagePaths),
|
|
||||||
isSelected: richTextMobileTabletController.isTextStyleTypeSelected(RichTextStyleType.italic),
|
|
||||||
onTap: () => richTextMobileTabletController.applyRichTextStyle(context, RichTextStyleType.italic)),
|
|
||||||
buildIconStyleText(
|
|
||||||
path: RichTextStyleType.underline.getIcon(imagePaths),
|
|
||||||
isSelected: richTextMobileTabletController.isTextStyleTypeSelected(RichTextStyleType.underline),
|
|
||||||
onTap: () => richTextMobileTabletController.applyRichTextStyle(context, RichTextStyleType.underline)),
|
|
||||||
buildIconStyleText(
|
|
||||||
path: RichTextStyleType.strikeThrough.getIcon(imagePaths),
|
|
||||||
isSelected: richTextMobileTabletController.isTextStyleTypeSelected(RichTextStyleType.strikeThrough),
|
|
||||||
onTap: () => richTextMobileTabletController.applyRichTextStyle(context, RichTextStyleType.strikeThrough))
|
|
||||||
])),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8),
|
|
||||||
child: PopupMenuOverlayWidget(
|
|
||||||
controller: richTextMobileTabletController.menuParagraphController,
|
|
||||||
listButtonAction: ParagraphType.values
|
|
||||||
.map((paragraph) => paragraph.buildButtonWidget(
|
|
||||||
context,
|
|
||||||
imagePaths,
|
|
||||||
(paragraph) => richTextMobileTabletController.applyParagraphType(paragraph)))
|
|
||||||
.toList(),
|
|
||||||
iconButton: buildWrapIconStyleText(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
|
||||||
spacing: 3,
|
|
||||||
isSelected: richTextMobileTabletController.focusMenuParagraph.value,
|
|
||||||
icon: buildIcon(
|
|
||||||
path: richTextMobileTabletController.selectedParagraph.value.getIcon(imagePaths),
|
|
||||||
color: AppColor.colorDefaultRichTextButton,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8),
|
|
||||||
child: PopupMenuOverlayWidget(
|
|
||||||
controller: richTextMobileTabletController.menuOrderListController,
|
|
||||||
listButtonAction: OrderListType.values
|
|
||||||
.map((orderType) => orderType.buildButtonWidget(
|
|
||||||
context,
|
|
||||||
imagePaths,
|
|
||||||
(orderType) => richTextMobileTabletController.applyOrderListType(orderType)))
|
|
||||||
.toList(),
|
|
||||||
iconButton: buildWrapIconStyleText(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
|
||||||
spacing: 3,
|
|
||||||
isSelected: richTextMobileTabletController.focusMenuOrderList.value,
|
|
||||||
icon: buildIcon(
|
|
||||||
path: richTextMobileTabletController.selectedOrderList.value.getIcon(imagePaths),
|
|
||||||
color: AppColor.colorDefaultRichTextButton,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildComposerEditor(BuildContext context) {
|
Widget _buildComposerEditor(BuildContext context) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
final argsComposer = controller.composerArguments.value;
|
final argsComposer = controller.composerArguments.value;
|
||||||
@@ -627,10 +515,10 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
switch(argsComposer.emailActionType) {
|
switch(argsComposer.emailActionType) {
|
||||||
case EmailActionType.compose:
|
case EmailActionType.compose:
|
||||||
case EmailActionType.composeFromEmailAddress:
|
case EmailActionType.composeFromEmailAddress:
|
||||||
return _buildHtmlEditor(HtmlExtension.editorStartTags, context);
|
return _buildHtmlEditor(context);
|
||||||
case EmailActionType.edit:
|
case EmailActionType.edit:
|
||||||
return controller.emailContentsViewState.value.fold(
|
return controller.emailContentsViewState.value.fold(
|
||||||
(failure) => _buildHtmlEditor(HtmlExtension.editorStartTags, context),
|
(failure) => _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags),
|
||||||
(success) {
|
(success) {
|
||||||
if (success is GetEmailContentLoading) {
|
if (success is GetEmailContentLoading) {
|
||||||
return Padding(
|
return Padding(
|
||||||
@@ -642,9 +530,9 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
if (contentHtml.isEmpty == true) {
|
if (contentHtml.isEmpty == true) {
|
||||||
contentHtml = HtmlExtension.editorStartTags;
|
contentHtml = HtmlExtension.editorStartTags;
|
||||||
}
|
}
|
||||||
return _buildHtmlEditor(contentHtml, context);
|
return _buildHtmlEditor(context, initialContent: contentHtml);
|
||||||
} else {
|
} else {
|
||||||
return _buildHtmlEditor(HtmlExtension.editorStartTags, context);
|
return _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
case EmailActionType.reply:
|
case EmailActionType.reply:
|
||||||
@@ -656,14 +544,14 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
if (contentHtml.isEmpty == true) {
|
if (contentHtml.isEmpty == true) {
|
||||||
contentHtml = HtmlExtension.editorStartTags;
|
contentHtml = HtmlExtension.editorStartTags;
|
||||||
}
|
}
|
||||||
return _buildHtmlEditor(contentHtml, context);
|
return _buildHtmlEditor(context, initialContent: contentHtml);
|
||||||
default:
|
default:
|
||||||
return _buildHtmlEditor(HtmlExtension.editorStartTags, context);
|
return _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHtmlEditor(String initialContent, BuildContext context) {
|
Widget _buildHtmlEditor(BuildContext context, {String? initialContent}) {
|
||||||
final richTextMobileTabletController = controller.richTextMobileTabletController;
|
final richTextMobileTabletController = controller.richTextMobileTabletController;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20),
|
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20),
|
||||||
@@ -671,17 +559,14 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
key: const Key('composer_editor'),
|
key: const Key('composer_editor'),
|
||||||
minHeight: 550,
|
minHeight: 550,
|
||||||
addDefaultSelectionMenuItems: false,
|
addDefaultSelectionMenuItems: false,
|
||||||
initialContent: initialContent,
|
initialContent: initialContent ?? '',
|
||||||
onCreated: (editorApi) {
|
onCreated: (editorApi) {
|
||||||
richTextMobileTabletController.htmlEditorApi = editorApi;
|
richTextMobileTabletController.htmlEditorApi = editorApi;
|
||||||
if(responsiveUtils.isMobile(context)){
|
|
||||||
controller.keyboardRichTextController.onCreateHTMLEditor(
|
controller.keyboardRichTextController.onCreateHTMLEditor(
|
||||||
editorApi,
|
editorApi,
|
||||||
onEnterKeyDown: controller.onEnterKeyDown,
|
onEnterKeyDown: controller.onEnterKeyDown,
|
||||||
|
context: context,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
richTextMobileTabletController.listenHtmlEditorApi();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
-171
@@ -1,138 +1,12 @@
|
|||||||
import 'package:core/core.dart';
|
import 'package:core/core.dart';
|
||||||
import 'package:custom_pop_up_menu/custom_pop_up_menu.dart';
|
|
||||||
import 'package:enough_html_editor/enough_html_editor.dart';
|
import 'package:enough_html_editor/enough_html_editor.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/controller/base_rich_text_controller.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/controller/base_rich_text_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/dropdown_menu_font_status.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/header_style_type.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/model/header_style_type.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/image_source.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/model/inline_image.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/order_list_type.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/paragraph_type.dart';
|
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart';
|
|
||||||
|
|
||||||
class RichTextMobileTabletController extends BaseRichTextController {
|
class RichTextMobileTabletController extends BaseRichTextController {
|
||||||
HtmlEditorApi? htmlEditorApi;
|
HtmlEditorApi? htmlEditorApi;
|
||||||
final listTextStyleApply = RxList<RichTextStyleType>();
|
|
||||||
final selectedTextColor = Colors.black.obs;
|
|
||||||
final selectedTextBackgroundColor = Colors.white.obs;
|
|
||||||
final selectedFontName = SafeFont.sansSerif.obs;
|
|
||||||
|
|
||||||
final menuHeaderStyleStatus = DropdownMenuFontStatus.closed.obs;
|
|
||||||
|
|
||||||
bool get isMenuHeaderStyleOpen => menuHeaderStyleStatus.value == DropdownMenuFontStatus.open;
|
|
||||||
|
|
||||||
final selectedParagraph = ParagraphType.alignLeft.obs;
|
|
||||||
final selectedOrderList = OrderListType.bulletedList.obs;
|
|
||||||
|
|
||||||
final focusMenuOrderList = RxBool(false);
|
|
||||||
final focusMenuParagraph = RxBool(false);
|
|
||||||
|
|
||||||
final menuParagraphController = CustomPopupMenuController();
|
|
||||||
final menuOrderListController = CustomPopupMenuController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onReady() {
|
|
||||||
super.onReady();
|
|
||||||
menuParagraphController.addListener(() {
|
|
||||||
focusMenuParagraph.value = menuParagraphController.menuIsShowing;
|
|
||||||
});
|
|
||||||
menuOrderListController.addListener(() {
|
|
||||||
focusMenuOrderList.value = menuOrderListController.menuIsShowing;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void listenHtmlEditorApi() {
|
|
||||||
htmlEditorApi?.onFormatSettingsChanged = (formatSettings) {
|
|
||||||
listTextStyleApply.clear();
|
|
||||||
if (formatSettings.isBold) {
|
|
||||||
listTextStyleApply.add(RichTextStyleType.bold);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formatSettings.isItalic) {
|
|
||||||
listTextStyleApply.add(RichTextStyleType.italic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formatSettings.isUnderline) {
|
|
||||||
listTextStyleApply.add(RichTextStyleType.underline);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formatSettings.isStrikeThrough) {
|
|
||||||
listTextStyleApply.add(RichTextStyleType.strikeThrough);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyRichTextStyle(
|
|
||||||
BuildContext context, RichTextStyleType textStyleType) async {
|
|
||||||
switch (textStyleType) {
|
|
||||||
case RichTextStyleType.textColor:
|
|
||||||
openMenuSelectColor(context, selectedTextColor.value,
|
|
||||||
onResetToDefault: () {
|
|
||||||
selectedTextColor.value = Colors.black;
|
|
||||||
htmlEditorApi?.setColorTextForeground(selectedTextColor.value);
|
|
||||||
}, onSelectColor: (selectedColor) {
|
|
||||||
final newColor = selectedColor ?? Colors.black;
|
|
||||||
selectedTextColor.value = newColor;
|
|
||||||
htmlEditorApi?.setColorTextForeground(selectedTextColor.value);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case RichTextStyleType.textBackgroundColor:
|
|
||||||
openMenuSelectColor(context, selectedTextBackgroundColor.value,
|
|
||||||
onResetToDefault: () {
|
|
||||||
selectedTextBackgroundColor.value = Colors.white;
|
|
||||||
htmlEditorApi
|
|
||||||
?.setColorTextBackground(selectedTextBackgroundColor.value);
|
|
||||||
}, onSelectColor: (selectedColor) {
|
|
||||||
final newColor = selectedColor ?? Colors.white;
|
|
||||||
selectedTextBackgroundColor.value = newColor;
|
|
||||||
htmlEditorApi
|
|
||||||
?.setColorTextBackground(selectedTextBackgroundColor.value);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case RichTextStyleType.bold:
|
|
||||||
await htmlEditorApi?.formatBold().then((value) {
|
|
||||||
_selectTextStyleType(RichTextStyleType.bold);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case RichTextStyleType.italic:
|
|
||||||
await htmlEditorApi?.formatItalic().then((value) {
|
|
||||||
_selectTextStyleType(RichTextStyleType.italic);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case RichTextStyleType.underline:
|
|
||||||
await htmlEditorApi?.formatUnderline().then((value) {
|
|
||||||
_selectTextStyleType(RichTextStyleType.underline);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case RichTextStyleType.strikeThrough:
|
|
||||||
await htmlEditorApi?.formatStrikeThrough().then((value) {
|
|
||||||
_selectTextStyleType(RichTextStyleType.strikeThrough);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_selectTextStyleType(RichTextStyleType richTextStyleType) {
|
|
||||||
if (listTextStyleApply.contains(richTextStyleType)) {
|
|
||||||
listTextStyleApply.remove(richTextStyleType);
|
|
||||||
} else {
|
|
||||||
listTextStyleApply.add(richTextStyleType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isTextStyleTypeSelected(RichTextStyleType richTextStyleType) {
|
|
||||||
return listTextStyleApply.contains(richTextStyleType);
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyNewFontStyle(SafeFont? newFont) {
|
|
||||||
final fontSelected = newFont ?? SafeFont.sansSerif;
|
|
||||||
selectedFontName.value = fontSelected;
|
|
||||||
htmlEditorApi?.setFont(selectedFontName.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void insertImage(InlineImage image, {double? maxWithEditor}) async {
|
void insertImage(InlineImage image, {double? maxWithEditor}) async {
|
||||||
log('RichTextMobileTabletController::insertImage(): $image | maxWithEditor: $maxWithEditor');
|
log('RichTextMobileTabletController::insertImage(): $image | maxWithEditor: $maxWithEditor');
|
||||||
@@ -148,49 +22,4 @@ class RichTextMobileTabletController extends BaseRichTextController {
|
|||||||
final styleSelected = newStyle ?? HeaderStyleType.normal;
|
final styleSelected = newStyle ?? HeaderStyleType.normal;
|
||||||
htmlEditorApi?.formatHeader(styleSelected.styleValue);
|
htmlEditorApi?.formatHeader(styleSelected.styleValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyParagraphType(ParagraphType newParagraph) async {
|
|
||||||
selectedParagraph.value = newParagraph;
|
|
||||||
switch(newParagraph) {
|
|
||||||
case ParagraphType.alignLeft:
|
|
||||||
await htmlEditorApi?.formatAlignLeft();
|
|
||||||
break;
|
|
||||||
case ParagraphType.alignRight:
|
|
||||||
await htmlEditorApi?.formatAlignRight();
|
|
||||||
break;
|
|
||||||
case ParagraphType.alignCenter:
|
|
||||||
await htmlEditorApi?.formatAlignCenter();
|
|
||||||
break;
|
|
||||||
case ParagraphType.justify:
|
|
||||||
await htmlEditorApi?.formatAlignJustify();
|
|
||||||
break;
|
|
||||||
case ParagraphType.indent:
|
|
||||||
await htmlEditorApi?.formatIndent();
|
|
||||||
break;
|
|
||||||
case ParagraphType.outdent:
|
|
||||||
await htmlEditorApi?.formatOutent();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
menuParagraphController.hideMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyOrderListType(OrderListType newOrderList) async {
|
|
||||||
selectedOrderList.value = newOrderList;
|
|
||||||
switch(newOrderList) {
|
|
||||||
case OrderListType.bulletedList:
|
|
||||||
await htmlEditorApi?.insertUnorderedList();
|
|
||||||
break;
|
|
||||||
case OrderListType.numberedList:
|
|
||||||
await htmlEditorApi?.insertOrderedList();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
menuOrderListController.hideMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onClose() {
|
|
||||||
menuParagraphController.dispose();
|
|
||||||
menuOrderListController.dispose();
|
|
||||||
super.onClose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,44 +55,66 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController> {
|
|||||||
backgroundColor: Colors.black38,
|
backgroundColor: Colors.black38,
|
||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
onTap: () => controller.clearFocusEditor(context),
|
onTap: () => controller.clearFocusEditor(context),
|
||||||
child: Align(alignment: Alignment.center, child: Card(
|
child: KeyboardRichText(
|
||||||
color: Colors.transparent,
|
richTextController: controller.keyboardRichTextController,
|
||||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
keyBroadToolbar: RichTextKeyboardToolBar(
|
||||||
child: Container(
|
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
||||||
decoration: const BoxDecoration(
|
richTextController: controller.keyboardRichTextController,
|
||||||
color: Colors.white,
|
titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16))),
|
titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground,
|
||||||
width: _responsiveUtils.getSizeScreenWidth(context) * 0.9,
|
titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground,
|
||||||
height: _responsiveUtils.getSizeScreenHeight(context) * 0.9,
|
titleFormatBottomSheet: AppLocalizations.of(context).titleFormat,
|
||||||
child: ClipRRect(
|
titleBack: AppLocalizations.of(context).format,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
),
|
||||||
child: _buildBodyDesktop(context)
|
child: Align(alignment: Alignment.center, child: Card(
|
||||||
)
|
color: Colors.transparent,
|
||||||
)
|
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||||
|
width: _responsiveUtils.getSizeScreenWidth(context) * 0.9,
|
||||||
|
height: _responsiveUtils.getSizeScreenHeight(context) * 0.9,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||||
|
child: _buildBodyDesktop(context)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
|
||||||
),
|
),
|
||||||
tabletLarge: Scaffold(
|
tabletLarge: Scaffold(
|
||||||
backgroundColor: Colors.black38,
|
backgroundColor: Colors.black38,
|
||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
onTap: () => controller.clearFocusEditor(context),
|
onTap: () => controller.clearFocusEditor(context),
|
||||||
child: Align(alignment: Alignment.center, child: Card(
|
child: KeyboardRichText(
|
||||||
color: Colors.transparent,
|
richTextController: controller.keyboardRichTextController,
|
||||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
keyBroadToolbar: RichTextKeyboardToolBar(
|
||||||
child: Container(
|
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
||||||
decoration: const BoxDecoration(
|
richTextController: controller.keyboardRichTextController,
|
||||||
color: Colors.white,
|
titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16))),
|
titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground,
|
||||||
width: _responsiveUtils.getSizeScreenWidth(context) * 0.6,
|
titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground,
|
||||||
height: _responsiveUtils.getSizeScreenHeight(context) * 0.9,
|
titleFormatBottomSheet: AppLocalizations.of(context).titleFormat,
|
||||||
child: ClipRRect(
|
titleBack: AppLocalizations.of(context).format,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
),
|
||||||
child: _buildBodyDesktop(context)
|
child: Align(alignment: Alignment.center, child: Card(
|
||||||
)
|
color: Colors.transparent,
|
||||||
)
|
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||||
|
width: _responsiveUtils.getSizeScreenWidth(context) * 0.9,
|
||||||
|
height: _responsiveUtils.getSizeScreenHeight(context) * 0.9,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||||
|
child: _buildBodyDesktop(context)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
),
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
desktop: Scaffold(
|
desktop: Scaffold(
|
||||||
@@ -135,6 +157,7 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController> {
|
|||||||
color: Colors.black)))),
|
color: Colors.black)))),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Expanded(child: SingleChildScrollView(
|
Expanded(child: SingleChildScrollView(
|
||||||
|
controller: controller.scrollController,
|
||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
@@ -287,135 +310,136 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController> {
|
|||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Obx(() => (IdentityInputFieldBuilder(
|
Obx(() => (IdentityInputFieldBuilder(
|
||||||
AppLocalizations.of(context).name,
|
AppLocalizations.of(context).name,
|
||||||
controller.errorNameIdentity.value,
|
controller.errorNameIdentity.value,
|
||||||
editingController: controller.inputNameIdentityController,
|
editingController: controller.inputNameIdentityController,
|
||||||
focusNode: controller.inputNameIdentityFocusNode,
|
focusNode: controller.inputNameIdentityFocusNode,
|
||||||
isMandatory: true)
|
isMandatory: true)
|
||||||
..addOnChangeInputNameAction((value) => controller.updateNameIdentity(context, value)))
|
..addOnChangeInputNameAction((value) => controller.updateNameIdentity(context, value)))
|
||||||
.build()),
|
.build()),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (controller.actionType == IdentityActionType.create) {
|
if (controller.actionType == IdentityActionType.create) {
|
||||||
return (IdentityDropListFieldBuilder(
|
return (IdentityDropListFieldBuilder(
|
||||||
_imagePaths,
|
_imagePaths,
|
||||||
AppLocalizations.of(context).email.inCaps,
|
AppLocalizations.of(context).email.inCaps,
|
||||||
controller.emailOfIdentity.value,
|
controller.emailOfIdentity.value,
|
||||||
controller.listEmailAddressDefault)
|
controller.listEmailAddressDefault)
|
||||||
..addOnSelectEmailAddressDropListAction((emailAddress) =>
|
..addOnSelectEmailAddressDropListAction((emailAddress) =>
|
||||||
controller.updateEmailOfIdentity(emailAddress))
|
controller.updateEmailOfIdentity(emailAddress))
|
||||||
).build();
|
).build();
|
||||||
} else {
|
|
||||||
return IdentityFieldNoEditableBuilder(
|
|
||||||
AppLocalizations.of(context).email.inCaps,
|
|
||||||
controller.emailOfIdentity.value
|
|
||||||
).build();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
Obx(() => (IdentityDropListFieldBuilder(
|
|
||||||
_imagePaths,
|
|
||||||
AppLocalizations.of(context).reply_to_address,
|
|
||||||
controller.replyToOfIdentity.value,
|
|
||||||
controller.listEmailAddressOfReplyTo)
|
|
||||||
..addOnSelectEmailAddressDropListAction((newEmailAddress) =>
|
|
||||||
controller.updaterReplyToOfIdentity(newEmailAddress)))
|
|
||||||
.build()),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
Obx(() => (IdentityInputWithDropListFieldBuilder(
|
|
||||||
AppLocalizations.of(context).bcc_to_address,
|
|
||||||
controller.errorBccIdentity.value,
|
|
||||||
controller.inputBccIdentityController)
|
|
||||||
..addOnSelectedSuggestionAction((newEmailAddress) {
|
|
||||||
controller.inputBccIdentityController.text = newEmailAddress?.email ?? '';
|
|
||||||
controller.updateBccOfIdentity(newEmailAddress);
|
|
||||||
})
|
|
||||||
..addOnChangeInputSuggestionAction((pattern) {
|
|
||||||
controller.validateInputBccAddress(context, pattern);
|
|
||||||
if (pattern == null || pattern.trim().isEmpty) {
|
|
||||||
controller.updateBccOfIdentity(null);
|
|
||||||
} else {
|
} else {
|
||||||
controller.updateBccOfIdentity(EmailAddress(null, pattern));
|
return IdentityFieldNoEditableBuilder(
|
||||||
|
AppLocalizations.of(context).email.inCaps,
|
||||||
|
controller.emailOfIdentity.value
|
||||||
|
).build();
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
..addOnSuggestionCallbackAction((pattern) =>
|
const SizedBox(height: 24),
|
||||||
controller.getSuggestionEmailAddress(pattern)))
|
Obx(() => (IdentityDropListFieldBuilder(
|
||||||
.build()
|
_imagePaths,
|
||||||
),
|
AppLocalizations.of(context).reply_to_address,
|
||||||
const SizedBox(height: 32),
|
controller.replyToOfIdentity.value,
|
||||||
Text(AppLocalizations.of(context).signature,
|
controller.listEmailAddressOfReplyTo)
|
||||||
style: const TextStyle(
|
..addOnSelectEmailAddressDropListAction((newEmailAddress) =>
|
||||||
fontWeight: FontWeight.normal,
|
controller.updaterReplyToOfIdentity(newEmailAddress)))
|
||||||
fontSize: 14,
|
.build()),
|
||||||
color: AppColor.colorContentEmail,
|
const SizedBox(height: 24),
|
||||||
|
Obx(() => (IdentityInputWithDropListFieldBuilder(
|
||||||
|
AppLocalizations.of(context).bcc_to_address,
|
||||||
|
controller.errorBccIdentity.value,
|
||||||
|
controller.inputBccIdentityController)
|
||||||
|
..addOnSelectedSuggestionAction((newEmailAddress) {
|
||||||
|
controller.inputBccIdentityController.text = newEmailAddress?.email ?? '';
|
||||||
|
controller.updateBccOfIdentity(newEmailAddress);
|
||||||
|
})
|
||||||
|
..addOnChangeInputSuggestionAction((pattern) {
|
||||||
|
controller.validateInputBccAddress(context, pattern);
|
||||||
|
if (pattern == null || pattern.trim().isEmpty) {
|
||||||
|
controller.updateBccOfIdentity(null);
|
||||||
|
} else {
|
||||||
|
controller.updateBccOfIdentity(EmailAddress(null, pattern));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
..addOnSuggestionCallbackAction((pattern) =>
|
||||||
|
controller.getSuggestionEmailAddress(pattern)))
|
||||||
|
.build()
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 32),
|
||||||
const SizedBox(height: 8),
|
Text(AppLocalizations.of(context).signature,
|
||||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
style: const TextStyle(
|
||||||
Obx(() => _buildSignatureButton(context, SignatureType.plainText)),
|
fontWeight: FontWeight.normal,
|
||||||
const SizedBox(width: 10),
|
fontSize: 14,
|
||||||
Obx(() => _buildSignatureButton(context, SignatureType.htmlTemplate)),
|
color: AppColor.colorContentEmail,
|
||||||
]),
|
),
|
||||||
const SizedBox(height: 8),
|
),
|
||||||
Obx(() => Container(
|
const SizedBox(height: 8),
|
||||||
decoration: BoxDecoration(
|
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
borderRadius: BorderRadius.circular(10),
|
Obx(() => _buildSignatureButton(context, SignatureType.plainText)),
|
||||||
border: Border.all(color: AppColor.colorInputBorderCreateMailbox),
|
const SizedBox(width: 10),
|
||||||
|
Obx(() => _buildSignatureButton(context, SignatureType.htmlTemplate)),
|
||||||
|
]),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Obx(() => Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(color: AppColor.colorInputBorderCreateMailbox),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
if (controller.signatureType.value == SignatureType.plainText)
|
||||||
|
_buildSignaturePlainTextTemplate(context)
|
||||||
|
else
|
||||||
|
_buildSignatureHtmlTemplate(context)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
child: Row(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
|
children: [
|
||||||
child: Stack(
|
Expanded(
|
||||||
children: [
|
child: buildTextButton(
|
||||||
if (controller.signatureType.value == SignatureType.plainText)
|
AppLocalizations.of(context).cancel,
|
||||||
_buildSignaturePlainTextTemplate(context)
|
textStyle: const TextStyle(
|
||||||
else
|
fontWeight: FontWeight.w500,
|
||||||
_buildSignatureHtmlTemplate(context)
|
fontSize: 17,
|
||||||
]
|
color: AppColor.colorTextButton,
|
||||||
),
|
),
|
||||||
)),
|
backgroundColor: AppColor.emailAddressChipColor,
|
||||||
const SizedBox(height: 24),
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
color: Colors.white,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: buildTextButton(
|
|
||||||
AppLocalizations.of(context).cancel,
|
|
||||||
textStyle: const TextStyle(
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
fontSize: 17,
|
|
||||||
color: AppColor.colorTextButton,
|
|
||||||
),
|
|
||||||
backgroundColor: AppColor.emailAddressChipColor,
|
|
||||||
width: 128,
|
|
||||||
height: 44,
|
|
||||||
radius: 10,
|
|
||||||
onTap: () => controller.closeView(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Expanded(
|
|
||||||
child: Obx(() => buildTextButton(
|
|
||||||
controller.actionType == IdentityActionType.create
|
|
||||||
? AppLocalizations.of(context).create
|
|
||||||
: AppLocalizations.of(context).save,
|
|
||||||
width: 128,
|
width: 128,
|
||||||
height: 44,
|
height: 44,
|
||||||
radius: 10,
|
radius: 10,
|
||||||
onTap: () => controller.createNewIdentity(context))),
|
onTap: () => controller.closeView(context),
|
||||||
),
|
),
|
||||||
]
|
),
|
||||||
),
|
const SizedBox(width: 12),
|
||||||
)
|
Expanded(
|
||||||
]),
|
child: Obx(() => buildTextButton(
|
||||||
),
|
controller.actionType == IdentityActionType.create
|
||||||
),
|
? AppLocalizations.of(context).create
|
||||||
|
: AppLocalizations.of(context).save,
|
||||||
|
width: 128,
|
||||||
|
height: 44,
|
||||||
|
radius: 10,
|
||||||
|
onTap: () => controller.createNewIdentity(context))),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
richTextController: controller.keyboardRichTextController,
|
richTextController: controller.keyboardRichTextController,
|
||||||
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
|
||||||
keyBroadToolbar: RichTextKeyboardToolBar(
|
keyBroadToolbar: RichTextKeyboardToolBar(
|
||||||
|
titleBack: AppLocalizations.of(context).titleFormat,
|
||||||
|
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
||||||
isLandScapeMode: _responsiveUtils.isLandscapeMobile(context),
|
isLandScapeMode: _responsiveUtils.isLandscapeMobile(context),
|
||||||
richTextController: controller.keyboardRichTextController,
|
richTextController: controller.keyboardRichTextController,
|
||||||
titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles,
|
titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles,
|
||||||
@@ -516,6 +540,7 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController> {
|
|||||||
htmlEditorController,
|
htmlEditorController,
|
||||||
onFocus: controller.onFocusHTMLEditor,
|
onFocus: controller.onFocusHTMLEditor,
|
||||||
onEnterKeyDown: controller.onEnterKeyDown,
|
onEnterKeyDown: controller.onEnterKeyDown,
|
||||||
|
context: context,
|
||||||
);
|
);
|
||||||
controller.signatureHtmlEditorMobileController = htmlEditorController;
|
controller.signatureHtmlEditorMobileController = htmlEditorController;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,12 +37,11 @@ class VacationView extends GetWidget<VacationController> with RichTextButtonMixi
|
|||||||
onTap: () => FocusScope.of(context).unfocus(),
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
child: KeyboardRichText(
|
child: KeyboardRichText(
|
||||||
richTextController: controller.richTextControllerForMobile,
|
richTextController: controller.richTextControllerForMobile,
|
||||||
backgroundKeyboardToolBarColor: Colors.grey,
|
|
||||||
keyBroadToolbar: RichTextKeyboardToolBar(
|
keyBroadToolbar: RichTextKeyboardToolBar(
|
||||||
|
titleBack: AppLocalizations.of(context).format,
|
||||||
|
backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
|
||||||
titleFormatBottomSheet: AppLocalizations.of(context).format,
|
titleFormatBottomSheet: AppLocalizations.of(context).format,
|
||||||
richTextController: controller.richTextControllerForMobile,
|
richTextController: controller.richTextControllerForMobile,
|
||||||
insertImage: () {},
|
|
||||||
insertAttachment: () {},
|
|
||||||
titleQuickStyleBottomSheet: AppLocalizations.of(context).quickStyles,
|
titleQuickStyleBottomSheet: AppLocalizations.of(context).quickStyles,
|
||||||
titleBackgroundBottomSheet: AppLocalizations.of(context).background,
|
titleBackgroundBottomSheet: AppLocalizations.of(context).background,
|
||||||
titleForegroundBottomSheet: AppLocalizations.of(context).foreground,
|
titleForegroundBottomSheet: AppLocalizations.of(context).foreground,
|
||||||
@@ -479,6 +478,7 @@ class VacationView extends GetWidget<VacationController> with RichTextButtonMixi
|
|||||||
htmlApi,
|
htmlApi,
|
||||||
onFocus: controller.onFocusHTMLEditor,
|
onFocus: controller.onFocusHTMLEditor,
|
||||||
onEnterKeyDown: controller.onEnterKeyDown,
|
onEnterKeyDown: controller.onEnterKeyDown,
|
||||||
|
context: context,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
+6
-6
@@ -219,7 +219,7 @@ packages:
|
|||||||
name: convert
|
name: convert
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.1.0"
|
||||||
core:
|
core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -361,7 +361,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.0"
|
||||||
enough_html_editor:
|
enough_html_editor:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: email_supported
|
ref: email_supported
|
||||||
@@ -757,7 +757,7 @@ packages:
|
|||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: master
|
ref: master
|
||||||
resolved-ref: f5652f21f7b7005bcdcefb45fc406c876ce05618
|
resolved-ref: ab07a8a03d63e20f6ea5e62bcc1ca8cdc1fd93ff
|
||||||
url: "https://github.com/linagora/jmap-dart-client.git"
|
url: "https://github.com/linagora/jmap-dart-client.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
@@ -1104,7 +1104,7 @@ packages:
|
|||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: master
|
ref: master
|
||||||
resolved-ref: "3dc2e65ee12bf6df9c341ccc229a5dfc9d16405f"
|
resolved-ref: "9a863d1d6392441e7d7aad19d1c9a74da44af3a7"
|
||||||
url: "https://github.com/linagora/rich-text-composer.git"
|
url: "https://github.com/linagora/rich-text-composer.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
@@ -1203,7 +1203,7 @@ packages:
|
|||||||
name: source_gen
|
name: source_gen
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.5"
|
version: "1.2.6"
|
||||||
source_helper:
|
source_helper:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1273,7 +1273,7 @@ packages:
|
|||||||
name: syncfusion_flutter_core
|
name: syncfusion_flutter_core
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "20.3.48"
|
version: "20.3.49"
|
||||||
syncfusion_flutter_datepicker:
|
syncfusion_flutter_datepicker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -131,12 +131,6 @@ dependencies:
|
|||||||
# hive
|
# hive
|
||||||
hive: 2.0.4
|
hive: 2.0.4
|
||||||
|
|
||||||
# enough_html_editor: Compose email for Mobile & Tablet
|
|
||||||
enough_html_editor:
|
|
||||||
git:
|
|
||||||
url: https://github.com/linagora/enough_html_editor.git
|
|
||||||
ref: email_supported
|
|
||||||
|
|
||||||
# html_editor_enhanced: Compose email for Web Browser
|
# html_editor_enhanced: Compose email for Web Browser
|
||||||
html_editor_enhanced:
|
html_editor_enhanced:
|
||||||
git:
|
git:
|
||||||
|
|||||||
Reference in New Issue
Block a user