From 0703d14761ce9b4be8705593c30bcc20dfc4eaa7 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 3 Apr 2025 15:27:55 +0700 Subject: [PATCH] TF-3601 Fix content gone blank in composer on IOS Signed-off-by: dab246 --- .../presentation/constants/constants_ui.dart | 6 +- .../html_content_viewer_widget.dart | 64 ++++++--------- .../presentation/composer_controller.dart | 1 + .../composer/presentation/composer_view.dart | 29 +++++++ ...dle_content_height_exceeded_extension.dart | 31 +++++++ .../mobile/editor_fullscreen_dialog_view.dart | 82 +++++++++++++++++++ .../view/mobile/mobile_editor_view.dart | 20 +++-- .../widgets/mobile/mobile_editor_widget.dart | 7 ++ .../email/presentation/email_view.dart | 45 +++------- .../event_body_content_widget.dart | 4 + ...e_message_with_message_clipped_widget.dart | 54 ++++++++++++ .../identity_creator_controller.dart | 4 +- .../presentation/identity_creator_view.dart | 4 +- .../vacation/vacation_controller.dart | 3 +- .../presentation/vacation/vacation_view.dart | 4 +- pubspec.lock | 4 +- 16 files changed, 274 insertions(+), 88 deletions(-) create mode 100644 lib/features/composer/presentation/extensions/handle_content_height_exceeded_extension.dart create mode 100644 lib/features/composer/presentation/view/mobile/editor_fullscreen_dialog_view.dart create mode 100644 lib/features/email/presentation/widgets/view_entire_message_with_message_clipped_widget.dart diff --git a/core/lib/presentation/constants/constants_ui.dart b/core/lib/presentation/constants/constants_ui.dart index aa869dcb5..b629e558e 100644 --- a/core/lib/presentation/constants/constants_ui.dart +++ b/core/lib/presentation/constants/constants_ui.dart @@ -1,3 +1,7 @@ class ConstantsUI { - static const fontApp = 'Inter'; + static const String fontApp = 'Inter'; + static const double htmlContentMaxHeight = 22000.0; + static const double composerHtmlContentMaxHeight = 20000.0; + static const double htmlContentMinHeight = 150; + static const double htmlContentOffsetHeight = 30.0; } \ No newline at end of file diff --git a/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart b/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart index f373a8683..0fc9fe109 100644 --- a/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart +++ b/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'dart:math' as math; import 'package:core/data/constants/constant.dart'; +import 'package:core/presentation/constants/constants_ui.dart'; import 'package:core/presentation/views/loading/cupertino_loading_widget.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/html/html_interaction.dart'; @@ -29,6 +29,9 @@ class HtmlContentViewer extends StatefulWidget { final bool keepWidthWhileLoading; final double? contentPadding; final bool useDefaultFont; + final double? maxHtmlContentHeight; + final double minHtmlContentHeight; + final double offsetHtmlContentHeight; final OnLoadWidthHtmlViewerAction? onLoadWidthHtmlViewer; final OnMailtoDelegateAction? onMailtoDelegateAction; @@ -42,9 +45,12 @@ class HtmlContentViewer extends StatefulWidget { required this.contentHtml, this.initialWidth, this.direction, + this.minHtmlContentHeight = ConstantsUI.htmlContentMinHeight, + this.offsetHtmlContentHeight = ConstantsUI.htmlContentMinHeight, this.keepWidthWhileLoading = false, this.contentPadding, this.useDefaultFont = false, + this.maxHtmlContentHeight, this.onLoadWidthHtmlViewer, this.onMailtoDelegateAction, this.onScrollHorizontalEnd, @@ -59,10 +65,6 @@ class HtmlContentViewer extends StatefulWidget { class _HtmlContentViewState extends State { - static const double _minHeight = 100.0; - static const double _iOSHtmlContentMaxHeight = 22000.0; - static const double _offsetHeight = 30.0; - late InAppWebViewController _webViewController; late double _actualHeight; late Set> _gestureRecognizers; @@ -109,7 +111,7 @@ class _HtmlContentViewState extends State { } void _initialData() { - _actualHeight = _minHeight; + _actualHeight = widget.minHtmlContentHeight; _htmlData = HtmlUtils.generateHtmlDocument( content: widget.contentHtml, direction: widget.direction, @@ -172,7 +174,7 @@ class _HtmlContentViewState extends State { if (PlatformInfo.isAndroid) { controller.addJavaScriptHandler( handlerName: HtmlInteraction.contentSizeChangedEventJSChannelName, - callback: _onHandleContentSizeChangedEvent + callback: (_) => _handleContentSizeChanged(), ); } } @@ -187,29 +189,7 @@ class _HtmlContentViewState extends State { InAppWebViewController controller, Size oldContentSize, Size newContentSize - ) async { - if (!mounted || _loadingBarNotifier.value) return; - - final maxContentHeight = math.max(oldContentSize.height, newContentSize.height); - if (maxContentHeight <= _actualHeight) return; - - double currentHeight = maxContentHeight + _offsetHeight; - - if (PlatformInfo.isIOS) { - final isClipped = currentHeight > _iOSHtmlContentMaxHeight; - if (isClipped) { - widget.onHtmlContentClippedAction?.call(true); - } - currentHeight = currentHeight.clamp(_minHeight, _iOSHtmlContentMaxHeight); - } - - if (_actualHeight != currentHeight) { - log('_HtmlContentViewState::_onContentSizeChanged: currentHeight = $currentHeight'); - setState(() { - _actualHeight = currentHeight; - }); - } - } + ) => _handleContentSizeChanged(); void _onHandleScrollEvent(List parameters) { log('_HtmlContentViewState::_onHandleScrollEvent():parameters: $parameters'); @@ -221,7 +201,7 @@ class _HtmlContentViewState extends State { } } - void _onHandleContentSizeChangedEvent(List parameters) async { + void _handleContentSizeChanged() async { if (!mounted || _loadingBarNotifier.value) return; final dynamic result = await _webViewController.evaluateJavascript(source: 'document.body.scrollHeight'); @@ -230,14 +210,17 @@ class _HtmlContentViewState extends State { final double maxContentHeight = result.toDouble(); if (maxContentHeight <= _actualHeight) return; - double currentHeight = maxContentHeight + _offsetHeight; + double currentHeight = maxContentHeight + widget.offsetHtmlContentHeight; - if (PlatformInfo.isIOS) { - final bool isClipped = currentHeight > _iOSHtmlContentMaxHeight; + if (PlatformInfo.isIOS && widget.maxHtmlContentHeight != null) { + final bool isClipped = currentHeight > widget.maxHtmlContentHeight!; if (isClipped) { widget.onHtmlContentClippedAction?.call(true); } - currentHeight = currentHeight.clamp(_minHeight, _iOSHtmlContentMaxHeight); + currentHeight = currentHeight.clamp( + widget.minHtmlContentHeight, + widget.maxHtmlContentHeight!, + ); } if (_actualHeight != currentHeight) { @@ -277,14 +260,17 @@ class _HtmlContentViewState extends State { } if (scrollHeight != null && scrollHeight > 0) { - double currentHeight = scrollHeight + _offsetHeight; + double currentHeight = scrollHeight + widget.offsetHtmlContentHeight; - if (PlatformInfo.isIOS) { - final bool isClipped = currentHeight > _iOSHtmlContentMaxHeight; + if (PlatformInfo.isIOS && widget.maxHtmlContentHeight != null) { + final bool isClipped = currentHeight > widget.maxHtmlContentHeight!; if (isClipped) { widget.onHtmlContentClippedAction?.call(true); } - currentHeight = currentHeight.clamp(_minHeight, _iOSHtmlContentMaxHeight); + currentHeight = currentHeight.clamp( + widget.minHtmlContentHeight, + widget.maxHtmlContentHeight!, + ); } if (_actualHeight != currentHeight || newGestureRecognizers != null) { diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 91b0c7757..49b267f8c 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -138,6 +138,7 @@ class ComposerController extends BaseController final listFromIdentities = RxList(); final isEmailChanged = Rx(false); final isMarkAsImportant = Rx(false); + final isContentHeightExceeded = Rx(false); final LocalFilePickerInteractor _localFilePickerInteractor; final LocalImagePickerInteractor _localImagePickerInteractor; diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index 357ef5700..ba6a8409e 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -1,5 +1,6 @@ import 'package:core/presentation/views/context_menu/simple_context_menu_action_builder.dart'; import 'package:core/presentation/views/responsive/responsive_widget.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -8,6 +9,7 @@ import 'package:get/get.dart'; import 'package:model/email/prefix_email_address.dart'; import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_content_height_exceeded_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/mark_as_important_extension.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'; @@ -25,6 +27,7 @@ import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/tabl 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/web/from_composer_drop_down_widget.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/view_entire_message_with_message_clipped_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -107,6 +110,7 @@ class ComposerView extends GetWidget { controller: controller.scrollController, physics: const ClampingScrollPhysics(), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Obx(() { if (controller.fromRecipientState.value == PrefixRecipientState.enabled) { @@ -260,8 +264,20 @@ class ComposerView extends GetWidget { contentViewState: controller.emailContentsViewState.value, onCreatedEditorAction: controller.onCreatedMobileEditorAction, onLoadCompletedEditorAction: controller.onLoadCompletedMobileEditorAction, + onEditorContentHeightChanged: controller.onEditorContentHeightChangedOnIOS, ), )), + Obx(() { + if (controller.isContentHeightExceeded.isTrue && PlatformInfo.isIOS) { + return ViewEntireMessageWithMessageClippedWidget( + buttonActionName: AppLocalizations.of(context).viewEntireMessage.toUpperCase(), + onViewEntireMessageAction: () => controller.viewEntireContent(context), + topPadding: 12, + ); + } else { + return const SizedBox.shrink(); + } + }), SizedBox(height: MediaQuery.viewInsetsOf(context).bottom + 64), ], ), @@ -296,6 +312,7 @@ class ComposerView extends GetWidget { controller: controller.scrollController, physics: const ClampingScrollPhysics(), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Obx(() => Column( children: [ @@ -433,8 +450,20 @@ class ComposerView extends GetWidget { contentViewState: controller.emailContentsViewState.value, onCreatedEditorAction: controller.onCreatedMobileEditorAction, onLoadCompletedEditorAction: controller.onLoadCompletedMobileEditorAction, + onEditorContentHeightChanged: controller.onEditorContentHeightChangedOnIOS, ), )), + Obx(() { + if (controller.isContentHeightExceeded.isTrue && PlatformInfo.isIOS) { + return ViewEntireMessageWithMessageClippedWidget( + buttonActionName: AppLocalizations.of(context).viewEntireMessage.toUpperCase(), + onViewEntireMessageAction: () => controller.viewEntireContent(context), + topPadding: 12, + ); + } else { + return const SizedBox.shrink(); + } + }), SizedBox(height: MediaQuery.viewInsetsOf(context).bottom + 64), ], ), diff --git a/lib/features/composer/presentation/extensions/handle_content_height_exceeded_extension.dart b/lib/features/composer/presentation/extensions/handle_content_height_exceeded_extension.dart new file mode 100644 index 000000000..c02dc935c --- /dev/null +++ b/lib/features/composer/presentation/extensions/handle_content_height_exceeded_extension.dart @@ -0,0 +1,31 @@ + +import 'package:core/presentation/constants/constants_ui.dart'; +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/composer/presentation/view/mobile/editor_fullscreen_dialog_view.dart'; + +extension HandleContentHeightExceededExtension on ComposerController { + + void onEditorContentHeightChangedOnIOS(double height) { + log('HandleContentHeightExceededExtension::onEditorContentHeightChangedOnIOS:height: $height'); + isContentHeightExceeded.value = height == ConstantsUI.composerHtmlContentMaxHeight; + } + + Future viewEntireContent(BuildContext context) async { + clearFocus(context); + + final currentContent = await getContentInEditor(); + log('HandleContentHeightExceededExtension::showComposerFullscreen:currentContent = $currentContent'); + Get.dialog( + EditorFullscreenDialogView( + content: currentContent, + imagePaths: imagePaths, + subject: subjectEmail.value, + ), + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + ); + } +} \ No newline at end of file diff --git a/lib/features/composer/presentation/view/mobile/editor_fullscreen_dialog_view.dart b/lib/features/composer/presentation/view/mobile/editor_fullscreen_dialog_view.dart new file mode 100644 index 000000000..96cff8a1b --- /dev/null +++ b/lib/features/composer/presentation/view/mobile/editor_fullscreen_dialog_view.dart @@ -0,0 +1,82 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:core/presentation/views/html_viewer/ios_html_content_viewer_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +import 'package:tmail_ui_user/main/utils/app_utils.dart'; + +class EditorFullscreenDialogView extends StatelessWidget { + final String content; + final ImagePaths imagePaths; + final String? subject; + + const EditorFullscreenDialogView({ + super.key, + required this.imagePaths, + required this.content, + this.subject, + }); + + @override + Widget build(BuildContext context) { + return Dialog( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16), + topLeft: Radius.circular(16), + ), + ), + insetPadding: EdgeInsets.zero, + alignment: Alignment.center, + backgroundColor: Colors.white, + child: Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16), + topLeft: Radius.circular(16), + ), + ), + width: double.infinity, + height: double.infinity, + clipBehavior: Clip.antiAlias, + child: Column( + children: [ + SizedBox( + height: 52, + child: Row( + children: [ + const SizedBox(width: 40), + Expanded(child: Text( + subject ?? AppLocalizations.of(context).compose_email, + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: Colors.black, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + )), + TMailButtonWidget.fromIcon( + icon: imagePaths.icComposerClose, + backgroundColor: Colors.transparent, + margin: const EdgeInsetsDirectional.only(end: 12), + onTapActionCallback: popBack, + ) + ], + ), + ), + const Divider(color: AppColor.colorDivider, height: 1), + Expanded( + child: IosHtmlContentViewerWidget( + contentHtml: content, + useDefaultFont: true, + direction: AppUtils.getCurrentDirection(context), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart b/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart index 03531bbbe..fd516a70e 100644 --- a/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart +++ b/lib/features/composer/presentation/view/mobile/mobile_editor_view.dart @@ -18,6 +18,7 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { final Either? contentViewState; final OnCreatedEditorAction onCreatedEditorAction; final OnLoadCompletedEditorAction onLoadCompletedEditorAction; + final OnEditorContentHeightChanged? onEditorContentHeightChanged; const MobileEditorView({ super.key, @@ -25,6 +26,7 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { required this.onLoadCompletedEditorAction, this.arguments, this.contentViewState, + this.onEditorContentHeightChanged, }); @override @@ -41,7 +43,8 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { content: HtmlExtension.editorStartTags, direction: AppUtils.getCurrentDirection(context), onCreatedEditorAction: onCreatedEditorAction, - onLoadCompletedEditorAction: onLoadCompletedEditorAction + onLoadCompletedEditorAction: onLoadCompletedEditorAction, + onEditorContentHeightChanged: onEditorContentHeightChanged, ); case EmailActionType.editDraft: case EmailActionType.editSendingEmail: @@ -58,7 +61,8 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { content: HtmlExtension.editorStartTags, direction: AppUtils.getCurrentDirection(context), onCreatedEditorAction: onCreatedEditorAction, - onLoadCompletedEditorAction: onLoadCompletedEditorAction + onLoadCompletedEditorAction: onLoadCompletedEditorAction, + onEditorContentHeightChanged: onEditorContentHeightChanged, ), (success) { if (success is GetEmailContentLoading) { @@ -77,7 +81,8 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { content: newContent, direction: AppUtils.getCurrentDirection(context), onCreatedEditorAction: onCreatedEditorAction, - onLoadCompletedEditorAction: onLoadCompletedEditorAction + onLoadCompletedEditorAction: onLoadCompletedEditorAction, + onEditorContentHeightChanged: onEditorContentHeightChanged, ); } } @@ -102,7 +107,8 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { content: emailContentQuoted, direction: AppUtils.getCurrentDirection(context), onCreatedEditorAction: onCreatedEditorAction, - onLoadCompletedEditorAction: onLoadCompletedEditorAction + onLoadCompletedEditorAction: onLoadCompletedEditorAction, + onEditorContentHeightChanged: onEditorContentHeightChanged, ); }, (success) { @@ -122,7 +128,8 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { content: emailContentQuoted, direction: AppUtils.getCurrentDirection(context), onCreatedEditorAction: onCreatedEditorAction, - onLoadCompletedEditorAction: onLoadCompletedEditorAction + onLoadCompletedEditorAction: onLoadCompletedEditorAction, + onEditorContentHeightChanged: onEditorContentHeightChanged, ); } } @@ -132,7 +139,8 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin { content: HtmlExtension.editorStartTags, direction: AppUtils.getCurrentDirection(context), onCreatedEditorAction: onCreatedEditorAction, - onLoadCompletedEditorAction: onLoadCompletedEditorAction + onLoadCompletedEditorAction: onLoadCompletedEditorAction, + onEditorContentHeightChanged: onEditorContentHeightChanged, ); } } diff --git a/lib/features/composer/presentation/widgets/mobile/mobile_editor_widget.dart b/lib/features/composer/presentation/widgets/mobile/mobile_editor_widget.dart index 5469946c9..a440c9975 100644 --- a/lib/features/composer/presentation/widgets/mobile/mobile_editor_widget.dart +++ b/lib/features/composer/presentation/widgets/mobile/mobile_editor_widget.dart @@ -1,10 +1,13 @@ +import 'package:core/presentation/constants/constants_ui.dart'; import 'package:core/utils/html/html_utils.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:rich_text_composer/rich_text_composer.dart'; typedef OnCreatedEditorAction = Function(BuildContext context, HtmlEditorApi editorApi, String content); typedef OnLoadCompletedEditorAction = Function(HtmlEditorApi editorApi, WebUri? url); +typedef OnEditorContentHeightChanged = Function(double height); class MobileEditorWidget extends StatelessWidget { @@ -12,6 +15,7 @@ class MobileEditorWidget extends StatelessWidget { final TextDirection direction; final OnCreatedEditorAction onCreatedEditorAction; final OnLoadCompletedEditorAction onLoadCompletedEditorAction; + final OnEditorContentHeightChanged? onEditorContentHeightChanged; const MobileEditorWidget({ super.key, @@ -19,6 +23,7 @@ class MobileEditorWidget extends StatelessWidget { required this.direction, required this.onCreatedEditorAction, required this.onLoadCompletedEditorAction, + this.onEditorContentHeightChanged, }); @override @@ -26,6 +31,7 @@ class MobileEditorWidget extends StatelessWidget { return HtmlEditor( key: const Key('mobile_editor'), minHeight: 550, + maxHeight: PlatformInfo.isIOS ? ConstantsUI.composerHtmlContentMaxHeight : null, addDefaultSelectionMenuItems: false, initialContent: content, customStyleCss: HtmlUtils.customCssStyleHtmlEditor( @@ -34,6 +40,7 @@ class MobileEditorWidget extends StatelessWidget { ), onCreated: (editorApi) => onCreatedEditorAction.call(context, editorApi, content), onCompleted: onLoadCompletedEditorAction, + onContentHeightChanged: PlatformInfo.isIOS ? onEditorContentHeightChanged : null, ); } } diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 775e0d3e9..4b68b2bd6 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -1,3 +1,4 @@ +import 'package:core/presentation/constants/constants_ui.dart'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart'; @@ -32,6 +33,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_emp import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_loading_bar_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/information_sender_and_receiver_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/mail_unsubscribed_banner.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/view_entire_message_with_message_clipped_widget.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -390,7 +392,7 @@ class EmailView extends GetWidget { else if (presentationEmail.id == controller.currentEmail?.id) Obx(() { if (controller.emailContents.value != null) { - String allEmailContents = controller.emailContents.value ?? ''; + final allEmailContents = controller.emailContents.value ?? ''; if (PlatformInfo.isWeb) { return Expanded( @@ -449,6 +451,7 @@ class EmailView extends GetWidget { direction: AppUtils.getCurrentDirection(context), contentPadding: 0, useDefaultFont: true, + maxHtmlContentHeight: ConstantsUI.htmlContentMaxHeight, onMailtoDelegateAction: controller.openMailToLink, onScrollHorizontalEnd: controller.toggleScrollPhysicsPagerView, onLoadWidthHtmlViewer: controller.emailSupervisorController.updateScrollPhysicPageView, @@ -458,38 +461,13 @@ class EmailView extends GetWidget { ), Obx(() { if (controller.isEmailContentClipped.isTrue) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text( - AppLocalizations.of(context).messageClipped, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: AppColor.steelGray400, - ), - ), - ), - TMailButtonWidget.fromText( - text: AppLocalizations.of(context).viewEntireMessage.toUpperCase(), - textStyle: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: AppColor.primaryColor, - fontSize: 14, - ), - margin: const EdgeInsetsDirectional.only( - start: 8, - end: 8, - bottom: 24, - ), - backgroundColor: Colors.transparent, - onTapActionCallback: () => - controller.onViewEntireMessage( - context: context, - emailContent: allEmailContents, - presentationEmail: presentationEmail, - ), - ), - ], + return ViewEntireMessageWithMessageClippedWidget( + buttonActionName: AppLocalizations.of(context).viewEntireMessage.toUpperCase(), + onViewEntireMessageAction: () => controller.onViewEntireMessage( + context: context, + emailContent: allEmailContents, + presentationEmail: presentationEmail, + ), ); } else { return const SizedBox.shrink(); @@ -515,7 +493,6 @@ class EmailView extends GetWidget { onMailtoDelegateAction: controller.openMailToLink, onScrollHorizontalEnd: controller.toggleScrollPhysicsPagerView, onLoadWidthHtmlViewer: controller.emailSupervisorController.updateScrollPhysicPageView, - onHtmlContentClippedAction: controller.onHtmlContentClippedAction, ); }) ); diff --git a/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart b/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart index 1c6fc6845..87295e4db 100644 --- a/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart +++ b/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart @@ -1,4 +1,5 @@ +import 'package:core/presentation/constants/constants_ui.dart'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart'; @@ -72,6 +73,9 @@ class EventBodyContentWidget extends StatelessWidget { return HtmlContentViewer( contentHtml: content, initialWidth: constraints.maxWidth, + maxHtmlContentHeight: PlatformInfo.isIOS + ? ConstantsUI.htmlContentMaxHeight + : null, direction: AppUtils.getCurrentDirection(context), onMailtoDelegateAction: onMailtoDelegateAction ); diff --git a/lib/features/email/presentation/widgets/view_entire_message_with_message_clipped_widget.dart b/lib/features/email/presentation/widgets/view_entire_message_with_message_clipped_widget.dart new file mode 100644 index 000000000..d24d2cd8c --- /dev/null +++ b/lib/features/email/presentation/widgets/view_entire_message_with_message_clipped_widget.dart @@ -0,0 +1,54 @@ + + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class ViewEntireMessageWithMessageClippedWidget extends StatelessWidget { + + final String buttonActionName; + final VoidCallback onViewEntireMessageAction; + final double? topPadding; + + const ViewEntireMessageWithMessageClippedWidget({ + super.key, + required this.buttonActionName, + required this.onViewEntireMessageAction, + this.topPadding, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (topPadding != null) + SizedBox(height: topPadding), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + AppLocalizations.of(context).messageClipped, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: AppColor.steelGray400, + ), + ), + ), + TMailButtonWidget.fromText( + text: buttonActionName, + textStyle: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: AppColor.primaryColor, + fontSize: 14, + ), + margin: const EdgeInsetsDirectional.only( + start: 8, + end: 8, + bottom: 24, + ), + backgroundColor: Colors.transparent, + onTapActionCallback: onViewEntireMessageAction, + ), + ], + ); + } +} diff --git a/lib/features/identity_creator/presentation/identity_creator_controller.dart b/lib/features/identity_creator/presentation/identity_creator_controller.dart index f89815997..1242846a9 100644 --- a/lib/features/identity_creator/presentation/identity_creator_controller.dart +++ b/lib/features/identity_creator/presentation/identity_creator_controller.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'package:collection/collection.dart'; +import 'package:core/presentation/constants/constants_ui.dart'; import 'package:core/presentation/extensions/list_nullable_extensions.dart'; import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; @@ -116,7 +117,6 @@ class IdentityCreatorController extends BaseController with DragDropFileMixin im PublicAssetController? publicAssetController; final GlobalKey htmlKey = GlobalKey(); - final htmlEditorMinHeight = 150; bool isLoadSignatureCompleted = false; bool _userScrolled = false; @@ -658,7 +658,7 @@ class IdentityCreatorController extends BaseController with DragDropFileMixin im await Future.delayed(const Duration(milliseconds: 500), () { final offset = scrollController.position.pixels + defaultKeyboardToolbarHeight + - htmlEditorMinHeight; + ConstantsUI.htmlContentMinHeight; scrollController.animateTo( offset, duration: const Duration(milliseconds: 1), diff --git a/lib/features/identity_creator/presentation/identity_creator_view.dart b/lib/features/identity_creator/presentation/identity_creator_view.dart index f9c8ac6ec..44a982878 100644 --- a/lib/features/identity_creator/presentation/identity_creator_view.dart +++ b/lib/features/identity_creator/presentation/identity_creator_view.dart @@ -1,5 +1,6 @@ import 'dart:math' as math; +import 'package:core/presentation/constants/constants_ui.dart'; import 'package:core/presentation/extensions/capitalize_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/style_utils.dart'; @@ -555,7 +556,8 @@ class IdentityCreatorView extends GetWidget Widget _buildHtmlEditor(BuildContext context, {String? initialContent}) { return HtmlEditor( key: controller.htmlKey, - minHeight: controller.htmlEditorMinHeight, + minHeight: ConstantsUI.htmlContentMinHeight.toInt(), + maxHeight: PlatformInfo.isIOS ? ConstantsUI.composerHtmlContentMaxHeight : null, addDefaultSelectionMenuItems: false, initialContent: initialContent ?? '', customStyleCss: HtmlUtils.customCssStyleHtmlEditor(direction: AppUtils.getCurrentDirection(context)), diff --git a/lib/features/manage_account/presentation/vacation/vacation_controller.dart b/lib/features/manage_account/presentation/vacation/vacation_controller.dart index 97424654e..b1b1100d7 100644 --- a/lib/features/manage_account/presentation/vacation/vacation_controller.dart +++ b/lib/features/manage_account/presentation/vacation/vacation_controller.dart @@ -33,7 +33,6 @@ class VacationController extends BaseController { final subjectTextController = TextEditingController(); final subjectTextFocusNode = FocusNode(); final richTextControllerForMobile = RichTextController(); - final htmlEditorMinHeight = 150; final GlobalKey htmlKey = GlobalKey(); @@ -338,7 +337,7 @@ class VacationController extends BaseController { await Scrollable.ensureVisible(htmlKey.currentContext!); await Future.delayed(const Duration(milliseconds: 500), () { scrollController.animateTo( - scrollController.position.pixels + defaultKeyboardToolbarHeight + htmlEditorMinHeight, + scrollController.position.pixels + defaultKeyboardToolbarHeight + ConstantsUI.htmlContentMinHeight, duration: const Duration(milliseconds: 1), curve: Curves.linear, ); diff --git a/lib/features/manage_account/presentation/vacation/vacation_view.dart b/lib/features/manage_account/presentation/vacation/vacation_view.dart index f7aa85ca0..b1439a0e3 100644 --- a/lib/features/manage_account/presentation/vacation/vacation_view.dart +++ b/lib/features/manage_account/presentation/vacation/vacation_view.dart @@ -1,4 +1,5 @@ +import 'package:core/presentation/constants/constants_ui.dart'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/keyboard_utils.dart'; import 'package:core/presentation/views/button/icon_button_web.dart'; @@ -503,7 +504,8 @@ class VacationView extends GetWidget with RichTextButtonMixi } else { return HtmlEditor( key: controller.htmlKey, - minHeight: controller.htmlEditorMinHeight, + minHeight: ConstantsUI.htmlContentMinHeight.toInt(), + maxHeight: PlatformInfo.isIOS ? ConstantsUI.composerHtmlContentMaxHeight : null, addDefaultSelectionMenuItems: false, initialContent: controller.vacationMessageHtmlText ?? '', customStyleCss: HtmlUtils.customCssStyleHtmlEditor(direction: AppUtils.getCurrentDirection(context)), diff --git a/pubspec.lock b/pubspec.lock index 0f25d05ba..ee51633d4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -493,10 +493,10 @@ packages: description: path: "." ref: master - resolved-ref: "590b825e406edd50556074eee32ab896afb99933" + resolved-ref: b95d69a865f17575924868159bca43ef47b67fcd url: "https://github.com/linagora/enough_html_editor.git" source: git - version: "0.1.1" + version: "0.1.2" enough_platform_widgets: dependency: transitive description: