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 1deb82264..66922d441 100644 --- a/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart +++ b/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart @@ -12,8 +12,8 @@ abstract class DomTransformer { /// All changes will be visible to subsequent transformers. Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient, }); /// Adds a HEAD element if necessary diff --git a/core/lib/presentation/utils/html_transformer/dom/add_target_blank_in_tag_a_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/add_target_blank_in_tag_a_transformers.dart index f1e877383..a66a387d9 100644 --- a/core/lib/presentation/utils/html_transformer/dom/add_target_blank_in_tag_a_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/add_target_blank_in_tag_a_transformers.dart @@ -8,8 +8,8 @@ class AddTargetBlankInTagATransformer extends DomTransformer { @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient, }) async { final elements = document.querySelectorAll('a'); await Future.wait(elements.map((element) async { diff --git a/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart index f51f531b1..aea1d9cca 100644 --- a/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart @@ -11,8 +11,8 @@ class AddTooltipLinkTransformer extends DomTransformer { @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient }) async { final linkElements = document.querySelectorAll('a[href^="http"]'); await Future.wait(linkElements.map((linkElement) async { diff --git a/core/lib/presentation/utils/html_transformer/dom/blockcode_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/blockcode_transformers.dart index 732e3272e..bc8dab461 100644 --- a/core/lib/presentation/utils/html_transformer/dom/blockcode_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/blockcode_transformers.dart @@ -10,8 +10,8 @@ class BlockCodeTransformer extends DomTransformer { @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient }) async { final codeElements = document.getElementsByTagName('pre'); await Future.wait(codeElements.map((element) async { diff --git a/core/lib/presentation/utils/html_transformer/dom/blockquoted_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/blockquoted_transformers.dart index 7eb40dc0d..e447aad75 100644 --- a/core/lib/presentation/utils/html_transformer/dom/blockquoted_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/blockquoted_transformers.dart @@ -10,8 +10,8 @@ class BlockQuotedTransformer extends DomTransformer { @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient }) async { final quotedElements = document.getElementsByTagName('blockquote'); await Future.wait(quotedElements.map((quotedElement) async { 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 6d2a7aeef..e8ee882d2 100644 --- a/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart @@ -12,29 +12,33 @@ import 'package:html/dom.dart'; class ImageTransformer extends DomTransformer { - final bool useLoadingAttribute; - - const ImageTransformer({this.useLoadingAttribute = false}); + const ImageTransformer(); @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient }) async { final imageElements = document.querySelectorAll('img'); await Future.wait(imageElements.map((imageElement) async { - final exStyle = imageElement.attributes['style']; + var exStyle = imageElement.attributes['style']; if (exStyle != null) { - imageElement.attributes['style'] = '$exStyle display: inline;max-width: 100%;'; + if (!exStyle.contains('display')) { + exStyle = '$exStyle display:inline;'; + } + if (!exStyle.contains('max-width')) { + exStyle = '$exStyle max-width:100%;'; + } + imageElement.attributes['style'] = exStyle; } else { - imageElement.attributes['style'] = 'display: inline;max-width: 100%;'; + imageElement.attributes['style'] = 'display:inline;max-width:100%;'; } final src = imageElement.attributes['src']; if (src == null) return; - if (src.startsWith('cid:') && dioClient != null && mapUrlDownloadCID != null) { + if (src.startsWith('cid:') && mapUrlDownloadCID != null) { final imageBase64 = await _convertCidToBase64Image( dioClient: dioClient, mapUrlDownloadCID: mapUrlDownloadCID, @@ -42,18 +46,8 @@ class ImageTransformer extends DomTransformer { ); imageElement.attributes['src'] = imageBase64 ?? src; } else if (src.startsWith('https://') || src.startsWith('http://')) { - if (useLoadingAttribute) { + if (!imageElement.attributes.containsKey('loading')) { imageElement.attributes['loading'] = 'lazy'; - } else { - final classAttribute = imageElement.attributes['class']; - if (classAttribute != null) { - imageElement.attributes['class'] = '$classAttribute lazy-loading'; - } else { - imageElement.attributes['class'] = 'lazy-loading'; - } - imageElement.attributes['data-src'] = src; - imageElement.attributes.remove('src'); - imageElement.attributes.remove('loading'); } } })); diff --git a/core/lib/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart index 54a7b0708..68e80933b 100644 --- a/core/lib/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart @@ -12,8 +12,8 @@ class RemoveTooltipLinkTransformer extends DomTransformer { @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient }) async { final linkElements = document.querySelectorAll('a.$nameClassToolTip'); await Future.wait(linkElements.map((linkElement) async { diff --git a/core/lib/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart b/core/lib/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart deleted file mode 100644 index 32f8d4c74..000000000 --- a/core/lib/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart +++ /dev/null @@ -1,32 +0,0 @@ - - -import 'package:core/data/network/dio_client.dart'; -import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart'; -import 'package:html/dom.dart'; - -class ReplaceLazyLoadImageTransformer extends DomTransformer { - - const ReplaceLazyLoadImageTransformer(); - - @override - Future process({ - required Document document, - Map? mapUrlDownloadCID, - DioClient? dioClient - }) async { - final imageElements = document.querySelectorAll('img.lazy-loading'); - await Future.wait(imageElements.map((imageElement) async { - final classAttribute = imageElement.attributes['class']; - if (classAttribute != null) { - final newClassAttribute = classAttribute.replaceFirst('lazy-loading', ''); - imageElement.attributes['class'] = newClassAttribute; - } - final dataSrc = imageElement.attributes['data-src']; - if (dataSrc != null) { - imageElement.attributes['src'] = dataSrc; - imageElement.attributes.remove('data-src'); - } - imageElement.attributes['loading'] = 'lazy'; - })); - } -} \ No newline at end of file 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 a1cde09b8..a021f60b9 100644 --- a/core/lib/presentation/utils/html_transformer/dom/script_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/script_transformers.dart @@ -10,8 +10,8 @@ class RemoveScriptTransformer extends DomTransformer { @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient }) async { final scriptElements = document.getElementsByTagName('script'); await Future.wait(scriptElements.map((scriptElement) async { diff --git a/core/lib/presentation/utils/html_transformer/dom/sigature_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/sigature_transformers.dart index 8539a7f59..c82bedf8f 100644 --- a/core/lib/presentation/utils/html_transformer/dom/sigature_transformers.dart +++ b/core/lib/presentation/utils/html_transformer/dom/sigature_transformers.dart @@ -10,8 +10,8 @@ class SignatureTransformer extends DomTransformer { @override Future process({ required Document document, + required DioClient dioClient, Map? mapUrlDownloadCID, - DioClient? dioClient }) async { final signatureElements = document.querySelectorAll('div.tmail-signature'); await Future.wait(signatureElements.map((element) async { diff --git a/core/lib/presentation/utils/html_transformer/html_utils.dart b/core/lib/presentation/utils/html_transformer/html_utils.dart index eafee3a71..28881d60d 100644 --- a/core/lib/presentation/utils/html_transformer/html_utils.dart +++ b/core/lib/presentation/utils/html_transformer/html_utils.dart @@ -79,6 +79,7 @@ class HtmlUtils { // Replace the placeholder with the actual image source img.src = src; + img.removeAttribute("data-src"); // Stop observing the image observer.unobserve(img); 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 f4e5a1624..034855b73 100644 --- a/core/lib/presentation/utils/html_transformer/message_content_transformer.dart +++ b/core/lib/presentation/utils/html_transformer/message_content_transformer.dart @@ -27,8 +27,8 @@ class MessageContentTransformer { ..._configuration.domTransformers.map((domTransformer) async => domTransformer.process( document: document, + dioClient: _dioClient, mapUrlDownloadCID: mapUrlDownloadCID, - dioClient: _dioClient ) ) ]); diff --git a/core/lib/presentation/utils/html_transformer/transform_configuration.dart b/core/lib/presentation/utils/html_transformer/transform_configuration.dart index df0576a43..f581e3d4c 100644 --- a/core/lib/presentation/utils/html_transformer/transform_configuration.dart +++ b/core/lib/presentation/utils/html_transformer/transform_configuration.dart @@ -7,7 +7,6 @@ import 'package:core/presentation/utils/html_transformer/dom/blockcode_transform import 'package:core/presentation/utils/html_transformer/dom/blockquoted_transformers.dart'; import 'package:core/presentation/utils/html_transformer/dom/image_transformers.dart'; import 'package:core/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart'; -import 'package:core/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart'; import 'package:core/presentation/utils/html_transformer/dom/script_transformers.dart'; import 'package:core/presentation/utils/html_transformer/dom/sigature_transformers.dart'; import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart'; @@ -29,51 +28,19 @@ class TransformConfiguration { this.textTransformers ); - factory TransformConfiguration.forReplyForwardEmail() => TransformConfiguration.create( - customDomTransformers: [ - const ReplaceLazyLoadImageTransformer(), - if (PlatformInfo.isWeb) - const RemoveTooltipLinkTransformer(), - const SignatureTransformer(), - ] - ); + factory TransformConfiguration.fromDomTransformers(List domTransformers) => TransformConfiguration(domTransformers, []); - factory TransformConfiguration.forDraftsEmail() => TransformConfiguration.create( - customDomTransformers: [ - const RemoveScriptTransformer(), - const BlockQuotedTransformer(), - const BlockCodeTransformer(), - const AddTargetBlankInTagATransformer(), - const ImageTransformer(useLoadingAttribute: true), - ] - ); + factory TransformConfiguration.empty() => const TransformConfiguration([], []); - factory TransformConfiguration.forComposeEmailPlatformWeb() => TransformConfiguration.create( - customDomTransformers: [ - const RemoveScriptTransformer(), - const BlockQuotedTransformer(), - const BlockCodeTransformer(), - const AddTargetBlankInTagATransformer(), - const ImageTransformer(useLoadingAttribute: true), - const SignatureTransformer(), - ] - ); + factory TransformConfiguration.forReplyForwardEmail() => TransformConfiguration.fromDomTransformers([ + if (PlatformInfo.isWeb) + const RemoveTooltipLinkTransformer(), + const SignatureTransformer(), + ]); - factory TransformConfiguration.forComposeEmail() => TransformConfiguration.create( - customDomTransformers: [ - const RemoveScriptTransformer(), - const BlockQuotedTransformer(), - const BlockCodeTransformer(), - const AddTargetBlankInTagATransformer(), - const ImageTransformer(), - const SignatureTransformer(), - ], - customTextTransformers: [ - const SanitizeAutolinkHtmlTransformers() - ] - ); + factory TransformConfiguration.forDraftsEmail() => TransformConfiguration.empty(); - factory TransformConfiguration.forPreviewEmailPlatformWeb() => TransformConfiguration.create( + factory TransformConfiguration.forPreviewEmailOnWeb() => TransformConfiguration.create( customDomTransformers: [ const RemoveScriptTransformer(), const BlockQuotedTransformer(), @@ -84,6 +51,8 @@ class TransformConfiguration { ] ); + factory TransformConfiguration.forPreviewEmail() => TransformConfiguration.standardConfiguration; + /// Provides easy access to a standard configuration that does not block external images. static const TransformConfiguration standardConfiguration = TransformConfiguration( standardDomTransformers, diff --git a/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart b/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart index d09c374d5..c372dbd94 100644 --- a/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart +++ b/core/lib/presentation/views/html_viewer/html_content_viewer_widget.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'dart:math'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/html_transformer/html_event_action.dart'; @@ -54,7 +55,6 @@ class HtmlContentViewer extends StatefulWidget { class _HtmlContentViewState extends State { late double actualHeight; - double minHeight = 100; double minWidth = 300; String? _htmlData; late InAppWebViewController _webViewController; @@ -108,6 +108,7 @@ class _HtmlContentViewState extends State { widget.onCreated?.call(controller); }, onLoadStop: _onLoadStop, + onContentSizeChanged: _onContentSizeChanged, shouldOverrideUrlLoading: _shouldOverrideUrlLoading, gestureRecognizers: { Factory(() => LongPressGestureRecognizer()), @@ -152,6 +153,21 @@ class _HtmlContentViewState extends State { ); } + void _onContentSizeChanged( + InAppWebViewController controller, + Size oldContentSize, + Size newContentSize + ) async { + log('_HtmlContentViewState::_onContentSizeChanged:oldContentSize: $oldContentSize | newContentSize: $newContentSize'); + final maxContentHeight = max(oldContentSize.height, newContentSize.height); + log('_HtmlContentViewState::_onContentSizeChanged:maxContentHeight: $maxContentHeight'); + if (maxContentHeight > actualHeight) { + setState(() { + actualHeight = maxContentHeight; + }); + } + } + void _onHandleScrollEvent(List parameters) { log('_HtmlContentViewState::_onHandleScrollRightEvent():parameters: $parameters'); final message = parameters.first; @@ -167,13 +183,11 @@ class _HtmlContentViewState extends State { final scrollHeight = await _webViewController.evaluateJavascript(source: 'document.body.scrollHeight'); if (scrollHeight != null && mounted) { final scrollHeightWithBuffer = scrollHeight + 30.0; - if (scrollHeightWithBuffer > minHeight) { + if (scrollHeightWithBuffer > actualHeight) { setState(() { actualHeight = scrollHeightWithBuffer; _isLoading = false; }); - } else { - actualHeight = minHeight; } } } diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 6383e8ba8..7583a7b26 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -1297,19 +1297,12 @@ class ComposerController extends BaseController { final session = mailboxDashBoardController.sessionCurrent; final accountId = mailboxDashBoardController.accountId.value; if (session != null && accountId != null) { - TransformConfiguration transformConfiguration = TransformConfiguration.forComposeEmail(); - if (isDraftEmail) { - transformConfiguration = TransformConfiguration.forDraftsEmail(); - } else if (PlatformInfo.isWeb) { - transformConfiguration = TransformConfiguration.forComposeEmailPlatformWeb(); - } - consumeState(_getEmailContentInteractor.execute( session, accountId, emailId, mailboxDashBoardController.baseDownloadUrl, - transformConfiguration + TransformConfiguration.empty() )); } } diff --git a/lib/features/email/domain/usecases/get_list_detailed_email_by_id_interator.dart b/lib/features/email/domain/usecases/get_list_detailed_email_by_id_interator.dart index 255acecf5..97a5810fb 100644 --- a/lib/features/email/domain/usecases/get_list_detailed_email_by_id_interator.dart +++ b/lib/features/email/domain/usecases/get_list_detailed_email_by_id_interator.dart @@ -69,11 +69,11 @@ class GetListDetailedEmailByIdInteractor { accountId: accountId, downloadUrl: baseDownloadUrl ); - TransformConfiguration transformConfiguration = TransformConfiguration.standardConfiguration; + TransformConfiguration transformConfiguration = TransformConfiguration.forPreviewEmail(); if (email.isDraft) { transformConfiguration = TransformConfiguration.forDraftsEmail(); } else if (PlatformInfo.isWeb) { - transformConfiguration = TransformConfiguration.forPreviewEmailPlatformWeb(); + transformConfiguration = TransformConfiguration.forPreviewEmailOnWeb(); } final newEmailContents = await _emailRepository.transformEmailContent( email.emailContentList, diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index d401e7880..a68bdc74f 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -393,8 +393,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { if (session != null && accountId != null) { final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl) ?? ''; TransformConfiguration transformConfiguration = PlatformInfo.isWeb - ? TransformConfiguration.forPreviewEmailPlatformWeb() - : TransformConfiguration.standardConfiguration; + ? TransformConfiguration.forPreviewEmailOnWeb() + : TransformConfiguration.forPreviewEmail(); consumeState(_getEmailContentInteractor.execute( session,