diff --git a/core/lib/core.dart b/core/lib/core.dart index d05cc3f27..d354c2689 100644 --- a/core/lib/core.dart +++ b/core/lib/core.dart @@ -35,6 +35,8 @@ export 'presentation/utils/app_toast.dart'; export 'presentation/utils/html_transformer/html_transform.dart'; export 'presentation/utils/html_transformer/transform_configuration.dart'; export 'presentation/utils/html_transformer/text/persist_preformatted_text_transformer.dart'; +export 'presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart'; +export 'presentation/utils/html_transformer/dom/sanitize_hyper_link_tag_in_html_transformers.dart'; export 'data/utils/device_manager.dart'; export 'utils/app_logger.dart'; export 'utils/benchmark.dart'; @@ -56,6 +58,7 @@ export 'utils/mail/named_address.dart'; export 'utils/application_manager.dart'; export 'utils/preview_eml_file_utils.dart'; export 'utils/logger/log_tracking.dart'; +export 'utils/html/html_utils.dart'; // Views export 'presentation/views/text/slogan_builder.dart'; diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index 3ef7133a2..1216917b3 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -26,11 +26,9 @@ import 'package:tmail_ui_user/features/email/data/datasource/print_file_datasour import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart'; import 'package:tmail_ui_user/features/email/domain/model/email_print.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart'; -import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/restore_deleted_message_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/view_entire_message_request.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; -import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; @@ -496,51 +494,6 @@ class EmailRepositoryImpl extends EmailRepository { return _printFileDataSource.printEmail(emailPrint); } - @override - Future> parseEmailByBlobIds(AccountId accountId, Set blobIds) { - return emailDataSource[DataSourceType.network]!.parseEmailByBlobIds(accountId, blobIds); - } - - @override - Future generatePreviewEmailEMLContent(PreviewEmailEMLRequest previewEmailEMLRequest) { - return emailDataSource[DataSourceType.network]!.generatePreviewEmailEMLContent(previewEmailEMLRequest); - } - - @override - Future sharePreviewEmailEMLContent(EMLPreviewer emlPreviewer) { - return emailDataSource[DataSourceType.local]!.sharePreviewEmailEMLContent(emlPreviewer); - } - - @override - Future getPreviewEmailEMLContentShared(String keyStored) { - return emailDataSource[DataSourceType.local]!.getPreviewEmailEMLContentShared(keyStored); - } - - @override - Future removePreviewEmailEMLContentShared(String keyStored) { - return emailDataSource[DataSourceType.local]!.removePreviewEmailEMLContentShared(keyStored); - } - - @override - Future storePreviewEMLContentToSessionStorage(EMLPreviewer emlPreviewer) { - return emailDataSource[DataSourceType.session]!.storePreviewEMLContentToSessionStorage(emlPreviewer); - } - - @override - Future getPreviewEMLContentInMemory(String keyStored) { - return emailDataSource[DataSourceType.session]!.getPreviewEMLContentInMemory(keyStored); - } - - @override - Future sanitizeHtmlContent( - String htmlContent, - TransformConfiguration configuration - ) { - return _htmlDataSource.transformHtmlEmailContent( - htmlContent, - configuration); - } - @override Future exportAllAttachments( AccountId accountId, diff --git a/lib/features/email/domain/model/preview_email_eml_request.dart b/lib/features/email/domain/model/preview_email_eml_request.dart index 74e521194..f2c762343 100644 --- a/lib/features/email/domain/model/preview_email_eml_request.dart +++ b/lib/features/email/domain/model/preview_email_eml_request.dart @@ -2,11 +2,13 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class PreviewEmailEMLRequest with EquatableMixin { final AccountId accountId; + final Session session; final String ownEmailAddress; final Id blobId; final Email email; @@ -17,6 +19,7 @@ class PreviewEmailEMLRequest with EquatableMixin { PreviewEmailEMLRequest({ required this.accountId, + required this.session, required this.ownEmailAddress, required this.blobId, required this.email, @@ -35,6 +38,7 @@ class PreviewEmailEMLRequest with EquatableMixin { @override List get props => [ accountId, + session, ownEmailAddress, blobId, email, diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 64e59e10b..6c4e3ece4 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -21,10 +21,8 @@ import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart' import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart'; import 'package:tmail_ui_user/features/email/domain/model/email_print.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart'; -import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/restore_deleted_message_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/view_entire_message_request.dart'; -import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; abstract class EmailRepository { @@ -172,26 +170,6 @@ abstract class EmailRepository { Future printEmail(EmailPrint emailPrint); - Future> parseEmailByBlobIds(AccountId accountId, Set blobIds); - - Future generatePreviewEmailEMLContent(PreviewEmailEMLRequest previewEmailEMLRequest); - - Future sharePreviewEmailEMLContent(EMLPreviewer emlPreviewer); - - Future getPreviewEmailEMLContentShared(String keyStored); - - Future removePreviewEmailEMLContentShared(String keyStored); - - Future storePreviewEMLContentToSessionStorage(EMLPreviewer emlPreviewer); - - Future getPreviewEMLContentInMemory(String keyStored); - - Future sanitizeHtmlContent( - String htmlContent, - TransformConfiguration configuration); - - - Future exportAllAttachments( AccountId accountId, EmailId emailId, diff --git a/lib/features/email/domain/state/parse_email_by_blob_id_state.dart b/lib/features/email/domain/state/parse_email_by_blob_id_state.dart index f4214cb4c..0d528b6f5 100644 --- a/lib/features/email/domain/state/parse_email_by_blob_id_state.dart +++ b/lib/features/email/domain/state/parse_email_by_blob_id_state.dart @@ -1,21 +1,37 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; class ParsingEmailByBlobId extends LoadingState {} class ParseEmailByBlobIdSuccess extends UIState { - + final AccountId? accountId; + final Session? session; + final String ownEmailAddress; final Email email; final Id blobId; - ParseEmailByBlobIdSuccess(this.email, this.blobId); + ParseEmailByBlobIdSuccess({ + required this.email, + required this.blobId, + required this.accountId, + required this.session, + required this.ownEmailAddress, + }); @override - List get props => [email, blobId]; + List get props => [ + email, + blobId, + accountId, + session, + ownEmailAddress, + ]; } class ParseEmailByBlobIdFailure extends FeatureFailure { ParseEmailByBlobIdFailure(dynamic exception) : super(exception: exception); -} \ No newline at end of file +} diff --git a/lib/features/email/domain/state/preview_email_from_eml_file_state.dart b/lib/features/email/domain/state/preview_email_from_eml_file_state.dart index 30abb03aa..89bb7339b 100644 --- a/lib/features/email/domain/state/preview_email_from_eml_file_state.dart +++ b/lib/features/email/domain/state/preview_email_from_eml_file_state.dart @@ -1,20 +1,34 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; class PreviewingEmailFromEmlFile extends LoadingState {} class PreviewEmailFromEmlFileSuccess extends UIState { - final EMLPreviewer emlPreviewer; + final AccountId? accountId; + final Session? session; + final String ownEmailAddress; - PreviewEmailFromEmlFileSuccess(this.emlPreviewer); + PreviewEmailFromEmlFileSuccess( + this.emlPreviewer, + this.accountId, + this.session, + this.ownEmailAddress, + ); @override - List get props => [emlPreviewer]; + List get props => [ + emlPreviewer, + accountId, + session, + ownEmailAddress, + ]; } class PreviewEmailFromEmlFileFailure extends FeatureFailure { - - PreviewEmailFromEmlFileFailure(dynamic exception) : super(exception: exception); -} \ No newline at end of file + PreviewEmailFromEmlFileFailure(dynamic exception) + : super(exception: exception); +} diff --git a/lib/features/email/domain/state/preview_pdf_file_state.dart b/lib/features/email/domain/state/preview_pdf_file_state.dart deleted file mode 100644 index c6d476522..000000000 --- a/lib/features/email/domain/state/preview_pdf_file_state.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:core/presentation/state/failure.dart'; - -class PreviewPDFFileFailure extends FeatureFailure { - - PreviewPDFFileFailure(dynamic exception) : super(exception: exception); -} \ No newline at end of file diff --git a/lib/features/email/domain/usecases/download_attachment_for_web_interactor.dart b/lib/features/email/domain/usecases/download_attachment_for_web_interactor.dart index f625e0874..5ec2edfa0 100644 --- a/lib/features/email/domain/usecases/download_attachment_for_web_interactor.dart +++ b/lib/features/email/domain/usecases/download_attachment_for_web_interactor.dart @@ -18,13 +18,13 @@ import 'package:tmail_ui_user/features/login/domain/repository/credential_reposi import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class DownloadAttachmentForWebInteractor { - final DownloadRepository _downloadRepository; + final DownloadRepository downloadRepository; final CredentialRepository credentialRepository; final AccountRepository _accountRepository; final AuthenticationOIDCRepository _authenticationOIDCRepository; DownloadAttachmentForWebInteractor( - this._downloadRepository, + this.downloadRepository, this.credentialRepository, this._accountRepository, this._authenticationOIDCRepository); @@ -56,7 +56,7 @@ class DownloadAttachmentForWebInteractor { ); } - final bytesDownloaded = await _downloadRepository.downloadAttachmentForWeb( + final bytesDownloaded = await downloadRepository.downloadAttachmentForWeb( taskId, attachment, accountId, diff --git a/lib/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart b/lib/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart index 3e4e5e262..dfd6165aa 100644 --- a/lib/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart +++ b/lib/features/email/domain/usecases/get_html_content_from_attachment_interactor.dart @@ -9,7 +9,6 @@ import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:model/download/download_task_id.dart'; import 'package:model/email/attachment.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_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/usecases/download_attachment_for_web_interactor.dart'; @@ -17,11 +16,9 @@ import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment class GetHtmlContentFromAttachmentInteractor { GetHtmlContentFromAttachmentInteractor( this._downloadAttachmentForWebInteractor, - this._emailRepository, ); final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor; - final EmailRepository _emailRepository; Stream> execute( AccountId accountId, @@ -89,10 +86,10 @@ class GetHtmlContentFromAttachmentInteractor { Attachment attachment, ) async { try { - final sanitizedHtmlContent = await _emailRepository.sanitizeHtmlContent( - htmlContent, - transformConfiguration, - ); + final sanitizedHtmlContent = await _downloadAttachmentForWebInteractor + .downloadRepository + .sanitizeHtmlContent(htmlContent, transformConfiguration); + return Right(GetHtmlContentFromAttachmentSuccess( sanitizedHtmlContent: sanitizedHtmlContent, htmlAttachmentTitle: attachment.generateFileName(), diff --git a/lib/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart b/lib/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart index 5cc7df496..42d73f293 100644 --- a/lib/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart +++ b/lib/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart @@ -1,19 +1,19 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_preview_email_eml_content_shared_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class GetPreviewEmailEMLContentSharedInteractor { - final EmailRepository _emailRepository; + final DownloadRepository _downloadRepository; - const GetPreviewEmailEMLContentSharedInteractor(this._emailRepository); + const GetPreviewEmailEMLContentSharedInteractor(this._downloadRepository); Stream> execute(String keyStored) async* { try { yield Right(GettingPreviewEmailEMLContentShared()); - final previewEMLContent = await _emailRepository + final previewEMLContent = await _downloadRepository .getPreviewEmailEMLContentShared(keyStored); yield Right(GetPreviewEmailEMLContentSharedSuccess(previewEMLContent)); diff --git a/lib/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart b/lib/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart index 77eb82d55..4b523db7f 100644 --- a/lib/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart +++ b/lib/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart @@ -1,18 +1,18 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_preview_eml_content_in_memory_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class GetPreviewEmlContentInMemoryInteractor { - final EmailRepository _emailRepository; + final DownloadRepository _downloadRepository; - const GetPreviewEmlContentInMemoryInteractor(this._emailRepository); + const GetPreviewEmlContentInMemoryInteractor(this._downloadRepository); Stream> execute(String keyStored) async* { try { yield Right(GettingPreviewEMLContentInMemory()); - final emlPreviewer = await _emailRepository.getPreviewEMLContentInMemory(keyStored); + final emlPreviewer = await _downloadRepository.getPreviewEMLContentInMemory(keyStored); yield Right(GetPreviewEMLContentInMemorySuccess(emlPreviewer)); } catch (e) { yield Left(GetPreviewEMLContentInMemoryFailure( diff --git a/lib/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart b/lib/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart index 97b04ba42..416f44f13 100644 --- a/lib/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart +++ b/lib/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart @@ -1,21 +1,23 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/move_preview_eml_content_from_persistent_to_memory_state.dart'; import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class MovePreviewEmlContentFromPersistentToMemoryInteractor { - final EmailRepository _emailRepository; + final DownloadRepository _downloadRepository; - const MovePreviewEmlContentFromPersistentToMemoryInteractor(this._emailRepository); + const MovePreviewEmlContentFromPersistentToMemoryInteractor( + this._downloadRepository, + ); Stream> execute(EMLPreviewer emlPreviewer) async* { try { yield Right(MovingPreviewEmailEMLContentFromPersistentToMemory()); await Future.wait([ - _emailRepository.removePreviewEmailEMLContentShared(emlPreviewer.id), - _emailRepository.storePreviewEMLContentToSessionStorage(emlPreviewer), + _downloadRepository.removePreviewEmailEMLContentShared(emlPreviewer.id), + _downloadRepository.storePreviewEMLContentToSessionStorage(emlPreviewer), ]); yield Right(MovePreviewEmailEMLContentFromPersistentToMemorySuccess()); } catch (e) { diff --git a/lib/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart b/lib/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart index 45748c59c..a920c859f 100644 --- a/lib/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart +++ b/lib/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart @@ -3,29 +3,38 @@ import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class ParseEmailByBlobIdInteractor { - final EmailRepository _emailRepository; + final DownloadRepository _downloadRepository; - const ParseEmailByBlobIdInteractor(this._emailRepository); + const ParseEmailByBlobIdInteractor(this._downloadRepository); - Stream> execute(AccountId accountId, Id blobId) async* { + Stream> execute( + AccountId accountId, + Session session, + String ownEmailAddress, + Id blobId, + ) async* { try { yield Right(ParsingEmailByBlobId()); - final emailParsed = await _emailRepository.parseEmailByBlobIds( + final emailParsed = await _downloadRepository.parseEmailByBlobIds( accountId, {blobId}, ); yield Right(ParseEmailByBlobIdSuccess( - emailParsed.first, - blobId, + email: emailParsed.first, + blobId: blobId, + session: session, + accountId: accountId, + ownEmailAddress: ownEmailAddress, )); } catch (e) { yield Left(ParseEmailByBlobIdFailure(e)); } } -} \ No newline at end of file +} diff --git a/lib/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart b/lib/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart index 4676d275b..15a38ebc3 100644 --- a/lib/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart +++ b/lib/features/email/domain/usecases/preview_email_from_eml_file_interactor.dart @@ -3,14 +3,14 @@ import 'package:core/presentation/state/success.dart'; import 'package:core/utils/platform_info.dart'; import 'package:dartz/dartz.dart'; import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart'; import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class PreviewEmailFromEmlFileInteractor { - final EmailRepository _emailRepository; + final DownloadRepository _downloadRepository; - const PreviewEmailFromEmlFileInteractor(this._emailRepository); + const PreviewEmailFromEmlFileInteractor(this._downloadRepository); Stream> execute( PreviewEmailEMLRequest previewEmailEMLRequest, @@ -18,7 +18,7 @@ class PreviewEmailFromEmlFileInteractor { try { yield Right(PreviewingEmailFromEmlFile()); - final previewEMLContent = await _emailRepository + final previewEMLContent = await _downloadRepository .generatePreviewEmailEMLContent(previewEmailEMLRequest); final emlPreviewer = EMLPreviewer( @@ -29,13 +29,22 @@ class PreviewEmailFromEmlFileInteractor { if (PlatformInfo.isWeb) { if (previewEmailEMLRequest.isShared) { - await _emailRepository.sharePreviewEmailEMLContent(emlPreviewer); + await _downloadRepository.sharePreviewEmailEMLContent(emlPreviewer); } else { - await _emailRepository.storePreviewEMLContentToSessionStorage(emlPreviewer); + await _downloadRepository.storePreviewEMLContentToSessionStorage( + emlPreviewer, + ); } } - yield Right(PreviewEmailFromEmlFileSuccess(emlPreviewer)); + yield Right( + PreviewEmailFromEmlFileSuccess( + emlPreviewer, + previewEmailEMLRequest.accountId, + previewEmailEMLRequest.session, + previewEmailEMLRequest.ownEmailAddress, + ), + ); } catch (e) { yield Left(PreviewEmailFromEmlFileFailure(e)); } diff --git a/lib/features/email/domain/usecases/remove_preview_email_eml_content_shared_interactor.dart b/lib/features/email/domain/usecases/remove_preview_email_eml_content_shared_interactor.dart index 68d88f589..cf410104d 100644 --- a/lib/features/email/domain/usecases/remove_preview_email_eml_content_shared_interactor.dart +++ b/lib/features/email/domain/usecases/remove_preview_email_eml_content_shared_interactor.dart @@ -1,18 +1,18 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:dartz/dartz.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/remove_preview_email_eml_content_shared_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class RemovePreviewEmailEmlContentSharedInteractor { - final EmailRepository _emailRepository; + final DownloadRepository _downloadRepository; - const RemovePreviewEmailEmlContentSharedInteractor(this._emailRepository); + const RemovePreviewEmailEmlContentSharedInteractor(this._downloadRepository); Stream> execute(String keyStored) async* { try { yield Right(RemovingPreviewEmailEMLContentShared()); - await _emailRepository.removePreviewEmailEMLContentShared(keyStored); + await _downloadRepository.removePreviewEmailEMLContentShared(keyStored); yield Right(RemovePreviewEmailEMLContentSharedSuccess()); } catch (e) { yield Left(RemovePreviewEmailEMLContentSharedFailure(e)); diff --git a/lib/features/email/presentation/bindings/email_bindings.dart b/lib/features/email/presentation/bindings/email_bindings.dart index 3f663b602..53ceb3495 100644 --- a/lib/features/email/presentation/bindings/email_bindings.dart +++ b/lib/features/email/presentation/bindings/email_bindings.dart @@ -3,11 +3,8 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachments_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_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/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; -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/store_opened_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/bindings/email_interactor_bindings.dart'; @@ -30,9 +27,6 @@ class EmailBindings extends Bindings { Get.find(), Get.find(), Get.find(), - Get.find(), - Get.find(), - Get.find(), Get.find(), currentEmailId: currentEmailId, ), tag: tag); diff --git a/lib/features/email/presentation/bindings/email_interactor_bindings.dart b/lib/features/email/presentation/bindings/email_interactor_bindings.dart index a084986b9..03492864b 100644 --- a/lib/features/email/presentation/bindings/email_interactor_bindings.dart +++ b/lib/features/email/presentation/bindings/email_interactor_bindings.dart @@ -16,18 +16,14 @@ import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachments_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_entire_message_as_document_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/get_stored_email_state_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; -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/store_opened_email_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart'; @@ -126,13 +122,7 @@ class EmailInteractorBindings extends InteractorsBindings { Get.lazyPut(() => GetStoredEmailStateInteractor(Get.find())); Get.lazyPut(() => StoreOpenedEmailInteractor(Get.find())); Get.lazyPut(() => PrintEmailInteractor(Get.find())); - Get.lazyPut(() => ParseEmailByBlobIdInteractor(Get.find())); - Get.lazyPut(() => PreviewEmailFromEmlFileInteractor(Get.find())); IdentityInteractorsBindings().dependencies(); - Get.lazyPut(() => GetHtmlContentFromAttachmentInteractor( - Get.find(), - Get.find(), - )); Get.lazyPut(() => ExportAllAttachmentsInteractor( Get.find(), Get.find(), diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index c791d076e..775a4ea38 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -2,15 +2,11 @@ import 'dart:async'; import 'dart:io'; import 'package:core/core.dart'; -import 'package:core/presentation/utils/html_transformer/dom/sanitize_hyper_link_tag_in_html_transformers.dart'; import 'package:core/presentation/utils/html_transformer/text/new_line_transformer.dart'; import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_unescape_html_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:dartz/dartz.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_file_dialog/flutter_file_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -36,12 +32,10 @@ import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart'; import 'package:tmail_ui_user/features/base/state/button_state.dart'; -import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart'; import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart'; import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart'; import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart'; -import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/send_receipt_to_sender_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/view_entire_message_request.dart'; import 'package:tmail_ui_user/features/email/domain/state/calendar_event_accept_state.dart'; @@ -54,13 +48,9 @@ import 'package:tmail_ui_user/features/email/domain/state/export_all_attachments 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_entire_message_as_document_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/parse_calendar_event_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart'; -import 'package:tmail_ui_user/features/email/domain/state/preview_pdf_file_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/print_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/send_receipt_to_sender_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; @@ -71,13 +61,10 @@ import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachme import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_entire_message_as_document_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/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/maybe_calendar_event_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/parse_calendar_event_interactor.dart'; -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/send_receipt_to_sender_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart'; @@ -87,8 +74,8 @@ import 'package:tmail_ui_user/features/email/presentation/bindings/mdn_interacto import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_attendee_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_organizer_extension.dart'; -import 'package:tmail_ui_user/features/email/presentation/extensions/handle_open_attachment_list_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/handle_mail_action_by_shortcut_action_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/extensions/handle_open_attachment_list_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/update_attendance_status_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; @@ -97,15 +84,13 @@ import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscrib import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.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'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_download_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; @@ -133,8 +118,6 @@ import 'package:tmail_ui_user/main/utils/app_utils.dart'; class SingleEmailController extends BaseController with AppLoaderMixin { final mailboxDashBoardController = Get.find(); - final _downloadManager = Get.find(); - final _printUtils = Get.find(); final GetEmailContentInteractor _getEmailContentInteractor; final MarkAsEmailReadInteractor _markAsEmailReadInteractor; @@ -143,9 +126,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; final StoreOpenedEmailInteractor _storeOpenedEmailInteractor; final PrintEmailInteractor _printEmailInteractor; - final ParseEmailByBlobIdInteractor _parseEmailByBlobIdInteractor; - final PreviewEmailFromEmlFileInteractor _previewEmailFromEmlFileInteractor; - final GetHtmlContentFromAttachmentInteractor _getHtmlContentFromAttachmentInteractor; final ExportAllAttachmentsInteractor _exportAllAttachmentsInteractor; final EmailId? _currentEmailId; @@ -218,9 +198,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { this._getAllIdentitiesInteractor, this._storeOpenedEmailInteractor, this._printEmailInteractor, - this._parseEmailByBlobIdInteractor, - this._previewEmailFromEmlFileInteractor, - this._getHtmlContentFromAttachmentInteractor, this._exportAllAttachmentsInteractor, { EmailId? currentEmailId, }) : _currentEmailId = currentEmailId; @@ -281,24 +258,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _handlePrintEmailSuccess(success); } else if (success is CalendarEventReplySuccess) { calendarEventSuccess(success); - } else if (success is ParseEmailByBlobIdSuccess) { - _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: () { - if (currentContext == null || attachments.isEmpty) return; - handleDownloadAttachmentAction(success.attachment); - }, - responsiveUtils: responsiveUtils, - )); - } else if (success is GettingHtmlContentFromAttachment) { - _updateAttachmentsViewState(success.attachment.blobId, Right(success)); } else { super.handleSuccessViewState(success); } @@ -320,14 +279,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _showMessageWhenEmailPrintingFailed(failure); } else if (failure is CalendarEventReplyFailure) { _calendarEventFailure(failure); - } else if (failure is ParseEmailByBlobIdFailure) { - _handleParseEmailByBlobIdFailure(failure); - } else if (failure is PreviewEmailFromEmlFileFailure) { - _handlePreviewEmailFromEMLFileFailure(failure); - } else if (failure is GetHtmlContentFromAttachmentFailure) { - _handleGetHtmlContentFromAttachmentFailure(failure); - } else if (failure is PreviewPDFFileFailure) { - _handlePreviewPDFFileFailure(failure); } else { super.handleFailureViewState(failure); } @@ -427,7 +378,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mailboxDashBoardController.downloadController.downloadUIAction, (action) { if (action is UpdateAttachmentsViewStateAction) { - _updateAttachmentsViewState(action.blobId, Right(action.success)); + _updateAttachmentsViewState(action.blobId, action.viewState); } }, )); @@ -921,20 +872,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin { return isDownloadAllSupported() && attachments.length > 1; } - void _downloadPDFFile(Uint8List bytes, String fileName) { - _downloadManager.createAnchorElementDownloadFileWeb(bytes, fileName); - } - - void _printPDFFile(Uint8List bytes, String fileName) async { - await _printUtils.printPDFFile(bytes, fileName); - } - void _updateAttachmentsViewState( Id? attachmentBlobId, - Either viewState) { - if (attachmentBlobId != null) { - attachmentsViewState[attachmentBlobId] = viewState; - } + Either viewState, + ) { + if (attachmentBlobId != null) { + attachmentsViewState[attachmentBlobId] = viewState; + } } void moveToMailbox(PresentationEmail email) async { @@ -1156,23 +1100,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ); } - Future openMailToLink(Uri? uri) async { - if (uri == null) return; - - final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(uri.toString()); - log('SingleEmailController::openMailToLink(): ${uri.toString()}'); - if (!RouteUtils.canOpenComposerFromNavigationRouter(navigationRouter)) return; - - mailboxDashBoardController.openComposer( - ComposerArguments.fromMailtoUri( - listEmailAddress: navigationRouter.listEmailAddress, - cc: navigationRouter.cc, - bcc: navigationRouter.bcc, - subject: navigationRouter.subject, - body: navigationRouter.body - ) - ); - } + Future openMailToLink(Uri? uri) => + mailboxDashBoardController.openMailToLink(uri); void deleteEmailPermanently(PresentationEmail email) { emailActionReactor.deleteEmailPermanently( @@ -1697,7 +1626,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } else if (PlatformInfo.isMobile) { exportAttachment(attachment); } else { - log('EmailView::handleDownloadAttachmentAction: THE PLATFORM IS SUPPORTED'); + log('$runtimeType::handleDownloadAttachmentAction: THE PLATFORM IS SUPPORTED'); } } @@ -1715,258 +1644,18 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void handleViewAttachmentAction(BuildContext context, Attachment attachment) { - if (PlatformInfo.isWeb && PlatformInfo.isCanvasKit && attachment.isPDFFile) { - previewPDFFileAction(context, attachment); - } else if (attachment.isEMLFile) { - previewEMLFileAction(attachment.blobId, AppLocalizations.of(context)); - } 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( - attachment, - previewerSupported: attachmentPreviewSupported(attachment), - ); - } - } - - bool attachmentPreviewSupported(Attachment attachment) { - return attachment.isImage || attachment.isText || attachment.isJson; - } - - ({ - bool canDownloadAttachment, - AccountId? accountId, - String? downloadUrl, - Id? blobId, - }) evaluateAttachment( - Attachment attachment, - ) { - final accountId = mailboxDashBoardController.accountId.value; - dynamic downloadUrl; - try { - downloadUrl = mailboxDashBoardController.sessionCurrent - ?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); - } catch (e) { - logError('SingleEmailController::_getEmailContentAction(): $e'); - downloadUrl = null; - } - 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 previewPDFFileAction(BuildContext context, Attachment attachment) async { - if (accountId == null || session == null) { - appToast.showToastErrorMessage( - context, - AppLocalizations.of(context).noPreviewAvailable); - return; - } - - try { - final downloadUrl = session!.getDownloadUrl( - jmapUrl: dynamicUrlInterceptors.jmapUrl, - ); - - await Get.generalDialog( - barrierColor: Colors.black.withValues(alpha: 0.8), - pageBuilder: (_, __, ___) { - return PointerInterceptor( - child: PDFViewer( - attachment: attachment, - accountId: accountId!, - downloadUrl: downloadUrl, - downloadAction: _downloadPDFFile, - printAction: _printPDFFile, - ) - ); - }, - ); - } catch (e) { - logError('SingleEmailController::previewPDFFileAction(): $e'); - consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(e)))); - } - } - - void previewEMLFileAction(Id? blobId, AppLocalizations appLocalizations) { - SmartDialog.showLoading( - msg: appLocalizations.loadingPleaseWait, - maskColor: Colors.black38, - ); - - if (accountId == null) { - consumeState(Stream.value(Left(ParseEmailByBlobIdFailure(NotFoundAccountIdException())))); - return; - } - - if (blobId == null) { - consumeState(Stream.value(Left(ParseEmailByBlobIdFailure(NotFoundBlobIdException([]))))); - return; - } - - consumeState(_parseEmailByBlobIdInteractor.execute(accountId!, blobId)); - } - - void _handleParseEmailByBlobIdSuccess(ParseEmailByBlobIdSuccess success) { - if (session == null) { - consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(NotFoundSessionException())))); - return; - } - - if (accountId == null) { - consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(NotFoundAccountIdException())))); - return; - } - - if (currentContext == null) { - consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(NotFoundContextException())))); - return; - } - - try { - consumeState(_previewEmailFromEmlFileInteractor.execute( - PreviewEmailEMLRequest( - accountId: accountId!, - ownEmailAddress: ownEmailAddress, - blobId: success.blobId, - email: success.email, - locale: Localizations.localeOf(currentContext!), - appLocalizations: AppLocalizations.of(currentContext!), - baseDownloadUrl: session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl), - ), - )); - } catch (e) { - logError('SingleEmailController::_handleParseEmailByBlobIdSuccess(): $e'); - consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(e)))); - } - } - - void _handleParseEmailByBlobIdFailure(ParseEmailByBlobIdFailure failure) { - SmartDialog.dismiss(); - toastManager.showMessageFailure(failure); - } - - void _handlePreviewPDFFileFailure(PreviewPDFFileFailure failure) { - SmartDialog.dismiss(); - toastManager.showMessageFailure(failure); - } - - void _handlePreviewEmailFromEMLFileFailure(PreviewEmailFromEmlFileFailure failure) { - SmartDialog.dismiss(); - toastManager.showMessageFailure(failure); - } - - void _handlePreviewEmailFromEMLFileSuccess(PreviewEmailFromEmlFileSuccess success) { - SmartDialog.dismiss(); - - if (PlatformInfo.isWeb) { - bool isOpen = HtmlUtils.openNewWindowByUrl( - RouteUtils.createUrlWebLocationBar( - AppRoutes.emailEMLPreviewer, - previewId: success.emlPreviewer.id - ).toString(), - ); - - if (!isOpen) { - toastManager.showMessageFailure(PreviewEmailFromEmlFileFailure(CannotOpenNewWindowException())); - } - } else if (PlatformInfo.isMobile) { - if (currentContext == null) { - toastManager.showMessageFailure(PreviewEmailFromEmlFileFailure(NotFoundContextException())); - return; - } - - if (PlatformInfo.isAndroid) { - showModalSheetToPreviewEMLAttachment( - currentContext!, - success.emlPreviewer, - ); - } if (PlatformInfo.isIOS) { - showDialogToPreviewEMLAttachment( - currentContext!, - success.emlPreviewer, - ); - } - } - } - - void showModalSheetToPreviewEMLAttachment( - BuildContext context, - EMLPreviewer emlPreviewer, - ) { - showModalBottomSheet( + mailboxDashBoardController.previewAttachmentAction( 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, - imagePaths: imagePaths, - onMailtoDelegateAction: openMailToLink, - onPreviewEMLDelegateAction: (uri) => _openEMLPreviewer(context, uri), - onDownloadAttachmentDelegateAction: (uri) => - _downloadAttachmentInEMLPreview(uri), - ), + attachment: attachment, + onDownloadAttachment: (attachment) { + handleDownloadAttachmentAction( + attachment, + previewerSupported: attachment.isPreviewSupported, ); }, ); } - void showDialogToPreviewEMLAttachment(BuildContext context, EMLPreviewer emlPreviewer) { - Get.dialog( - EmailPreviewerDialogView( - emlPreviewer: emlPreviewer, - imagePaths: imagePaths, - onMailtoDelegateAction: openMailToLink, - onPreviewEMLDelegateAction: (uri) => _openEMLPreviewer(context, uri), - onDownloadAttachmentDelegateAction: (uri) => - _downloadAttachmentInEMLPreview(uri), - ), - barrierColor: AppColor.colorDefaultCupertinoActionSheet, - ); - } - Future _openEMLPreviewer(BuildContext context, Uri? uri) async { log('SingleEmailController::_openEMLPreviewer:uri = $uri'); if (uri == null) return; @@ -1975,7 +1664,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin { log('SingleEmailController::_openEMLPreviewer:blobId = $blobId'); if (blobId.isEmpty) return; - previewEMLFileAction(Id(blobId), AppLocalizations.of(context)); + mailboxDashBoardController.previewEMLFileAction( + appLocalizations: AppLocalizations.of(context), + blobId: Id(blobId), + ); } Future _downloadAttachmentInEMLPreview(Uri? uri) async { @@ -2009,15 +1701,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ); } - void _handleGetHtmlContentFromAttachmentFailure(GetHtmlContentFromAttachmentFailure failure) { - _updateAttachmentsViewState(failure.attachment.blobId, Left(failure)); - if (currentOverlayContext != null && currentContext != null) { - appToast.showToastErrorMessage( - currentOverlayContext!, - AppLocalizations.of(currentContext!).thisHtmlAttachmentCannotBePreviewed); - } - } - void onHtmlContentClippedAction(bool isClipped) { log('SingleEmailController::onHtmlContentClippedAction:isClipped = $isClipped'); isEmailContentClipped.value = isClipped; @@ -2054,13 +1737,17 @@ class SingleEmailController extends BaseController with AppLoaderMixin { onSuccess: (success) { SmartDialog.dismiss(); - showDialogToPreviewEMLAttachment( - context, - EMLPreviewer( + mailboxDashBoardController.showDialogToPreviewEMLAttachment( + context: context, + emlPreviewer: EMLPreviewer( id: presentationEmail.id?.asString ?? '', title: presentationEmail.subject ?? '', content: success.messageDocument, ), + imagePaths: imagePaths, + onMailtoAction: openMailToLink, + onPreviewAction: (uri) => _openEMLPreviewer(context, uri), + onDownloadAction: _downloadAttachmentInEMLPreview, ); }, onFailure: (_) { diff --git a/lib/features/email/presentation/extensions/attachment_extension.dart b/lib/features/email/presentation/extensions/attachment_extension.dart index 97509687a..bb309a16b 100644 --- a/lib/features/email/presentation/extensions/attachment_extension.dart +++ b/lib/features/email/presentation/extensions/attachment_extension.dart @@ -48,4 +48,8 @@ extension AttachmentExtension on Attachment { bool get isJson => (type?.isJsonFile() ?? false) || name?.endsWith('.json') == true; + + bool get isPreviewSupported { + return isImage || isText || isJson || isPDFFile || isEMLFile || isHTMLFile; + } } \ No newline at end of file diff --git a/lib/features/email/presentation/mixin/preview_attachment_mixin.dart b/lib/features/email/presentation/mixin/preview_attachment_mixin.dart new file mode 100644 index 000000000..842ab7e11 --- /dev/null +++ b/lib/features/email/presentation/mixin/preview_attachment_mixin.dart @@ -0,0 +1,444 @@ +import 'dart:typed_data'; + +import 'package:core/core.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:model/download/download_task_id.dart'; +import 'package:model/email/attachment.dart'; +import 'package:model/extensions/session_extension.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart'; +import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.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/parse_email_by_blob_id_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.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/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/presentation/extensions/attachment_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/eml_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'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:tmail_ui_user/main/routes/app_routes.dart'; +import 'package:tmail_ui_user/main/routes/route_utils.dart'; +import 'package:tmail_ui_user/main/utils/toast_manager.dart'; + +typedef OnDownloadAttachmentAction = void Function(Attachment attachment); + +mixin PreviewAttachmentMixin { + final DownloadManager _downloadManager = Get.find(); + final PrintUtils _printUtils = Get.find(); + final AppToast _appToast = Get.find(); + final ToastManager _toastManager = Get.find(); + final DynamicUrlInterceptors _dynamicUrlInterceptors = + Get.find(); + + void previewAttachmentAction({ + required BuildContext context, + required Attachment attachment, + required AccountId? accountId, + required Session? session, + required String ownEmailAddress, + required BaseController controller, + required ParseEmailByBlobIdInteractor parseEmailInteractor, + required GetHtmlContentFromAttachmentInteractor getHtmlInteractor, + required OnDownloadAttachmentAction onDownloadAttachment, + }) { + if (PlatformInfo.isWeb && attachment.isPDFFile) { + _previewPDFFile( + context: context, + attachment: attachment, + accountId: accountId, + session: session, + ); + } else if (attachment.isEMLFile) { + previewEMLFileAction( + appLocalizations: AppLocalizations.of(context), + accountId: accountId, + session: session, + ownEmailAddress: ownEmailAddress, + blobId: attachment.blobId, + controller: controller, + parseEmailByBlobIdInteractor: parseEmailInteractor, + ); + } else if (attachment.isHTMLFile) { + _previewHtmlFileAction( + session: session, + accountId: accountId, + attachment: attachment, + controller: controller, + getHtmlInteractor: getHtmlInteractor, + ); + } else { + onDownloadAttachment(attachment); + } + } + + Future _previewPDFFile({ + required BuildContext context, + required Attachment attachment, + required AccountId? accountId, + required Session? session, + }) async { + if (accountId == null || session == null) { + _appToast.showToastErrorMessage( + context, + AppLocalizations.of(context).noPreviewAvailable, + ); + return; + } + + try { + final downloadUrl = session.getDownloadUrl( + jmapUrl: _dynamicUrlInterceptors.jmapUrl, + ); + + await Get.generalDialog( + barrierColor: Colors.black.withValues(alpha: 0.8), + pageBuilder: (_, __, ___) { + return PointerInterceptor( + child: PDFViewer( + attachment: attachment, + accountId: accountId, + downloadUrl: downloadUrl, + downloadAction: _downloadPDFFile, + printAction: _printPDFFile, + ), + ); + }, + ); + } catch (e) { + if (context.mounted) { + _appToast.showToastErrorMessage( + context, + AppLocalizations.of(context).noPreviewAvailable, + ); + } + } + } + + void _downloadPDFFile(Uint8List bytes, String fileName) { + _downloadManager.createAnchorElementDownloadFileWeb(bytes, fileName); + } + + Future _printPDFFile(Uint8List bytes, String fileName) async { + await _printUtils.printPDFFile(bytes, fileName); + } + + void previewEMLFileAction({ + required AppLocalizations appLocalizations, + required AccountId? accountId, + required Session? session, + required String ownEmailAddress, + required Id? blobId, + required ParseEmailByBlobIdInteractor parseEmailByBlobIdInteractor, + required BaseController controller, + }) { + SmartDialog.showLoading( + msg: appLocalizations.loadingPleaseWait, + maskColor: Colors.black38, + ); + + if (session == null) { + _emitFailure( + controller: controller, + failure: ParseEmailByBlobIdFailure(NotFoundSessionException()), + ); + return; + } + + if (accountId == null) { + _emitFailure( + controller: controller, + failure: ParseEmailByBlobIdFailure(NotFoundAccountIdException()), + ); + return; + } + + if (blobId == null) { + _emitFailure( + controller: controller, + failure: ParseEmailByBlobIdFailure(NotFoundBlobIdException([])), + ); + return; + } + + controller.consumeState( + parseEmailByBlobIdInteractor.execute( + accountId, + session, + ownEmailAddress, + blobId, + ), + ); + } + + ({ + bool canDownloadAttachment, + AccountId? accountId, + String? downloadUrl, + Id? blobId, + }) evaluateAttachment({ + required Session? session, + required AccountId? accountId, + required Attachment attachment, + }) { + String? downloadUrl; + try { + downloadUrl = session?.getDownloadUrl( + jmapUrl: _dynamicUrlInterceptors.jmapUrl, + ); + } catch (e) { + downloadUrl = null; + } + 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, + ); + } + + void _previewHtmlFileAction({ + required Session? session, + required AccountId? accountId, + required Attachment attachment, + required BaseController controller, + required GetHtmlContentFromAttachmentInteractor getHtmlInteractor, + }) { + final attachmentEvaluation = evaluateAttachment( + accountId: accountId, + session: session, + attachment: attachment, + ); + + if (!attachmentEvaluation.canDownloadAttachment) { + _emitFailure( + controller: controller, + failure: GetHtmlContentFromAttachmentFailure( + exception: null, + attachment: attachment, + ), + ); + return; + } + + controller.consumeState( + getHtmlInteractor.execute( + attachmentEvaluation.accountId!, + attachment, + DownloadTaskId(attachmentEvaluation.blobId!.value), + attachmentEvaluation.downloadUrl!, + TransformConfiguration.create( + customDomTransformers: [SanitizeHyperLinkTagInHtmlTransformer()], + customTextTransformers: [ + const StandardizeHtmlSanitizingTransformers() + ], + ), + ), + ); + } + + void _emitFailure({ + required BaseController controller, + required FeatureFailure failure, + }) { + controller.consumeState(Stream.value(Left(failure))); + } + + void handleParseEmailByBlobIdSuccess({ + required BuildContext? context, + required AccountId? accountId, + required Session? session, + required String ownEmailAddress, + required Id blobId, + required Email email, + required BaseController controller, + required PreviewEmailFromEmlFileInteractor previewInteractor, + }) { + if (session == null) { + _emitFailure( + controller: controller, + failure: PreviewEmailFromEmlFileFailure(NotFoundSessionException()), + ); + return; + } + + if (accountId == null) { + _emitFailure( + controller: controller, + failure: PreviewEmailFromEmlFileFailure(NotFoundAccountIdException()), + ); + return; + } + + if (context == null) { + _emitFailure( + controller: controller, + failure: PreviewEmailFromEmlFileFailure(NotFoundContextException()), + ); + return; + } + + try { + controller.consumeState(previewInteractor.execute( + PreviewEmailEMLRequest( + accountId: accountId, + session: session, + ownEmailAddress: ownEmailAddress, + blobId: blobId, + email: email, + locale: Localizations.localeOf(context), + appLocalizations: AppLocalizations.of(context), + baseDownloadUrl: session.getDownloadUrl( + jmapUrl: _dynamicUrlInterceptors.jmapUrl, + ), + ), + )); + } catch (e) { + _emitFailure( + controller: controller, + failure: PreviewEmailFromEmlFileFailure(e), + ); + } + } + + void handleParseEmailByBlobIdFailure(ParseEmailByBlobIdFailure failure) { + SmartDialog.dismiss(); + _toastManager.showMessageFailure(failure); + } + + void handlePreviewEmailFromEMLFileFailure( + PreviewEmailFromEmlFileFailure failure, + ) { + SmartDialog.dismiss(); + _toastManager.showMessageFailure(failure); + } + + void handlePreviewEmailFromEMLFileSuccess({ + required EMLPreviewer emlPreviewer, + required BuildContext? context, + required ImagePaths imagePaths, + required OnMailtoDelegateAction onMailtoAction, + required OnDownloadAttachmentDelegateAction onDownloadAction, + required OnPreviewEMLDelegateAction onPreviewAction, + }) { + SmartDialog.dismiss(); + + if (PlatformInfo.isWeb) { + bool isOpen = HtmlUtils.openNewWindowByUrl( + RouteUtils.createUrlWebLocationBar( + AppRoutes.emailEMLPreviewer, + previewId: emlPreviewer.id, + ).toString(), + ); + + if (!isOpen) { + _toastManager.showMessageFailure( + PreviewEmailFromEmlFileFailure(CannotOpenNewWindowException()), + ); + } + } else if (PlatformInfo.isMobile) { + if (context == null) { + _toastManager.showMessageFailure( + PreviewEmailFromEmlFileFailure(NotFoundContextException()), + ); + return; + } + + if (PlatformInfo.isAndroid) { + showModalSheetToPreviewEMLAttachment( + context: context, + emlPreviewer: emlPreviewer, + imagePaths: imagePaths, + onMailtoAction: onMailtoAction, + onDownloadAction: onDownloadAction, + onPreviewAction: onPreviewAction, + ); + } else if (PlatformInfo.isIOS) { + showDialogToPreviewEMLAttachment( + context: context, + emlPreviewer: emlPreviewer, + imagePaths: imagePaths, + onMailtoAction: onMailtoAction, + onDownloadAction: onDownloadAction, + onPreviewAction: onPreviewAction, + ); + } + } + } + + void showModalSheetToPreviewEMLAttachment({ + required BuildContext context, + required EMLPreviewer emlPreviewer, + required ImagePaths imagePaths, + required OnMailtoDelegateAction onMailtoAction, + required OnDownloadAttachmentDelegateAction onDownloadAction, + required OnPreviewEMLDelegateAction onPreviewAction, + }) { + 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, + imagePaths: imagePaths, + onMailtoDelegateAction: onMailtoAction, + onPreviewEMLDelegateAction: onPreviewAction, + onDownloadAttachmentDelegateAction: onDownloadAction, + ), + ); + }, + ); + } + + void showDialogToPreviewEMLAttachment({ + required BuildContext context, + required EMLPreviewer emlPreviewer, + required ImagePaths imagePaths, + required OnMailtoDelegateAction onMailtoAction, + required OnDownloadAttachmentDelegateAction onDownloadAction, + required OnPreviewEMLDelegateAction onPreviewAction, + }) { + Get.dialog( + EmailPreviewerDialogView( + emlPreviewer: emlPreviewer, + imagePaths: imagePaths, + onMailtoDelegateAction: onMailtoAction, + onPreviewEMLDelegateAction: onPreviewAction, + onDownloadAttachmentDelegateAction: onDownloadAction, + ), + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + ); + } +} diff --git a/lib/features/email_previewer/email_previewer_bindings.dart b/lib/features/email_previewer/email_previewer_bindings.dart index b7cee5274..5f819db1c 100644 --- a/lib/features/email_previewer/email_previewer_bindings.dart +++ b/lib/features/email_previewer/email_previewer_bindings.dart @@ -1,27 +1,5 @@ - -import 'package:core/data/model/source_type/data_source_type.dart'; import 'package:core/data/network/download/download_manager.dart'; -import 'package:core/presentation/resources/image_paths.dart'; -import 'package:core/utils/file_utils.dart'; -import 'package:core/utils/preview_eml_file_utils.dart'; -import 'package:core/utils/print_utils.dart'; import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/base/base_bindings.dart'; -import 'package:tmail_ui_user/features/caching/utils/local_storage_manager.dart'; -import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dart'; -import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; -import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart'; -import 'package:tmail_ui_user/features/email/data/datasource/print_file_datasource.dart'; -import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart'; -import 'package:tmail_ui_user/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart'; -import 'package:tmail_ui_user/features/email/data/datasource_impl/email_local_storage_datasource_impl.dart'; -import 'package:tmail_ui_user/features/email/data/datasource_impl/email_session_storage_datasource_impl.dart'; -import 'package:tmail_ui_user/features/email/data/datasource_impl/html_datasource_impl.dart'; -import 'package:tmail_ui_user/features/email/data/datasource_impl/print_file_datasource_impl.dart'; -import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; -import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; -import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_email_eml_content_shared_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart'; @@ -30,25 +8,14 @@ import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob 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/remove_preview_email_eml_content_shared_interactor.dart'; import 'package:tmail_ui_user/features/email_previewer/email_previewer_controller.dart'; -import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart'; -import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/state_datasource_impl.dart'; -import 'package:tmail_ui_user/features/mailbox/data/local/state_cache_manager.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/download_interactor_bindings.dart'; -import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_manager.dart'; -import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_worker_queue.dart'; -import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_manager.dart'; -import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart'; -import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart'; -import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; -import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; -import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; -import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart'; - -class EmailPreviewerBindings extends BaseBindings { +class EmailPreviewerBindings extends Bindings { @override - void bindingsController() { - Get.lazyPut(() => EmailPreviewerController( + void dependencies() { + DownloadInteractorBindings().dependencies(); + Get.lazyPut( + () => EmailPreviewerController( Get.find(), Get.find(), Get.find(), @@ -56,87 +23,8 @@ class EmailPreviewerBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), - Get.find())); + Get.find(), + ), + ); } - - @override - void bindingsDataSource() { - Get.lazyPut(() => Get.find()); - Get.lazyPut(() => Get.find()); - Get.lazyPut(() => Get.find()); - Get.lazyPut(() => Get.find()); - } - - @override - void bindingsDataSourceImpl() { - Get.lazyPut(() => EmailDataSourceImpl( - Get.find(), - Get.find())); - Get.lazyPut(() => HtmlDataSourceImpl( - Get.find(), - Get.find())); - Get.lazyPut(() => StateDataSourceImpl( - Get.find(), - Get.find(), - Get.find())); - Get.lazyPut(() => PrintFileDataSourceImpl( - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find())); - Get.lazyPut(() => EmailHiveCacheDataSourceImpl( - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find(), - Get.find())); - Get.lazyPut(() => EmailLocalStorageDataSourceImpl( - Get.find(), - Get.find(), - Get.find())); - Get.lazyPut(() => EmailSessionStorageDatasourceImpl( - Get.find(), - Get.find())); - } - - @override - void bindingsInteractor() { - Get.lazyPut(() => GetPreviewEmailEMLContentSharedInteractor( - Get.find())); - Get.lazyPut(() => MovePreviewEmlContentFromPersistentToMemoryInteractor( - Get.find())); - Get.lazyPut(() => RemovePreviewEmailEmlContentSharedInteractor( - Get.find())); - Get.lazyPut(() => GetPreviewEmlContentInMemoryInteractor( - Get.find())); - Get.lazyPut(() => ParseEmailByBlobIdInteractor( - Get.find())); - Get.lazyPut(() => PreviewEmailFromEmlFileInteractor( - Get.find())); - - DownloadInteractorBindings().dependencies(); - } - - @override - void bindingsRepository() { - Get.lazyPut(() => Get.find()); - } - - @override - void bindingsRepositoryImpl() { - Get.lazyPut(() => EmailRepositoryImpl( - { - DataSourceType.network: Get.find(), - DataSourceType.hiveCache: Get.find(), - DataSourceType.local: Get.find(), - DataSourceType.session: Get.find(), - }, - Get.find(), - Get.find(), - Get.find())); - } -} \ No newline at end of file +} diff --git a/lib/features/email_previewer/email_previewer_controller.dart b/lib/features/email_previewer/email_previewer_controller.dart index 30068fc35..5a628529f 100644 --- a/lib/features/email_previewer/email_previewer_controller.dart +++ b/lib/features/email_previewer/email_previewer_controller.dart @@ -169,7 +169,12 @@ class EmailPreviewerController extends ReloadableController { _accountId = session.accountId; if (_keyStored != null) { - _parseEmailByBlobId(session.accountId, _keyStored!); + _parseEmailByBlobId( + accountId: _accountId!, + session: _session!, + ownEmailAddress: session.getOwnEmailAddressOrEmpty(), + blobId: _keyStored!, + ); } } @@ -244,9 +249,16 @@ class EmailPreviewerController extends ReloadableController { return uri.toString(); } - void _parseEmailByBlobId(AccountId accountId, String blobId) { + void _parseEmailByBlobId({ + required AccountId accountId, + required Session session, + required String ownEmailAddress, + required String blobId, + }) { consumeState(_parseEmailByBlobIdInteractor.execute( accountId, + session, + ownEmailAddress, Id(blobId), )); } @@ -271,6 +283,7 @@ class EmailPreviewerController extends ReloadableController { consumeState(_previewEmailFromEmlFileInteractor.execute( PreviewEmailEMLRequest( accountId: _accountId!, + session: _session!, ownEmailAddress: _session!.getOwnEmailAddressOrUsername(), blobId: success.blobId, email: success.email, diff --git a/lib/features/mailbox_dashboard/data/repository/download_repository_impl.dart b/lib/features/mailbox_dashboard/data/repository/download_repository_impl.dart index f53b122ff..65e2b0c7b 100644 --- a/lib/features/mailbox_dashboard/data/repository/download_repository_impl.dart +++ b/lib/features/mailbox_dashboard/data/repository/download_repository_impl.dart @@ -1,22 +1,32 @@ import 'dart:async'; import 'dart:typed_data'; -import 'package:core/presentation/state/failure.dart'; -import 'package:core/presentation/state/success.dart'; +import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/account/account_request.dart'; import 'package:model/download/download_task_id.dart'; import 'package:model/email/attachment.dart'; +import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; +import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart'; +import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/download_datasource.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; class DownloadRepositoryImpl extends DownloadRepository { - final DownloadDatasource _datasource; + final DownloadDatasource _downloadDatasource; + final Map _emailDataSource; + final HtmlDataSource _htmlDataSource; - DownloadRepositoryImpl(this._datasource); + DownloadRepositoryImpl( + this._downloadDatasource, + this._emailDataSource, + this._htmlDataSource, + ); @override Future downloadAttachmentForWeb( @@ -28,7 +38,7 @@ class DownloadRepositoryImpl extends DownloadRepository { StreamController>? onReceiveController, CancelToken? cancelToken, }) { - return _datasource.downloadAttachmentForWeb( + return _downloadDatasource.downloadAttachmentForWeb( taskId, attachment, accountId, @@ -50,7 +60,7 @@ class DownloadRepositoryImpl extends DownloadRepository { StreamController>? onReceiveController, CancelToken? cancelToken, }) { - return _datasource.downloadAllAttachmentsForWeb( + return _downloadDatasource.downloadAllAttachmentsForWeb( accountId, emailId, baseDownloadAllUrl, @@ -61,4 +71,64 @@ class DownloadRepositoryImpl extends DownloadRepository { cancelToken: cancelToken, ); } + + @override + Future sanitizeHtmlContent( + String htmlContent, + TransformConfiguration configuration, + ) { + return _htmlDataSource.transformHtmlEmailContent( + htmlContent, + configuration, + ); + } + + @override + Future> parseEmailByBlobIds( + AccountId accountId, + Set blobIds, + ) { + return _emailDataSource[DataSourceType.network]! + .parseEmailByBlobIds(accountId, blobIds); + } + + @override + Future generatePreviewEmailEMLContent( + PreviewEmailEMLRequest previewEmailEMLRequest, + ) { + return _emailDataSource[DataSourceType.network]! + .generatePreviewEmailEMLContent(previewEmailEMLRequest); + } + + @override + Future storePreviewEMLContentToSessionStorage( + EMLPreviewer emlPreviewer, + ) { + return _emailDataSource[DataSourceType.session]! + .storePreviewEMLContentToSessionStorage(emlPreviewer); + } + + @override + Future sharePreviewEmailEMLContent(EMLPreviewer emlPreviewer) { + return _emailDataSource[DataSourceType.local]! + .sharePreviewEmailEMLContent(emlPreviewer); + } + + @override + Future getPreviewEmailEMLContentShared(String keyStored) { + return _emailDataSource[DataSourceType.local]! + .getPreviewEmailEMLContentShared(keyStored); + } + + @override + Future removePreviewEmailEMLContentShared(String keyStored) { + return _emailDataSource[DataSourceType.local]! + .removePreviewEmailEMLContentShared(keyStored); + } + + @override + Future getPreviewEMLContentInMemory(String keyStored) { + return _emailDataSource[DataSourceType.session]! + .getPreviewEMLContentInMemory(keyStored); + } } diff --git a/lib/features/mailbox_dashboard/domain/repository/download_repository.dart b/lib/features/mailbox_dashboard/domain/repository/download_repository.dart index 26d4a1854..df818eef8 100644 --- a/lib/features/mailbox_dashboard/domain/repository/download_repository.dart +++ b/lib/features/mailbox_dashboard/domain/repository/download_repository.dart @@ -3,13 +3,17 @@ import 'dart:typed_data'; import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; +import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/account/account_request.dart'; import 'package:model/download/download_task_id.dart'; import 'package:model/email/attachment.dart'; +import 'package:tmail_ui_user/features/email/domain/model/preview_email_eml_request.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; abstract class DownloadRepository { Future downloadAttachmentForWeb( @@ -32,4 +36,27 @@ abstract class DownloadRepository { StreamController>? onReceiveController, CancelToken? cancelToken, }); + + Future sanitizeHtmlContent( + String htmlContent, + TransformConfiguration configuration, + ); + + Future> parseEmailByBlobIds(AccountId accountId, Set blobIds); + + Future generatePreviewEmailEMLContent( + PreviewEmailEMLRequest previewEmailEMLRequest, + ); + + Future sharePreviewEmailEMLContent(EMLPreviewer emlPreviewer); + + Future storePreviewEMLContentToSessionStorage( + EMLPreviewer emlPreviewer, + ); + + Future getPreviewEmailEMLContentShared(String keyStored); + + Future removePreviewEmailEMLContentShared(String keyStored); + + Future getPreviewEMLContentInMemory(String keyStored); } diff --git a/lib/features/mailbox_dashboard/presentation/action/download_ui_action.dart b/lib/features/mailbox_dashboard/presentation/action/download_ui_action.dart index 627831359..d98404f03 100644 --- a/lib/features/mailbox_dashboard/presentation/action/download_ui_action.dart +++ b/lib/features/mailbox_dashboard/presentation/action/download_ui_action.dart @@ -1,3 +1,6 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:model/email/attachment.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart'; @@ -12,13 +15,13 @@ class DownloadUIAction extends UIAction { } class UpdateAttachmentsViewStateAction extends DownloadUIAction { - UpdateAttachmentsViewStateAction(this.blobId, this.success); + UpdateAttachmentsViewStateAction(this.blobId, this.viewState); final Id? blobId; - final dynamic success; + final Either viewState; @override - List get props => [blobId, success]; + List get props => [blobId, viewState]; } class DownloadAttachmentsQuicklyAction extends DownloadUIAction { @@ -29,3 +32,12 @@ class DownloadAttachmentsQuicklyAction extends DownloadUIAction { @override List get props => [attachment]; } + +class OpenMailtoLinkFromPreviewAttachmentAction extends DownloadUIAction { + OpenMailtoLinkFromPreviewAttachmentAction(this.uri); + + final Uri? uri; + + @override + List get props => [uri]; +} diff --git a/lib/features/mailbox_dashboard/presentation/bindings/download_interactor_bindings.dart b/lib/features/mailbox_dashboard/presentation/bindings/download_interactor_bindings.dart index 8390f7308..eae580942 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/download_interactor_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/download_interactor_bindings.dart @@ -1,8 +1,25 @@ +import 'package:core/core.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/interactors_bindings.dart'; +import 'package:tmail_ui_user/features/caching/utils/local_storage_manager.dart'; +import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dart'; +import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; +import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart'; +import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart'; +import 'package:tmail_ui_user/features/email/data/datasource_impl/email_local_storage_datasource_impl.dart'; +import 'package:tmail_ui_user/features/email/data/datasource_impl/email_session_storage_datasource_impl.dart'; +import 'package:tmail_ui_user/features/email/data/datasource_impl/html_datasource_impl.dart'; +import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_all_attachments_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_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/get_preview_email_eml_content_shared_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/get_preview_eml_content_in_memory_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/move_preview_eml_content_from_persistent_to_memory_interactor.dart'; +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/remove_preview_email_eml_content_shared_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart'; import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart'; import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; @@ -10,6 +27,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/downloa import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/download_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/download_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; +import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; class DownloadInteractorBindings extends InteractorsBindings { @@ -21,6 +39,31 @@ class DownloadInteractorBindings extends InteractorsBindings { Get.find(), ), ); + Get.lazyPut( + () => EmailDataSourceImpl( + Get.find(), + Get.find(), + ), + ); + Get.lazyPut( + () => HtmlDataSourceImpl( + Get.find(), + Get.find(), + ), + ); + Get.lazyPut( + () => EmailSessionStorageDatasourceImpl( + Get.find(), + Get.find(), + ), + ); + Get.lazyPut( + () => EmailLocalStorageDataSourceImpl( + Get.find(), + Get.find(), + Get.find(), + ), + ); } @override @@ -41,6 +84,38 @@ class DownloadInteractorBindings extends InteractorsBindings { Get.find(), ), ); + Get.lazyPut( + () => ParseEmailByBlobIdInteractor(Get.find()), + ); + Get.lazyPut( + () => PreviewEmailFromEmlFileInteractor(Get.find()), + ); + Get.lazyPut( + () => GetHtmlContentFromAttachmentInteractor( + Get.find(), + ), + ); + Get.lazyPut( + () => MovePreviewEmlContentFromPersistentToMemoryInteractor( + Get.find(), + ), + ); + Get.lazyPut( + () => RemovePreviewEmailEmlContentSharedInteractor( + Get.find(), + ), + ); + + Get.lazyPut( + () => GetPreviewEmailEMLContentSharedInteractor( + Get.find(), + ), + ); + Get.lazyPut( + () => GetPreviewEmlContentInMemoryInteractor( + Get.find(), + ), + ); } @override @@ -50,11 +125,23 @@ class DownloadInteractorBindings extends InteractorsBindings { @override void bindingsRepositoryImpl() { - Get.lazyPut(() => DownloadRepositoryImpl(Get.find())); + Get.lazyPut( + () => DownloadRepositoryImpl( + Get.find(), + { + DataSourceType.session: Get.find(), + DataSourceType.local: Get.find(), + DataSourceType.network: Get.find(), + }, + Get.find(), + ), + ); } @override void bindingsDataSource() { Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => Get.find()); } } diff --git a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart index 6b56b5843..37e4f616d 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -34,10 +34,13 @@ import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_perman import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_all_attachments_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_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/get_restored_deleted_message_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; +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/restore_deleted_message_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/bindings/email_bindings.dart'; @@ -175,6 +178,9 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), + Get.find(), + Get.find(), )); Get.put(SearchController( Get.find(), diff --git a/lib/features/mailbox_dashboard/presentation/controller/download/download_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/download/download_controller.dart index f7d78aaea..de7d9f85d 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/download/download_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/download/download_controller.dart @@ -16,6 +16,7 @@ import 'package:get/get.dart'; import 'package:get/get_navigation/src/dialog/dialog_route.dart'; import 'package:http_parser/http_parser.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:model/download/download_task_id.dart'; import 'package:model/email/attachment.dart'; @@ -28,9 +29,18 @@ import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart'; import 'package:tmail_ui_user/features/email/domain/state/download_all_attachments_for_web_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_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/parse_email_by_blob_id_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_all_attachments_for_web_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_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/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/presentation/extensions/attachment_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/mixin/preview_attachment_mixin.dart'; +import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/html_attachment_previewer.dart'; import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart'; @@ -47,16 +57,23 @@ import 'package:uuid/uuid.dart'; typedef UpdateDownloadTaskStateCallback = DownloadTaskState Function(DownloadTaskState currentState); -class DownloadController extends BaseController { +class DownloadController extends BaseController with PreviewAttachmentMixin { final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor; final DownloadAllAttachmentsForWebInteractor _downloadAllAttachmentsForWebInteractor; final DownloadManager _downloadManager; + final ParseEmailByBlobIdInteractor parseEmailByBlobIdInteractor; + final PreviewEmailFromEmlFileInteractor previewEmailFromEmlFileInteractor; + final GetHtmlContentFromAttachmentInteractor + getHtmlContentFromAttachmentInteractor; DownloadController( this._downloadAttachmentForWebInteractor, this._downloadAllAttachmentsForWebInteractor, this._downloadManager, + this.parseEmailByBlobIdInteractor, + this.previewEmailFromEmlFileInteractor, + this.getHtmlContentFromAttachmentInteractor, ); final listDownloadTaskState = RxList(); @@ -335,7 +352,7 @@ class DownloadController extends BaseController { ) { _pushDownloadUIAction(UpdateAttachmentsViewStateAction( success.attachment.blobId, - success, + Right(success), )); deleteDownloadTask(success.taskId); @@ -446,7 +463,10 @@ class DownloadController extends BaseController { if (failure.attachment != null) { _pushDownloadUIAction( - UpdateAttachmentsViewStateAction(failure.attachment?.blobId, failure), + UpdateAttachmentsViewStateAction( + failure.attachment?.blobId, + Left(failure), + ), ); } @@ -464,7 +484,6 @@ class DownloadController extends BaseController { appToast.showToastErrorMessage(currentOverlayContext!, message); } - @override void handleSuccessViewState(Success success) { if (success is DownloadAttachmentForWebSuccess) { @@ -472,15 +491,77 @@ class DownloadController extends BaseController { } else if (success is StartDownloadAttachmentForWeb) { _pushDownloadUIAction(UpdateAttachmentsViewStateAction( success.attachment.blobId, - success, + Right(success), )); } else if (success is DownloadingAttachmentForWeb) { _pushDownloadUIAction(UpdateAttachmentsViewStateAction( success.attachment.blobId, - success, + Right(success), )); } else if (success is DownloadAllAttachmentsForWebSuccess) { deleteDownloadTask(success.taskId); + } else if (success is ParseEmailByBlobIdSuccess) { + handleParseEmailByBlobIdSuccess( + context: currentContext, + accountId: success.accountId, + session: success.session, + ownEmailAddress: success.ownEmailAddress, + blobId: success.blobId, + email: success.email, + controller: this, + previewInteractor: previewEmailFromEmlFileInteractor, + ); + } else if (success is PreviewEmailFromEmlFileSuccess) { + handlePreviewEmailFromEMLFileSuccess( + emlPreviewer: success.emlPreviewer, + context: currentContext, + imagePaths: imagePaths, + onMailtoAction: _openMailtoLink, + onDownloadAction: (uri) async { + if (uri == null) return; + + final attachment = EmailUtils.parsingAttachmentByUri(uri); + if (attachment == null) return; + + _downloadAttachmentQuickly(attachment); + }, + onPreviewAction: (uri) async { + if (currentContext != null && uri?.path.isNotEmpty == true) { + previewEMLFileAction( + appLocalizations: AppLocalizations.of(currentContext!), + accountId: success.accountId, + session: success.session, + ownEmailAddress: success.ownEmailAddress, + blobId: Id(uri!.path), + controller: this, + parseEmailByBlobIdInteractor: parseEmailByBlobIdInteractor, + ); + } + }, + ); + } else if (success is GetHtmlContentFromAttachmentSuccess) { + _pushDownloadUIAction( + UpdateAttachmentsViewStateAction( + success.attachment.blobId, + Right(success), + ), + ); + + Get.dialog(HtmlAttachmentPreviewer( + title: success.htmlAttachmentTitle, + htmlContent: success.sanitizedHtmlContent, + mailToClicked: _openMailtoLink, + downloadAttachmentClicked: () => + _downloadAttachmentQuickly(success.attachment), + responsiveUtils: responsiveUtils, + )); + } else if (success is GettingHtmlContentFromAttachment) { + _pushDownloadUIAction( + UpdateAttachmentsViewStateAction( + success.attachment.blobId, + Right(success), + ), + ); } else { super.handleSuccessViewState(success); } @@ -492,11 +573,40 @@ class DownloadController extends BaseController { _downloadAllAttachmentsForWebFailure(failure); } else if (failure is DownloadAttachmentForWebFailure) { _downloadAttachmentForWebFailureAction(failure); + } else if (failure is ParseEmailByBlobIdFailure) { + handleParseEmailByBlobIdFailure(failure); + } else if (failure is PreviewEmailFromEmlFileFailure) { + handlePreviewEmailFromEMLFileFailure(failure); + } else if (failure is GetHtmlContentFromAttachmentFailure) { + _handleGetHtmlContentFromAttachmentFailure(failure); } else { super.handleFailureViewState(failure); } } + void _handleGetHtmlContentFromAttachmentFailure( + GetHtmlContentFromAttachmentFailure failure, + ) { + _pushDownloadUIAction( + UpdateAttachmentsViewStateAction( + failure.attachment.blobId, + Left(failure), + ), + ); + + if (currentOverlayContext != null && currentContext != null) { + appToast.showToastErrorMessage( + currentOverlayContext!, + AppLocalizations.of(currentContext!) + .thisHtmlAttachmentCannotBePreviewed, + ); + } + } + + Future _openMailtoLink(Uri? uri) async { + _pushDownloadUIAction(OpenMailtoLinkFromPreviewAttachmentAction(uri)); + } + @override void onClose() { _downloadProgressStateSubscription?.cancel(); diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 5fe6be7ab..750654de1 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -123,6 +123,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_download_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preferences_setting_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_reactive_obx_variable_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_save_email_as_draft_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_store_email_sort_order_extension.dart'; @@ -767,6 +768,9 @@ class MailboxDashBoardController extends ReloadableController if (action is DownloadAttachmentsQuicklyAction) { downloadAttachmentForWeb(attachment: action.attachment); downloadController.clearDownloadUIAction(); + } else if (action is OpenMailtoLinkFromPreviewAttachmentAction) { + openMailToLink(action.uri); + downloadController.clearDownloadUIAction(); } }, ); diff --git a/lib/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart new file mode 100644 index 000000000..a2d2dd74b --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/handle_preview_attachment_extension.dart @@ -0,0 +1,84 @@ +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:model/email/attachment.dart'; +import 'package:tmail_ui_user/features/email/presentation/mixin/preview_attachment_mixin.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:tmail_ui_user/main/routes/route_utils.dart'; + +extension HandlePreviewAttachmentExtension on MailboxDashBoardController { + void previewAttachmentAction({ + required BuildContext context, + required Attachment attachment, + required OnDownloadAttachmentAction onDownloadAttachment, + }) => + downloadController.previewAttachmentAction( + context: context, + attachment: attachment, + accountId: accountId.value, + session: sessionCurrent, + ownEmailAddress: ownEmailAddress.value, + controller: downloadController, + parseEmailInteractor: downloadController.parseEmailByBlobIdInteractor, + getHtmlInteractor: + downloadController.getHtmlContentFromAttachmentInteractor, + onDownloadAttachment: onDownloadAttachment, + ); + + void previewEMLFileAction({ + required AppLocalizations appLocalizations, + required Id? blobId, + }) => + downloadController.previewEMLFileAction( + appLocalizations: appLocalizations, + accountId: accountId.value, + session: sessionCurrent, + ownEmailAddress: ownEmailAddress.value, + blobId: blobId, + controller: downloadController, + parseEmailByBlobIdInteractor: + downloadController.parseEmailByBlobIdInteractor, + ); + + void showDialogToPreviewEMLAttachment({ + required BuildContext context, + required EMLPreviewer emlPreviewer, + required ImagePaths imagePaths, + required OnMailtoDelegateAction onMailtoAction, + required OnDownloadAttachmentDelegateAction onDownloadAction, + required OnPreviewEMLDelegateAction onPreviewAction, + }) => + downloadController.showDialogToPreviewEMLAttachment( + context: context, + emlPreviewer: emlPreviewer, + imagePaths: imagePaths, + onMailtoAction: onMailtoAction, + onDownloadAction: onDownloadAction, + onPreviewAction: onPreviewAction, + ); + + Future openMailToLink(Uri? uri) async { + if (uri == null) return; + final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink( + uri.toString(), + ); + log('$runtimeType::openMailToLink(): ${uri.toString()}'); + if (!RouteUtils.canOpenComposerFromNavigationRouter(navigationRouter)) { + return; + } + + openComposer(ComposerArguments.fromMailtoUri( + listEmailAddress: navigationRouter.listEmailAddress, + cc: navigationRouter.cc, + bcc: navigationRouter.bcc, + subject: navigationRouter.subject, + body: navigationRouter.body, + )); + } +} diff --git a/lib/main/utils/app_utils.dart b/lib/main/utils/app_utils.dart index 7dc061d1e..db55c69c1 100644 --- a/lib/main/utils/app_utils.dart +++ b/lib/main/utils/app_utils.dart @@ -1,5 +1,4 @@ import 'package:core/core.dart'; -import 'package:core/utils/html/html_utils.dart'; import 'package:date_format/date_format.dart' as date_format; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/test/features/email/domain/usecases/parse_email_by_blob_id_interactor_test.dart b/test/features/email/domain/usecases/parse_email_by_blob_id_interactor_test.dart index 46c2cd50d..d17bf3e84 100644 --- a/test/features/email/domain/usecases/parse_email_by_blob_id_interactor_test.dart +++ b/test/features/email/domain/usecases/parse_email_by_blob_id_interactor_test.dart @@ -5,28 +5,30 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:model/extensions/session_extension.dart'; import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/download_repository.dart'; import '../../../../fixtures/account_fixtures.dart'; import '../../../../fixtures/email_fixtures.dart'; - +import '../../../../fixtures/session_fixtures.dart'; import 'parse_email_by_blob_id_interactor_test.mocks.dart'; -@GenerateNiceMocks([MockSpec()]) +@GenerateNiceMocks([MockSpec()]) void main() { group('ParseEmailByBlobIdInteractor::execute::', () { - late MockEmailRepository mockEmailRepository; + late MockDownloadRepository mockDownloadRepository; late ParseEmailByBlobIdInteractor parseEmailByBlobIdInteractor; setUp(() { - mockEmailRepository = MockEmailRepository(); + mockDownloadRepository = MockDownloadRepository(); parseEmailByBlobIdInteractor = - ParseEmailByBlobIdInteractor(mockEmailRepository); + ParseEmailByBlobIdInteractor(mockDownloadRepository); }); final accountId = AccountFixtures.aliceAccountId; + final session = SessionFixtures.aliceSession; final blobId = Id('blob-id'); test( @@ -35,11 +37,16 @@ void main() { // Arrange final parsedEmail = EmailFixtures.email1; - when(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + when(mockDownloadRepository.parseEmailByBlobIds(accountId, {blobId})) .thenAnswer((_) async => [parsedEmail]); // Act - final result = parseEmailByBlobIdInteractor.execute(accountId, blobId); + final result = parseEmailByBlobIdInteractor.execute( + accountId, + session, + session.getOwnEmailAddressOrEmpty(), + blobId, + ); // Assert @@ -47,13 +54,19 @@ void main() { result, emitsInOrder([ Right(ParsingEmailByBlobId()), - Right(ParseEmailByBlobIdSuccess(parsedEmail, blobId)), + Right(ParseEmailByBlobIdSuccess( + email: parsedEmail, + blobId: blobId, + accountId: accountId, + session: session, + ownEmailAddress: session.getOwnEmailAddressOrEmpty(), + )), ]), ); - verify(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + verify(mockDownloadRepository.parseEmailByBlobIds(accountId, {blobId})) .called(1); - verifyNoMoreInteractions(mockEmailRepository); + verifyNoMoreInteractions(mockDownloadRepository); }); test( @@ -62,11 +75,16 @@ void main() { // Arrange final exception = Exception('Failed to parse email'); - when(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + when(mockDownloadRepository.parseEmailByBlobIds(accountId, {blobId})) .thenThrow(exception); // Act - final result = parseEmailByBlobIdInteractor.execute(accountId, blobId); + final result = parseEmailByBlobIdInteractor.execute( + accountId, + session, + session.getOwnEmailAddressOrEmpty(), + blobId, + ); // Assert await expectLater( @@ -77,9 +95,9 @@ void main() { ]), ); - verify(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + verify(mockDownloadRepository.parseEmailByBlobIds(accountId, {blobId})) .called(1); - verifyNoMoreInteractions(mockEmailRepository); + verifyNoMoreInteractions(mockDownloadRepository); }); }); } diff --git a/test/features/email/presentation/controller/single_email_controller_test.dart b/test/features/email/presentation/controller/single_email_controller_test.dart index 770ae1649..1e86615e8 100644 --- a/test/features/email/presentation/controller/single_email_controller_test.dart +++ b/test/features/email/presentation/controller/single_email_controller_test.dart @@ -32,13 +32,10 @@ import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_reje import 'package:tmail_ui_user/features/email/domain/usecases/export_all_attachments_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_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/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/maybe_calendar_event_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/parse_calendar_event_interactor.dart'; -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/store_opened_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; @@ -97,14 +94,11 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), - MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -133,12 +127,9 @@ void main() { final responsiveUtils = MockResponsiveUtils(); final uuid = MockUuid(); final printEmailInteractor = MockPrintEmailInteractor(); - final parseEmailByBlobIdInteractor = MockParseEmailByBlobIdInteractor(); - final previewEmailFromEmlFileInteractor = MockPreviewEmailFromEmlFileInteractor(); final printUtils = MockPrintUtils(); final applicationManager = MockApplicationManager(); final mockToastManager = MockToastManager(); - final getHtmlContentFromAttachmentInteractor = MockGetHtmlContentFromAttachmentInteractor(); final mockTwakeAppManager = MockTwakeAppManager(); final exportAllAttachmentsInteractor = MockExportAllAttachmentsInteractor(); @@ -192,9 +183,6 @@ void main() { getAllIdentitiesInteractor, storeOpenedEmailInteractor, printEmailInteractor, - parseEmailByBlobIdInteractor, - previewEmailFromEmlFileInteractor, - getHtmlContentFromAttachmentInteractor, exportAllAttachmentsInteractor, ); });