diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index b3659447f..4e72c1f4e 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -272,6 +272,7 @@ extension AppColor on Color { static const m3Primary95 = Color(0xFFE3F1FF); static const gray49454F = Color(0xFF49454F); static const lightGrayF9FAFB = Color(0xFFF9FAFB); + static const black4D4D4D = Color(0xFF4D4D4D); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/lib/features/composer/presentation/extensions/sanitize_signature_in_email_content_extension.dart b/lib/features/composer/presentation/extensions/sanitize_signature_in_email_content_extension.dart index 039c12b9d..11d4187fa 100644 --- a/lib/features/composer/presentation/extensions/sanitize_signature_in_email_content_extension.dart +++ b/lib/features/composer/presentation/extensions/sanitize_signature_in_email_content_extension.dart @@ -10,7 +10,7 @@ extension SanitizeSignatureInEmailContentExtension on ComposerController { if (emailContent == null) return; final emailDocument = parse(emailContent); - final existedSignatureButton = emailDocument.querySelector('button.tmail-signature-button'); + final existedSignatureButton = emailDocument.querySelector('.tmail-signature-button'); if (existedSignatureButton != null) return; final signature = emailDocument.querySelector('div.tmail-signature'); @@ -26,7 +26,7 @@ extension SanitizeSignatureInEmailContentExtension on ComposerController { void synchronizeInitEmailDraftHash(String? emailContent) { try { final emailDocument = parse(emailContent); - final signatureButton = emailDocument.querySelector('button.tmail-signature-button'); + final signatureButton = emailDocument.querySelector('.tmail-signature-button'); if (signatureButton == null) return; restoringSignatureButton = false; diff --git a/lib/features/composer/presentation/widgets/web/signature_tooltip_widget.dart b/lib/features/composer/presentation/widgets/web/signature_tooltip_widget.dart new file mode 100644 index 000000000..44919fccb --- /dev/null +++ b/lib/features/composer/presentation/widgets/web/signature_tooltip_widget.dart @@ -0,0 +1,40 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/utils/theme_utils.dart'; +import 'package:flutter/material.dart'; + +class SignatureTooltipWidget extends StatelessWidget { + final String message; + + const SignatureTooltipWidget({super.key, required this.message}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: AppColor.black4D4D4D, + borderRadius: const BorderRadius.all(Radius.circular(10)), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.16), + blurRadius: 24, + ), + BoxShadow( + color: Colors.black.withValues(alpha: 0.08), + blurRadius: 2, + ) + ] + ), + child: Text( + message, + style: ThemeUtils.textStyleInter600().copyWith( + color: Colors.white, + fontSize: 12, + height: 20 / 12, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ); + } +} diff --git a/lib/features/composer/presentation/widgets/web/web_editor_widget.dart b/lib/features/composer/presentation/widgets/web/web_editor_widget.dart index 332fd6ac0..10c414234 100644 --- a/lib/features/composer/presentation/widgets/web/web_editor_widget.dart +++ b/lib/features/composer/presentation/widgets/web/web_editor_widget.dart @@ -6,6 +6,8 @@ import 'package:core/utils/html/html_template.dart'; import 'package:core/utils/html/html_utils.dart'; import 'package:flutter/material.dart'; import 'package:html_editor_enhanced/html_editor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/web/signature_tooltip_widget.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:universal_html/html.dart' hide VoidCallback; typedef OnChangeContentEditorAction = Function(String? text); @@ -74,6 +76,11 @@ class _WebEditorState extends State { late HtmlEditorController _editorController; bool _dropListenerRegistered = false; Function(Event)? _dropListener; + + OverlayEntry? _signatureTooltipEntry; + final GlobalKey _signatureTooltipKey = GlobalKey(); + double _signatureTooltipLeft = 0; + bool _signatureTooltipReady = false; @override void initState() { @@ -108,6 +115,7 @@ class _WebEditorState extends State { window.removeEventListener("message", _dropListener!); _dropListener = null; } + _hideSignatureTooltip(); super.dispose(); } @@ -179,7 +187,92 @@ class _WebEditorState extends State { onImageUpload: widget.onPasteImageSuccessAction, onImageUploadError: widget.onPasteImageFailureAction, onInitialTextLoadComplete: widget.onInitialContentLoadComplete, + onSignatureHoverIn: (position, isContentVisible) { + log('_WebEditorState::build: onSignatureHoverIn position: $position'); + _showSignatureTooltipAtPosition( + position, + isContentVisible + ? AppLocalizations.of(context).hideSignature + : AppLocalizations.of(context).showSignature, + ); + }, + onSignatureHoverOut: () { + log('_WebEditorState::build: onSignatureHoverOut'); + _hideSignatureTooltip(); + }, ), ); } + + void _showSignatureTooltipAtPosition( + SignaturePosition position, + String message, + ) { + try { + final overlay = Overlay.maybeOf(context); + _signatureTooltipEntry?.remove(); + + _signatureTooltipReady = false; + _signatureTooltipLeft = position.left; + + _signatureTooltipEntry = OverlayEntry( + builder: (context) { + return Positioned( + top: position.top + position.height + 8, + left: _signatureTooltipLeft, + child: Material( + color: Colors.transparent, + child: Opacity( + opacity: _signatureTooltipReady ? 1 : 0, + child: SignatureTooltipWidget( + key: _signatureTooltipKey, + message: message, + ), + ), + ), + ); + }, + ); + + overlay?.insert(_signatureTooltipEntry!); + + WidgetsBinding.instance.addPostFrameCallback((_) { + try { + final renderBox = _signatureTooltipKey.currentContext + ?.findRenderObject() as RenderBox?; + if (renderBox == null) return; + + final tooltipWidth = renderBox.size.width; + final screenWidth = MediaQuery.of(context).size.width; + + final centerLeft = + position.left + (position.width / 2) - (tooltipWidth / 2); + final leftAligned = position.left; + final rightAligned = position.left + position.width - tooltipWidth; + + if (centerLeft < 8) { + _signatureTooltipLeft = leftAligned; + } else if (centerLeft + tooltipWidth > screenWidth - 8) { + _signatureTooltipLeft = rightAligned; + } else { + _signatureTooltipLeft = centerLeft; + } + + _signatureTooltipReady = true; + _signatureTooltipEntry?.markNeedsBuild(); + } catch (e) { + logError( + '_WebEditorState::_showTooltipAtPosition:addPostFrameCallback:Exception = $e', + ); + } + }); + } catch (e) { + logError('_WebEditorState::_showTooltipAtPosition:Exception = $e'); + } + } + + void _hideSignatureTooltip() { + _signatureTooltipEntry?.remove(); + _signatureTooltipEntry = null; + } } \ No newline at end of file diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index a0b468807..8eb045361 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4665,5 +4665,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "hideSignature": "Hide signature", + "@hideSignature": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "showSignature": "Show signature", + "@showSignature": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 1cfa57aec..58fb1b9e8 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -4920,4 +4920,18 @@ class AppLocalizations { name: 'dialogWarningMessageForForwardsToOtherDomains', ); } + + String get hideSignature { + return Intl.message( + 'Hide signature', + name: 'hideSignature', + ); + } + + String get showSignature { + return Intl.message( + 'Show signature', + name: 'showSignature', + ); + } } diff --git a/pubspec.lock b/pubspec.lock index 181726acf..e31ba9f32 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1268,10 +1268,10 @@ packages: description: path: "." ref: main - resolved-ref: "7184ed773603b0bc8d4863a6d60141f46e65c37e" + resolved-ref: "05f78b3e2d4535ade646667db5d5602234fe7b5e" url: "https://github.com/linagora/html-editor-enhanced.git" source: git - version: "3.2.1" + version: "3.2.3" html_unescape: dependency: transitive description: