diff --git a/core/lib/utils/html/html_utils.dart b/core/lib/utils/html/html_utils.dart
index 614cb97ea..872ca9ddf 100644
--- a/core/lib/utils/html/html_utils.dart
+++ b/core/lib/utils/html/html_utils.dart
@@ -220,9 +220,12 @@ class HtmlUtils {
const selection = window.getSelection();
if (selection && selection.rangeCount > 0) {
window._savedRange = selection.getRangeAt(0).cloneRange();
- return selection.toString();
+ const result = selection.toString()
+ window.parent.postMessage(JSON.stringify({ "type": "toDart: saveSelection", result }), "*");
+ return result;
}
delete window._savedRange;
+ window.parent.postMessage(JSON.stringify({ "type": "toDart: saveSelection", result: "" }), "*");
return "";
})();''',
name: 'saveSelection');
@@ -236,9 +239,12 @@ class HtmlUtils {
selection.removeAllRanges();
selection.addRange(window._savedRange);
delete window._savedRange;
- return selection.toString();
+ const result = selection.toString()
+ window.parent.postMessage(JSON.stringify({ "type": "toDart: restoreSelection", result }), "*");
+ return result;
}
}
+ window.parent.postMessage(JSON.stringify({ "type": "toDart: restoreSelection", result: "" }), "*");
return "";
})();''',
name: 'restoreSelection');
@@ -247,8 +253,11 @@ class HtmlUtils {
script: '''
(() => {
if(window._savedRange) {
- return window._savedRange.toString();
+ const result = window._savedRange.toString();
+ window.parent.postMessage(JSON.stringify({ "type": "toDart: getSavedSelection", result }), "*");
+ return result;
} else {
+ window.parent.postMessage(JSON.stringify({ "type": "toDart: getSavedSelection", result: "" }), "*");
return "";
}
})();''',
diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart
index 41c3682f6..ecfb57db9 100644
--- a/lib/features/composer/presentation/composer_view_web.dart
+++ b/lib/features/composer/presentation/composer_view_web.dart
@@ -134,6 +134,9 @@ class ComposerView extends GetWidget {
saveToDraftsAction: () => controller.handleClickSaveAsDraftsButton(context),
saveToTemplateAction: () => controller.handleClickSaveAsTemplateButton(context),
deleteComposerAction: controller.handleClickDeleteComposer,
+ onOpenAiAssistantModal: controller.isAIScribeAvailable
+ ? controller.openAIAssistantModal
+ : null,
)),
ConstrainedBox(
constraints: BoxConstraints(
diff --git a/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart b/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart
index 936fdef2f..89b92b696 100644
--- a/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart
+++ b/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart
@@ -4,6 +4,7 @@ import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/platform_info.dart';
import 'package:custom_pop_up_menu/custom_pop_up_menu.dart';
import 'package:flutter/material.dart';
+import 'package:scribe/scribe/ai/presentation/widgets/button/ai_assistant_button.dart';
import 'package:tmail_ui_user/features/base/widget/highlight_svg_icon_on_hover.dart';
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart';
@@ -32,6 +33,7 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
final VoidCallback saveToTemplateAction;
final VoidCallback deleteComposerAction;
final VoidCallback toggleMarkAsImportantAction;
+ final OnOpenAiAssistantModal? onOpenAiAssistantModal;
const MobileResponsiveAppBarComposerWidget({
super.key,
@@ -55,6 +57,7 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
required this.saveToTemplateAction,
required this.deleteComposerAction,
required this.toggleMarkAsImportantAction,
+ this.onOpenAiAssistantModal,
});
@override
@@ -74,6 +77,14 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
onTapActionCallback: onCloseViewAction
),
const Spacer(),
+ if (onOpenAiAssistantModal != null)
+ AiAssistantButton(
+ imagePaths: imagePaths,
+ margin: const EdgeInsetsDirectional.only(
+ end: MobileAppBarComposerWidgetStyle.space,
+ ),
+ onOpenAiAssistantModal: onOpenAiAssistantModal!,
+ ),
TMailButtonWidget.fromIcon(
icon: imagePaths.icRichToolbar,
padding: MobileAppBarComposerWidgetStyle.richTextIconPadding,
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 b825e19fb..e675f0faa 100644
--- a/lib/features/composer/presentation/widgets/web/web_editor_widget.dart
+++ b/lib/features/composer/presentation/widgets/web/web_editor_widget.dart
@@ -205,6 +205,22 @@ class _WebEditorState extends State with TextSelectionMixin {
name: HtmlUtils.deleteSelectionContent.name,
script: HtmlUtils.deleteSelectionContent.script,
),
+ WebScript(
+ name: HtmlUtils.saveSelection.name,
+ script: HtmlUtils.saveSelection.script,
+ ),
+ WebScript(
+ name: HtmlUtils.restoreSelection.name,
+ script: HtmlUtils.restoreSelection.script,
+ ),
+ WebScript(
+ name: HtmlUtils.getSavedSelection.name,
+ script: HtmlUtils.getSavedSelection.script,
+ ),
+ WebScript(
+ name: HtmlUtils.clearSavedSelection.name,
+ script: HtmlUtils.clearSavedSelection.script,
+ ),
WebScript(
name: HtmlUtils.recalculateEditorHeight(maxHeight: maxHeight).name,
script: HtmlUtils.recalculateEditorHeight(maxHeight: maxHeight).script,
diff --git a/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_actions_bottom_sheet.dart b/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_actions_bottom_sheet.dart
index 693505012..411392b8f 100644
--- a/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_actions_bottom_sheet.dart
+++ b/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_actions_bottom_sheet.dart
@@ -2,6 +2,7 @@ import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:flutter/material.dart';
+import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:scribe/scribe.dart';
class AiScribeMobileActionsBottomSheet extends StatefulWidget {
@@ -196,39 +197,41 @@ class _AiScribeMobileActionsBottomSheetState
final hasContent = widget.content?.isNotEmpty ?? false;
- return Container(
- height: double.infinity,
- decoration: const BoxDecoration(
- color: AIScribeColors.background,
- ),
- child: SafeArea(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: [
- Expanded(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: [
- _buildHeader(context, localizations),
- _buildTextCard(context),
- if(hasContent)
- Flexible(
- child: ValueListenableBuilder(
- valueListenable: _selectedCategory,
- builder: (context, selectedCategory, _) {
- return selectedCategory == null
- ? _buildMenuListView(menuActions)
- : _buildSubmenuListView();
- },
+ return PointerInterceptor(
+ child: Container(
+ height: double.infinity,
+ decoration: const BoxDecoration(
+ color: AIScribeColors.background,
+ ),
+ child: SafeArea(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Expanded(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ _buildHeader(context, localizations),
+ _buildTextCard(context),
+ if(hasContent)
+ Flexible(
+ child: ValueListenableBuilder(
+ valueListenable: _selectedCategory,
+ builder: (context, selectedCategory, _) {
+ return selectedCategory == null
+ ? _buildMenuListView(menuActions)
+ : _buildSubmenuListView();
+ },
+ ),
),
- ),
- ],
+ ],
+ ),
),
- ),
- _buildBottomBar(context),
- ],
+ _buildBottomBar(context),
+ ],
+ ),
),
),
);
diff --git a/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_suggestion_bottom_sheet.dart b/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_suggestion_bottom_sheet.dart
index 7a3a3528a..08c05286d 100644
--- a/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_suggestion_bottom_sheet.dart
+++ b/scribe/lib/scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_suggestion_bottom_sheet.dart
@@ -1,5 +1,6 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/material.dart';
+import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:scribe/scribe.dart';
class AiScribeMobileSuggestionBottomSheet extends StatefulWidget {
@@ -41,27 +42,29 @@ class _AiScribeMobileSuggestionBottomSheetState
Widget build(BuildContext context) {
final localizations = ScribeLocalizations.of(context);
- return Container(
- height: double.infinity,
- decoration: const BoxDecoration(
- color: AIScribeColors.background,
- ),
- child: SafeArea(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: [
- Padding(
- padding: AIScribeSizes.suggestionHeaderPadding,
- child: AiScribeSuggestionHeader(
- title: aiAction.getLabel(localizations),
- imagePaths: imagePaths,
+ return PointerInterceptor(
+ child: Container(
+ height: double.infinity,
+ decoration: const BoxDecoration(
+ color: AIScribeColors.background,
+ ),
+ child: SafeArea(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Padding(
+ padding: AIScribeSizes.suggestionHeaderPadding,
+ child: AiScribeSuggestionHeader(
+ title: aiAction.getLabel(localizations),
+ imagePaths: imagePaths,
+ ),
),
- ),
- Flexible(
- child: buildStateContent(context),
- ),
- ],
+ Flexible(
+ child: buildStateContent(context),
+ ),
+ ],
+ ),
),
),
);