diff --git a/lib/features/composer/presentation/base_composer_view.dart b/lib/features/composer/presentation/base_composer_view.dart index b405a7e77..ed4d9b940 100644 --- a/lib/features/composer/presentation/base_composer_view.dart +++ b/lib/features/composer/presentation/base_composer_view.dart @@ -25,9 +25,10 @@ import 'package:tmail_ui_user/features/base/widget/custom_scroll_behavior.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/prefix_recipient_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart'; -import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.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/main/localizations/app_localizations.dart'; @@ -148,104 +149,65 @@ abstract class BaseComposerView extends GetWidget } Widget buildEmailAddress(BuildContext context) { - return Column( + return Obx(() => Column( children: [ - Obx(() { - return (EmailAddressInputBuilder( - context, - imagePaths, - responsiveUtils, - PrefixEmailAddress.to, - controller.listToEmailAddress, - controller.listEmailAddressType, - expandMode: controller.toAddressExpandMode.value, - controller: controller.toEmailAddressController, - focusNode: controller.toAddressFocusNode, + RecipientComposerWidget( + prefix: PrefixEmailAddress.to, + listEmailAddress: controller.listToEmailAddress, + ccState: controller.ccRecipientState.value, + bccState: controller.bccRecipientState.value, + expandMode: controller.toAddressExpandMode.value, + controller: controller.toEmailAddressController, + focusNode: controller.toAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyToEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.getNextFocusOfToEmailAddress(), + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onAddEmailAddressTypeAction: controller.addEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.ccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.cc, + listEmailAddress: controller.listCcEmailAddress, + expandMode: controller.ccAddressExpandMode.value, + controller: controller.ccEmailAddressController, + focusNode: controller.ccAddressFocusNode, autoDisposeFocusNode: false, - keyTagEditor: controller.keyToEmailTagEditor, + keyTagEditor: controller.keyCcEmailTagEditor, isInitial: controller.isInitialRecipient.value, - nextFocusNode: controller.getNextFocusOfToEmailAddress() - ) - ..addOnFocusEmailAddressChangeAction(controller.onEmailAddressFocusChange) - ..addOnShowFullListEmailAddressAction(controller.showFullEmailAddress) - ..addOnAddEmailAddressTypeAction(controller.addEmailAddressType) - ..addOnUpdateListEmailAddressAction(controller.updateListEmailAddress) - ..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion) - ..addOnFocusNextAddressAction(controller.handleFocusNextAddressAction) - ).build(); - }), - Obx(() { - if (controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true) { - return const Divider(color: AppColor.colorDividerComposer, height: 1); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true) { - return (EmailAddressInputBuilder( - context, - imagePaths, - responsiveUtils, - PrefixEmailAddress.cc, - controller.listCcEmailAddress, - controller.listEmailAddressType, - focusNode: controller.ccAddressFocusNode, - expandMode: controller.ccAddressExpandMode.value, - controller: controller.ccEmailAddressController, - keyTagEditor: controller.keyCcEmailTagEditor, - autoDisposeFocusNode: false, - isInitial: controller.isInitialRecipient.value, - nextFocusNode: controller.getNextFocusOfCcEmailAddress() - ) - ..addOnFocusEmailAddressChangeAction(controller.onEmailAddressFocusChange) - ..addOnShowFullListEmailAddressAction(controller.showFullEmailAddress) - ..addOnDeleteEmailAddressTypeAction(controller.deleteEmailAddressType) - ..addOnUpdateListEmailAddressAction(controller.updateListEmailAddress) - ..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion) - ..addOnFocusNextAddressAction(controller.handleFocusNextAddressAction) - ).build(); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true) { - return const Divider(color: AppColor.colorDividerComposer, height: 1); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true) { - return (EmailAddressInputBuilder( - context, - imagePaths, - responsiveUtils, - PrefixEmailAddress.bcc, - controller.listBccEmailAddress, - controller.listEmailAddressType, - focusNode: controller.bccAddressFocusNode, - expandMode: controller.bccAddressExpandMode.value, - controller: controller.bccEmailAddressController, - autoDisposeFocusNode: false, - keyTagEditor: controller.keyBccEmailTagEditor, - isInitial: controller.isInitialRecipient.value, - nextFocusNode: controller.subjectEmailInputFocusNode - ) - ..addOnFocusEmailAddressChangeAction(controller.onEmailAddressFocusChange) - ..addOnShowFullListEmailAddressAction(controller.showFullEmailAddress) - ..addOnDeleteEmailAddressTypeAction(controller.deleteEmailAddressType) - ..addOnUpdateListEmailAddressAction(controller.updateListEmailAddress) - ..addOnSuggestionEmailAddress(controller.getAutoCompleteSuggestion) - ..addOnFocusNextAddressAction(controller.handleFocusNextAddressAction) - ).build(); - } else { - return const SizedBox.shrink(); - } - }), + nextFocusNode: controller.getNextFocusOfCcEmailAddress(), + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.bccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.bcc, + listEmailAddress: controller.listBccEmailAddress, + expandMode: controller.bccAddressExpandMode.value, + controller: controller.bccEmailAddressController, + focusNode: controller.bccAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyBccEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.subjectEmailInputFocusNode, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), ], - ); + )); } Widget buildSubjectEmail(BuildContext context) { @@ -279,7 +241,7 @@ abstract class BaseComposerView extends GetWidget ); } - Widget buildDivider() => const Divider(color: AppColor.colorDividerComposer, height: 1); + Widget buildDivider() => const Divider(color: AppColor.colorLineComposer, height: 1); Widget buildAttachmentsWidget(BuildContext context) { return Obx(() { diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 7699285d7..5bd9a678a 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -50,6 +50,7 @@ import 'package:tmail_ui_user/features/composer/presentation/controller/rich_tex import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.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/prefix_recipient_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/save_to_draft_view_event.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart'; @@ -95,7 +96,6 @@ class ComposerController extends BaseController { final composerArguments = Rxn(); final isEnableEmailSendButton = false.obs; final isInitialRecipient = false.obs; - final listEmailAddressType = [].obs; final subjectEmail = Rxn(); final screenDisplayMode = ScreenDisplayMode.normal.obs; final toAddressExpandMode = ExpandMode.EXPAND.obs; @@ -105,6 +105,8 @@ class ComposerController extends BaseController { final listIdentities = [].obs; final emailContentsViewState = Rxn>(); final hasRequestReadReceipt = false.obs; + final ccRecipientState = PrefixRecipientState.disabled.obs; + final bccRecipientState = PrefixRecipientState.disabled.obs; final LocalFilePickerInteractor _localFilePickerInteractor; final DeviceInfoPlugin _deviceInfoPlugin; @@ -594,12 +596,12 @@ class ComposerController extends BaseController { } if (listCcEmailAddress.isNotEmpty) { - listEmailAddressType.add(PrefixEmailAddress.cc); + ccRecipientState.value = PrefixRecipientState.enabled; ccAddressExpandMode.value = ExpandMode.COLLAPSE; } if (listBccEmailAddress.isNotEmpty) { - listEmailAddressType.add(PrefixEmailAddress.bcc); + bccRecipientState.value = PrefixRecipientState.enabled; bccAddressExpandMode.value = ExpandMode.COLLAPSE; } @@ -1375,18 +1377,28 @@ class ComposerController extends BaseController { } void addEmailAddressType(PrefixEmailAddress prefixEmailAddress) { - listEmailAddressType.add(prefixEmailAddress); + switch(prefixEmailAddress) { + case PrefixEmailAddress.cc: + ccRecipientState.value = PrefixRecipientState.enabled; + break; + case PrefixEmailAddress.bcc: + bccRecipientState.value = PrefixRecipientState.enabled; + break; + default: + break; + } } void deleteEmailAddressType(PrefixEmailAddress prefixEmailAddress) { - listEmailAddressType.remove(prefixEmailAddress); updateListEmailAddress(prefixEmailAddress, []); switch(prefixEmailAddress) { case PrefixEmailAddress.cc: + ccRecipientState.value = PrefixRecipientState.disabled; ccAddressFocusNode = FocusNode(); ccEmailAddressController.clear(); break; case PrefixEmailAddress.bcc: + bccRecipientState.value = PrefixRecipientState.disabled; bccAddressFocusNode = FocusNode(); bccEmailAddressController.clear(); break; @@ -1570,8 +1582,8 @@ class ComposerController extends BaseController { } void _applyBccEmailAddressFromIdentity(Set listEmailAddress) { - if (!listEmailAddressType.contains(PrefixEmailAddress.bcc)) { - listEmailAddressType.add(PrefixEmailAddress.bcc); + if (bccRecipientState.value == PrefixRecipientState.disabled) { + bccRecipientState.value = PrefixRecipientState.enabled; } listBccEmailAddress = listEmailAddress.toList(); toAddressExpandMode.value = ExpandMode.COLLAPSE; @@ -1585,7 +1597,7 @@ class ComposerController extends BaseController { .where((address) => !listEmailAddress.contains(address)) .toList(); if (listBccEmailAddress.isEmpty) { - listEmailAddressType.remove(PrefixEmailAddress.bcc); + bccRecipientState.value = PrefixRecipientState.disabled; } toAddressExpandMode.value = ExpandMode.COLLAPSE; ccAddressExpandMode.value = ExpandMode.COLLAPSE; @@ -1823,9 +1835,9 @@ class ComposerController extends BaseController { } FocusNode? getNextFocusOfToEmailAddress() { - if (listEmailAddressType.contains(PrefixEmailAddress.cc) == true) { + if (ccRecipientState.value == PrefixRecipientState.enabled) { return ccAddressFocusNode; - } else if (listEmailAddressType.contains(PrefixEmailAddress.bcc) == true) { + } else if (bccRecipientState.value == PrefixRecipientState.enabled) { return bccAddressFocusNode; } else { return subjectEmailInputFocusNode; @@ -1833,7 +1845,7 @@ class ComposerController extends BaseController { } FocusNode? getNextFocusOfCcEmailAddress() { - if (listEmailAddressType.contains(PrefixEmailAddress.bcc) == true) { + if (bccRecipientState.value == PrefixRecipientState.enabled) { return bccAddressFocusNode; } else { return subjectEmailInputFocusNode; @@ -1847,4 +1859,8 @@ class ComposerController extends BaseController { bool get isNetworkConnectionAvailable => networkConnectionController.isNetworkConnectionAvailable(); UserProfile? get userProfile => mailboxDashBoardController.userProfile.value; + + void openContextMenuOption(BuildContext context) { + + } } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 0744bdc80..40701eeda 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -1,25 +1,24 @@ -import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:core/presentation/extensions/html_extension.dart'; import 'package:core/presentation/views/button/icon_button_web.dart'; -import 'package:core/presentation/views/image/avatar_builder.dart'; import 'package:core/presentation/views/responsive/responsive_widget.dart'; -import 'package:core/utils/direction_utils.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; -import 'package:model/email/email_action_type.dart'; +import 'package:model/email/prefix_email_address.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; -import 'package:tmail_ui_user/features/base/widget/cupertino_loading_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/base_composer_view.dart'; -import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; -import 'package:tmail_ui_user/features/composer/presentation/widgets/email_editor_widget.dart'; +import 'package:tmail_ui_user/features/composer/presentation/view/desktop_container_view.dart'; +import 'package:tmail_ui_user/features/composer/presentation/view/mobile_container_view.dart'; +import 'package:tmail_ui_user/features/composer/presentation/view/tablet_container_view.dart'; +import 'package:tmail_ui_user/features/composer/presentation/view/web_editor_view.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/app_bar_composer_widget.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/bottom_bar_composer_widget.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile_app_bar_composer_widget.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/subject_composer_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/toolbar_rich_text_builder.dart'; -import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_content_state.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -import 'package:tmail_ui_user/main/utils/app_utils.dart'; class ComposerView extends BaseComposerView { @@ -29,185 +28,475 @@ class ComposerView extends BaseComposerView { Widget build(BuildContext context) { return ResponsiveWidget( responsiveUtils: responsiveUtils, - mobile: Scaffold( - backgroundColor: Colors.white, - body: Container( - color: Colors.white, - child: LayoutBuilder(builder: (context, constraints) { - return PointerInterceptor(child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - buildAppBar(context), - buildDivider(), - buildFromEmailAddress(context), - buildDivider(), - _buildEmailAddressWeb(context, constraints), - buildDivider(), - buildSubjectEmail(context), - buildDivider(), - Padding( - padding: const EdgeInsetsDirectional.symmetric(horizontal: 16), - child: _buildListButton(context, constraints) - ), - buildDivider(), - buildAttachmentsWidget(context), - ToolbarRichTextWebBuilder( - richTextWebController: controller.richTextWebController, - padding: ComposerStyle.getRichTextButtonPadding(context, responsiveUtils), - ), - buildInlineLoadingView(controller), - Expanded(child: _buildEditorForm(context)) - ] - )); - }) - ) - ), - desktop: Obx(() { - return Stack(children: [ - if (controller.screenDisplayMode.value == ScreenDisplayMode.normal) - PositionedDirectional(end: 5, bottom: 5, child: Card( - elevation: 20, - color: Colors.transparent, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(ComposerStyle.radius))), - child: Container( - decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(ComposerStyle.radius))), - width: responsiveUtils.getSizeScreenWidth(context) * 0.5, - height: responsiveUtils.getSizeScreenHeight(context) * 0.75, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(ComposerStyle.radius)), - child: LayoutBuilder(builder: (context, constraints) => - PointerInterceptor(child: _buildBodyForDesktop(context, constraints)) - ) - ) - ) - )), - if (controller.screenDisplayMode.value == ScreenDisplayMode.minimize) - PositionedDirectional(end: 5, bottom: 5, child: Card( - elevation: 20, - 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: 500, - height: 50, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(16)), - child: PointerInterceptor(child: Row(children: [ - Padding( - padding: const EdgeInsetsDirectional.only(start: 10), - child: buildIconWeb( - icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).saveAndClose, - onTap: () => controller.saveToDraftAndClose(context) - )), - buildIconWeb( - icon: SvgPicture.asset(imagePaths.icFullScreenComposer, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).fullscreen, - onTap: () => controller.displayScreenTypeComposerAction(ScreenDisplayMode.fullScreen)), - buildIconWeb( - icon: SvgPicture.asset(imagePaths.icChevronUp, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).show, - onTap: () => controller.displayScreenTypeComposerAction(ScreenDisplayMode.normal)), - Expanded(child: Padding( - padding: const EdgeInsetsDirectional.only(start: 16, end: 80), - child: buildTitleComposer(context), - )), - ])) - ) - ) + mobile: MobileContainerView( + childBuilder: (context, constraints) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Obx(() => MobileAppBarComposerWidget( + isCodeViewEnabled: controller.richTextWebController.codeViewEnabled, + isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled, + openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions, + isSendButtonEnabled: controller.isEnableEmailSendButton.value, + onCloseViewAction: () => controller.saveToDraftAndClose(context), + attachFileAction: () => controller.openFilePickerByType(context, FileType.any), + insertImageAction: () => controller.insertImage(context, constraints.maxWidth), + sendMessageAction: () => controller.sendEmailAction(context), + openContextMenuAction: () => {}, )), - if (controller.screenDisplayMode.value == ScreenDisplayMode.fullScreen) - Scaffold( - backgroundColor: Colors.black38, - body: Align(alignment: Alignment.center, child: Card( - color: Colors.transparent, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(ComposerStyle.radius))), - child: Container( - decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(ComposerStyle.radius))), - width: responsiveUtils.getSizeScreenWidth(context) * 0.85, - height: responsiveUtils.getSizeScreenHeight(context) * 0.9, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(ComposerStyle.radius)), - child: LayoutBuilder(builder: (context, constraints) => - PointerInterceptor(child: _buildBodyForDesktop(context, constraints))) - ) - ) - ) - ) - ) - ]); - }), - tablet: Scaffold( - backgroundColor: Colors.black38, - body: Center( - child: Card( - elevation: 20, - margin: ComposerStyle.getMarginForTabletWeb(context, responsiveUtils), - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(ComposerStyle.radius))), - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(ComposerStyle.radius))), - width: ComposerStyle.getWidthForTabletWeb(context, responsiveUtils), - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(ComposerStyle.radius)), - child: LayoutBuilder(builder: (context, constraints) => PointerInterceptor( - child: _buildBodyForDesktop( + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget( context, - constraints + constraints, + responsiveUtils ) - )) - ) - ) - ) - ) - ) - ); - } - - Widget _buildAppBarDesktop(BuildContext context) { - return Container( - height: 52, - padding: const EdgeInsetsDirectional.symmetric(horizontal: 32), - child: Row( - children: [ - buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).saveAndClose, - onTap: () => controller.saveToDraftAndClose(context) - ), - if (responsiveUtils.isDesktop(context)) - ...[ - Obx(() => buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset( - controller.screenDisplayMode.value == ScreenDisplayMode.fullScreen - ? imagePaths.icFullScreenExit - : imagePaths.icFullScreenComposer, - fit: BoxFit.fill ), - tooltip: AppLocalizations.of(context).fullscreen, - onTap: () => controller.displayScreenTypeComposerAction( - controller.screenDisplayMode.value == ScreenDisplayMode.fullScreen - ? ScreenDisplayMode.normal - : ScreenDisplayMode.fullScreen + child: SingleChildScrollView( + controller: controller.scrollControllerEmailAddress, + child: Obx(() => Column( + children: [ + RecipientComposerWidget( + prefix: PrefixEmailAddress.to, + listEmailAddress: controller.listToEmailAddress, + ccState: controller.ccRecipientState.value, + bccState: controller.bccRecipientState.value, + expandMode: controller.toAddressExpandMode.value, + controller: controller.toEmailAddressController, + focusNode: controller.toAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyToEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + padding: ComposerStyle.mobileRecipientPadding, + margin: ComposerStyle.mobileRecipientMargin, + nextFocusNode: controller.getNextFocusOfToEmailAddress(), + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onAddEmailAddressTypeAction: controller.addEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.ccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.cc, + listEmailAddress: controller.listCcEmailAddress, + expandMode: controller.ccAddressExpandMode.value, + controller: controller.ccEmailAddressController, + focusNode: controller.ccAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyCcEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.getNextFocusOfCcEmailAddress(), + padding: ComposerStyle.mobileRecipientPadding, + margin: ComposerStyle.mobileRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.bccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.bcc, + listEmailAddress: controller.listBccEmailAddress, + expandMode: controller.bccAddressExpandMode.value, + controller: controller.bccEmailAddressController, + focusNode: controller.bccAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyBccEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.subjectEmailInputFocusNode, + padding: ComposerStyle.mobileRecipientPadding, + margin: ComposerStyle.mobileRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + ], + )), ) - )), - buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset(imagePaths.icMinimize, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).minimize, - onTap: () => controller.displayScreenTypeComposerAction(ScreenDisplayMode.minimize) ), - ], - Expanded(child: buildTitleComposer(context)), - const SizedBox(width: 120), - ] + SubjectComposerWidget( + focusNode: controller.subjectEmailInputFocusNode, + textController: controller.subjectEmailInputController, + onTextChange: controller.setSubjectEmail, + padding: ComposerStyle.mobileSubjectPadding, + margin: ComposerStyle.mobileSubjectMargin, + ), + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: ComposerStyle.borderColor, + width: 1 + ) + ), + color: ComposerStyle.backgroundEditorColor + ), + child: Stack( + children: [ + Obx(() => Padding( + padding: ComposerStyle.mobileEditorPadding, + child: WebEditorView( + editorController: controller.richTextWebController.editorController, + arguments: controller.composerArguments.value, + contentViewState: controller.emailContentsViewState.value, + currentWebContent: controller.textEditorWeb, + onInitial: controller.handleInitHtmlEditorWeb, + onChangeContent: controller.onChangeTextEditorWeb, + onFocus: controller.handleOnFocusHtmlEditorWeb, + onUnFocus: controller.handleOnUnFocusHtmlEditorWeb, + onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, + onEditorSettings: controller.richTextWebController.onEditorSettingsChange, + ), + )), + Obx(() { + if (controller.richTextWebController.isFormattingOptionsEnabled) { + return Align( + alignment: AlignmentDirectional.bottomCenter, + child: ToolbarRichTextWebBuilder( + richTextWebController: controller.richTextWebController, + padding: ComposerStyle.richToolbarPadding, + decoration: const BoxDecoration( + color: ComposerStyle.richToolbarColor, + boxShadow: ComposerStyle.richToolbarShadow + ), + ), + ); + } else { + return const SizedBox.shrink(); + } + }) + ], + ), + ) + ), + ] + ); + } ), + desktop: Obx(() => DesktopContainerView( + childBuilder: (context, constraints) { + return Column(children: [ + Obx(() => AppBarComposerWidget( + emailSubject: controller.subjectEmail.value ?? '', + displayMode: controller.screenDisplayMode.value, + onCloseViewAction: () => controller.saveToDraftAndClose(context), + onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, + constraints: constraints, + )), + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget( + context, + constraints, + responsiveUtils + ) + ), + child: SingleChildScrollView( + controller: controller.scrollControllerEmailAddress, + child: Obx(() => Column( + children: [ + RecipientComposerWidget( + prefix: PrefixEmailAddress.to, + listEmailAddress: controller.listToEmailAddress, + ccState: controller.ccRecipientState.value, + bccState: controller.bccRecipientState.value, + expandMode: controller.toAddressExpandMode.value, + controller: controller.toEmailAddressController, + focusNode: controller.toAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyToEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + padding: ComposerStyle.desktopRecipientPadding, + margin: ComposerStyle.desktopRecipientMargin, + nextFocusNode: controller.getNextFocusOfToEmailAddress(), + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onAddEmailAddressTypeAction: controller.addEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.ccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.cc, + listEmailAddress: controller.listCcEmailAddress, + expandMode: controller.ccAddressExpandMode.value, + controller: controller.ccEmailAddressController, + focusNode: controller.ccAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyCcEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.getNextFocusOfCcEmailAddress(), + padding: ComposerStyle.desktopRecipientPadding, + margin: ComposerStyle.desktopRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.bccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.bcc, + listEmailAddress: controller.listBccEmailAddress, + expandMode: controller.bccAddressExpandMode.value, + controller: controller.bccEmailAddressController, + focusNode: controller.bccAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyBccEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.subjectEmailInputFocusNode, + padding: ComposerStyle.desktopRecipientPadding, + margin: ComposerStyle.desktopRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + ], + )), + ) + ), + SubjectComposerWidget( + focusNode: controller.subjectEmailInputFocusNode, + textController: controller.subjectEmailInputController, + onTextChange: controller.setSubjectEmail, + padding: ComposerStyle.desktopSubjectPadding, + margin: ComposerStyle.desktopSubjectMargin, + ), + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: ComposerStyle.borderColor, + width: 1 + ) + ), + color: ComposerStyle.backgroundEditorColor + ), + child: Stack( + children: [ + Obx(() => Padding( + padding: ComposerStyle.desktopEditorPadding, + child: WebEditorView( + editorController: controller.richTextWebController.editorController, + arguments: controller.composerArguments.value, + contentViewState: controller.emailContentsViewState.value, + currentWebContent: controller.textEditorWeb, + onInitial: controller.handleInitHtmlEditorWeb, + onChangeContent: controller.onChangeTextEditorWeb, + onFocus: controller.handleOnFocusHtmlEditorWeb, + onUnFocus: controller.handleOnUnFocusHtmlEditorWeb, + onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, + onEditorSettings: controller.richTextWebController.onEditorSettingsChange, + ), + )), + Obx(() { + if (controller.richTextWebController.isFormattingOptionsEnabled) { + return Align( + alignment: AlignmentDirectional.bottomCenter, + child: ToolbarRichTextWebBuilder( + richTextWebController: controller.richTextWebController, + padding: ComposerStyle.richToolbarPadding, + decoration: const BoxDecoration( + color: ComposerStyle.richToolbarColor, + boxShadow: ComposerStyle.richToolbarShadow + ), + ), + ); + } else { + return const SizedBox.shrink(); + } + }) + ], + ), + ) + ), + Obx(() => BottomBarComposerWidget( + isCodeViewEnabled: controller.richTextWebController.codeViewEnabled, + isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled, + openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions, + attachFileAction: () => controller.openFilePickerByType(context, FileType.any), + insertImageAction: () => controller.insertImage(context, constraints.maxWidth), + showCodeViewAction: controller.richTextWebController.toggleCodeView, + deleteComposerAction: () => controller.closeComposer(context), + saveToDraftAction: () => controller.saveToDraftAction(context), + sendMessageAction: () => controller.sendEmailAction(context), + )), + ]); + }, + displayMode: controller.screenDisplayMode.value, + emailSubject: controller.subjectEmail.value ?? '', + onCloseViewAction: () => controller.saveToDraftAndClose(context), + onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, + )), + tablet: TabletContainerView( + childBuilder: (context, constraints) { + return Column(children: [ + Obx(() => AppBarComposerWidget( + emailSubject: controller.subjectEmail.value ?? '', + onCloseViewAction: () => controller.saveToDraftAndClose(context), + constraints: constraints, + )), + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget( + context, + constraints, + responsiveUtils + ) + ), + child: SingleChildScrollView( + controller: controller.scrollControllerEmailAddress, + child: Obx(() => Column( + children: [ + RecipientComposerWidget( + prefix: PrefixEmailAddress.to, + listEmailAddress: controller.listToEmailAddress, + ccState: controller.ccRecipientState.value, + bccState: controller.bccRecipientState.value, + expandMode: controller.toAddressExpandMode.value, + controller: controller.toEmailAddressController, + focusNode: controller.toAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyToEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + padding: ComposerStyle.tabletRecipientPadding, + margin: ComposerStyle.tabletRecipientMargin, + nextFocusNode: controller.getNextFocusOfToEmailAddress(), + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onAddEmailAddressTypeAction: controller.addEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.ccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.cc, + listEmailAddress: controller.listCcEmailAddress, + expandMode: controller.ccAddressExpandMode.value, + controller: controller.ccEmailAddressController, + focusNode: controller.ccAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyCcEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.getNextFocusOfCcEmailAddress(), + padding: ComposerStyle.tabletRecipientPadding, + margin: ComposerStyle.tabletRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + if (controller.bccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.bcc, + listEmailAddress: controller.listBccEmailAddress, + expandMode: controller.bccAddressExpandMode.value, + controller: controller.bccEmailAddressController, + focusNode: controller.bccAddressFocusNode, + autoDisposeFocusNode: false, + keyTagEditor: controller.keyBccEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.subjectEmailInputFocusNode, + padding: ComposerStyle.tabletRecipientPadding, + margin: ComposerStyle.tabletRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + ), + ], + )), + ) + ), + SubjectComposerWidget( + focusNode: controller.subjectEmailInputFocusNode, + textController: controller.subjectEmailInputController, + onTextChange: controller.setSubjectEmail, + padding: ComposerStyle.tabletSubjectPadding, + margin: ComposerStyle.tabletSubjectMargin, + ), + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: ComposerStyle.borderColor, + width: 1 + ) + ), + color: ComposerStyle.backgroundEditorColor + ), + child: Stack( + children: [ + Obx(() => Padding( + padding: ComposerStyle.tabletEditorPadding, + child: WebEditorView( + editorController: controller.richTextWebController.editorController, + arguments: controller.composerArguments.value, + contentViewState: controller.emailContentsViewState.value, + currentWebContent: controller.textEditorWeb, + onInitial: controller.handleInitHtmlEditorWeb, + onChangeContent: controller.onChangeTextEditorWeb, + onFocus: controller.handleOnFocusHtmlEditorWeb, + onUnFocus: controller.handleOnUnFocusHtmlEditorWeb, + onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, + onEditorSettings: controller.richTextWebController.onEditorSettingsChange, + ), + )), + Obx(() { + if (controller.richTextWebController.isFormattingOptionsEnabled) { + return Align( + alignment: AlignmentDirectional.bottomCenter, + child: ToolbarRichTextWebBuilder( + richTextWebController: controller.richTextWebController, + padding: ComposerStyle.richToolbarPadding, + decoration: const BoxDecoration( + color: ComposerStyle.richToolbarColor, + boxShadow: ComposerStyle.richToolbarShadow + ), + ), + ); + } else { + return const SizedBox.shrink(); + } + }) + ], + ), + ) + ), + Obx(() => BottomBarComposerWidget( + isCodeViewEnabled: controller.richTextWebController.codeViewEnabled, + isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled, + openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions, + attachFileAction: () => controller.openFilePickerByType(context, FileType.any), + insertImageAction: () => controller.insertImage(context, constraints.maxWidth), + showCodeViewAction: controller.richTextWebController.toggleCodeView, + deleteComposerAction: () => controller.closeComposer(context), + saveToDraftAction: () => controller.saveToDraftAction(context), + sendMessageAction: () => controller.sendEmailAction(context), + )), + ]); + }, + ) ); } @@ -245,251 +534,4 @@ class ComposerView extends BaseComposerView { ) ]; } - - Widget _buildBottomBarDesktop(BuildContext context, BoxConstraints constraints) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 16), - color: Colors.white, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( - constraints: constraints.widthConstraints(), - child: buildBottomBar(context), - ), - ), - ); - } - - Widget _buildBodyForDesktop(BuildContext context, BoxConstraints constraints) { - return Column(children: [ - _buildAppBarDesktop(context), - buildDivider(), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(width: 16), - 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() - ), - const SizedBox(width: 16), - Expanded(child: Column(children: [ - buildFromEmailAddress(context), - buildDivider(), - _buildEmailAddressWeb(context, constraints), - buildDivider(), - buildSubjectEmail(context), - buildDivider(), - _buildListButton(context, constraints), - ])) - ] - ), - buildDivider(), - buildAttachmentsWidget(context), - ToolbarRichTextWebBuilder( - richTextWebController: controller.richTextWebController, - padding: ComposerStyle.getRichTextButtonPadding(context, responsiveUtils), - ), - buildInlineLoadingView(controller), - Expanded(child: _buildEditorForm(context)), - buildDivider(), - _buildBottomBarDesktop(context, constraints), - ]); - } - - Widget _buildEmailAddressWeb(BuildContext context, BoxConstraints constraints) { - return ConstrainedBox( - constraints: BoxConstraints(maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget(context, constraints, responsiveUtils)), - child: SingleChildScrollView( - controller: controller.scrollControllerEmailAddress, - child: buildEmailAddress(context), - ) - ); - } - - Widget _buildListButton(BuildContext context, BoxConstraints constraints) { - return Transform( - transform: Matrix4.translationValues( - DirectionUtils.isDirectionRTLByLanguage(context) ? 0.0 : -5.0, - 0.0, - 0.0 - ), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 5), - child: Row(children: [ - buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, - width: 24, - height: 24, - colorFilter: AppColor.colorTextButton.asFilter(), - fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).attach_file, - onTap: () => controller.openFilePickerByType(context, FileType.any) - ), - const SizedBox(width: 4), - Obx(() { - final opacity = controller.richTextWebController.codeViewEnabled ? 0.5 : 1.0; - return AbsorbPointer( - absorbing: controller.richTextWebController.codeViewEnabled, - child: buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset( - imagePaths.icInsertImage, - colorFilter: AppColor.colorTextButton.withOpacity(opacity).asFilter(), - fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).insertImage, - onTap: () => controller.insertImage(context, constraints.maxWidth) - ), - ); - }), - const SizedBox(width: 4), - Obx(() { - return buildIconWeb( - minSize: 40, - colorSelected: controller.richTextWebController.codeViewEnabled - ? AppColor.colorSelectedRichTextButton - : Colors.transparent, - iconPadding: EdgeInsets.zero, - icon: SvgPicture.asset( - imagePaths.icStyleCodeView, - colorFilter: AppColor.colorTextButton.asFilter(), - fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).codeView, - onTap: controller.richTextWebController.toggleCodeView); - }), - ]) - ) - ); - } - - Widget _buildEditorForm(BuildContext context) { - return Obx(() { - final argsComposer = controller.composerArguments.value; - - if (argsComposer == null) { - return const SizedBox.shrink(); - } - - final currentTextEditor = controller.textEditorWeb; - - switch(argsComposer.emailActionType) { - case EmailActionType.compose: - case EmailActionType.composeFromEmailAddress: - case EmailActionType.composeFromMailtoURL: - case EmailActionType.composeFromFileShared: - return _buildHtmlEditor( - context, - currentTextEditor ?? HtmlExtension.editorStartTags - ); - case EmailActionType.editDraft: - case EmailActionType.editSendingEmail: - case EmailActionType.composeFromContentShared: - case EmailActionType.reopenComposerBrowser: - final emailContentsViewState = controller.emailContentsViewState.value; - if (emailContentsViewState == null) { - return const SizedBox.shrink(); - } - return emailContentsViewState.fold( - (failure) => _buildHtmlEditor( - context, - currentTextEditor ?? HtmlExtension.editorStartTags - ), - (success) { - if (success is GetEmailContentLoading) { - return const CupertinoLoadingWidget(padding: EdgeInsets.all(16.0)); - } else if (success is GetEmailContentSuccess) { - var contentHtml = success.htmlEmailContent; - if (contentHtml.isEmpty == true) { - contentHtml = HtmlExtension.editorStartTags; - } - return _buildHtmlEditor( - context, - currentTextEditor ?? contentHtml - ); - } else { - return _buildHtmlEditor( - context, - currentTextEditor ?? HtmlExtension.editorStartTags - ); - } - }); - case EmailActionType.reply: - case EmailActionType.replyAll: - case EmailActionType.forward: - final emailContentsViewState = controller.emailContentsViewState.value; - if (emailContentsViewState == null) { - return const SizedBox.shrink(); - } - return emailContentsViewState.fold( - (failure) { - final emailContentQuoted = controller.getEmailContentQuotedAsHtml( - context: context, - emailContent: '', - emailActionType: argsComposer.emailActionType, - presentationEmail: argsComposer.presentationEmail! - ); - return _buildHtmlEditor( - context, - currentTextEditor ?? emailContentQuoted - ); - }, - (success) { - if (success is TransformHtmlEmailContentLoading) { - return const CupertinoLoadingWidget(padding: EdgeInsets.all(16.0)); - } else if (success is TransformHtmlEmailContentSuccess) { - final emailContentQuoted = controller.getEmailContentQuotedAsHtml( - context: context, - emailContent: success.htmlContent, - emailActionType: argsComposer.emailActionType, - presentationEmail: argsComposer.presentationEmail! - ); - return _buildHtmlEditor( - context, - currentTextEditor ?? emailContentQuoted - ); - } else { - final emailContentQuoted = controller.getEmailContentQuotedAsHtml( - context: context, - emailContent: '', - emailActionType: argsComposer.emailActionType, - presentationEmail: argsComposer.presentationEmail! - ); - return _buildHtmlEditor( - context, - currentTextEditor ?? emailContentQuoted - ); - } - } - ); - default: - return _buildHtmlEditor( - context, - currentTextEditor ?? HtmlExtension.editorStartTags - ); - } - }); - } - - Widget _buildHtmlEditor(BuildContext context, String initContent) { - return Padding( - padding: ComposerStyle.getEditorPadding(context, responsiveUtils), - child: EmailEditorWidget( - controller: controller, - content: initContent, - direction: AppUtils.getCurrentDirection(context), - ), - ); - } } \ No newline at end of file diff --git a/lib/features/composer/presentation/controller/rich_text_web_controller.dart b/lib/features/composer/presentation/controller/rich_text_web_controller.dart index b35b34c4b..1ed5ec0b0 100644 --- a/lib/features/composer/presentation/controller/rich_text_web_controller.dart +++ b/lib/features/composer/presentation/controller/rich_text_web_controller.dart @@ -10,6 +10,7 @@ import 'package:get/get.dart'; import 'package:html_editor_enhanced/html_editor.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/code_view_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/dropdown_menu_font_status.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/formatting_options_state.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'; @@ -35,6 +36,7 @@ class RichTextWebController extends BaseRichTextController { final focusMenuParagraph = RxBool(false); final menuFontStatus = DropdownMenuFontStatus.closed.obs; final menuHeaderStyleStatus = DropdownMenuFontStatus.closed.obs; + final formattingOptionsState = FormattingOptionsState.disabled.obs; final menuParagraphController = CustomPopupMenuController(); final menuOrderListController = CustomPopupMenuController(); @@ -271,6 +273,16 @@ class RichTextWebController extends BaseRichTextController { } } + void toggleFormattingOptions() { + final newState = isFormattingOptionsEnabled + ? FormattingOptionsState.disabled + : FormattingOptionsState.enabled; + + formattingOptionsState.value = newState; + } + + bool get isFormattingOptionsEnabled => formattingOptionsState.value == FormattingOptionsState.enabled; + @override void onClose() { menuParagraphController.dispose(); diff --git a/lib/features/composer/presentation/model/formatting_options_state.dart b/lib/features/composer/presentation/model/formatting_options_state.dart new file mode 100644 index 000000000..985d5da7c --- /dev/null +++ b/lib/features/composer/presentation/model/formatting_options_state.dart @@ -0,0 +1,5 @@ + +enum FormattingOptionsState { + enabled, + disabled +} \ No newline at end of file diff --git a/lib/features/composer/presentation/model/prefix_recipient_state.dart b/lib/features/composer/presentation/model/prefix_recipient_state.dart new file mode 100644 index 000000000..4c11ebac7 --- /dev/null +++ b/lib/features/composer/presentation/model/prefix_recipient_state.dart @@ -0,0 +1,5 @@ + +enum PrefixRecipientState { + enabled, + disabled +} \ No newline at end of file diff --git a/lib/features/composer/presentation/styles/composer_style.dart b/lib/features/composer/presentation/styles/composer_style.dart index 61948eda5..ee6b16931 100644 --- a/lib/features/composer/presentation/styles/composer_style.dart +++ b/lib/features/composer/presentation/styles/composer_style.dart @@ -1,11 +1,43 @@ +import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/utils/platform_info.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; class ComposerStyle { + static const double radius = 28; - static const double radius = 24; + static const Color borderColor = AppColor.colorLineComposer; + static const Color backgroundEditorColor = Colors.white; + static const Color richToolbarColor = Colors.white; + + static const EdgeInsetsGeometry richToolbarPadding = EdgeInsetsDirectional.symmetric(horizontal: 24, vertical: 8); + static const EdgeInsetsGeometry desktopRecipientPadding = EdgeInsetsDirectional.only(end: 24); + static const EdgeInsetsGeometry desktopRecipientMargin = EdgeInsetsDirectional.only(start: 24); + static const EdgeInsetsGeometry desktopSubjectMargin = EdgeInsetsDirectional.only(start: 24); + static const EdgeInsetsGeometry desktopSubjectPadding = EdgeInsetsDirectional.only(end: 24, top: 12, bottom: 12); + static const EdgeInsetsGeometry desktopEditorPadding = EdgeInsetsDirectional.symmetric(horizontal: 20); + static const EdgeInsetsGeometry tabletRecipientPadding = EdgeInsetsDirectional.only(end: 24); + static const EdgeInsetsGeometry tabletRecipientMargin = EdgeInsetsDirectional.only(start: 24); + static const EdgeInsetsGeometry tabletSubjectMargin = EdgeInsetsDirectional.only(start: 24); + static const EdgeInsetsGeometry tabletSubjectPadding = EdgeInsetsDirectional.only(end: 24, top: 12, bottom: 12); + static const EdgeInsetsGeometry tabletEditorPadding = EdgeInsetsDirectional.symmetric(horizontal: 20); + static const EdgeInsetsGeometry mobileRecipientPadding = EdgeInsetsDirectional.only(end: 16); + static const EdgeInsetsGeometry mobileRecipientMargin = EdgeInsetsDirectional.only(start: 16); + static const EdgeInsetsGeometry mobileSubjectMargin = EdgeInsetsDirectional.only(start: 16); + static const EdgeInsetsGeometry mobileSubjectPadding = EdgeInsetsDirectional.only(end: 16, top: 12, bottom: 12); + static const EdgeInsetsGeometry mobileEditorPadding = EdgeInsetsDirectional.symmetric(horizontal: 12); + + static const List richToolbarShadow = [ + BoxShadow( + color: AppColor.colorShadowBgContentEmail, + blurRadius: 24 + ), + BoxShadow( + color: AppColor.colorShadowBgContentEmail, + blurRadius: 2 + ), + ]; static EdgeInsetsGeometry getAppBarPadding(BuildContext context, ResponsiveUtils responsiveUtils) { if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeMobile(context)) { @@ -23,38 +55,6 @@ class ComposerStyle { } } - static EdgeInsetsGeometry getToAddressPadding(BuildContext context, ResponsiveUtils responsiveUtils) { - if (PlatformInfo.isWeb) { - if (responsiveUtils.isMobile(context)) { - return const EdgeInsetsDirectional.only(start: 16, end: 8); - } else { - return const EdgeInsetsDirectional.symmetric(horizontal: 8); - } - } else { - if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeMobile(context)) { - return const EdgeInsetsDirectional.symmetric(horizontal: 16); - } else { - return const EdgeInsetsDirectional.only(start: 8, end: 16); - } - } - } - - static EdgeInsetsGeometry getCcBccAddressPadding(BuildContext context, ResponsiveUtils responsiveUtils) { - if (PlatformInfo.isWeb) { - if (responsiveUtils.isMobile(context)) { - return const EdgeInsetsDirectional.only(start: 16); - } else { - return const EdgeInsetsDirectional.symmetric(horizontal: 8); - } - } else { - if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeMobile(context)) { - return const EdgeInsetsDirectional.only(start: 16); - } else { - return const EdgeInsetsDirectional.symmetric(horizontal: 8); - } - } - } - static EdgeInsetsGeometry getSubjectPadding(BuildContext context, ResponsiveUtils responsiveUtils) { if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeMobile(context)) { return const EdgeInsetsDirectional.symmetric(horizontal: 16, vertical: 8); @@ -71,14 +71,6 @@ class ComposerStyle { } } - static EdgeInsetsGeometry getPadding(BuildContext context, ResponsiveUtils responsiveUtils) { - if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeMobile(context)) { - return const EdgeInsetsDirectional.symmetric(horizontal: 8); - } else { - return const EdgeInsetsDirectional.symmetric(horizontal: 32); - } - } - static double getAppBarHeight(BuildContext context, ResponsiveUtils responsiveUtils) { if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeMobile(context)) { return 57; @@ -103,14 +95,6 @@ class ComposerStyle { } } - static EdgeInsetsGeometry getRichTextButtonPadding(BuildContext context, ResponsiveUtils responsiveUtils) { - if (responsiveUtils.isMobile(context)) { - return const EdgeInsetsDirectional.symmetric(horizontal: 16, vertical: 8); - } else { - return const EdgeInsetsDirectional.only(start: 88, end: 48, top: 8, bottom: 8); - } - } - static EdgeInsetsGeometry getEditorPadding(BuildContext context, ResponsiveUtils responsiveUtils) { if (PlatformInfo.isWeb) { if (responsiveUtils.isMobile(context)) { @@ -144,23 +128,6 @@ class ComposerStyle { } } - static EdgeInsetsGeometry getMarginForTabletWeb(BuildContext context, ResponsiveUtils responsiveUtils) { - if (responsiveUtils.isTablet(context)) { - return const EdgeInsetsDirectional.all(24); - } else { - return const EdgeInsetsDirectional.symmetric(vertical: 24); - } - } - - static double getWidthForTabletWeb(BuildContext context, ResponsiveUtils responsiveUtils) { - final currentWidth = responsiveUtils.getSizeScreenWidth(context); - if (responsiveUtils.isTablet(context)) { - return currentWidth; - } else { - return currentWidth * 0.7; - } - } - static int getMaxItemRowListAttachment(BuildContext context, BoxConstraints constraints) { if (constraints.maxWidth < ResponsiveUtils.minTabletWidth) { return 2; @@ -175,7 +142,6 @@ class ComposerStyle { return constraints.maxWidth / getMaxItemRowListAttachment(context, constraints); } - static double getMaxHeightEmailAddressWidget(BuildContext context, BoxConstraints constraints, ResponsiveUtils responsiveUtils) { if (responsiveUtils.isDesktop(context)) { return constraints.maxHeight > 0 ? constraints.maxHeight * 0.3 : 150.0; diff --git a/lib/features/composer/presentation/widgets/toolbar_rich_text_builder.dart b/lib/features/composer/presentation/widgets/toolbar_rich_text_builder.dart index c320b2a30..9b53cd64b 100644 --- a/lib/features/composer/presentation/widgets/toolbar_rich_text_builder.dart +++ b/lib/features/composer/presentation/widgets/toolbar_rich_text_builder.dart @@ -4,6 +4,7 @@ import 'package:core/utils/app_logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; +import 'package:pointer_interceptor/pointer_interceptor.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/controller/rich_text_web_controller.dart'; @@ -22,12 +23,16 @@ class ToolbarRichTextWebBuilder extends StatelessWidget with RichTextButtonMixin final ImagePaths _imagePaths = Get.find(); final EdgeInsetsGeometry? padding; final List? extendedOption; + final AlignmentGeometry? alignment; + final Decoration? decoration; ToolbarRichTextWebBuilder({ Key? key, required this.richTextWebController, this.padding, this.extendedOption, + this.alignment, + this.decoration, }) : super(key: key); @override @@ -36,187 +41,190 @@ class ToolbarRichTextWebBuilder extends StatelessWidget with RichTextButtonMixin final codeViewEnabled = richTextWebController.codeViewEnabled; final opacity = codeViewEnabled ? 0.5 : 1.0; - return Container( - padding: padding ?? const EdgeInsetsDirectional.only(start: 20, top: 8, bottom: 8), - alignment: AlignmentDirectional.centerStart, - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - runSpacing: 8, - children: [ - if (extendedOption?.isNotEmpty == true) - ...extendedOption!, - AbsorbPointer( - absorbing: codeViewEnabled, - child: DropDownMenuHeaderStyleWidget( - icon: buildWrapIconStyleText( - isSelected: richTextWebController.isMenuHeaderStyleOpen, - icon: SvgPicture.asset( - RichTextStyleType.headerStyle.getIcon(_imagePaths), - colorFilter: AppColor.colorDefaultRichTextButton.withOpacity(opacity).asFilter(), - fit: BoxFit.fill), - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), - tooltip: RichTextStyleType.headerStyle.getTooltipButton(context) + return PointerInterceptor( + child: Container( + padding: padding ?? const EdgeInsetsDirectional.only(start: 20, top: 8, bottom: 8), + decoration: decoration, + width: double.infinity, + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + runSpacing: 8, + children: [ + if (extendedOption?.isNotEmpty == true) + ...extendedOption!, + AbsorbPointer( + absorbing: codeViewEnabled, + child: DropDownMenuHeaderStyleWidget( + icon: buildWrapIconStyleText( + isSelected: richTextWebController.isMenuHeaderStyleOpen, + icon: SvgPicture.asset( + RichTextStyleType.headerStyle.getIcon(_imagePaths), + colorFilter: AppColor.colorDefaultRichTextButton.withOpacity(opacity).asFilter(), + fit: BoxFit.fill), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), + tooltip: RichTextStyleType.headerStyle.getTooltipButton(context) + ), + items: HeaderStyleType.values, + onMenuStateChange: (isOpen) { + log('ComposerView::_buildToolbarRichTextWidget(): MenuHeaderStyleStatus: $isOpen'); + final newStatus = isOpen + ? DropdownMenuFontStatus.open + : DropdownMenuFontStatus.closed; + richTextWebController.menuHeaderStyleStatus.value = newStatus; + }, + onChanged: (newStyle) => richTextWebController.applyHeaderStyle(newStyle)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: Container( + width: 130, + padding: const EdgeInsets.only(left: 4.0, right: 4.0), + child: DropDownButtonWidget( + items: FontNameType.values, + itemSelected: richTextWebController.selectedFontName.value, + onChanged: (newFont) => richTextWebController.applyNewFontStyle(newFont), + onMenuStateChange: (isOpen) { + log('ComposerView::_buildToolbarRichTextWidget(): MenuFontStatus: $isOpen'); + final newStatus = isOpen + ? DropdownMenuFontStatus.open + : DropdownMenuFontStatus.closed; + richTextWebController.menuFontStatus.value = newStatus; + }, + heightItem: 40, + sizeIconChecked: 16, + radiusButton: 8, + opacity: opacity, + dropdownWidth: 200, + colorButton: richTextWebController.isMenuFontOpen + ? AppColor.colorBackgroundWrapIconStyleCode + : Colors.white, + iconArrowDown: SvgPicture.asset(_imagePaths.icStyleArrowDown), + tooltip: RichTextStyleType.fontName.getTooltipButton(context), + supportSelectionIcon: true)), + ), + Padding( + padding: const EdgeInsetsDirectional.only(end: 4.0), + child: AbsorbPointer( + absorbing: codeViewEnabled, + child: buildWrapIconStyleText( + icon: buildIconWithTooltip( + path: RichTextStyleType.textColor.getIcon(_imagePaths), + color: richTextWebController.selectedTextColor.value, + tooltip: RichTextStyleType.textColor.getTooltipButton(context), + opacity: opacity), + onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.textColor)), + ), + ), + Padding( + padding: const EdgeInsetsDirectional.only(end: 4.0), + child: AbsorbPointer( + absorbing: codeViewEnabled, + child: buildWrapIconStyleText( + padding: const EdgeInsets.symmetric(vertical: 9, horizontal: 7), + spacing: 3, + icon: buildIconColorBackgroundText( + iconData: RichTextStyleType.textBackgroundColor.getIconData(), + colorSelected: richTextWebController.selectedTextBackgroundColor.value, + tooltip: RichTextStyleType.textBackgroundColor.getTooltipButton(context), + opacity: opacity), + onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.textBackgroundColor)), + ), + ), + Padding( + padding: const EdgeInsetsDirectional.only(end: 4.0), + child: buildWrapIconStyleText( + hasDropdown: false, + padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 5), + icon: Wrap(children: [ + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.bold.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.bold), + tooltip: RichTextStyleType.bold.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.bold)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.italic.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.italic), + tooltip: RichTextStyleType.italic.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.italic)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.underline.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.underline), + tooltip: RichTextStyleType.underline.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.underline)), + ), + AbsorbPointer( + absorbing: codeViewEnabled, + child: buildIconStyleText( + path: RichTextStyleType.strikeThrough.getIcon(_imagePaths), + isSelected: richTextWebController.isTextStyleTypeSelected( + RichTextStyleType.strikeThrough), + tooltip: RichTextStyleType.strikeThrough.getTooltipButton(context), + opacity: opacity, + onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.strikeThrough)), + ) + ])), + ), + Padding( + padding: const EdgeInsetsDirectional.only(end: 4.0), + child: AbsorbPointer( + absorbing: codeViewEnabled, + child: PopupMenuOverlayWidget( + controller: richTextWebController.menuParagraphController, + listButtonAction: ParagraphType.values + .map((paragraph) => paragraph.buildButtonWidget( + context, + _imagePaths, + (paragraph) => richTextWebController.applyParagraphType(paragraph))) + .toList(), + iconButton: buildWrapIconStyleText( + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), + spacing: 3, + isSelected: richTextWebController.focusMenuParagraph.value, + icon: buildIconWithTooltip( + path: richTextWebController.selectedParagraph.value.getIcon(_imagePaths), + color: AppColor.colorDefaultRichTextButton, + opacity: opacity, + tooltip: RichTextStyleType.paragraph.getTooltipButton(context))), ), - items: HeaderStyleType.values, - onMenuStateChange: (isOpen) { - log('ComposerView::_buildToolbarRichTextWidget(): MenuHeaderStyleStatus: $isOpen'); - final newStatus = isOpen - ? DropdownMenuFontStatus.open - : DropdownMenuFontStatus.closed; - richTextWebController.menuHeaderStyleStatus.value = newStatus; - }, - onChanged: (newStyle) => richTextWebController.applyHeaderStyle(newStyle)), - ), - AbsorbPointer( - absorbing: codeViewEnabled, - child: Container( - width: 130, - padding: const EdgeInsets.only(left: 4.0, right: 4.0), - child: DropDownButtonWidget( - items: FontNameType.values, - itemSelected: richTextWebController.selectedFontName.value, - onChanged: (newFont) => richTextWebController.applyNewFontStyle(newFont), - onMenuStateChange: (isOpen) { - log('ComposerView::_buildToolbarRichTextWidget(): MenuFontStatus: $isOpen'); - final newStatus = isOpen - ? DropdownMenuFontStatus.open - : DropdownMenuFontStatus.closed; - richTextWebController.menuFontStatus.value = newStatus; - }, - heightItem: 40, - sizeIconChecked: 16, - radiusButton: 8, - opacity: opacity, - dropdownWidth: 200, - colorButton: richTextWebController.isMenuFontOpen - ? AppColor.colorBackgroundWrapIconStyleCode - : Colors.white, - iconArrowDown: SvgPicture.asset(_imagePaths.icStyleArrowDown), - tooltip: RichTextStyleType.fontName.getTooltipButton(context), - supportSelectionIcon: true)), - ), - Padding( - padding: const EdgeInsetsDirectional.only(end: 4.0), - child: AbsorbPointer( - absorbing: codeViewEnabled, - child: buildWrapIconStyleText( - icon: buildIconWithTooltip( - path: RichTextStyleType.textColor.getIcon(_imagePaths), - color: richTextWebController.selectedTextColor.value, - tooltip: RichTextStyleType.textColor.getTooltipButton(context), - opacity: opacity), - onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.textColor)), + ), ), - ), - Padding( - padding: const EdgeInsetsDirectional.only(end: 4.0), - child: AbsorbPointer( - absorbing: codeViewEnabled, - child: buildWrapIconStyleText( - padding: const EdgeInsets.symmetric(vertical: 9, horizontal: 7), - spacing: 3, - icon: buildIconColorBackgroundText( - iconData: RichTextStyleType.textBackgroundColor.getIconData(), - colorSelected: richTextWebController.selectedTextBackgroundColor.value, - tooltip: RichTextStyleType.textBackgroundColor.getTooltipButton(context), - opacity: opacity), - onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.textBackgroundColor)), - ), - ), - Padding( - padding: const EdgeInsetsDirectional.only(end: 4.0), - child: buildWrapIconStyleText( - hasDropdown: false, - padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 5), - icon: Wrap(children: [ - AbsorbPointer( - absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.bold.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.bold), - tooltip: RichTextStyleType.bold.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.bold)), - ), - AbsorbPointer( - absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.italic.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.italic), - tooltip: RichTextStyleType.italic.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.italic)), - ), - AbsorbPointer( - absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.underline.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected(RichTextStyleType.underline), - tooltip: RichTextStyleType.underline.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.underline)), - ), - AbsorbPointer( - absorbing: codeViewEnabled, - child: buildIconStyleText( - path: RichTextStyleType.strikeThrough.getIcon(_imagePaths), - isSelected: richTextWebController.isTextStyleTypeSelected( - RichTextStyleType.strikeThrough), - tooltip: RichTextStyleType.strikeThrough.getTooltipButton(context), - opacity: opacity, - onTap: () => richTextWebController.applyRichTextStyle(context, RichTextStyleType.strikeThrough)), - ) - ])), - ), - Padding( - padding: const EdgeInsetsDirectional.only(end: 4.0), - child: AbsorbPointer( - absorbing: codeViewEnabled, - child: PopupMenuOverlayWidget( - controller: richTextWebController.menuParagraphController, - listButtonAction: ParagraphType.values - .map((paragraph) => paragraph.buildButtonWidget( + Padding( + padding: const EdgeInsetsDirectional.only(end: 4.0), + child: AbsorbPointer( + absorbing: codeViewEnabled, + child: PopupMenuOverlayWidget( + controller: richTextWebController.menuOrderListController, + listButtonAction: OrderListType.values + .map((orderType) => orderType.buildButtonWidget( context, _imagePaths, - (paragraph) => richTextWebController.applyParagraphType(paragraph))) - .toList(), - iconButton: buildWrapIconStyleText( + (orderType) => richTextWebController.applyOrderListType(orderType))) + .toList(), + iconButton: buildWrapIconStyleText( padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), spacing: 3, - isSelected: richTextWebController.focusMenuParagraph.value, + isSelected: richTextWebController.focusMenuOrderList.value, icon: buildIconWithTooltip( - path: richTextWebController.selectedParagraph.value.getIcon(_imagePaths), + path: richTextWebController.selectedOrderList.value.getIcon(_imagePaths), color: AppColor.colorDefaultRichTextButton, opacity: opacity, - tooltip: RichTextStyleType.paragraph.getTooltipButton(context))), + tooltip: RichTextStyleType.orderList.getTooltipButton(context))), + ), ), - ), - ), - Padding( - padding: const EdgeInsetsDirectional.only(end: 4.0), - child: AbsorbPointer( - absorbing: codeViewEnabled, - child: PopupMenuOverlayWidget( - controller: richTextWebController.menuOrderListController, - listButtonAction: OrderListType.values - .map((orderType) => orderType.buildButtonWidget( - context, - _imagePaths, - (orderType) => richTextWebController.applyOrderListType(orderType))) - .toList(), - iconButton: buildWrapIconStyleText( - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), - spacing: 3, - isSelected: richTextWebController.focusMenuOrderList.value, - icon: buildIconWithTooltip( - path: richTextWebController.selectedOrderList.value.getIcon(_imagePaths), - color: AppColor.colorDefaultRichTextButton, - opacity: opacity, - tooltip: RichTextStyleType.orderList.getTooltipButton(context))), - ), - ), - ) - ] + ) + ] + ), ), ); }); diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 2175ee677..e096e96a3 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-08-31T14:39:56.761446", + "@@last_modified": "2023-09-06T11:36:27.238808", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1686,12 +1686,6 @@ "placeholders_order": [], "placeholders": {} }, - "codeView": "Code view", - "@codeView": { - "type": "text", - "placeholders_order": [], - "placeholders": {} - }, "headerStyle": "Style", "@headerStyle": { "type": "text", @@ -3217,5 +3211,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "formattingOptions": "Formatting options", + "@formattingOptions": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "embedCode": "Embed code", + "@embedCode": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 0d81d81ea..6a4807636 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1721,12 +1721,6 @@ class AppLocalizations { name: 'formatTextBackgroundColor'); } - String get codeView { - return Intl.message( - 'Code view', - name: 'codeView'); - } - String get headerStyle { return Intl.message( 'Style', @@ -3317,4 +3311,18 @@ class AppLocalizations { name: 'addCondition', ); } + + String get formattingOptions { + return Intl.message( + 'Formatting options', + name: 'formattingOptions' + ); + } + + String get embedCode { + return Intl.message( + 'Embed code', + name: 'embedCode' + ); + } } \ No newline at end of file