diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index fe4d8c7b7..a4e6a484d 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -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/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'; 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/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/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/upload/presentation/extensions/list_upload_file_state_extension.dart'; import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart'; @@ -90,19 +83,33 @@ class ComposerView extends GetWidget }, child: Scaffold( backgroundColor: Colors.black38, - body: 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: [ + body: LayoutBuilder(builder: (context, constraints) { + return rich_text_composer.KeyboardRichText( + richTextController: controller.keyboardRichTextController, + keyBroadToolbar: RichTextKeyboardToolBar( + backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, + insertAttachment: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context)), + insertImage: () => controller.insertImage(context, constraints.maxWidth), + richTextController: controller.keyboardRichTextController, + titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles, + titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground, + titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground, + titleFormatBottomSheet: AppLocalizations.of(context).titleFormat, + 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: const EdgeInsets.symmetric(horizontal: 16), child: _buildAppBar(context, controller.isEnableEmailSendButton.value)), @@ -110,11 +117,13 @@ class ComposerView extends GetWidget Expanded(child: _buildBodyTablet(context)), const Divider(color: AppColor.colorDividerComposer, height: 1), Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)), - ]), + ]), + ) ) ) - ) - )) + )), + ); + }) ) ) ); @@ -415,8 +424,8 @@ class ComposerView extends GetWidget ]) ), richTextController: controller.keyboardRichTextController, - backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, keyBroadToolbar: RichTextKeyboardToolBar( + backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, isLandScapeMode: responsiveUtils.isLandscapeMobile(context), insertAttachment: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context)), insertImage: () => controller.insertImage(context, maxWidth), @@ -425,50 +434,51 @@ class ComposerView extends GetWidget titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground, titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground, titleFormatBottomSheet: AppLocalizations.of(context).titleFormat, + titleBack: AppLocalizations.of(context).format, ), ); } Widget _buildBodyTablet(BuildContext context) { return SingleChildScrollView( - physics: const ClampingScrollPhysics(), - 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), - Padding( - padding: const EdgeInsets.only(left: 60, right: 25), - child: Column(children: [ - _buildToolbarRichTextWidget(context), - _buildAttachmentsWidget(context), - buildInlineLoadingView(controller), - _buildComposerEditor(context), - ]) - ) - ]) + controller: controller.scrollController, + physics: const ClampingScrollPhysics(), + 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), + Padding( + padding: const EdgeInsets.only(left: 60, right: 25), + child: Column(children: [ + _buildAttachmentsWidget(context), + buildInlineLoadingView(controller), + _buildComposerEditor(context), + ]) + ) + ]) ); } @@ -494,128 +504,6 @@ class ComposerView extends GetWidget }); } - 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( - 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) { return Obx(() { final argsComposer = controller.composerArguments.value; @@ -627,10 +515,10 @@ class ComposerView extends GetWidget switch(argsComposer.emailActionType) { case EmailActionType.compose: case EmailActionType.composeFromEmailAddress: - return _buildHtmlEditor(HtmlExtension.editorStartTags, context); + return _buildHtmlEditor(context); case EmailActionType.edit: return controller.emailContentsViewState.value.fold( - (failure) => _buildHtmlEditor(HtmlExtension.editorStartTags, context), + (failure) => _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags), (success) { if (success is GetEmailContentLoading) { return Padding( @@ -642,9 +530,9 @@ class ComposerView extends GetWidget if (contentHtml.isEmpty == true) { contentHtml = HtmlExtension.editorStartTags; } - return _buildHtmlEditor(contentHtml, context); + return _buildHtmlEditor(context, initialContent: contentHtml); } else { - return _buildHtmlEditor(HtmlExtension.editorStartTags, context); + return _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags); } }); case EmailActionType.reply: @@ -656,14 +544,14 @@ class ComposerView extends GetWidget if (contentHtml.isEmpty == true) { contentHtml = HtmlExtension.editorStartTags; } - return _buildHtmlEditor(contentHtml, context); + return _buildHtmlEditor(context, initialContent: contentHtml); 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; return Padding( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20), @@ -671,17 +559,14 @@ class ComposerView extends GetWidget key: const Key('composer_editor'), minHeight: 550, addDefaultSelectionMenuItems: false, - initialContent: initialContent, + initialContent: initialContent ?? '', onCreated: (editorApi) { richTextMobileTabletController.htmlEditorApi = editorApi; - if(responsiveUtils.isMobile(context)){ controller.keyboardRichTextController.onCreateHTMLEditor( editorApi, onEnterKeyDown: controller.onEnterKeyDown, + context: context, ); - } else { - richTextMobileTabletController.listenHtmlEditorApi(); - } }, ), ); diff --git a/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart b/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart index 78ae6a706..7e321968a 100644 --- a/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart +++ b/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart @@ -1,138 +1,12 @@ 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: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/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/image_source.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 { HtmlEditorApi? htmlEditorApi; - final listTextStyleApply = RxList(); - 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 { log('RichTextMobileTabletController::insertImage(): $image | maxWithEditor: $maxWithEditor'); @@ -148,49 +22,4 @@ class RichTextMobileTabletController extends BaseRichTextController { final styleSelected = newStyle ?? HeaderStyleType.normal; 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(); - } } diff --git a/lib/features/identity_creator/presentation/identity_creator_view.dart b/lib/features/identity_creator/presentation/identity_creator_view.dart index 192ef7d2d..f8d642ef0 100644 --- a/lib/features/identity_creator/presentation/identity_creator_view.dart +++ b/lib/features/identity_creator/presentation/identity_creator_view.dart @@ -55,44 +55,66 @@ class IdentityCreatorView extends GetWidget { backgroundColor: Colors.black38, body: GestureDetector( onTap: () => controller.clearFocusEditor(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) - ) - ) + child: KeyboardRichText( + richTextController: controller.keyboardRichTextController, + keyBroadToolbar: RichTextKeyboardToolBar( + backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, + richTextController: controller.keyboardRichTextController, + titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles, + titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground, + titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground, + titleFormatBottomSheet: AppLocalizations.of(context).titleFormat, + titleBack: AppLocalizations.of(context).format, + ), + 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( backgroundColor: Colors.black38, body: GestureDetector( onTap: () => controller.clearFocusEditor(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.6, - height: _responsiveUtils.getSizeScreenHeight(context) * 0.9, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(16)), - child: _buildBodyDesktop(context) - ) - ) + child: KeyboardRichText( + richTextController: controller.keyboardRichTextController, + keyBroadToolbar: RichTextKeyboardToolBar( + backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, + richTextController: controller.keyboardRichTextController, + titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles, + titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground, + titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground, + titleFormatBottomSheet: AppLocalizations.of(context).titleFormat, + titleBack: AppLocalizations.of(context).format, + ), + 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( @@ -135,6 +157,7 @@ class IdentityCreatorView extends GetWidget { color: Colors.black)))), const SizedBox(height: 8), Expanded(child: SingleChildScrollView( + controller: controller.scrollController, physics: const ClampingScrollPhysics(), child: Padding( padding: const EdgeInsets.all(24.0), @@ -287,135 +310,136 @@ class IdentityCreatorView extends GetWidget { physics: const ClampingScrollPhysics(), child: Padding( padding: const EdgeInsets.all(24.0), - child: Column(children: [ - Obx(() => (IdentityInputFieldBuilder( - AppLocalizations.of(context).name, - controller.errorNameIdentity.value, - editingController: controller.inputNameIdentityController, - focusNode: controller.inputNameIdentityFocusNode, - isMandatory: true) - ..addOnChangeInputNameAction((value) => controller.updateNameIdentity(context, value))) - .build()), - const SizedBox(height: 24), - Obx(() { - if (controller.actionType == IdentityActionType.create) { - return (IdentityDropListFieldBuilder( - _imagePaths, - AppLocalizations.of(context).email.inCaps, - controller.emailOfIdentity.value, - controller.listEmailAddressDefault) - ..addOnSelectEmailAddressDropListAction((emailAddress) => - controller.updateEmailOfIdentity(emailAddress)) - ).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); + child: Column(children: [ + Obx(() => (IdentityInputFieldBuilder( + AppLocalizations.of(context).name, + controller.errorNameIdentity.value, + editingController: controller.inputNameIdentityController, + focusNode: controller.inputNameIdentityFocusNode, + isMandatory: true) + ..addOnChangeInputNameAction((value) => controller.updateNameIdentity(context, value))) + .build()), + const SizedBox(height: 24), + Obx(() { + if (controller.actionType == IdentityActionType.create) { + return (IdentityDropListFieldBuilder( + _imagePaths, + AppLocalizations.of(context).email.inCaps, + controller.emailOfIdentity.value, + controller.listEmailAddressDefault) + ..addOnSelectEmailAddressDropListAction((emailAddress) => + controller.updateEmailOfIdentity(emailAddress)) + ).build(); } else { - controller.updateBccOfIdentity(EmailAddress(null, pattern)); + return IdentityFieldNoEditableBuilder( + AppLocalizations.of(context).email.inCaps, + controller.emailOfIdentity.value + ).build(); } - }) - ..addOnSuggestionCallbackAction((pattern) => - controller.getSuggestionEmailAddress(pattern))) - .build() - ), - const SizedBox(height: 32), - Text(AppLocalizations.of(context).signature, - style: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, - color: AppColor.colorContentEmail, + }), + 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 { + controller.updateBccOfIdentity(EmailAddress(null, pattern)); + } + }) + ..addOnSuggestionCallbackAction((pattern) => + controller.getSuggestionEmailAddress(pattern))) + .build() ), - ), - const SizedBox(height: 8), - Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - Obx(() => _buildSignatureButton(context, SignatureType.plainText)), - 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), + const SizedBox(height: 32), + Text(AppLocalizations.of(context).signature, + style: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 14, + color: AppColor.colorContentEmail, + ), + ), + const SizedBox(height: 8), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Obx(() => _buildSignatureButton(context, SignatureType.plainText)), + 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, - ), - 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, - 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, + 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.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, - backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, keyBroadToolbar: RichTextKeyboardToolBar( + titleBack: AppLocalizations.of(context).titleFormat, + backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, isLandScapeMode: _responsiveUtils.isLandscapeMobile(context), richTextController: controller.keyboardRichTextController, titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles, @@ -516,6 +540,7 @@ class IdentityCreatorView extends GetWidget { htmlEditorController, onFocus: controller.onFocusHTMLEditor, onEnterKeyDown: controller.onEnterKeyDown, + context: context, ); controller.signatureHtmlEditorMobileController = htmlEditorController; }, diff --git a/lib/features/manage_account/presentation/vacation/vacation_view.dart b/lib/features/manage_account/presentation/vacation/vacation_view.dart index 81440f0d0..47feeb56c 100644 --- a/lib/features/manage_account/presentation/vacation/vacation_view.dart +++ b/lib/features/manage_account/presentation/vacation/vacation_view.dart @@ -37,12 +37,11 @@ class VacationView extends GetWidget with RichTextButtonMixi onTap: () => FocusScope.of(context).unfocus(), child: KeyboardRichText( richTextController: controller.richTextControllerForMobile, - backgroundKeyboardToolBarColor: Colors.grey, keyBroadToolbar: RichTextKeyboardToolBar( + titleBack: AppLocalizations.of(context).format, + backgroundKeyboardToolBarColor: AppColor.colorBackgroundKeyboard, titleFormatBottomSheet: AppLocalizations.of(context).format, richTextController: controller.richTextControllerForMobile, - insertImage: () {}, - insertAttachment: () {}, titleQuickStyleBottomSheet: AppLocalizations.of(context).quickStyles, titleBackgroundBottomSheet: AppLocalizations.of(context).background, titleForegroundBottomSheet: AppLocalizations.of(context).foreground, @@ -479,6 +478,7 @@ class VacationView extends GetWidget with RichTextButtonMixi htmlApi, onFocus: controller.onFocusHTMLEditor, onEnterKeyDown: controller.onEnterKeyDown, + context: context, ); } ); diff --git a/pubspec.lock b/pubspec.lock index fb7ba76ef..94120d932 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -219,7 +219,7 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.1.0" core: dependency: "direct main" description: @@ -361,7 +361,7 @@ packages: source: hosted version: "1.4.0" enough_html_editor: - dependency: "direct main" + dependency: transitive description: path: "." ref: email_supported @@ -757,7 +757,7 @@ packages: description: path: "." ref: master - resolved-ref: f5652f21f7b7005bcdcefb45fc406c876ce05618 + resolved-ref: ab07a8a03d63e20f6ea5e62bcc1ca8cdc1fd93ff url: "https://github.com/linagora/jmap-dart-client.git" source: git version: "0.0.1" @@ -1104,7 +1104,7 @@ packages: description: path: "." ref: master - resolved-ref: "3dc2e65ee12bf6df9c341ccc229a5dfc9d16405f" + resolved-ref: "9a863d1d6392441e7d7aad19d1c9a74da44af3a7" url: "https://github.com/linagora/rich-text-composer.git" source: git version: "0.0.1" @@ -1203,7 +1203,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.5" + version: "1.2.6" source_helper: dependency: transitive description: @@ -1273,7 +1273,7 @@ packages: name: syncfusion_flutter_core url: "https://pub.dartlang.org" source: hosted - version: "20.3.48" + version: "20.3.49" syncfusion_flutter_datepicker: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9bc4b864e..4a9bef799 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -131,12 +131,6 @@ dependencies: # hive 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: git: