TF-4142 Close link overlay when click email content view
This commit is contained in:
@@ -16,6 +16,7 @@ import 'package:universal_html/html.dart' as html;
|
|||||||
typedef OnClickHyperLinkAction = Function(Uri?);
|
typedef OnClickHyperLinkAction = Function(Uri?);
|
||||||
typedef OnMailtoClicked = void Function(Uri? uri);
|
typedef OnMailtoClicked = void Function(Uri? uri);
|
||||||
typedef OnIFrameKeyboardShortcutAction = void Function(KeyShortcut keyShortcut);
|
typedef OnIFrameKeyboardShortcutAction = void Function(KeyShortcut keyShortcut);
|
||||||
|
typedef OnIFrameClickAction = void Function();
|
||||||
|
|
||||||
class HtmlContentViewerOnWeb extends StatefulWidget {
|
class HtmlContentViewerOnWeb extends StatefulWidget {
|
||||||
|
|
||||||
@@ -34,6 +35,8 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
|
|||||||
|
|
||||||
final OnIFrameKeyboardShortcutAction? onIFrameKeyboardShortcutAction;
|
final OnIFrameKeyboardShortcutAction? onIFrameKeyboardShortcutAction;
|
||||||
|
|
||||||
|
final OnIFrameClickAction? onIFrameClickAction;
|
||||||
|
|
||||||
// if widthContent is bigger than width of htmlContent, set this to true let widget able to resize to width of htmlContent
|
// if widthContent is bigger than width of htmlContent, set this to true let widget able to resize to width of htmlContent
|
||||||
final bool allowResizeToDocumentSize;
|
final bool allowResizeToDocumentSize;
|
||||||
|
|
||||||
@@ -47,6 +50,7 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
|
|||||||
final double offsetHtmlContentHeight;
|
final double offsetHtmlContentHeight;
|
||||||
final double? viewMaxHeight;
|
final double? viewMaxHeight;
|
||||||
final bool autoAdjustHeight;
|
final bool autoAdjustHeight;
|
||||||
|
final bool useLinkTooltipOverlay;
|
||||||
|
|
||||||
const HtmlContentViewerOnWeb({
|
const HtmlContentViewerOnWeb({
|
||||||
Key? key,
|
Key? key,
|
||||||
@@ -65,12 +69,14 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
|
|||||||
this.keepAlive = false,
|
this.keepAlive = false,
|
||||||
this.disableScrolling = false,
|
this.disableScrolling = false,
|
||||||
this.autoAdjustHeight = false,
|
this.autoAdjustHeight = false,
|
||||||
|
this.useLinkTooltipOverlay = false,
|
||||||
this.fontSize = 14,
|
this.fontSize = 14,
|
||||||
this.htmlContentMinHeight = ConstantsUI.htmlContentMinHeight,
|
this.htmlContentMinHeight = ConstantsUI.htmlContentMinHeight,
|
||||||
this.htmlContentMinWidth = ConstantsUI.htmlContentMinWidth,
|
this.htmlContentMinWidth = ConstantsUI.htmlContentMinWidth,
|
||||||
this.offsetHtmlContentHeight = ConstantsUI.htmlContentOffsetHeight,
|
this.offsetHtmlContentHeight = ConstantsUI.htmlContentOffsetHeight,
|
||||||
this.viewMaxHeight,
|
this.viewMaxHeight,
|
||||||
this.onIFrameKeyboardShortcutAction,
|
this.onIFrameKeyboardShortcutAction,
|
||||||
|
this.onIFrameClickAction,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -124,6 +130,9 @@ class _HtmlContentViewerOnWebState extends State<HtmlContentViewerOnWeb>
|
|||||||
} else if (_isIframeKeyboardEventTriggered(type)) {
|
} else if (_isIframeKeyboardEventTriggered(type)) {
|
||||||
_handleOnIFrameKeyboardEvent(data);
|
_handleOnIFrameKeyboardEvent(data);
|
||||||
return;
|
return;
|
||||||
|
} else if (_isIframeClickEventTriggered(type)) {
|
||||||
|
_handleOnIFrameClickEvent(data);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data['message'] == iframeOnLoadMessage) {
|
if (data['message'] == iframeOnLoadMessage) {
|
||||||
@@ -288,6 +297,20 @@ class _HtmlContentViewerOnWebState extends State<HtmlContentViewerOnWeb>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _isIframeClickEventTriggered(String? type) {
|
||||||
|
return widget.useLinkTooltipOverlay &&
|
||||||
|
type?.contains('toDart: iframeClick') == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleOnIFrameClickEvent(dynamic data) {
|
||||||
|
try {
|
||||||
|
log('$runtimeType::_handleOnIFrameClickEvent: $data');
|
||||||
|
widget.onIFrameClickAction?.call();
|
||||||
|
} catch (e) {
|
||||||
|
logError('$runtimeType::_handleOnIFrameClickEvent: Exception = $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant HtmlContentViewerOnWeb oldWidget) {
|
void didUpdateWidget(covariant HtmlContentViewerOnWeb oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
@@ -431,6 +454,8 @@ class _HtmlContentViewerOnWebState extends State<HtmlContentViewerOnWeb>
|
|||||||
),
|
),
|
||||||
if (widget.onIFrameKeyboardShortcutAction != null)
|
if (widget.onIFrameKeyboardShortcutAction != null)
|
||||||
HtmlInteraction.scriptHandleIframeKeyboardListener(_createdViewId),
|
HtmlInteraction.scriptHandleIframeKeyboardListener(_createdViewId),
|
||||||
|
if (widget.useLinkTooltipOverlay)
|
||||||
|
HtmlInteraction.scriptsHandleIframeClickListener(_createdViewId),
|
||||||
].join();
|
].join();
|
||||||
|
|
||||||
final htmlTemplate = HtmlUtils.generateHtmlDocument(
|
final htmlTemplate = HtmlUtils.generateHtmlDocument(
|
||||||
|
|||||||
@@ -405,4 +405,18 @@ class HtmlInteraction {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
''';
|
''';
|
||||||
|
|
||||||
|
static String scriptsHandleIframeClickListener(String viewId) => '''
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener('click', function (e) {
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
view: '$viewId',
|
||||||
|
type: 'toDart: iframeClick',
|
||||||
|
};
|
||||||
|
window.parent.postMessage(JSON.stringify(payload), "*");
|
||||||
|
} catch (_) {}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
''';
|
||||||
}
|
}
|
||||||
@@ -325,6 +325,12 @@ class RichTextWebController extends GetxController {
|
|||||||
|
|
||||||
bool get isFormattingOptionsEnabled => formattingOptionsState.value == FormattingOptionsState.enabled;
|
bool get isFormattingOptionsEnabled => formattingOptionsState.value == FormattingOptionsState.enabled;
|
||||||
|
|
||||||
|
void openInsertLink() {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
editorController.setFocus();
|
||||||
|
editorController.openInsertLinkDialog();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
menuParagraphController.dispose();
|
menuParagraphController.dispose();
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
|||||||
|
|
||||||
extension HandleInsertLinkComposerExtension on ComposerController {
|
extension HandleInsertLinkComposerExtension on ComposerController {
|
||||||
void openInsertLink() {
|
void openInsertLink() {
|
||||||
richTextWebController?.editorController.openInsertLinkDialog();
|
richTextWebController?.openInsertLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkOverlayOptions createLinkOverlayOptions(BuildContext context) {
|
LinkOverlayOptions createLinkOverlayOptions(BuildContext context) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import 'package:tmail_ui_user/features/base/widget/optional_expanded.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/widget/optional_scroll.dart';
|
import 'package:tmail_ui_user/features/base/widget/optional_scroll.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart';
|
import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_event_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_event_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/extensions/handle_on_iframe_click_in_email_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/extensions/validate_display_free_busy_message_extension.dart';
|
import 'package:tmail_ui_user/features/email/presentation/extensions/validate_display_free_busy_message_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/styles/email_view_styles.dart';
|
import 'package:tmail_ui_user/features/email/presentation/styles/email_view_styles.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart';
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart';
|
||||||
@@ -340,6 +341,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
presentationEmail: controller.currentEmail,
|
presentationEmail: controller.currentEmail,
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
isInsideThreadDetailView: isInsideThreadDetailView,
|
isInsideThreadDetailView: isInsideThreadDetailView,
|
||||||
|
onIFrameClickAction: controller.handleOnIFrameClick,
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -361,8 +363,10 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
useDefaultFontStyle: true,
|
useDefaultFontStyle: true,
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
enableQuoteToggle: true,
|
enableQuoteToggle: true,
|
||||||
|
useLinkTooltipOverlay: true,
|
||||||
fontSize: isMobileResponsive ? 16 : 14,
|
fontSize: isMobileResponsive ? 16 : 14,
|
||||||
onIFrameKeyboardShortcutAction: onIFrameKeyboardShortcutAction,
|
onIFrameKeyboardShortcutAction: onIFrameKeyboardShortcutAction,
|
||||||
|
onIFrameClickAction: controller.handleOnIFrameClick,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (PlatformInfo.isIOS) {
|
} else if (PlatformInfo.isIOS) {
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:html_editor_enhanced/html_editor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart';
|
||||||
|
|
||||||
|
extension HandleOnIframeClickInEmailExtension on SingleEmailController {
|
||||||
|
void handleOnIFrameClick() {
|
||||||
|
log('$runtimeType::handleOnIFrameClick');
|
||||||
|
if (LinkOverlayManager.instance.hasActiveOverlays) {
|
||||||
|
LinkOverlayManager.instance.hideAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:core/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart';
|
||||||
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
|
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
|
import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
|
||||||
@@ -18,6 +19,7 @@ class CalendarEventDetailWidget extends StatelessWidget {
|
|||||||
final PresentationEmail? presentationEmail;
|
final PresentationEmail? presentationEmail;
|
||||||
final ScrollController? scrollController;
|
final ScrollController? scrollController;
|
||||||
final bool isInsideThreadDetailView;
|
final bool isInsideThreadDetailView;
|
||||||
|
final OnIFrameClickAction? onIFrameClickAction;
|
||||||
|
|
||||||
const CalendarEventDetailWidget({
|
const CalendarEventDetailWidget({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -27,6 +29,7 @@ class CalendarEventDetailWidget extends StatelessWidget {
|
|||||||
this.presentationEmail,
|
this.presentationEmail,
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
this.isInsideThreadDetailView = false,
|
this.isInsideThreadDetailView = false,
|
||||||
|
this.onIFrameClickAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -65,6 +68,7 @@ class CalendarEventDetailWidget extends StatelessWidget {
|
|||||||
onMailtoDelegateAction: onMailtoDelegateAction,
|
onMailtoDelegateAction: onMailtoDelegateAction,
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
isInsideThreadDetailView: isInsideThreadDetailView,
|
isInsideThreadDetailView: isInsideThreadDetailView,
|
||||||
|
onIFrameClickAction: onIFrameClickAction,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class EventBodyContentWidget extends StatelessWidget {
|
|||||||
final OnMailtoDelegateAction? onMailtoDelegateAction;
|
final OnMailtoDelegateAction? onMailtoDelegateAction;
|
||||||
final ScrollController? scrollController;
|
final ScrollController? scrollController;
|
||||||
final bool isInsideThreadDetailView;
|
final bool isInsideThreadDetailView;
|
||||||
|
final OnIFrameClickAction? onIFrameClickAction;
|
||||||
|
|
||||||
const EventBodyContentWidget({
|
const EventBodyContentWidget({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -23,6 +24,7 @@ class EventBodyContentWidget extends StatelessWidget {
|
|||||||
this.onMailtoDelegateAction,
|
this.onMailtoDelegateAction,
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
this.isInsideThreadDetailView = false,
|
this.isInsideThreadDetailView = false,
|
||||||
|
this.onIFrameClickAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -51,9 +53,11 @@ class EventBodyContentWidget extends StatelessWidget {
|
|||||||
widthContent: constraints.maxWidth,
|
widthContent: constraints.maxWidth,
|
||||||
contentHtml: content,
|
contentHtml: content,
|
||||||
useDefaultFontStyle: true,
|
useDefaultFontStyle: true,
|
||||||
|
useLinkTooltipOverlay: true,
|
||||||
mailtoDelegate: onMailtoDelegateAction,
|
mailtoDelegate: onMailtoDelegateAction,
|
||||||
direction: AppUtils.getCurrentDirection(context),
|
direction: AppUtils.getCurrentDirection(context),
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
|
onIFrameClickAction: onIFrameClickAction,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user