TF-3267 Implement HTML attachment preview

This commit is contained in:
DatDang
2024-12-06 10:07:53 +07:00
committed by Dat H. Pham
parent 3ddb81a8c4
commit ac91cae0db
22 changed files with 558 additions and 18 deletions
@@ -8,6 +8,7 @@ import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_
import 'package:core/presentation/utils/html_transformer/text/new_line_transformer.dart';
import 'package:core/presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart';
import 'package:core/utils/html/html_utils.dart';
import 'package:core/presentation/utils/html_transformer/dom/sanitize_hyper_link_tag_in_html_transformers.dart';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
@@ -58,6 +59,7 @@ import 'package:tmail_ui_user/features/email/domain/state/download_attachment_fo
import 'package:tmail_ui_user/features/email/domain/state/download_attachments_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/export_attachment_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_html_content_from_attachment_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart';
@@ -82,6 +84,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/parse_calendar_even
import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/send_receipt_to_sender_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/store_event_attendance_status_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart';
@@ -99,6 +102,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_lis
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_dialog_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_dialog_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/html_attachment_previewer.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/pdf_viewer/pdf_viewer.dart';
import 'package:tmail_ui_user/features/email_previewer/email_previewer_dialog_view.dart';
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
@@ -149,6 +153,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
final StoreEventAttendanceStatusInteractor _storeEventAttendanceStatusInteractor;
final ParseEmailByBlobIdInteractor _parseEmailByBlobIdInteractor;
final PreviewEmailFromEmlFileInteractor _previewEmailFromEmlFileInteractor;
final GetHtmlContentFromAttachmentInteractor _getHtmlContentFromAttachmentInteractor;
CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor;
SendReceiptToSenderInteractor? _sendReceiptToSenderInteractor;
@@ -204,6 +209,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
this._storeEventAttendanceStatusInteractor,
this._parseEmailByBlobIdInteractor,
this._previewEmailFromEmlFileInteractor,
this._getHtmlContentFromAttachmentInteractor,
);
@override
@@ -263,6 +269,19 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_handleParseEmailByBlobIdSuccess(success);
} else if (success is PreviewEmailFromEmlFileSuccess) {
_handlePreviewEmailFromEMLFileSuccess(success);
} else if (success is GetHtmlContentFromAttachmentSuccess) {
_updateAttachmentsViewState(success.attachment.blobId, Right(success));
Get.dialog(HtmlAttachmentPreviewer(
title: success.htmlAttachmentTitle,
htmlContent: success.sanitizedHtmlContent,
mailToClicked: openMailToLink,
downloadAttachmentClicked: () {
downloadAttachmentForWeb(success.attachment);
},
responsiveUtils: responsiveUtils,
));
} else if (success is GettingHtmlContentFromAttachment) {
_updateAttachmentsViewState(success.attachment.blobId, Right(success));
}
}
@@ -290,6 +309,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_handleParseEmailByBlobIdFailure(failure);
} else if (failure is PreviewEmailFromEmlFileFailure) {
_handlePreviewEmailFromEMLFileFailure(failure);
} else if (failure is GetHtmlContentFromAttachmentFailure) {
_handleGetHtmlContentFromAttachmentFailure(failure);
}
}
@@ -1155,7 +1176,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
KeyWordIdentifier.emailFlagged: success.markStarAction == MarkStarAction.markStar,
});
mailboxDashBoardController.setSelectedEmail(newEmail);
final emailId = newEmail?.id;
if (emailId == null) return;
mailboxDashBoardController.updateEmailFlagByEmailIds(
@@ -1932,11 +1953,61 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
previewPDFFileAction(context, attachment);
} else if (attachment.isEMLFile) {
previewEMLFileAction(attachment.blobId, AppLocalizations.of(context));
} else {
} else if (attachment.isHTMLFile) {
final attachmentEvaluation = evaluateAttachment(attachment);
if (!attachmentEvaluation.canDownloadAttachment) {
consumeState(Stream.value(Left(GetHtmlContentFromAttachmentFailure(
exception: null,
attachment: attachment,
))));
return;
}
consumeState(_getHtmlContentFromAttachmentInteractor.execute(
attachmentEvaluation.accountId!,
attachment,
DownloadTaskId(attachmentEvaluation.blobId!.value),
attachmentEvaluation.downloadUrl!,
TransformConfiguration.create(
customDomTransformers: [SanitizeHyperLinkTagInHtmlTransformer()],
customTextTransformers: [const StandardizeHtmlSanitizingTransformers()],
),
));
}else {
handleDownloadAttachmentAction(context, attachment);
}
}
({
bool canDownloadAttachment,
AccountId? accountId,
String? downloadUrl,
Id? blobId,
}) evaluateAttachment(
Attachment attachment,
) {
final accountId = mailboxDashBoardController.accountId.value;
final downloadUrl = mailboxDashBoardController.sessionCurrent
?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl);
final blobId = attachment.blobId;
if (accountId == null || downloadUrl == null || blobId == null) {
return (
canDownloadAttachment: false,
accountId: accountId,
downloadUrl: downloadUrl,
blobId: blobId,
);
}
return (
canDownloadAttachment: true,
accountId: accountId,
downloadUrl: downloadUrl,
blobId: blobId,
);
}
Future<void> previewPDFFileAction(BuildContext context, Attachment attachment) async {
if (accountId == null || session == null) {
appToast.showToastErrorMessage(
@@ -2121,4 +2192,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
ComposerArguments.fromMailtoUri(listEmailAddress: listEmailAddressMailTo)
);
}
void _handleGetHtmlContentFromAttachmentFailure(GetHtmlContentFromAttachmentFailure failure) {
_updateAttachmentsViewState(failure.attachment.blobId, Left(failure));
if (currentOverlayContext != null && currentContext != null) {
appToast.showToastErrorMessage(
currentOverlayContext!,
AppLocalizations.of(currentContext!).thisHtmlAttachmentCannotBePreviewed);
}
}
}