TF-3644 Handle scroll thread detail when cursor is in email content area
Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
@@ -32,6 +32,7 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
|
||||
final bool allowResizeToDocumentSize;
|
||||
|
||||
final bool keepWidthWhileLoading;
|
||||
final ScrollController? scrollController;
|
||||
|
||||
const HtmlContentViewerOnWeb({
|
||||
Key? key,
|
||||
@@ -45,6 +46,7 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
|
||||
this.onClickHyperLinkAction,
|
||||
this.keepWidthWhileLoading = false,
|
||||
this.contentPadding,
|
||||
this.scrollController,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -65,10 +67,11 @@ class _HtmlContentViewerOnWebState extends State<HtmlContentViewerOnWeb> {
|
||||
String? _htmlData;
|
||||
bool _isLoading = true;
|
||||
double minHeight = 100;
|
||||
late final StreamSubscription<html.MessageEvent> sizeListener;
|
||||
late final StreamSubscription<html.MessageEvent> _onMessageSubscription;
|
||||
bool _iframeLoaded = false;
|
||||
static const String iframeOnLoadMessage = 'iframeHasBeenLoaded';
|
||||
static const String onClickHyperLinkName = 'onClickHyperLink';
|
||||
static const String onScrollChangedEvent = 'onScrollChanged';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -77,64 +80,112 @@ class _HtmlContentViewerOnWebState extends State<HtmlContentViewerOnWeb> {
|
||||
_actualWidth = widget.widthContent;
|
||||
_createdViewId = _getRandString(10);
|
||||
_setUpWeb();
|
||||
_onMessageSubscription = html.window.onMessage.listen(_handleMessageEvent);
|
||||
}
|
||||
|
||||
sizeListener = html.window.onMessage.listen((event) {
|
||||
var data = json.decode(event.data);
|
||||
void _handleMessageEvent(html.MessageEvent event) {
|
||||
try {
|
||||
final data = json.decode(event.data);
|
||||
|
||||
if (data['view'] != _createdViewId) return;
|
||||
final viewId = data['view'];
|
||||
if (viewId != _createdViewId) return;
|
||||
|
||||
final type = data['type'];
|
||||
if (_isScrollChangedEventTriggered(type)) {
|
||||
_handleIframeOnScrollChangedListener(data, widget.scrollController!);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data['message'] == iframeOnLoadMessage) {
|
||||
_iframeLoaded = true;
|
||||
}
|
||||
|
||||
if (!_iframeLoaded) return;
|
||||
|
||||
if (data['type'] != null && data['type'].contains('toDart: htmlHeight')) {
|
||||
final docHeight = data['height'] ?? _actualHeight;
|
||||
if (docHeight != null && mounted) {
|
||||
final scrollHeightWithBuffer = docHeight + 30.0;
|
||||
if (scrollHeightWithBuffer > minHeight) {
|
||||
setState(() {
|
||||
_actualHeight = scrollHeightWithBuffer;
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (mounted && _isLoading) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
if (_isHtmlContentHeightEventTriggered(type)) {
|
||||
_handleContentHeightEvent(data['height']);
|
||||
} else if (_isHtmlContentWidthEventTriggered(type)) {
|
||||
_handleContentWidthEvent(data['width']);
|
||||
} else if (_isMailtoLinkEventTriggered(type)) {
|
||||
_handleMailtoLinkEvent(data['url']);
|
||||
} else if (_isHyperLinkEventTriggered(type)) {
|
||||
_handleHyperLinkEvent(data['url']);
|
||||
}
|
||||
} catch (e) {
|
||||
logError('_HtmlContentViewerOnWebState::_handleMessageEvent:Exception = $e');
|
||||
}
|
||||
}
|
||||
|
||||
if (data['type'] != null && data['type'].contains('toDart: htmlWidth') && !widget.keepWidthWhileLoading) {
|
||||
final docWidth = data['width'] ?? _actualWidth;
|
||||
if (docWidth != null && mounted) {
|
||||
if (docWidth > _minWidth && widget.allowResizeToDocumentSize) {
|
||||
setState(() {
|
||||
_actualWidth = docWidth;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
bool _isScrollChangedEventTriggered(String? type) {
|
||||
return widget.scrollController != null &&
|
||||
type?.contains('toDart: $onScrollChangedEvent') == true;
|
||||
}
|
||||
|
||||
if (data['type'] != null && data['type'].contains('toDart: OpenLink')) {
|
||||
final link = data['url'];
|
||||
if (link != null && mounted) {
|
||||
final urlString = link as String;
|
||||
if (urlString.startsWith('mailto:')) {
|
||||
widget.mailtoDelegate?.call(Uri.parse(urlString));
|
||||
}
|
||||
}
|
||||
}
|
||||
void _handleIframeOnScrollChangedListener(
|
||||
dynamic data,
|
||||
ScrollController controller,
|
||||
) {
|
||||
final deltaY = data['deltaY'] ?? 0.0;
|
||||
final newOffset = controller.offset + deltaY;
|
||||
log('_HtmlContentViewerOnWebState::_handleIframeOnScrollChangedListener:deltaY = $deltaY | newOffset = $newOffset');
|
||||
if (newOffset < controller.position.minScrollExtent) {
|
||||
controller.jumpTo(controller.position.minScrollExtent);
|
||||
} else if (newOffset > controller.position.maxScrollExtent) {
|
||||
controller.jumpTo(controller.position.maxScrollExtent);
|
||||
} else {
|
||||
controller.jumpTo(newOffset);
|
||||
}
|
||||
}
|
||||
|
||||
if (data['type'] != null && data['type'].contains('toDart: $onClickHyperLinkName')) {
|
||||
final link = data['url'] as String?;
|
||||
if (link != null && mounted) {
|
||||
widget.onClickHyperLinkAction?.call(Uri.parse(link));
|
||||
}
|
||||
bool _isHtmlContentHeightEventTriggered(String? type) =>
|
||||
type?.contains('toDart: htmlHeight') == true;
|
||||
|
||||
void _handleContentHeightEvent(dynamic height) {
|
||||
final docHeight = height ?? _actualHeight;
|
||||
if (docHeight != null && mounted) {
|
||||
final scrollHeightWithBuffer = docHeight + 30.0;
|
||||
if (scrollHeightWithBuffer > minHeight) {
|
||||
setState(() {
|
||||
_actualHeight = scrollHeightWithBuffer;
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (mounted && _isLoading) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool _isHtmlContentWidthEventTriggered(String? type) =>
|
||||
type?.contains('toDart: htmlWidth') == true &&
|
||||
!widget.keepWidthWhileLoading;
|
||||
|
||||
void _handleContentWidthEvent(dynamic width) {
|
||||
final docWidth = width ?? _actualWidth;
|
||||
if (docWidth != null && mounted &&
|
||||
docWidth > _minWidth &&
|
||||
widget.allowResizeToDocumentSize) {
|
||||
setState(() => _actualWidth = docWidth);
|
||||
}
|
||||
}
|
||||
|
||||
bool _isMailtoLinkEventTriggered(String? type) =>
|
||||
type?.contains('toDart: OpenLink') == true;
|
||||
|
||||
void _handleMailtoLinkEvent(dynamic url) {
|
||||
if (url != null && mounted && url is String && url.startsWith('mailto:')) {
|
||||
widget.mailtoDelegate?.call(Uri.tryParse(url));
|
||||
}
|
||||
}
|
||||
|
||||
bool _isHyperLinkEventTriggered(String? type) =>
|
||||
type?.contains('toDart: $onClickHyperLinkName') == true;
|
||||
|
||||
void _handleHyperLinkEvent(dynamic url) {
|
||||
if (url != null && mounted && url is String) {
|
||||
widget.onClickHyperLinkAction?.call(Uri.tryParse(url));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -246,6 +297,17 @@ class _HtmlContentViewerOnWebState extends State<HtmlContentViewerOnWeb> {
|
||||
|
||||
resizeObserver.observe(document.body);
|
||||
}
|
||||
|
||||
${widget.scrollController != null ? '''
|
||||
window.addEventListener('wheel', function (event) {
|
||||
const deltaY = event.deltaY;
|
||||
window.parent.postMessage(JSON.stringify({
|
||||
"view": "$_createdViewId",
|
||||
"type": "toDart: $onScrollChangedEvent",
|
||||
"deltaY": deltaY
|
||||
}), "*");
|
||||
});
|
||||
''' : ''}
|
||||
</script>
|
||||
''';
|
||||
|
||||
@@ -362,7 +424,7 @@ class _HtmlContentViewerOnWebState extends State<HtmlContentViewerOnWeb> {
|
||||
@override
|
||||
void dispose() {
|
||||
_htmlData = null;
|
||||
sizeListener.cancel();
|
||||
_onMessageSubscription.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
||||
this.isFirstEmailInThreadDetail = false,
|
||||
this.threadSubject,
|
||||
this.onToggleThreadDetailCollapseExpand,
|
||||
this.scrollController,
|
||||
});
|
||||
|
||||
final bool isInsideThreadDetailView;
|
||||
@@ -63,7 +64,8 @@ class EmailView extends GetWidget<SingleEmailController> {
|
||||
final bool isFirstEmailInThreadDetail;
|
||||
final String? threadSubject;
|
||||
final VoidCallback? onToggleThreadDetailCollapseExpand;
|
||||
|
||||
final ScrollController? scrollController;
|
||||
|
||||
@override
|
||||
String? get tag => emailId?.id.value;
|
||||
|
||||
@@ -388,6 +390,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
||||
direction: AppUtils.getCurrentDirection(context),
|
||||
contentPadding: 0,
|
||||
useDefaultFont: true,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
if (controller.mailboxDashBoardController.isDisplayedOverlayViewOnIFrame)
|
||||
PointerInterceptor(
|
||||
|
||||
@@ -82,6 +82,7 @@ extension GetThreadDetailEmailViews on ThreadDetailController {
|
||||
onToggleThreadDetailCollapseExpand: () {
|
||||
toggleThreadDetailCollapeExpand(presentationEmail);
|
||||
},
|
||||
scrollController: scrollController,
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
|
||||
Reference in New Issue
Block a user