From 27f64d97a82f0530989ef42b8f1a51dfb9a7c8a0 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 14 Jan 2025 02:02:58 +0700 Subject: [PATCH] TF-3416 Handle open EML attachment in EML previewer on mobile --- .../html_content_viewer_widget.dart | 20 +++-- core/lib/utils/preview_eml_file_utils.dart | 1 + .../email_datasource_impl.dart | 22 ++++-- .../controller/single_email_controller.dart | 75 ++++++++++++------- .../email_previewer_dialog_view.dart | 3 + 5 files changed, 83 insertions(+), 38 deletions(-) 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 964a84149..00bff2d25 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 @@ -6,6 +6,7 @@ import 'package:core/utils/app_logger.dart'; import 'package:core/utils/html/html_interaction.dart'; import 'package:core/utils/html/html_utils.dart'; import 'package:core/utils/platform_info.dart'; +import 'package:core/utils/preview_eml_file_utils.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -16,6 +17,7 @@ import 'package:url_launcher/url_launcher_string.dart'; typedef OnScrollHorizontalEndAction = Function(bool leftDirection); typedef OnLoadWidthHtmlViewerAction = Function(bool isScrollPageViewActivated); typedef OnMailtoDelegateAction = Future Function(Uri? uri); +typedef OnPreviewEMLDelegateAction = Future Function(Uri? uri); class HtmlContentViewer extends StatefulWidget { @@ -26,6 +28,7 @@ class HtmlContentViewer extends StatefulWidget { final OnLoadWidthHtmlViewerAction? onLoadWidthHtmlViewer; final OnMailtoDelegateAction? onMailtoDelegateAction; final OnScrollHorizontalEndAction? onScrollHorizontalEnd; + final OnPreviewEMLDelegateAction? onPreviewEMLDelegateAction; const HtmlContentViewer({ Key? key, @@ -34,7 +37,8 @@ class HtmlContentViewer extends StatefulWidget { this.direction, this.onLoadWidthHtmlViewer, this.onMailtoDelegateAction, - this.onScrollHorizontalEnd + this.onScrollHorizontalEnd, + this.onPreviewEMLDelegateAction, }) : super(key: key); @override @@ -246,7 +250,7 @@ class _HtmlContentViewState extends State { NavigationAction navigationAction ) async { final url = navigationAction.request.url?.toString(); - + log('_HtmlContentViewState::_shouldOverrideUrlLoading: URL = $url'); if (url == null) { return NavigationActionPolicy.CANCEL; } @@ -256,9 +260,15 @@ class _HtmlContentViewState extends State { } final requestUri = Uri.parse(url); - final mailtoHandler = widget.onMailtoDelegateAction; - if (mailtoHandler != null && requestUri.isScheme('mailto')) { - await mailtoHandler(requestUri); + if (widget.onMailtoDelegateAction != null && + requestUri.isScheme('mailto')) { + await widget.onMailtoDelegateAction?.call(requestUri); + return NavigationActionPolicy.CANCEL; + } + + if (widget.onPreviewEMLDelegateAction != null && + requestUri.isScheme(PreviewEmlFileUtils.emlPreviewerScheme)) { + await widget.onPreviewEMLDelegateAction?.call(requestUri); return NavigationActionPolicy.CANCEL; } diff --git a/core/lib/utils/preview_eml_file_utils.dart b/core/lib/utils/preview_eml_file_utils.dart index 992e1daa5..9a4bafab8 100644 --- a/core/lib/utils/preview_eml_file_utils.dart +++ b/core/lib/utils/preview_eml_file_utils.dart @@ -7,6 +7,7 @@ import 'package:html/dom.dart'; import 'package:html/parser.dart'; class PreviewEmlFileUtils { + static const String emlPreviewerScheme = 'eml-previewer'; Element? _createEmailElement({ required String subjectPrefix, diff --git a/lib/features/email/data/datasource_impl/email_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_datasource_impl.dart index a157345e1..fa9d7c060 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -452,11 +452,8 @@ class EmailDataSourceImpl extends EmailDataSource { final iconBase64Data = await _fileUtils.convertImageAssetToBase64( attachment.getIcon(_imagePaths)); - final link = attachment.isEMLFile && PlatformInfo.isWeb - ? RouteUtils.createUrlWebLocationBar( - AppRoutes.emailEMLPreviewer, - previewId: attachment.blobId?.value, - ).toString() + final link = attachment.isEMLFile + ? _generateEMLAttachmentLink(attachment.blobId?.value) : null; final previewAttachment = PreviewAttachment( @@ -501,6 +498,21 @@ class EmailDataSourceImpl extends EmailDataSource { }).catchError(_exceptionThrower.throwException); } + String _generateEMLAttachmentLink(String? blobId) { + if (blobId == null) return ''; + + if (PlatformInfo.isWeb) { + return RouteUtils.createUrlWebLocationBar( + AppRoutes.emailEMLPreviewer, + previewId: blobId, + ).toString(); + } else if (PlatformInfo.isMobile) { + return '${PreviewEmlFileUtils.emlPreviewerScheme}://$blobId'; + } else { + return ''; + } + } + Future _transformEmailContent( List emailContents, Map mapCidImageDownloadUrl, diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 0f2033b40..d1bb82d91 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -93,6 +93,7 @@ import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_ev import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart'; import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_bottom_sheet_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_dialog_builder.dart'; @@ -1919,7 +1920,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { if (PlatformInfo.isWeb && PlatformInfo.isCanvasKit && attachment.isPDFFile) { previewPDFFileAction(context, attachment); } else if (attachment.isEMLFile) { - previewEMLFileAction(attachment, AppLocalizations.of(context)); + previewEMLFileAction(attachment.blobId, AppLocalizations.of(context)); } else { handleDownloadAttachmentAction(context, attachment); } @@ -1952,7 +1953,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ); } - void previewEMLFileAction(Attachment attachment, AppLocalizations appLocalizations) { + void previewEMLFileAction(Id? blobId, AppLocalizations appLocalizations) { SmartDialog.showLoading( msg: appLocalizations.loadingPleaseWait, maskColor: Colors.black38, @@ -1963,15 +1964,12 @@ class SingleEmailController extends BaseController with AppLoaderMixin { return; } - if (attachment.blobId == null) { + if (blobId == null) { consumeState(Stream.value(Left(ParseEmailByBlobIdFailure(NotFoundBlobIdException([]))))); return; } - consumeState(_parseEmailByBlobIdInteractor.execute( - accountId!, - attachment.blobId!, - )); + consumeState(_parseEmailByBlobIdInteractor.execute(accountId!, blobId)); } void _handleParseEmailByBlobIdSuccess(ParseEmailByBlobIdSuccess success) { @@ -2033,30 +2031,51 @@ class SingleEmailController extends BaseController with AppLoaderMixin { return; } - showModalBottomSheet( - context: currentContext!, - showDragHandle: true, - useSafeArea: true, - isScrollControlled: true, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20.0), - topRight: Radius.circular(20.0), - ), - ), - builder: (_) { - return DraggableScrollableSheet( - initialChildSize: 1.0, - builder: (__, ___) => EmailPreviewerDialogView( - emlPreviewer: success.emlPreviewer, - onMailtoDelegateAction: openMailToLink, - ) - ); - }, - ); + showModalSheetToPreviewEMLAttachment( + currentContext!, + success.emlPreviewer); } } + void showModalSheetToPreviewEMLAttachment( + BuildContext context, + EMLPreviewer emlPreviewer, + ) { + showModalBottomSheet( + context: context, + showDragHandle: true, + useSafeArea: true, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20.0), + topRight: Radius.circular(20.0), + ), + ), + builder: (_) { + return DraggableScrollableSheet( + initialChildSize: 1.0, + builder: (context, ___) => EmailPreviewerDialogView( + emlPreviewer: emlPreviewer, + onMailtoDelegateAction: openMailToLink, + onPreviewEMLDelegateAction: (uri) => _openEMLPreviewer(context, uri), + ), + ); + }, + ); + } + + Future _openEMLPreviewer(BuildContext context, Uri? uri) async { + log('SingleEmailController::_openEMLPreviewer:uri = $uri'); + if (uri == null) return; + + final blobId = uri.authority; + log('SingleEmailController::_openEMLPreviewer:blobId = $blobId'); + if (blobId.isEmpty) return; + + previewEMLFileAction(Id(blobId), AppLocalizations.of(context)); + } + void handleMailToAttendees(CalendarOrganizer? organizer, List? attendees) { final listEmailAddressAttendees = attendees ?.map((attendee) => EmailAddress(attendee.name?.name, attendee.mailto?.mailAddress.value)) diff --git a/lib/features/email_previewer/email_previewer_dialog_view.dart b/lib/features/email_previewer/email_previewer_dialog_view.dart index 919127bc1..85c482fa8 100644 --- a/lib/features/email_previewer/email_previewer_dialog_view.dart +++ b/lib/features/email_previewer/email_previewer_dialog_view.dart @@ -9,11 +9,13 @@ class EmailPreviewerDialogView extends StatelessWidget { final EMLPreviewer emlPreviewer; final OnMailtoDelegateAction onMailtoDelegateAction; + final OnPreviewEMLDelegateAction onPreviewEMLDelegateAction; const EmailPreviewerDialogView({ super.key, required this.emlPreviewer, required this.onMailtoDelegateAction, + required this.onPreviewEMLDelegateAction, }); @override @@ -26,6 +28,7 @@ class EmailPreviewerDialogView extends StatelessWidget { initialWidth: context.width, direction: AppUtils.getCurrentDirection(context), onMailtoDelegateAction: onMailtoDelegateAction, + onPreviewEMLDelegateAction: onPreviewEMLDelegateAction, ), ), );