TF-3601 Fix preview EML file with long content in iOS

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-03-31 03:45:05 +07:00
committed by Dat H. Pham
parent d01618c32e
commit 1c97c8a189
3 changed files with 203 additions and 15 deletions
@@ -0,0 +1,102 @@
import 'dart:async';
import 'package:core/data/constants/constant.dart';
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
import 'package:core/utils/html/html_interaction.dart';
import 'package:core/utils/html/html_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart' as launcher;
import 'package:url_launcher/url_launcher_string.dart';
class IosHtmlContentViewerWidget extends StatefulWidget {
final String contentHtml;
final TextDirection? direction;
final bool useDefaultFont;
final OnMailtoDelegateAction? onMailtoDelegateAction;
final OnPreviewEMLDelegateAction? onPreviewEMLDelegateAction;
final OnDownloadAttachmentDelegateAction? onDownloadAttachmentDelegateAction;
const IosHtmlContentViewerWidget({
Key? key,
required this.contentHtml,
this.direction,
this.useDefaultFont = false,
this.onMailtoDelegateAction,
this.onPreviewEMLDelegateAction,
this.onDownloadAttachmentDelegateAction,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _IosHtmlContentViewerWidgetState();
}
class _IosHtmlContentViewerWidgetState extends State<IosHtmlContentViewerWidget> {
@override
Widget build(BuildContext context) {
return InAppWebView(
initialSettings: InAppWebViewSettings(transparentBackground: true),
onWebViewCreated: _onWebViewCreated,
shouldOverrideUrlLoading: _shouldOverrideUrlLoading,
gestureRecognizers: {
Factory<LongPressGestureRecognizer>(() => LongPressGestureRecognizer()),
},
);
}
Future<void> _onWebViewCreated(InAppWebViewController controller) async {
await controller.loadData(data: HtmlUtils.generateHtmlDocument(
content: widget.contentHtml,
direction: widget.direction,
javaScripts: HtmlInteraction.scriptsHandleLazyLoadingBackgroundImage,
useDefaultFont: widget.useDefaultFont,
));
}
Future<NavigationActionPolicy?> _shouldOverrideUrlLoading(
InAppWebViewController controller,
NavigationAction navigationAction
) async {
final url = navigationAction.request.url?.toString();
if (url == null) {
return NavigationActionPolicy.CANCEL;
}
if (navigationAction.isForMainFrame && url == 'about:blank') {
return NavigationActionPolicy.ALLOW;
}
final requestUri = Uri.parse(url);
if (widget.onMailtoDelegateAction != null &&
requestUri.isScheme(Constant.mailtoScheme)) {
await widget.onMailtoDelegateAction?.call(requestUri);
return NavigationActionPolicy.CANCEL;
}
if (widget.onPreviewEMLDelegateAction != null &&
requestUri.isScheme(Constant.emlPreviewerScheme)) {
await widget.onPreviewEMLDelegateAction?.call(requestUri);
return NavigationActionPolicy.CANCEL;
}
if (widget.onDownloadAttachmentDelegateAction != null &&
requestUri.isScheme(Constant.attachmentScheme)) {
await widget.onDownloadAttachmentDelegateAction?.call(requestUri);
return NavigationActionPolicy.CANCEL;
}
if (await launcher.canLaunchUrl(Uri.parse(url))) {
await launcher.launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication
);
}
return NavigationActionPolicy.CANCEL;
}
}
@@ -2428,9 +2428,17 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
return; return;
} }
showModalSheetToPreviewEMLAttachment( if (PlatformInfo.isAndroid) {
currentContext!, showModalSheetToPreviewEMLAttachment(
success.emlPreviewer); currentContext!,
success.emlPreviewer,
);
} if (PlatformInfo.isIOS) {
showDialogToPreviewEMLAttachment(
currentContext!,
success.emlPreviewer,
);
}
} }
} }
@@ -2454,6 +2462,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
initialChildSize: 1.0, initialChildSize: 1.0,
builder: (context, ___) => EmailPreviewerDialogView( builder: (context, ___) => EmailPreviewerDialogView(
emlPreviewer: emlPreviewer, emlPreviewer: emlPreviewer,
imagePaths: imagePaths,
onMailtoDelegateAction: openMailToLink, onMailtoDelegateAction: openMailToLink,
onPreviewEMLDelegateAction: (uri) => _openEMLPreviewer(context, uri), onPreviewEMLDelegateAction: (uri) => _openEMLPreviewer(context, uri),
onDownloadAttachmentDelegateAction: (uri) => onDownloadAttachmentDelegateAction: (uri) =>
@@ -2464,6 +2473,20 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
); );
} }
void showDialogToPreviewEMLAttachment(BuildContext context, EMLPreviewer emlPreviewer) {
Get.dialog(
EmailPreviewerDialogView(
emlPreviewer: emlPreviewer,
imagePaths: imagePaths,
onMailtoDelegateAction: openMailToLink,
onPreviewEMLDelegateAction: (uri) => _openEMLPreviewer(context, uri),
onDownloadAttachmentDelegateAction: (uri) =>
_downloadAttachmentInEMLPreview(context, uri),
),
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
);
}
Future<void> _openEMLPreviewer(BuildContext context, Uri? uri) async { Future<void> _openEMLPreviewer(BuildContext context, Uri? uri) async {
log('SingleEmailController::_openEMLPreviewer:uri = $uri'); log('SingleEmailController::_openEMLPreviewer:uri = $uri');
if (uri == null) return; if (uri == null) return;
@@ -1,13 +1,20 @@
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/html_content_viewer_widget.dart'; import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
import 'package:core/presentation/views/html_viewer/ios_html_content_viewer_widget.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart'; import 'package:tmail_ui_user/main/utils/app_utils.dart';
class EmailPreviewerDialogView extends StatelessWidget { class EmailPreviewerDialogView extends StatelessWidget {
final EMLPreviewer emlPreviewer; final EMLPreviewer emlPreviewer;
final ImagePaths imagePaths;
final OnMailtoDelegateAction onMailtoDelegateAction; final OnMailtoDelegateAction onMailtoDelegateAction;
final OnPreviewEMLDelegateAction onPreviewEMLDelegateAction; final OnPreviewEMLDelegateAction onPreviewEMLDelegateAction;
final OnDownloadAttachmentDelegateAction onDownloadAttachmentDelegateAction; final OnDownloadAttachmentDelegateAction onDownloadAttachmentDelegateAction;
@@ -15,6 +22,7 @@ class EmailPreviewerDialogView extends StatelessWidget {
const EmailPreviewerDialogView({ const EmailPreviewerDialogView({
super.key, super.key,
required this.emlPreviewer, required this.emlPreviewer,
required this.imagePaths,
required this.onMailtoDelegateAction, required this.onMailtoDelegateAction,
required this.onPreviewEMLDelegateAction, required this.onPreviewEMLDelegateAction,
required this.onDownloadAttachmentDelegateAction, required this.onDownloadAttachmentDelegateAction,
@@ -22,18 +30,73 @@ class EmailPreviewerDialogView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( if (PlatformInfo.isIOS) {
backgroundColor: Colors.white, return Dialog(
body: SingleChildScrollView( shape: const RoundedRectangleBorder(
child: HtmlContentViewer( borderRadius: BorderRadius.only(
contentHtml: emlPreviewer.content, topRight: Radius.circular(16),
initialWidth: context.width, topLeft: Radius.circular(16),
direction: AppUtils.getCurrentDirection(context), ),
onMailtoDelegateAction: onMailtoDelegateAction,
onPreviewEMLDelegateAction: onPreviewEMLDelegateAction,
onDownloadAttachmentDelegateAction: onDownloadAttachmentDelegateAction,
), ),
), 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 Spacer(),
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: emlPreviewer.content,
useDefaultFont: true,
direction: AppUtils.getCurrentDirection(context),
onMailtoDelegateAction: onMailtoDelegateAction,
onPreviewEMLDelegateAction: onPreviewEMLDelegateAction,
onDownloadAttachmentDelegateAction: onDownloadAttachmentDelegateAction,
),
),
],
),
),
);
} else {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: HtmlContentViewer(
contentHtml: emlPreviewer.content,
initialWidth: context.width,
useDefaultFont: true,
direction: AppUtils.getCurrentDirection(context),
onMailtoDelegateAction: onMailtoDelegateAction,
onPreviewEMLDelegateAction: onPreviewEMLDelegateAction,
onDownloadAttachmentDelegateAction: onDownloadAttachmentDelegateAction,
),
),
);
}
} }
} }