TF-880: Apply rich text toolbar at keyboard

This commit is contained in:
ManhNTX
2022-09-22 06:00:16 +07:00
committed by Dat H. Pham
parent 6ac4952a37
commit 00f781b67f
5 changed files with 211 additions and 223 deletions
@@ -147,6 +147,7 @@ extension AppColor on Color {
static const colorDividerVertical = Color(0xFF99A2AD); static const colorDividerVertical = Color(0xFF99A2AD);
static const colorCloseButton = Color(0xFF818C99); static const colorCloseButton = Color(0xFF818C99);
static const colorDropShadow = Color(0x0F000000); static const colorDropShadow = Color(0x0F000000);
static const colorBackgroundKeyboard = Color(0xFFD2D5DC);
static const mapGradientColor = [ static const mapGradientColor = [
[Color(0xFF21D4FD), Color(0xFFB721FF)], [Color(0xFF21D4FD), Color(0xFFB721FF)],
@@ -28,6 +28,7 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:rich_text_composer/rich_text_composer.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.dart'; import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.dart';
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
@@ -113,6 +114,8 @@ class ComposerController extends BaseController {
final ccEmailAddressController = TextEditingController(); final ccEmailAddressController = TextEditingController();
final bccEmailAddressController = TextEditingController(); final bccEmailAddressController = TextEditingController();
final RichTextController keyboardRichTextController = RichTextController();
List<Attachment> initialAttachments = <Attachment>[]; List<Attachment> initialAttachments = <Attachment>[];
String? _textEditorWeb; String? _textEditorWeb;
List<EmailContent>? _emailContents; List<EmailContent>? _emailContents;
@@ -215,6 +218,7 @@ class ComposerController extends BaseController {
ccEmailAddressController.dispose(); ccEmailAddressController.dispose();
bccEmailAddressController.dispose(); bccEmailAddressController.dispose();
uploadInlineImageWorker.dispose(); uploadInlineImageWorker.dispose();
keyboardRichTextController.dispose();
super.dispose(); super.dispose();
} }
@@ -1076,6 +1080,7 @@ class ComposerController extends BaseController {
toAddressExpandMode.value = ExpandMode.COLLAPSE; toAddressExpandMode.value = ExpandMode.COLLAPSE;
ccAddressExpandMode.value = ExpandMode.COLLAPSE; ccAddressExpandMode.value = ExpandMode.COLLAPSE;
bccAddressExpandMode.value = ExpandMode.COLLAPSE; bccAddressExpandMode.value = ExpandMode.COLLAPSE;
htmlEditorApi?.unfocus();
} }
} }
@@ -9,6 +9,8 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
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: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/drop_down_button_widget.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart'; import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart';
@@ -51,13 +53,14 @@ class ComposerView extends GetWidget<ComposerController>
controller.saveEmailAsDrafts(context, canPop: false); controller.saveEmailAsDrafts(context, canPop: false);
return true; return true;
}, },
child: GestureDetector( child: LayoutBuilder(
onTap: () { builder: (context, constraints) => GestureDetector(
controller.clearFocusEditor(context); onTap: () {
}, controller.clearFocusEditor(context);
child: Scaffold( },
backgroundColor: Colors.white, child: Scaffold(
body: SafeArea( backgroundColor: Colors.white,
body: SafeArea(
right: responsiveUtils.isLandscapeMobile(context), right: responsiveUtils.isLandscapeMobile(context),
left: responsiveUtils.isLandscapeMobile(context), left: responsiveUtils.isLandscapeMobile(context),
child: Container( child: Container(
@@ -65,11 +68,12 @@ class ComposerView extends GetWidget<ComposerController>
child: Column(children: [ child: Column(children: [
Obx(() => _buildAppBar(context, controller.isEnableEmailSendButton.value)), Obx(() => _buildAppBar(context, controller.isEnableEmailSendButton.value)),
const Divider(color: AppColor.colorDividerComposer, height: 1), const Divider(color: AppColor.colorDividerComposer, height: 1),
Expanded(child: _buildBodyMobile(context)) Expanded(child: _buildBodyMobile(context, constraints.maxWidth))
]) ])
) ),
), ),
) )
),
) )
); );
} }
@@ -283,67 +287,77 @@ class ComposerView extends GetWidget<ComposerController>
} }
Widget _buildEmailAddress(BuildContext context) { Widget _buildEmailAddress(BuildContext context) {
return Column( return Focus(
children: [ onFocusChange: (focus) {
Obx(() => Padding( if(focus) {
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), controller.htmlEditorApi?.unfocus();
child: (EmailAddressInputBuilder(context, imagePaths, }
PrefixEmailAddress.to, },
controller.listToEmailAddress, child: Column(
controller.listEmailAddressType, children: [
expandMode: controller.toAddressExpandMode.value, Obx(() => Padding(
controller: controller.toEmailAddressController, padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0),
isInitial: controller.isInitialRecipient.value) child: (EmailAddressInputBuilder(context, imagePaths,
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus)) PrefixEmailAddress.to,
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress)) controller.listToEmailAddress,
..addOnAddEmailAddressTypeAction((prefixEmailAddress) => controller.addEmailAddressType(prefixEmailAddress)) controller.listEmailAddressType,
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress)) expandMode: controller.toAddressExpandMode.value,
..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion)) controller: controller.toEmailAddressController,
.build() isInitial: controller.isInitialRecipient.value)
)), ..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true ..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
? const Divider(color: AppColor.colorDividerComposer, height: 1) ..addOnAddEmailAddressTypeAction((prefixEmailAddress) => controller.addEmailAddressType(prefixEmailAddress))
: const SizedBox.shrink()), ..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true ..addOnOpenSuggestionBoxEmailAddress(() => controller.getAutoCompleteSuggestion(''))
? Padding( ..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), .build()
child: (EmailAddressInputBuilder(context, imagePaths, )),
PrefixEmailAddress.cc, Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true
controller.listCcEmailAddress, ? const Divider(color: AppColor.colorDividerComposer, height: 1)
controller.listEmailAddressType, : const SizedBox.shrink()),
expandMode: controller.ccAddressExpandMode.value, Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true
controller: controller.ccEmailAddressController, ? Padding(
isInitial: controller.isInitialRecipient.value,) padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0),
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus)) child: (EmailAddressInputBuilder(context, imagePaths,
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress)) PrefixEmailAddress.cc,
..addOnDeleteEmailAddressTypeAction((prefixEmailAddress) => controller.deleteEmailAddressType(prefixEmailAddress)) controller.listCcEmailAddress,
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress)) controller.listEmailAddressType,
..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion)) expandMode: controller.ccAddressExpandMode.value,
.build()) controller: controller.ccEmailAddressController,
: const SizedBox.shrink() isInitial: controller.isInitialRecipient.value,)
), ..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true ..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
? const Divider(color: AppColor.colorDividerComposer, height: 1) ..addOnDeleteEmailAddressTypeAction((prefixEmailAddress) => controller.deleteEmailAddressType(prefixEmailAddress))
: const SizedBox.shrink()), ..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true ..addOnOpenSuggestionBoxEmailAddress(() => controller.getAutoCompleteSuggestion(''))
? Padding( ..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), .build())
child: (EmailAddressInputBuilder(context, imagePaths, : const SizedBox.shrink()
PrefixEmailAddress.bcc, ),
controller.listBccEmailAddress, Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true
controller.listEmailAddressType, ? const Divider(color: AppColor.colorDividerComposer, height: 1)
expandMode: controller.bccAddressExpandMode.value, : const SizedBox.shrink()),
controller: controller.bccEmailAddressController, Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true
isInitial: controller.isInitialRecipient.value,) ? Padding(
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus)) padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0),
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress)) child: (EmailAddressInputBuilder(context, imagePaths,
..addOnDeleteEmailAddressTypeAction((prefixEmailAddress) => controller.deleteEmailAddressType(prefixEmailAddress)) PrefixEmailAddress.bcc,
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress)) controller.listBccEmailAddress,
..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion)) controller.listEmailAddressType,
.build()) expandMode: controller.bccAddressExpandMode.value,
: const SizedBox.shrink() controller: controller.bccEmailAddressController,
), isInitial: controller.isInitialRecipient.value,)
], ..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
..addOnDeleteEmailAddressTypeAction((prefixEmailAddress) => controller.deleteEmailAddressType(prefixEmailAddress))
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
..addOnOpenSuggestionBoxEmailAddress(() => controller.getAutoCompleteSuggestion(''))
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
.build())
: const SizedBox.shrink()
),
],
),
); );
} }
@@ -373,99 +387,81 @@ class ComposerView extends GetWidget<ComposerController>
); );
} }
Widget _buildListButton(BuildContext context, BoxConstraints constraints) { Widget _buildBodyMobile(BuildContext context, double maxWidth) {
return Transform( return rich_text_composer.KeyboardRichText(
transform: Matrix4.translationValues(-10.0, 0.0, 0.0), child: SingleChildScrollView(
child: Padding( physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.symmetric(vertical: 5), child: Column(children: [
child: Row(children: [ Obx(() => controller.identitySelected.value != null
buildIconWeb( ? _buildFromEmailAddress(context)
icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, color: AppColor.colorTextButton, fit: BoxFit.fill), : const SizedBox.shrink()),
tooltip: AppLocalizations.of(context).attach_file, Obx(() => controller.identitySelected.value != null
onTap: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context))), ? const Divider(color: AppColor.colorDividerComposer, height: 1)
buildIconWeb( : const SizedBox.shrink()),
minSize: 40, _buildEmailAddress(context),
iconPadding: EdgeInsets.zero, const Divider(color: AppColor.colorDividerComposer, height: 1),
icon: SvgPicture.asset(imagePaths.icInsertImage, Padding(padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: _buildSubjectEmail(context)),
color: AppColor.colorTextButton, const Divider(color: AppColor.colorDividerComposer, height: 1),
fit: BoxFit.fill), _buildAttachmentsWidget(context),
tooltip: AppLocalizations.of(context).insertImage, buildInlineLoadingView(controller),
onTap: () => controller.insertImage(context, constraints.maxWidth)) _buildComposerEditor(context),
]) ])
) ),
); richTextController: controller.keyboardRichTextController,
} backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard,
keyBroadToolbar: RichTextKeyboardToolBar(
Widget _buildBodyMobile(BuildContext context) { isLandScapeMode: responsiveUtils.isLandscapeMobile(context),
return SingleChildScrollView( insertAttachment: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context)),
physics: const ClampingScrollPhysics(), insertImage: () => controller.insertImage(context, maxWidth),
child: LayoutBuilder( richTextController: controller.keyboardRichTextController,
builder: (context, constraints) => Column(children: [ titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles,
Obx(() => controller.identitySelected.value != null titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground,
? _buildFromEmailAddress(context) titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground,
: const SizedBox.shrink()), titleFormatBottomSheet: AppLocalizations.of(context).titleFormat,
Obx(() => controller.identitySelected.value != null ),
? const Divider(color: AppColor.colorDividerComposer, height: 1)
: const SizedBox.shrink()),
_buildEmailAddress(context),
const Divider(color: AppColor.colorDividerComposer, height: 1),
Padding(padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: _buildSubjectEmail(context)),
const Divider(color: AppColor.colorDividerComposer, height: 1),
Padding(padding: const EdgeInsets.symmetric(horizontal: 16), child: _buildListButton(context, constraints)),
const Divider(color: AppColor.colorDividerComposer, height: 1),
_buildAttachmentsWidget(context),
_buildToolbarMobileWidget(context),
buildInlineLoadingView(controller),
_buildComposerEditor(context),
]),
)
); );
} }
Widget _buildBodyTablet(BuildContext context) { Widget _buildBodyTablet(BuildContext context) {
return SingleChildScrollView( return SingleChildScrollView(
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
child: LayoutBuilder( child: Column(children: [
builder: (context, constraints) => Column(children: [ Padding(
Padding( padding: const EdgeInsets.only(left: 16),
padding: const EdgeInsets.only(left: 16), child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding(padding: const EdgeInsets.only(top: 20),
Padding(padding: const EdgeInsets.only(top: 20), child: (AvatarBuilder()
child: (AvatarBuilder() ..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '')
..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '') ..size(56)
..size(56) ..addTextStyle(const TextStyle(fontWeight: FontWeight.w600, fontSize: 28, color: Colors.white))
..addTextStyle(const TextStyle(fontWeight: FontWeight.w600, fontSize: 28, color: Colors.white)) ..backgroundColor(AppColor.colorAvatar))
..backgroundColor(AppColor.colorAvatar))
.build()), .build()),
Expanded(child: Padding( Expanded(child: Padding(
padding: const EdgeInsets.only(left: 16), padding: const EdgeInsets.only(left: 16),
child: Column(children: [ child: Column(children: [
Obx(() => controller.identitySelected.value != null Obx(() => controller.identitySelected.value != null
? _buildFromEmailAddress(context) ? _buildFromEmailAddress(context)
: const SizedBox.shrink()), : const SizedBox.shrink()),
Obx(() => controller.identitySelected.value != null Obx(() => controller.identitySelected.value != null
? const Divider(color: AppColor.colorDividerComposer, height: 1) ? const Divider(color: AppColor.colorDividerComposer, height: 1)
: const SizedBox.shrink()), : const SizedBox.shrink()),
_buildEmailAddress(context), _buildEmailAddress(context),
const Divider(color: AppColor.colorDividerComposer, height: 1), const Divider(color: AppColor.colorDividerComposer, height: 1),
Padding(padding: const EdgeInsets.only(right: 16), child: _buildSubjectEmail(context)), Padding(padding: const EdgeInsets.only(right: 16), child: _buildSubjectEmail(context)),
const Divider(color: AppColor.colorDividerComposer, height: 1), ]),
_buildListButton(context, constraints), ))
]), ])),
)) 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),
_buildToolbarRichTextWidget(context), buildInlineLoadingView(controller),
_buildAttachmentsWidget(context), _buildComposerEditor(context),
buildInlineLoadingView(controller), ])
_buildComposerEditor(context), )
]) ])
)
]),
)
); );
} }
@@ -624,10 +620,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); return _buildHtmlEditor('', context);
case EmailActionType.edit: case EmailActionType.edit:
return controller.emailContentsViewState.value.fold( return controller.emailContentsViewState.value.fold(
(failure) => _buildHtmlEditor(HtmlExtension.editorStartTags), (failure) => _buildHtmlEditor(HtmlExtension.editorStartTags, context),
(success) { (success) {
if (success is GetEmailContentLoading) { if (success is GetEmailContentLoading) {
return Padding( return Padding(
@@ -639,9 +635,9 @@ class ComposerView extends GetWidget<ComposerController>
if (contentHtml.isEmpty == true) { if (contentHtml.isEmpty == true) {
contentHtml = HtmlExtension.editorStartTags; contentHtml = HtmlExtension.editorStartTags;
} }
return _buildHtmlEditor(contentHtml); return _buildHtmlEditor(contentHtml, context);
} else { } else {
return _buildHtmlEditor(HtmlExtension.editorStartTags); return _buildHtmlEditor(HtmlExtension.editorStartTags, context);
} }
}); });
case EmailActionType.reply: case EmailActionType.reply:
@@ -653,26 +649,31 @@ class ComposerView extends GetWidget<ComposerController>
if (contentHtml.isEmpty == true) { if (contentHtml.isEmpty == true) {
contentHtml = HtmlExtension.editorStartTags; contentHtml = HtmlExtension.editorStartTags;
} }
return _buildHtmlEditor(contentHtml); return _buildHtmlEditor(contentHtml, context);
default: default:
return _buildHtmlEditor(HtmlExtension.editorStartTags); return _buildHtmlEditor(HtmlExtension.editorStartTags, context);
} }
}); });
} }
Widget _buildHtmlEditor(String initialContent) { Widget _buildHtmlEditor(String initialContent, BuildContext context) {
final richTextMobileTabletController = controller.richTextMobileTabletController; final richTextMobileTabletController = controller.richTextMobileTabletController;
return Padding( return Padding(
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20, top: 10), padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20),
child: HtmlEditor( child: HtmlEditor(
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) {
if(responsiveUtils.isMobile(context)){
controller.keyboardRichTextController.onCreateHTMLEditor(editorApi);
} else {
richTextMobileTabletController.htmlEditorApi = editorApi; richTextMobileTabletController.htmlEditorApi = editorApi;
richTextMobileTabletController.listenHtmlEditorApi(); richTextMobileTabletController.listenHtmlEditorApi();
}), }
},
),
); );
} }
@@ -765,55 +766,4 @@ class ComposerView extends GetWidget<ComposerController>
double _getMaxWidthItemListAttachment(BuildContext context, BoxConstraints constraints) { double _getMaxWidthItemListAttachment(BuildContext context, BoxConstraints constraints) {
return constraints.maxWidth / _getMaxItemRowListAttachment(context, constraints); return constraints.maxWidth / _getMaxItemRowListAttachment(context, constraints);
} }
Widget _buildToolbarMobileWidget(BuildContext context) {
return Obx(() {
final richTextController = 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: [
buildWrapIconStyleText(
hasDropdown: false,
padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 5),
icon: Wrap(children: [
RichTextStyleType.bold,
RichTextStyleType.italic,
RichTextStyleType.underline
].map((formatStyle) => buildIconStyleText(
path: formatStyle.getIcon(imagePaths),
isSelected: richTextController.isTextStyleTypeSelected(formatStyle),
onTap: () => richTextController.applyRichTextStyle(context, formatStyle)))
.toList())
),
Padding(
padding: const EdgeInsets.only(left: 4),
child: buildWrapIconStyleText(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5),
icon: buildIconColorBackgroundTextWithoutTooltip(
iconData: RichTextStyleType.textColor.getIconData(),
colorSelected: richTextController.selectedTextColor.value),
onTap: () => richTextController.applyRichTextStyle(
context,
RichTextStyleType.textColor))),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: buildWrapIconStyleText(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5),
icon: buildIconColorBackgroundTextWithoutTooltip(
iconData: RichTextStyleType.textBackgroundColor.getIconData(),
colorSelected: richTextController.selectedTextBackgroundColor.value,
),
onTap: () => richTextController.applyRichTextStyle(
context,
RichTextStyleType.textBackgroundColor)),
),
],
),
);
});
}
} }
@@ -2299,4 +2299,32 @@ class AppLocalizations {
name: 'foreground' name: 'foreground'
); );
} }
String get titleFormat {
return Intl.message(
'Format',
name: 'titleFormat'
);
}
String get titleQuickStyles {
return Intl.message(
'Quick styles',
name: 'titleQuickStyles'
);
}
String get titleBackground {
return Intl.message(
'Background',
name: 'titleBackground'
);
}
String get titleForeground {
return Intl.message(
'Foreground',
name: 'titleForeground'
);
}
} }
+4
View File
@@ -42,6 +42,10 @@ dependencies:
forward: forward:
path: forward path: forward
rich_text_composer:
git:
url: https://github.com/linagora/rich-text-composer.git
ref: apply_rich_text_bottom_sheet
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2