From be6006510e416b74a6ad1c7deb09d46c691ed238 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 17 Mar 2022 16:24:40 +0700 Subject: [PATCH] TF-330 Fix can not scroll email content in browser --- .../html_content_viewer_on_web_widget.dart | 74 ++++++++++++------- .../email/presentation/email_view.dart | 69 +++++++++-------- .../widgets/email_content_item_builder.dart | 16 +++- 3 files changed, 94 insertions(+), 65 deletions(-) diff --git a/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart b/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart index 22dd8a3d2..f7d35749e 100644 --- a/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart +++ b/core/lib/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart @@ -6,20 +6,22 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/html_viewer/html_viewer_controller_for_web.dart'; import 'package:flutter/material.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; -import 'dart:developer' as developer; import 'package:universal_html/html.dart' as html; import 'package:core/presentation/utils/shims/dart_ui.dart' as ui; +import 'package:core/utils/app_logger.dart' as logger; class HtmlContentViewerOnWeb extends StatefulWidget { final String contentHtml; final double widthContent; + final double heightContent; final HtmlViewerControllerForWeb controller; const HtmlContentViewerOnWeb({ Key? key, required this.contentHtml, required this.widthContent, + required this.heightContent, required this.controller, }) : super(key: key); @@ -33,16 +35,20 @@ class _HtmlContentViewerOnWebState extends State { late String createdViewId; /// The actual height of the editor, used to automatically set the height late double actualHeight; + /// The actual width of the editor, used to automatically set the width + late double actualWidth; Future? webInit; String? _htmlData; bool _isLoading = true; int minHeight = 100; + int minWidth = 300; @override void initState() { super.initState(); - actualHeight = 400; + actualHeight = widget.heightContent; + actualWidth = widget.widthContent; createdViewId = _getRandString(10); widget.controller.viewId = createdViewId; _setUpWeb(); @@ -67,6 +73,10 @@ class _HtmlContentViewerOnWebState extends State { var height = document.body.scrollHeight; window.parent.postMessage(JSON.stringify({"view": "$createdViewId", "type": "toDart: htmlHeight", "height": height}), "*"); } + if (data["type"].includes("getWidth")) { + var width = document.body.scrollWidth; + window.parent.postMessage(JSON.stringify({"view": "$createdViewId", "type": "toDart: htmlWidth", "width": width}), "*"); + } if (data["type"].includes("execCommand")) { if (data["argument"] === null) { document.execCommand(data["command"], false); @@ -90,7 +100,7 @@ class _HtmlContentViewerOnWebState extends State { #editor { outline: 0px solid transparent; min-height: ${minHeight}px; - min-width: 300px; + min-width: ${minWidth}px; color: #000000; font-family: verdana; } @@ -122,30 +132,30 @@ class _HtmlContentViewerOnWebState extends State { _htmlData = _generateHtmlDocument(widget.contentHtml); final iframe = html.IFrameElement() - ..width = widget.widthContent.toString() + ..width = actualWidth.toString() ..height = actualHeight.toString() ..srcdoc = _htmlData ?? '' ..style.border = 'none' ..style.overflow = 'hidden' ..onLoad.listen((event) async { - var data = {'type': 'toIframe: getHeight'}; - data['view'] = createdViewId; - final jsonEncoder = JsonEncoder(); - var jsonStr = jsonEncoder.convert(data); - html.window.postMessage(jsonStr, '*'); + final dataGetHeight = {'type': 'toIframe: getHeight', 'view' : createdViewId}; + final dataGetWidth = {'type': 'toIframe: getWidth', 'view' : createdViewId}; - html.window.onBeforeUnload.listen((event) { - event.preventDefault(); - }); + final jsonEncoder = JsonEncoder(); + final jsonGetHeight = jsonEncoder.convert(dataGetHeight); + final jsonGetWidth = jsonEncoder.convert(dataGetWidth); + + logger.log('HtmlContentViewerOnWeb() | onLoad | jsonGetHeight: $jsonGetHeight'); + logger.log('HtmlContentViewerOnWeb() | onLoad | jsonGetWidth: $jsonGetWidth'); + + html.window.postMessage(jsonGetHeight, '*'); + html.window.postMessage(jsonGetWidth, '*'); html.window.onMessage.listen((event) { var data = json.decode(event.data); - developer.log('onMessage(): data: $data', name: 'HtmlContentViewerOnWeb'); - if (data['type'] != null && - data['type'].contains('toDart: htmlHeight') && - data['view'] == createdViewId) { + if (data['type'] != null && data['type'].contains('toDart: htmlHeight') && data['view'] == createdViewId) { final docHeight = data['height'] ?? actualHeight; - developer.log('onMessage(): docHeight: $docHeight', name: 'HtmlContentViewerOnWeb'); + logger.log('HtmlContentViewerOnWeb() | onMessage | docHeight: $docHeight'); if (docHeight != null && mounted) { final scrollHeightWithBuffer = docHeight + 30.0; if (scrollHeightWithBuffer > minHeight) { @@ -161,9 +171,20 @@ class _HtmlContentViewerOnWebState extends State { }); } } - if (data['type'] != null && - data['type'].contains('toDart: onChangeContent') && - data['view'] == createdViewId) { + + if (data['type'] != null && data['type'].contains('toDart: htmlWidth') && data['view'] == createdViewId) { + final docWidth = data['width'] ?? actualWidth; + logger.log('HtmlContentViewerOnWeb() | onMessage | docWidth: $docWidth'); + if (docWidth != null && mounted) { + if (docWidth > minWidth) { + setState(() { + actualWidth = docWidth; + }); + } + } + } + + if (data['type'] != null && data['type'].contains('toDart: onChangeContent') && data['view'] == createdViewId) { if (Scrollable.of(context) != null) { Scrollable.of(context)!.position.ensureVisible( context.findRenderObject()!, @@ -174,9 +195,6 @@ class _HtmlContentViewerOnWebState extends State { }); }); - iframe.setAttribute('scrolling', 'no'); - iframe.setAttribute('seamless', 'seamless'); - ui.platformViewRegistry.registerViewFactory(createdViewId, (int viewId) => iframe); if (mounted) { @@ -193,9 +211,13 @@ class _HtmlContentViewerOnWebState extends State { children: [ SizedBox( height: actualHeight, - width: widget.widthContent, + width: actualWidth, child: _buildWebView(), ), + PointerInterceptor(child: SizedBox( + height: actualHeight, + width: actualWidth, + )), if (_isLoading) _buildLoadingView() ], ); @@ -222,10 +244,10 @@ class _HtmlContentViewerOnWebState extends State { future: webInit, builder: (context, snapshot) { if (snapshot.hasData) { - return PointerInterceptor(child: HtmlElementView( + return HtmlElementView( key: ValueKey(htmlData), viewType: createdViewId, - )); + ); } else { return Container(); } diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 91931833d..a81490d99 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -143,30 +143,33 @@ class EmailView extends GetView { padding: EdgeInsets.only(bottom: 16, left: 16, right: 16, top: 10), alignment: Alignment.center, color: Colors.white, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded(child: _buildEmailSubject()), - _buildEmailTime(context), - ]), - _buildDivider(edgeInsets: EdgeInsets.only(top: 16)), - Obx(() => emailController.currentEmail != null - ? _buildEmailAddress( - context, - emailController.currentEmail!, - emailController.emailAddressExpandMode.value, - emailController.isDisplayFullEmailAddress.value) - : SizedBox.shrink()), - _buildDivider(edgeInsets: EdgeInsets.only(top: 4)), - _buildAttachments(context), - _buildListEmailContent(), - ], - ) + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded(child: _buildEmailSubject()), + _buildEmailTime(context), + ]), + _buildDivider(edgeInsets: EdgeInsets.only(top: 16)), + Obx(() => emailController.currentEmail != null + ? _buildEmailAddress( + context, + emailController.currentEmail!, + emailController.emailAddressExpandMode.value, + emailController.isDisplayFullEmailAddress.value) + : SizedBox.shrink()), + _buildDivider(edgeInsets: EdgeInsets.only(top: 4)), + _buildAttachments(context), + _buildListEmailContent(context, constraints), + ], + ); + }) ); } @@ -445,7 +448,7 @@ class EmailView extends GetView { ); } - Widget _buildListEmailContent() { + Widget _buildListEmailContent(BuildContext context, BoxConstraints constraints) { return Obx(() => emailController.viewState.value.fold( (failure) => SizedBox.shrink(), (success) { @@ -453,18 +456,14 @@ class EmailView extends GetView { return EmailContentPlaceHolderLoading(responsiveUtils: responsiveUtils); } else { if (emailController.emailContents.isNotEmpty) { - return ListView.builder( - primary: false, - shrinkWrap: true, - padding: EdgeInsets.only(top: 10), - key: Key('list_email_content'), - itemCount: emailController.emailContents.length, - itemBuilder: (context, index) => - EmailContentItemBuilder( + return Column(children: [ + ...emailController.emailContents.map((content) => EmailContentItemBuilder( context, - emailController.emailContents[index], + content, + constraints, loadingWidget: EmailContentPlaceHolderLoading(responsiveUtils: responsiveUtils) - ).build()); + ).build()).toList(), + ]); } else { return SizedBox.shrink(); } diff --git a/lib/features/email/presentation/widgets/email_content_item_builder.dart b/lib/features/email/presentation/widgets/email_content_item_builder.dart index 3149dc474..612521636 100644 --- a/lib/features/email/presentation/widgets/email_content_item_builder.dart +++ b/lib/features/email/presentation/widgets/email_content_item_builder.dart @@ -9,10 +9,12 @@ class EmailContentItemBuilder { final BuildContext _context; final EmailContent _emailContent; final Widget? loadingWidget; + final BoxConstraints _constraints; EmailContentItemBuilder( this._context, this._emailContent, + this._constraints, { this.loadingWidget } @@ -31,13 +33,19 @@ class EmailContentItemBuilder { } Widget _buildItem() { + log('EmailContentItemBuilder() | maxWidth: ${_constraints.maxWidth}'); + log('EmailContentItemBuilder() | heightScreen: ${MediaQuery.of(_context).size.height}'); switch(_emailContent.type) { case EmailContentType.textHtml: if (kIsWeb) { - return HtmlContentViewerOnWeb( - widthContent: MediaQuery.of(_context).size.width, - contentHtml: _emailContent.content, - controller: HtmlViewerControllerForWeb()); + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: HtmlContentViewerOnWeb( + widthContent: _constraints.maxWidth, + heightContent: MediaQuery.of(_context).size.height, + contentHtml: _emailContent.content, + controller: HtmlViewerControllerForWeb()), + ); } else { return HtmlContentViewer( widthContent: MediaQuery.of(_context).size.width,