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 66922d441..b09b285c2 100644
--- a/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart
+++ b/core/lib/presentation/utils/html_transformer/base/dom_transformer.dart
@@ -1,5 +1,7 @@
import 'package:core/data/network/dio_client.dart';
+import 'package:core/utils/app_logger.dart';
+import 'package:dartz/dartz.dart';
import 'package:html/dom.dart';
/// Transforms the HTML DOM.
@@ -22,4 +24,26 @@ abstract class DomTransformer {
document.children.insert(0, Element.html('
'));
}
}
+
+ Tuple2? findImageUrlFromStyleTag(String style) {
+ try {
+ final regExp = RegExp(r'background-image:\s*url\(([^)]+)\).*?');
+ final match = regExp.firstMatch(style);
+ if (match == null) {
+ return null;
+ }
+
+ final backgroundImageUrl = match.group(0) ?? '';
+ final imageUrl = match.group(1)?.replaceAll('\'', '').replaceAll('"', '') ?? '';
+ log('DomTransformer::findImageUrlFromStyleTag:backgroundImageUrl: $backgroundImageUrl | imageUrl: $imageUrl');
+ if (backgroundImageUrl.isNotEmpty && imageUrl.isNotEmpty) {
+ return Tuple2(backgroundImageUrl, imageUrl);
+ } else {
+ return null;
+ }
+ } catch (e) {
+ logError('DomTransformer::findImageUrlFromStyleTag:Exception: $e');
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/core/lib/presentation/utils/html_transformer/dom/add_lazy_loading_for_background_image_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/add_lazy_loading_for_background_image_transformers.dart
new file mode 100644
index 000000000..44d047412
--- /dev/null
+++ b/core/lib/presentation/utils/html_transformer/dom/add_lazy_loading_for_background_image_transformers.dart
@@ -0,0 +1,29 @@
+import 'package:core/data/network/dio_client.dart';
+import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
+import 'package:core/utils/app_logger.dart';
+import 'package:html/dom.dart';
+
+class AddLazyLoadingForBackgroundImageTransformer extends DomTransformer {
+ const AddLazyLoadingForBackgroundImageTransformer();
+
+ @override
+ Future process({
+ required Document document,
+ required DioClient dioClient,
+ Map? mapUrlDownloadCID,
+ }) async {
+ final elements = document.querySelectorAll('[style*="background-image"]');
+ log('AddLazyLoadingForBackgroundImageTagTransformer::process:elements: ${elements.length}');
+ await Future.wait(elements.map((element) async {
+ var exStyle = element.attributes['style'];
+ final imageUrls = findImageUrlFromStyleTag(exStyle!);
+ if (imageUrls != null) {
+ exStyle = exStyle.replaceFirst(imageUrls.value1, '');
+ element.attributes['style'] = exStyle;
+ element.attributes['data-src'] = imageUrls.value2;
+ element.attributes.addAll({'lazy': ''});
+ log('AddLazyLoadingForBackgroundImageTagTransformer::process:NEW_ELEMENT: ${element.outerHtml}');
+ }
+ }));
+ }
+}
diff --git a/core/lib/presentation/utils/html_transformer/html_utils.dart b/core/lib/presentation/utils/html_transformer/html_utils.dart
index 4ae3f938c..abfd1f33a 100644
--- a/core/lib/presentation/utils/html_transformer/html_utils.dart
+++ b/core/lib/presentation/utils/html_transformer/html_utils.dart
@@ -72,6 +72,29 @@ class HtmlUtils {
''';
+ static const scriptsHandleLazyLoadingBackgroundImage = '''
+
+ ''';
+
static String customCssStyleHtmlEditor({TextDirection direction = TextDirection.ltr}) {
if (PlatformInfo.isWeb) {
return '''
diff --git a/core/lib/presentation/utils/html_transformer/transform_configuration.dart b/core/lib/presentation/utils/html_transformer/transform_configuration.dart
index f581e3d4c..4ee39adee 100644
--- a/core/lib/presentation/utils/html_transformer/transform_configuration.dart
+++ b/core/lib/presentation/utils/html_transformer/transform_configuration.dart
@@ -2,6 +2,7 @@
import 'package:core/core.dart';
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
import 'package:core/presentation/utils/html_transformer/base/text_transformer.dart';
+import 'package:core/presentation/utils/html_transformer/dom/add_lazy_loading_for_background_image_transformers.dart';
import 'package:core/presentation/utils/html_transformer/dom/add_target_blank_in_tag_a_transformers.dart';
import 'package:core/presentation/utils/html_transformer/dom/blockcode_transformers.dart';
import 'package:core/presentation/utils/html_transformer/dom/blockquoted_transformers.dart';
@@ -48,6 +49,7 @@ class TransformConfiguration {
const AddTargetBlankInTagATransformer(),
const ImageTransformer(),
const AddTooltipLinkTransformer(),
+ const AddLazyLoadingForBackgroundImageTransformer(),
]
);
@@ -86,6 +88,7 @@ class TransformConfiguration {
BlockCodeTransformer(),
AddTargetBlankInTagATransformer(),
ImageTransformer(),
+ AddLazyLoadingForBackgroundImageTransformer(),
];
static const List standardTextTransformers = [
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 0eda8c597..88028f9d8 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
@@ -47,6 +47,7 @@ class _HtmlContentViewState extends State {
late InAppWebViewController _webViewController;
late double _actualHeight;
late Set> _gestureRecognizers;
+ late String _customScripts;
final _loadingBarNotifier = ValueNotifier(true);
@@ -60,7 +61,6 @@ class _HtmlContentViewState extends State {
@override
void initState() {
super.initState();
- _actualHeight = _minHeight;
if (PlatformInfo.isAndroid) {
_gestureRecognizers = {
Factory(() => LongPressGestureRecognizer()),
@@ -71,13 +71,12 @@ class _HtmlContentViewState extends State {
Factory(() => LongPressGestureRecognizer()),
};
}
- _htmlData = generateHtml(
- widget.contentHtml,
- direction: widget.direction,
- javaScripts: PlatformInfo.isAndroid
- ? HtmlUtils.scriptsHandleContentSizeChanged
- : null
- );
+ if (PlatformInfo.isAndroid) {
+ _customScripts = HtmlUtils.scriptsHandleLazyLoadingBackgroundImage + HtmlUtils.scriptsHandleContentSizeChanged;
+ } else {
+ _customScripts = HtmlUtils.scriptsHandleLazyLoadingBackgroundImage;
+ }
+ _initialData();
}
@override
@@ -86,17 +85,19 @@ class _HtmlContentViewState extends State {
log('_HtmlContentViewState::didUpdateWidget():Old-Direction: ${oldWidget.direction} | Current-Direction: ${widget.direction}');
if (widget.contentHtml != oldWidget.contentHtml ||
widget.direction != oldWidget.direction) {
- _actualHeight = _minHeight;
- _htmlData = generateHtml(
- widget.contentHtml,
- direction: widget.direction,
- javaScripts: PlatformInfo.isAndroid
- ? HtmlUtils.scriptsHandleContentSizeChanged
- : null
- );
+ _initialData();
}
}
+ void _initialData() {
+ _actualHeight = _minHeight;
+ _htmlData = generateHtml(
+ widget.contentHtml,
+ direction: widget.direction,
+ javaScripts: _customScripts
+ );
+ }
+
@override
Widget build(BuildContext context) {
return Stack(children: [
diff --git a/core/test/utils/html_utils_test.dart b/core/test/utils/html_utils_test.dart
new file mode 100644
index 000000000..c1228052a
--- /dev/null
+++ b/core/test/utils/html_utils_test.dart
@@ -0,0 +1,34 @@
+import 'package:core/presentation/utils/html_transformer/dom/image_transformers.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ const imageTransformer = ImageTransformer();
+
+ group('findImageUrlFromStyleTag test', () {
+ test('Test findImageUrlFromStyleTag with valid input', () {
+ const style = 'background-image: url(\'example.com/image.jpg\');';
+ final result = imageTransformer.findImageUrlFromStyleTag(style);
+ expect(result!.value1, 'background-image: url(\'example.com/image.jpg\')');
+ expect(result.value2, 'example.com/image.jpg');
+ });
+
+ test('Test findImageUrlFromStyleTag with valid input and no quotation marks', () {
+ const style = 'background-image: url(example.com/image.jpg);';
+ final result = imageTransformer.findImageUrlFromStyleTag(style);
+ expect(result!.value1, 'background-image: url(example.com/image.jpg)');
+ expect(result.value2, 'example.com/image.jpg');
+ });
+
+ test('Test findImageUrlFromStyleTag with empty input', () {
+ const style = '';
+ final result = imageTransformer.findImageUrlFromStyleTag(style);
+ expect(result, null);
+ });
+
+ test('Test findImageUrlFromStyleTag with invalid input', () {
+ const style = 'background-image: invalid-url(\'example.com/image.jpg\');';
+ final result = imageTransformer.findImageUrlFromStyleTag(style);
+ expect(result, null);
+ });
+ });
+}
\ No newline at end of file