diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 4bd2cea26..2843a4446 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -147,6 +147,7 @@ extension AppColor on Color { static const colorDividerVertical = Color(0xFF99A2AD); static const colorCloseButton = Color(0xFF818C99); static const colorDropShadow = Color(0x0F000000); + static const colorBackgroundKeyboard = Color(0xFFD2D5DC); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 72eb18d51..8a76df2c7 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -28,6 +28,7 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:permission_handler/permission_handler.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/composer/domain/model/contact_suggestion_source.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 bccEmailAddressController = TextEditingController(); + final RichTextController keyboardRichTextController = RichTextController(); + List initialAttachments = []; String? _textEditorWeb; List? _emailContents; @@ -215,6 +218,7 @@ class ComposerController extends BaseController { ccEmailAddressController.dispose(); bccEmailAddressController.dispose(); uploadInlineImageWorker.dispose(); + keyboardRichTextController.dispose(); super.dispose(); } @@ -1076,6 +1080,7 @@ class ComposerController extends BaseController { toAddressExpandMode.value = ExpandMode.COLLAPSE; ccAddressExpandMode.value = ExpandMode.COLLAPSE; bccAddressExpandMode.value = ExpandMode.COLLAPSE; + htmlEditorApi?.unfocus(); } } diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index ed04c0bf4..c9117ec31 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -9,6 +9,8 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/identities/identity.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/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart'; @@ -51,13 +53,14 @@ class ComposerView extends GetWidget controller.saveEmailAsDrafts(context, canPop: false); return true; }, - child: GestureDetector( - onTap: () { - controller.clearFocusEditor(context); - }, - child: Scaffold( - backgroundColor: Colors.white, - body: SafeArea( + child: LayoutBuilder( + builder: (context, constraints) => GestureDetector( + onTap: () { + controller.clearFocusEditor(context); + }, + child: Scaffold( + backgroundColor: Colors.white, + body: SafeArea( right: responsiveUtils.isLandscapeMobile(context), left: responsiveUtils.isLandscapeMobile(context), child: Container( @@ -65,11 +68,12 @@ class ComposerView extends GetWidget child: Column(children: [ Obx(() => _buildAppBar(context, controller.isEnableEmailSendButton.value)), 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 } Widget _buildEmailAddress(BuildContext context) { - return Column( - children: [ - Obx(() => Padding( - padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), - child: (EmailAddressInputBuilder(context, imagePaths, - PrefixEmailAddress.to, - controller.listToEmailAddress, - controller.listEmailAddressType, - expandMode: controller.toAddressExpandMode.value, - controller: controller.toEmailAddressController, - isInitial: controller.isInitialRecipient.value) - ..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus)) - ..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress)) - ..addOnAddEmailAddressTypeAction((prefixEmailAddress) => controller.addEmailAddressType(prefixEmailAddress)) - ..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress)) - ..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion)) - .build() - )), - Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true - ? const Divider(color: AppColor.colorDividerComposer, height: 1) - : const SizedBox.shrink()), - Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true - ? Padding( - padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), - child: (EmailAddressInputBuilder(context, imagePaths, - PrefixEmailAddress.cc, - controller.listCcEmailAddress, - controller.listEmailAddressType, - expandMode: controller.ccAddressExpandMode.value, - controller: controller.ccEmailAddressController, - 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)) - ..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion)) - .build()) - : const SizedBox.shrink() - ), - Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true - ? const Divider(color: AppColor.colorDividerComposer, height: 1) - : const SizedBox.shrink()), - Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true - ? Padding( - padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), - child: (EmailAddressInputBuilder(context, imagePaths, - PrefixEmailAddress.bcc, - controller.listBccEmailAddress, - controller.listEmailAddressType, - expandMode: controller.bccAddressExpandMode.value, - 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)) - ..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion)) - .build()) - : const SizedBox.shrink() - ), - ], + return Focus( + onFocusChange: (focus) { + if(focus) { + controller.htmlEditorApi?.unfocus(); + } + }, + child: Column( + children: [ + Obx(() => Padding( + padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), + child: (EmailAddressInputBuilder(context, imagePaths, + PrefixEmailAddress.to, + controller.listToEmailAddress, + controller.listEmailAddressType, + expandMode: controller.toAddressExpandMode.value, + controller: controller.toEmailAddressController, + isInitial: controller.isInitialRecipient.value) + ..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus)) + ..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress)) + ..addOnAddEmailAddressTypeAction((prefixEmailAddress) => controller.addEmailAddressType(prefixEmailAddress)) + ..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress)) + ..addOnOpenSuggestionBoxEmailAddress(() => controller.getAutoCompleteSuggestion('')) + ..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word))) + .build() + )), + Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true + ? const Divider(color: AppColor.colorDividerComposer, height: 1) + : const SizedBox.shrink()), + Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true + ? Padding( + padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), + child: (EmailAddressInputBuilder(context, imagePaths, + PrefixEmailAddress.cc, + controller.listCcEmailAddress, + controller.listEmailAddressType, + expandMode: controller.ccAddressExpandMode.value, + controller: controller.ccEmailAddressController, + 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() + ), + Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true + ? const Divider(color: AppColor.colorDividerComposer, height: 1) + : const SizedBox.shrink()), + Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true + ? Padding( + padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0), + child: (EmailAddressInputBuilder(context, imagePaths, + PrefixEmailAddress.bcc, + controller.listBccEmailAddress, + controller.listEmailAddressType, + expandMode: controller.bccAddressExpandMode.value, + 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 ); } - Widget _buildListButton(BuildContext context, BoxConstraints constraints) { - return Transform( - transform: Matrix4.translationValues(-10.0, 0.0, 0.0), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 5), - child: Row(children: [ - buildIconWeb( - icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, color: AppColor.colorTextButton, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).attach_file, - onTap: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context))), - buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset(imagePaths.icInsertImage, - color: AppColor.colorTextButton, - fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).insertImage, - onTap: () => controller.insertImage(context, constraints.maxWidth)) - ]) - ) - ); - } - - Widget _buildBodyMobile(BuildContext context) { - return SingleChildScrollView( - physics: const ClampingScrollPhysics(), - child: LayoutBuilder( - builder: (context, constraints) => Column(children: [ - Obx(() => controller.identitySelected.value != null - ? _buildFromEmailAddress(context) - : const SizedBox.shrink()), - 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 _buildBodyMobile(BuildContext context, double maxWidth) { + return rich_text_composer.KeyboardRichText( + child: SingleChildScrollView( + physics: const ClampingScrollPhysics(), + child: Column(children: [ + Obx(() => controller.identitySelected.value != null + ? _buildFromEmailAddress(context) + : const SizedBox.shrink()), + 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), + _buildAttachmentsWidget(context), + buildInlineLoadingView(controller), + _buildComposerEditor(context), + ]) + ), + richTextController: controller.keyboardRichTextController, + backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, + keyBroadToolbar: RichTextKeyboardToolBar( + isLandScapeMode: responsiveUtils.isLandscapeMobile(context), + insertAttachment: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context)), + insertImage: () => controller.insertImage(context, maxWidth), + richTextController: controller.keyboardRichTextController, + titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles, + titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground, + titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground, + titleFormatBottomSheet: AppLocalizations.of(context).titleFormat, + ), ); } Widget _buildBodyTablet(BuildContext context) { return SingleChildScrollView( physics: const ClampingScrollPhysics(), - child: LayoutBuilder( - builder: (context, constraints) => Column(children: [ - Padding( - padding: const EdgeInsets.only(left: 16), - child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding(padding: const EdgeInsets.only(top: 20), - child: (AvatarBuilder() - ..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '') - ..size(56) - ..addTextStyle(const TextStyle(fontWeight: FontWeight.w600, fontSize: 28, color: Colors.white)) - ..backgroundColor(AppColor.colorAvatar)) + child: Column(children: [ + Padding( + padding: const EdgeInsets.only(left: 16), + child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding(padding: const EdgeInsets.only(top: 20), + child: (AvatarBuilder() + ..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '') + ..size(56) + ..addTextStyle(const TextStyle(fontWeight: FontWeight.w600, fontSize: 28, color: Colors.white)) + ..backgroundColor(AppColor.colorAvatar)) .build()), - Expanded(child: Padding( - padding: const EdgeInsets.only(left: 16), - child: Column(children: [ - Obx(() => controller.identitySelected.value != null - ? _buildFromEmailAddress(context) - : const SizedBox.shrink()), - 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.only(right: 16), child: _buildSubjectEmail(context)), - const Divider(color: AppColor.colorDividerComposer, height: 1), - _buildListButton(context, constraints), - ]), - )) - ])), - const Divider(color: AppColor.colorDividerComposer, height: 1), - Padding( - padding: const EdgeInsets.only(left: 60, right: 25), - child: Column(children: [ - _buildToolbarRichTextWidget(context), - _buildAttachmentsWidget(context), - buildInlineLoadingView(controller), - _buildComposerEditor(context), - ]) - ) - ]), - ) + Expanded(child: Padding( + padding: const EdgeInsets.only(left: 16), + child: Column(children: [ + Obx(() => controller.identitySelected.value != null + ? _buildFromEmailAddress(context) + : const SizedBox.shrink()), + 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.only(right: 16), child: _buildSubjectEmail(context)), + ]), + )) + ])), + const Divider(color: AppColor.colorDividerComposer, height: 1), + Padding( + padding: const EdgeInsets.only(left: 60, right: 25), + child: Column(children: [ + _buildToolbarRichTextWidget(context), + _buildAttachmentsWidget(context), + buildInlineLoadingView(controller), + _buildComposerEditor(context), + ]) + ) + ]) ); } @@ -624,10 +620,10 @@ class ComposerView extends GetWidget switch(argsComposer.emailActionType) { case EmailActionType.compose: case EmailActionType.composeFromEmailAddress: - return _buildHtmlEditor(HtmlExtension.editorStartTags); + return _buildHtmlEditor('', context); case EmailActionType.edit: return controller.emailContentsViewState.value.fold( - (failure) => _buildHtmlEditor(HtmlExtension.editorStartTags), + (failure) => _buildHtmlEditor(HtmlExtension.editorStartTags, context), (success) { if (success is GetEmailContentLoading) { return Padding( @@ -639,9 +635,9 @@ class ComposerView extends GetWidget if (contentHtml.isEmpty == true) { contentHtml = HtmlExtension.editorStartTags; } - return _buildHtmlEditor(contentHtml); + return _buildHtmlEditor(contentHtml, context); } else { - return _buildHtmlEditor(HtmlExtension.editorStartTags); + return _buildHtmlEditor(HtmlExtension.editorStartTags, context); } }); case EmailActionType.reply: @@ -653,26 +649,31 @@ class ComposerView extends GetWidget if (contentHtml.isEmpty == true) { contentHtml = HtmlExtension.editorStartTags; } - return _buildHtmlEditor(contentHtml); + return _buildHtmlEditor(contentHtml, context); default: - return _buildHtmlEditor(HtmlExtension.editorStartTags); + return _buildHtmlEditor(HtmlExtension.editorStartTags, context); } }); } - Widget _buildHtmlEditor(String initialContent) { + Widget _buildHtmlEditor(String initialContent, BuildContext context) { final richTextMobileTabletController = controller.richTextMobileTabletController; 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( - key: const Key('composer_editor'), - minHeight: 550, - addDefaultSelectionMenuItems: false, - initialContent: initialContent, - onCreated: (editorApi) { + key: const Key('composer_editor'), + minHeight: 550, + addDefaultSelectionMenuItems: false, + initialContent: initialContent, + onCreated: (editorApi) { + if(responsiveUtils.isMobile(context)){ + controller.keyboardRichTextController.onCreateHTMLEditor(editorApi); + } else { richTextMobileTabletController.htmlEditorApi = editorApi; richTextMobileTabletController.listenHtmlEditorApi(); - }), + } + }, + ), ); } @@ -765,55 +766,4 @@ class ComposerView extends GetWidget double _getMaxWidthItemListAttachment(BuildContext context, BoxConstraints 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)), - ), - ], - ), - ); - }); - } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 3d450cc56..012bae111 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2299,4 +2299,32 @@ class AppLocalizations { 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' + ); + } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index c31c4bc31..246ba72c3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,6 +42,10 @@ dependencies: 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. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2