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 f560a4a63..05ddb4764 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
@@ -16,6 +16,7 @@ import 'package:universal_html/html.dart' as html;
typedef OnClickHyperLinkAction = Function(Uri?);
typedef OnMailtoClicked = void Function(Uri? uri);
typedef OnIFrameKeyboardShortcutAction = void Function(KeyShortcut keyShortcut);
+typedef OnIFrameClickAction = void Function();
class HtmlContentViewerOnWeb extends StatefulWidget {
@@ -34,6 +35,8 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
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
final bool allowResizeToDocumentSize;
@@ -47,6 +50,7 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
final double offsetHtmlContentHeight;
final double? viewMaxHeight;
final bool autoAdjustHeight;
+ final bool useLinkTooltipOverlay;
const HtmlContentViewerOnWeb({
Key? key,
@@ -65,12 +69,14 @@ class HtmlContentViewerOnWeb extends StatefulWidget {
this.keepAlive = false,
this.disableScrolling = false,
this.autoAdjustHeight = false,
+ this.useLinkTooltipOverlay = false,
this.fontSize = 14,
this.htmlContentMinHeight = ConstantsUI.htmlContentMinHeight,
this.htmlContentMinWidth = ConstantsUI.htmlContentMinWidth,
this.offsetHtmlContentHeight = ConstantsUI.htmlContentOffsetHeight,
this.viewMaxHeight,
this.onIFrameKeyboardShortcutAction,
+ this.onIFrameClickAction,
}) : super(key: key);
@override
@@ -124,6 +130,9 @@ class _HtmlContentViewerOnWebState extends State
} else if (_isIframeKeyboardEventTriggered(type)) {
_handleOnIFrameKeyboardEvent(data);
return;
+ } else if (_isIframeClickEventTriggered(type)) {
+ _handleOnIFrameClickEvent(data);
+ return;
}
if (data['message'] == iframeOnLoadMessage) {
@@ -288,6 +297,20 @@ class _HtmlContentViewerOnWebState extends State
}
}
+ 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
void didUpdateWidget(covariant HtmlContentViewerOnWeb oldWidget) {
super.didUpdateWidget(oldWidget);
@@ -431,6 +454,8 @@ class _HtmlContentViewerOnWebState extends State
),
if (widget.onIFrameKeyboardShortcutAction != null)
HtmlInteraction.scriptHandleIframeKeyboardListener(_createdViewId),
+ if (widget.useLinkTooltipOverlay)
+ HtmlInteraction.scriptsHandleIframeClickListener(_createdViewId),
].join();
final htmlTemplate = HtmlUtils.generateHtmlDocument(
diff --git a/core/lib/utils/html/html_interaction.dart b/core/lib/utils/html/html_interaction.dart
index 0b33f01c7..4b1b78f34 100644
--- a/core/lib/utils/html/html_interaction.dart
+++ b/core/lib/utils/html/html_interaction.dart
@@ -405,4 +405,18 @@ class HtmlInteraction {
}
''';
+
+ static String scriptsHandleIframeClickListener(String viewId) => '''
+
+ ''';
}
\ No newline at end of file
diff --git a/lib/features/composer/presentation/controller/rich_text_web_controller.dart b/lib/features/composer/presentation/controller/rich_text_web_controller.dart
index 79e66c3ee..d4483793d 100644
--- a/lib/features/composer/presentation/controller/rich_text_web_controller.dart
+++ b/lib/features/composer/presentation/controller/rich_text_web_controller.dart
@@ -325,6 +325,12 @@ class RichTextWebController extends GetxController {
bool get isFormattingOptionsEnabled => formattingOptionsState.value == FormattingOptionsState.enabled;
+ void openInsertLink() {
+ FocusManager.instance.primaryFocus?.unfocus();
+ editorController.setFocus();
+ editorController.openInsertLinkDialog();
+ }
+
@override
void onClose() {
menuParagraphController.dispose();
diff --git a/lib/features/composer/presentation/extensions/handle_insert_link_composer_extension.dart b/lib/features/composer/presentation/extensions/handle_insert_link_composer_extension.dart
index 0b6ed3793..495341bd0 100644
--- a/lib/features/composer/presentation/extensions/handle_insert_link_composer_extension.dart
+++ b/lib/features/composer/presentation/extensions/handle_insert_link_composer_extension.dart
@@ -9,7 +9,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension HandleInsertLinkComposerExtension on ComposerController {
void openInsertLink() {
- richTextWebController?.editorController.openInsertLinkDialog();
+ richTextWebController?.openInsertLink();
}
LinkOverlayOptions createLinkOverlayOptions(BuildContext context) {
diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart
index b053e81ea..8f57b8939 100644
--- a/lib/features/email/presentation/email_view.dart
+++ b/lib/features/email/presentation/email_view.dart
@@ -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/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/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/styles/email_view_styles.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 {
presentationEmail: controller.currentEmail,
scrollController: scrollController,
isInsideThreadDetailView: isInsideThreadDetailView,
+ onIFrameClickAction: controller.handleOnIFrameClick,
)),
],
)
@@ -361,8 +363,10 @@ class EmailView extends GetWidget {
useDefaultFontStyle: true,
scrollController: scrollController,
enableQuoteToggle: true,
+ useLinkTooltipOverlay: true,
fontSize: isMobileResponsive ? 16 : 14,
onIFrameKeyboardShortcutAction: onIFrameKeyboardShortcutAction,
+ onIFrameClickAction: controller.handleOnIFrameClick,
),
);
} else if (PlatformInfo.isIOS) {
diff --git a/lib/features/email/presentation/extensions/handle_on_iframe_click_in_email_extension.dart b/lib/features/email/presentation/extensions/handle_on_iframe_click_in_email_extension.dart
new file mode 100644
index 000000000..24c9a8fde
--- /dev/null
+++ b/lib/features/email/presentation/extensions/handle_on_iframe_click_in_email_extension.dart
@@ -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();
+ }
+ }
+}
diff --git a/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart b/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart
index c952befdc..9e0887cb7 100644
--- a/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart
+++ b/lib/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart
@@ -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:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
@@ -18,6 +19,7 @@ class CalendarEventDetailWidget extends StatelessWidget {
final PresentationEmail? presentationEmail;
final ScrollController? scrollController;
final bool isInsideThreadDetailView;
+ final OnIFrameClickAction? onIFrameClickAction;
const CalendarEventDetailWidget({
super.key,
@@ -27,6 +29,7 @@ class CalendarEventDetailWidget extends StatelessWidget {
this.presentationEmail,
this.scrollController,
this.isInsideThreadDetailView = false,
+ this.onIFrameClickAction,
});
@override
@@ -65,6 +68,7 @@ class CalendarEventDetailWidget extends StatelessWidget {
onMailtoDelegateAction: onMailtoDelegateAction,
scrollController: scrollController,
isInsideThreadDetailView: isInsideThreadDetailView,
+ onIFrameClickAction: onIFrameClickAction,
)
),
],
diff --git a/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart b/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart
index 795d399f1..0152f09de 100644
--- a/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart
+++ b/lib/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart
@@ -16,6 +16,7 @@ class EventBodyContentWidget extends StatelessWidget {
final OnMailtoDelegateAction? onMailtoDelegateAction;
final ScrollController? scrollController;
final bool isInsideThreadDetailView;
+ final OnIFrameClickAction? onIFrameClickAction;
const EventBodyContentWidget({
super.key,
@@ -23,6 +24,7 @@ class EventBodyContentWidget extends StatelessWidget {
this.onMailtoDelegateAction,
this.scrollController,
this.isInsideThreadDetailView = false,
+ this.onIFrameClickAction,
});
@override
@@ -51,9 +53,11 @@ class EventBodyContentWidget extends StatelessWidget {
widthContent: constraints.maxWidth,
contentHtml: content,
useDefaultFontStyle: true,
+ useLinkTooltipOverlay: true,
mailtoDelegate: onMailtoDelegateAction,
direction: AppUtils.getCurrentDirection(context),
scrollController: scrollController,
+ onIFrameClickAction: onIFrameClickAction,
);
})
)