diff --git a/core/lib/core.dart b/core/lib/core.dart index de9c91d64..0ffdc7ecb 100644 --- a/core/lib/core.dart +++ b/core/lib/core.dart @@ -10,6 +10,7 @@ export 'presentation/extensions/html_extension.dart'; // Exceptions export 'domain/exceptions/download_file_exception.dart'; +export 'data/extensions/options_extensions.dart'; // Utils export 'presentation/utils/theme_utils.dart'; diff --git a/core/lib/data/extensions/options_extensions.dart b/core/lib/data/extensions/options_extensions.dart new file mode 100644 index 000000000..f20e898c1 --- /dev/null +++ b/core/lib/data/extensions/options_extensions.dart @@ -0,0 +1,12 @@ +import 'package:dio/dio.dart'; + +extension OptionsExtension on Options { + Options appendHeaders(Map additionalHeaders) { + if (this.headers != null) { + this.headers?.addAll(additionalHeaders); + } else { + this.headers = additionalHeaders; + } + return this; + } +} \ No newline at end of file diff --git a/core/lib/data/network/dio_client.dart b/core/lib/data/network/dio_client.dart index a2f79e3cc..b18d77a9e 100644 --- a/core/lib/data/network/dio_client.dart +++ b/core/lib/data/network/dio_client.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; +import 'package:core/core.dart'; class DioClient { static const jmapHeader = 'application/json;jmapVersion=rfc-8621'; @@ -16,10 +19,13 @@ class DioClient { CancelToken? cancelToken, ProgressCallback? onReceiveProgress, }) async { + final newOptions = options?.appendHeaders({HttpHeaders.acceptHeader : jmapHeader}) + ?? Options(headers: {HttpHeaders.acceptHeader : jmapHeader}) ; + return await _dio.get( path, queryParameters: queryParameters, - options: options, + options: newOptions, cancelToken: cancelToken, onReceiveProgress: onReceiveProgress) .then((value) => value.data) @@ -35,10 +41,13 @@ class DioClient { ProgressCallback? onSendProgress, ProgressCallback? onReceiveProgress, }) async { + final newOptions = options?.appendHeaders({HttpHeaders.acceptHeader : jmapHeader}) + ?? Options(headers: {HttpHeaders.acceptHeader : jmapHeader}) ; + return await _dio.post(path, data: data, queryParameters: queryParameters, - options: options, + options: newOptions, cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress) @@ -53,11 +62,14 @@ class DioClient { Options? options, CancelToken? cancelToken, }) async { + final newOptions = options?.appendHeaders({HttpHeaders.acceptHeader : jmapHeader}) + ?? Options(headers: {HttpHeaders.acceptHeader : jmapHeader}) ; + return await _dio.delete( path, data: data, queryParameters: queryParameters, - options: options, + options: newOptions, cancelToken: cancelToken) .then((value) => value.data) .catchError((error) => throw(error)); @@ -72,11 +84,14 @@ class DioClient { ProgressCallback? onSendProgress, ProgressCallback? onReceiveProgress }) async { + final newOptions = options?.appendHeaders({HttpHeaders.acceptHeader : jmapHeader}) + ?? Options(headers: {HttpHeaders.acceptHeader : jmapHeader}) ; + return await _dio.put( path, data: data, queryParameters: queryParameters, - options: options, + options: newOptions, cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress) diff --git a/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart b/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart index a1be6ece6..20bcd42a5 100644 --- a/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart +++ b/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart @@ -1,4 +1,5 @@ +import 'package:core/core.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:html/dom.dart'; @@ -10,7 +11,13 @@ abstract class DomTransformer { /// Uses the `DOM` [document] and specified [message] to transform the `document`. /// /// All changes will be visible to subsequent transformers. - void process(Document document, String message, TransformConfiguration configuration); + Future process( + Document document, + String message, + Map? mapUrlDownloadCID, + TransformConfiguration configuration, + DioClient dioClient + ); /// Adds a HEAD element if necessary void ensureDocumentHeadIsAvailable(Document document) { diff --git a/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart index 734a0bbcd..2c6fe19e0 100644 --- a/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart @@ -1,4 +1,8 @@ +import 'dart:convert'; + +import 'package:core/core.dart'; +import 'package:dio/dio.dart'; import 'package:html/dom.dart'; import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; @@ -8,16 +12,44 @@ class ImageTransformer extends DomTransformer { const ImageTransformer(); @override - void process(Document document, String message, TransformConfiguration configuration) { + Future process( + Document document, + String message, + Map? mapUrlDownloadCID, + TransformConfiguration configuration, + DioClient dioClient + ) async { final imageElements = document.getElementsByTagName('img'); - for (final imageElement in imageElements) { - final src = imageElement.attributes['src']; - if (src != null && src.startsWith('http:')) { - // always at least enforce HTTPS images: - final url = src.substring('http:'.length); - imageElement.attributes['src'] = 'https:$url'; - } + + await Future.wait(imageElements.map((imageElement) async { imageElement.attributes['style'] = 'display: inline;max-width: 100%;height: auto;'; + final src = imageElement.attributes['src']; + if (src != null + && src.isNotEmpty + && src.startsWith('cid:') + && mapUrlDownloadCID != null + ) { + final cid = src.replaceFirst('cid:', '').trim(); + final cidUrlDownload = mapUrlDownloadCID[cid]; + if (cidUrlDownload != null && cidUrlDownload.isNotEmpty) { + final imgBase64 = await loadAsyncNetworkImageToBase64(dioClient, cidUrlDownload); + if (imgBase64 != null && imgBase64.isNotEmpty) { + imageElement.attributes['src'] = 'data:image/jpeg;base64,$imgBase64'; + } + } + } + })); + } + + + Future loadAsyncNetworkImageToBase64(DioClient dioClient, String imageUrl) async { + try { + final response = await dioClient.get( + imageUrl, + options: Options(responseType: ResponseType.bytes)); + return base64Encode(response); + } catch (e) { + return imageUrl; } } } \ No newline at end of file diff --git a/core/lib/presentation/utils/html_transformer/dom/link_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/link_transformers.dart index c74c906d8..164b53087 100644 --- a/core/lib/presentation/utils/html_transformer/dom/link_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/link_transformers.dart @@ -1,4 +1,5 @@ +import 'package:core/data/network/dio_client.dart'; import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:html/dom.dart'; @@ -8,10 +9,16 @@ class EnsureRelationNoReferrerTransformer extends DomTransformer { const EnsureRelationNoReferrerTransformer(); @override - void process(Document document, String message, TransformConfiguration configuration) { + Future process( + Document document, + String message, + Map? mapUrlDownloadCID, + TransformConfiguration configuration, + DioClient dioClient + ) async { final linkElements = document.getElementsByTagName('a'); - for (final linkElement in linkElements) { + await Future.wait(linkElements.map((linkElement) async { linkElement.attributes['rel'] = 'noopener noreferrer'; - } + })); } } \ No newline at end of file diff --git a/core/lib/presentation/utils/html_transformer/dom/meta_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/meta_transformers.dart index be2b8a61e..36686cba6 100644 --- a/core/lib/presentation/utils/html_transformer/dom/meta_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/meta_transformers.dart @@ -1,4 +1,5 @@ +import 'package:core/data/network/dio_client.dart'; import 'package:html/dom.dart'; import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; @@ -13,11 +14,18 @@ class ViewPortTransformer extends DomTransformer { const ViewPortTransformer(); @override - void process(Document document, String message, TransformConfiguration configuration) { + Future process( + Document document, + String message, + Map? mapUrlDownloadCID, + TransformConfiguration configuration, + DioClient dioClient + ) async { final metaElements = document.getElementsByTagName('meta'); var viewportNeedsToBeAdded = true; var contentTypeNeedsToBeAdded = true; - for (final metaElement in metaElements) { + + await Future.wait(metaElements.map((metaElement) async { if (metaElement.attributes['name'] == 'viewport') { viewportNeedsToBeAdded = false; metaElement.attributes['content'] = 'width=device-width, initial-scale=1.0'; @@ -30,7 +38,8 @@ class ViewPortTransformer extends DomTransformer { metaElement.attributes['content'] = 'text/html; charset=utf-8'; } } - } + })); + if (contentTypeNeedsToBeAdded) { ensureDocumentHeadIsAvailable(document); document.head!.append(_contentTypeMetaElement); diff --git a/core/lib/presentation/utils/html_transformer/dom/script_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/script_transformers.dart index cd6d595d6..f4121b25d 100644 --- a/core/lib/presentation/utils/html_transformer/dom/script_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/script_transformers.dart @@ -1,4 +1,5 @@ +import 'package:core/data/network/dio_client.dart'; import 'package:html/dom.dart'; import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; @@ -8,10 +9,16 @@ class RemoveScriptTransformer extends DomTransformer { const RemoveScriptTransformer(); @override - void process(Document document, String message, TransformConfiguration configuration) { + Future process( + Document document, + String message, + Map? mapUrlDownloadCID, + TransformConfiguration configuration, + DioClient dioClient + ) async { final scriptElements = document.getElementsByTagName('script'); - for (final scriptElement in scriptElements) { + await Future.wait(scriptElements.map((scriptElement) async { scriptElement.remove(); - } + })); } } \ No newline at end of file diff --git a/core/lib/presentation/utils/html_transformer/html_transform.dart b/core/lib/presentation/utils/html_transformer/html_transform.dart index 29b72a798..c7d881288 100644 --- a/core/lib/presentation/utils/html_transformer/html_transform.dart +++ b/core/lib/presentation/utils/html_transformer/html_transform.dart @@ -1,3 +1,4 @@ +import 'package:core/core.dart'; import 'package:core/presentation/utils/html_transformer/message_content_transformer.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:html/dom.dart'; @@ -5,21 +6,27 @@ import 'package:html/dom.dart'; class HtmlTransform { final String _contentHtml; + Map? mapUrlDownloadCID; + DioClient dioClient; - HtmlTransform(this._contentHtml); + HtmlTransform( + this._contentHtml, + this.dioClient, + this.mapUrlDownloadCID + ); /// Transforms this message to HTML code. /// Optionally specify the [transformConfiguration] to control all aspects of the transformation /// - in that case other parameters are ignored. - String transformToHtml({TransformConfiguration? transformConfiguration}) { - final document = transformToDocument(transformConfiguration: transformConfiguration); + Future transformToHtml({TransformConfiguration? transformConfiguration}) async { + final document = await transformToDocument(transformConfiguration: transformConfiguration); return document.outerHtml; } /// Transforms this message to Document. - Document transformToDocument({TransformConfiguration? transformConfiguration}) { + Future transformToDocument({TransformConfiguration? transformConfiguration}) async { transformConfiguration ??= TransformConfiguration.create(); - final transformer = MessageContentTransformer(transformConfiguration); - return transformer.toDocument(_contentHtml); + final transformer = MessageContentTransformer(transformConfiguration, dioClient); + return await transformer.toDocument(_contentHtml, mapUrlDownloadCID); } } \ No newline at end of file diff --git a/core/lib/presentation/utils/html_transformer/message_content_transformer.dart b/core/lib/presentation/utils/html_transformer/message_content_transformer.dart index 4dcca68cb..d7cf1f8df 100644 --- a/core/lib/presentation/utils/html_transformer/message_content_transformer.dart +++ b/core/lib/presentation/utils/html_transformer/message_content_transformer.dart @@ -1,3 +1,4 @@ +import 'package:core/core.dart'; import 'package:core/presentation/utils/html_transformer/transform_configuration.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart' show parse; @@ -6,23 +7,24 @@ import 'package:html/parser.dart' show parse; class MessageContentTransformer { /// The configuration used for the transformation final TransformConfiguration configuration; + final DioClient dioClient; - MessageContentTransformer(this.configuration); + MessageContentTransformer(this.configuration, this.dioClient); - void transformDocument(Document document, String message) { - for (final domTransformer in configuration.domTransformers) { - domTransformer.process(document, message, configuration); - } + Future transformDocument( + Document document, + String message, + Map? mapUrlDownloadCID, + ) async { + await Future.wait(configuration.domTransformers.map((domTransformer) async { + await domTransformer.process(document, message, mapUrlDownloadCID, configuration, dioClient); + })); } - Document toDocument(String message) { + Future toDocument(String message, Map? mapUrlDownloadCID) async { var html = message; final document = parse(html); - transformDocument(document, message); + await transformDocument(document, message, mapUrlDownloadCID); return document; } - - String toHtml(String message) { - return toDocument(message).outerHtml; - } } \ No newline at end of file diff --git a/lib/features/composer/data/network/composer_api.dart b/lib/features/composer/data/network/composer_api.dart index f99685f51..131b17c1f 100644 --- a/lib/features/composer/data/network/composer_api.dart +++ b/lib/features/composer/data/network/composer_api.dart @@ -2,7 +2,6 @@ import 'dart:io'; import 'package:core/core.dart'; -import 'package:dio/dio.dart'; import 'package:model/model.dart'; class ComposerAPI { @@ -14,14 +13,7 @@ class ComposerAPI { Future uploadAttachment(UploadRequest uploadRequest) async { final resultJson = await _dioClient.post( Uri.decodeFull(uploadRequest.uploadUrl.toString()), - options: Options(headers: _buildHeaderRequestParam()), data: File(uploadRequest.fileInfo.filePath).readAsBytesSync()); return UploadResponse.fromJson(resultJson); } - - Map _buildHeaderRequestParam() { - final headerParam = _dioClient.getHeaders(); - headerParam[HttpHeaders.acceptHeader] = DioClient.jmapHeader; - return headerParam; - } } \ No newline at end of file diff --git a/lib/features/email/data/datasource/html_datasource.dart b/lib/features/email/data/datasource/html_datasource.dart index c3bafa717..5f736cc6a 100644 --- a/lib/features/email/data/datasource/html_datasource.dart +++ b/lib/features/email/data/datasource/html_datasource.dart @@ -2,5 +2,8 @@ import 'package:model/model.dart'; abstract class HtmlDataSource { - Future transformEmailContent(EmailContent emailContent); + Future transformEmailContent( + EmailContent emailContent, + Map mapUrlDownloadCID + ); } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/html_datasource_impl.dart b/lib/features/email/data/datasource_impl/html_datasource_impl.dart index 69dca84a9..4893aa60b 100644 --- a/lib/features/email/data/datasource_impl/html_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/html_datasource_impl.dart @@ -1,17 +1,22 @@ -import 'package:model/email/email_content.dart'; +import 'package:core/core.dart'; +import 'package:model/model.dart'; import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart'; import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart'; class HtmlDataSourceImpl extends HtmlDataSource { final HtmlAnalyzer _htmlAnalyzer; + final DioClient _dioClient; - HtmlDataSourceImpl(this._htmlAnalyzer); + HtmlDataSourceImpl(this._htmlAnalyzer, this._dioClient); @override - Future transformEmailContent(EmailContent emailContent) { + Future transformEmailContent( + EmailContent emailContent, + Map? mapUrlDownloadCID + ) { return Future.sync(() async { - return await _htmlAnalyzer.transformEmailContent(emailContent); + return await _htmlAnalyzer.transformEmailContent(emailContent, mapUrlDownloadCID, _dioClient); }).catchError((error) { throw error; }); diff --git a/lib/features/email/data/local/html_analyzer.dart b/lib/features/email/data/local/html_analyzer.dart index 2e43a4c59..8de4200b8 100644 --- a/lib/features/email/data/local/html_analyzer.dart +++ b/lib/features/email/data/local/html_analyzer.dart @@ -1,15 +1,23 @@ +import 'package:core/core.dart'; import 'package:core/presentation/utils/html_transformer/html_transform.dart'; import 'package:model/email/email_content_type.dart'; import 'package:model/model.dart'; class HtmlAnalyzer { - Future transformEmailContent(EmailContent emailContent) async { + Future transformEmailContent( + EmailContent emailContent, + Map? mapUrlDownloadCID, + DioClient dioClient + ) async { switch(emailContent.type) { case EmailContentType.textHtml: - final htmlTransform = HtmlTransform(emailContent.content); - final htmlContent = htmlTransform.transformToHtml(); + final htmlTransform = HtmlTransform( + emailContent.content, + dioClient, + mapUrlDownloadCID); + final htmlContent = await htmlTransform.transformToHtml(); return EmailContent(emailContent.type, htmlContent); default: return emailContent; diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index e27d29e0d..69117c7d5 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -72,10 +72,19 @@ class EmailRepositoryImpl extends EmailRepository { } @override - Future> transformEmailContent(List emailContents) async { + Future> transformEmailContent( + List emailContents, + List attachmentInlines, + String? baseUrlDownload, + AccountId accountId + ) async { + final mapUrlDownloadCID = Map.fromIterable( + attachmentInlines, + key: (attachment) => attachment.cid!, + value: (attachment) => attachment.getDownloadUrl(baseUrlDownload, accountId)); return await Future.wait(emailContents .map((emailContent) async { - return await _htmlDataSource.transformEmailContent(emailContent); + return await _htmlDataSource.transformEmailContent(emailContent, mapUrlDownloadCID); }) .toList()); } diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 1f325e6af..0dd43565e 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -35,5 +35,10 @@ abstract class EmailRepository { MarkStarAction markStarAction ); - Future> transformEmailContent(List emailContents); + Future> transformEmailContent( + List emailContents, + List attachmentInlines, + String? baseUrlDownload, + AccountId accountId + ); } \ No newline at end of file diff --git a/lib/features/email/domain/usecases/get_email_content_interactor.dart b/lib/features/email/domain/usecases/get_email_content_interactor.dart index a75bd83d2..1aa1061d8 100644 --- a/lib/features/email/domain/usecases/get_email_content_interactor.dart +++ b/lib/features/email/domain/usecases/get_email_content_interactor.dart @@ -11,13 +11,17 @@ class GetEmailContentInteractor { GetEmailContentInteractor(this.emailRepository); - Stream> execute(AccountId accountId, EmailId emailId) async* { + Stream> execute(AccountId accountId, EmailId emailId, String? baseDownloadUrl) async* { try { yield Right(LoadingState()); final email = await emailRepository.getEmailContent(accountId, emailId); if (email.emailContentList.isNotEmpty) { - final newEmailContents = await emailRepository.transformEmailContent(email.emailContentList); + final newEmailContents = await emailRepository.transformEmailContent( + email.emailContentList, + email.allAttachments.attachmentWithDispositionInlines, + baseDownloadUrl, + accountId); yield Right(GetEmailContentSuccess(newEmailContents, email.allAttachments)); } else { yield Left(GetEmailContentFailure(null)); diff --git a/lib/features/email/presentation/email_bindings.dart b/lib/features/email/presentation/email_bindings.dart index 0d3c09408..355db2b50 100644 --- a/lib/features/email/presentation/email_bindings.dart +++ b/lib/features/email/presentation/email_bindings.dart @@ -25,14 +25,17 @@ class EmailBindings extends Bindings { void dependencies() { Get.lazyPut(() => EmailDataSourceImpl(Get.find())); Get.lazyPut(() => Get.find()); - Get.lazyPut(() => HtmlDataSourceImpl(Get.find())); + Get.lazyPut(() => HtmlDataSourceImpl( + Get.find(), + Get.find())); Get.lazyPut(() => Get.find()); Get.lazyPut(() => EmailRepositoryImpl( Get.find(), Get.find())); Get.lazyPut(() => Get.find()); Get.put(SendEmailInteractor(Get.find())); - Get.lazyPut(() => GetEmailContentInteractor(Get.find())); + Get.lazyPut(() => GetEmailContentInteractor( + Get.find())); Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find())); Get.lazyPut(() => CredentialRepositoryImpl(Get.find())); Get.lazyPut(() => Get.find()); diff --git a/lib/features/email/presentation/email_controller.dart b/lib/features/email/presentation/email_controller.dart index b8d660046..8203ff6d8 100644 --- a/lib/features/email/presentation/email_controller.dart +++ b/lib/features/email/presentation/email_controller.dart @@ -88,7 +88,8 @@ class EmailController extends BaseController { } void _getEmailContentAction(AccountId accountId, EmailId emailId) async { - consumeState(_getEmailContentInteractor.execute(accountId, emailId)); + final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(); + consumeState(_getEmailContentInteractor.execute(accountId, emailId, baseDownloadUrl)); } @override diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 9c64d8af8..e49c62806 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -11,7 +11,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/app_bar_mail_w import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_file_tile_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/attachments_place_holder_loading_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart'; -import 'package:tmail_ui_user/features/email/presentation/extensions/list_attachment_extension.dart'; +import 'package:model/extensions/list_attachment_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_item_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_place_holder_loading_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/sender_and_receiver_information_tile_builder.dart'; diff --git a/lib/features/thread/presentation/thread_bindings.dart b/lib/features/thread/presentation/thread_bindings.dart index 6b98bc158..bc0c0c2c1 100644 --- a/lib/features/thread/presentation/thread_bindings.dart +++ b/lib/features/thread/presentation/thread_bindings.dart @@ -51,7 +51,9 @@ class ThreadBindings extends Bindings { Get.lazyPut(() => ScrollController()); Get.lazyPut(() => EmailDataSourceImpl(Get.find())); Get.lazyPut(() => Get.find()); - Get.lazyPut(() => HtmlDataSourceImpl(Get.find())); + Get.lazyPut(() => HtmlDataSourceImpl( + Get.find(), + Get.find())); Get.lazyPut(() => Get.find()); Get.lazyPut(() => EmailRepositoryImpl( Get.find(), diff --git a/model/lib/email/attachment.dart b/model/lib/email/attachment.dart index 8185f6abf..73ced9246 100644 --- a/model/lib/email/attachment.dart +++ b/model/lib/email/attachment.dart @@ -27,6 +27,8 @@ class Attachment with EquatableMixin { this.disposition, }); + bool cidNotEmpty() => cid != null && cid!.isNotEmpty; + String getDownloadUrl(String baseDownloadUrl, AccountId accountId) { final downloadUriTemplate = UriTemplate('$baseDownloadUrl'); final downloadUri = downloadUriTemplate.expand({ diff --git a/model/lib/email/email_content.dart b/model/lib/email/email_content.dart index a9e54b43f..9c995b217 100644 --- a/model/lib/email/email_content.dart +++ b/model/lib/email/email_content.dart @@ -1,6 +1,5 @@ import 'package:equatable/equatable.dart'; -import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:model/email/email_content_type.dart'; import 'package:model/model.dart'; @@ -11,19 +10,6 @@ class EmailContent with EquatableMixin { EmailContent(this.type, this.content); - bool hasImageInlineWithCid() => content.contains('cid:'); - - String getContentHasInlineAttachment(String baseDownloadUrl, AccountId accountId, List attachments) { - var contentValid = content; - attachments.forEach((attachment) { - if(attachment.cid != null) { - final urlDownloadImage = attachment.getDownloadUrl(baseDownloadUrl, accountId); - contentValid = content.replaceAll('cid:${attachment.cid}', '$urlDownloadImage'); - } - }); - return contentValid; - } - @override List get props => [type, content]; } \ No newline at end of file diff --git a/lib/features/email/presentation/extensions/list_attachment_extension.dart b/model/lib/extensions/list_attachment_extension.dart similarity index 64% rename from lib/features/email/presentation/extensions/list_attachment_extension.dart rename to model/lib/extensions/list_attachment_extension.dart index 1abfffc31..8760dd7d5 100644 --- a/lib/features/email/presentation/extensions/list_attachment_extension.dart +++ b/model/lib/extensions/list_attachment_extension.dart @@ -13,10 +13,11 @@ extension ListAttachmentExtension on List { } List get attachmentsWithDispositionAttachment { - return where((element) => element.disposition == ContentDisposition.attachment).toList(); + return where((attachment) => attachment.disposition == ContentDisposition.attachment).toList(); } List get attachmentWithDispositionInlines { - return where((element) => element.disposition == ContentDisposition.inline).toList(); + return where((attachment) => attachment.disposition == ContentDisposition.inline && attachment.cidNotEmpty()) + .toList(); } } \ No newline at end of file diff --git a/model/lib/model.dart b/model/lib/model.dart index 54f82f415..606bf7ce0 100644 --- a/model/lib/model.dart +++ b/model/lib/model.dart @@ -52,6 +52,7 @@ export 'extensions/list_mailbox_extension.dart'; export 'extensions/list_extension.dart'; export 'extensions/list_email_extension.dart'; export 'extensions/media_type_extension.dart'; +export 'extensions/list_attachment_extension.dart'; // Download export 'download/download_task_id.dart';