Display Scribe mobile (bottomsheet) only when responsive mobile

Previosuly, we display Scribe mobile (bottomsheet) if platform was mobile, so also Android or iOS tablet.

Now we choose to display Scribe mobile relatively to display screens instead of platform to display the desktop Scribe (context menu) for tablets.
This commit is contained in:
Théo Poizat
2026-01-26 16:07:40 +01:00
committed by Dat H. Pham
parent 6540ed29d1
commit 7a6a49fc7b
6 changed files with 29 additions and 7 deletions
@@ -3,6 +3,7 @@ import 'package:core/utils/html/html_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:core/utils/string_convert.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:scribe/scribe.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/mixin/text_selection_mixin.dart';
@@ -21,6 +22,11 @@ extension HandleAiScribeInComposerExtension on ComposerController {
return isAIScribeConfigEnabled && isAIScribeEndpointAvailable;
}
bool get isScribeMobile {
final context = Get.context;
return AiScribeMobileUtils.isScribeInMobileMode(context);
}
Future<String> _getTextOnlyContentInEditor() async {
try {
final htmlContent = await getContentInEditor();
@@ -207,7 +213,7 @@ extension HandleAiScribeInComposerExtension on ComposerController {
Future<void> onReplaceTextCallback(String text) async {
final selection = editorTextSelection.value?.selectedText;
final savedSelection = PlatformInfo.isMobile ? await getSavedSelection() : "";
final savedSelection = isScribeMobile ? await getSavedSelection() : "";
final shouldReplaceEverything = (selection == null || selection.isEmpty) && savedSelection.isEmpty;
@@ -232,7 +238,7 @@ extension HandleAiScribeInComposerExtension on ComposerController {
clearFocusRecipients();
clearFocusSubject();
if (PlatformInfo.isMobile) {
if (isScribeMobile) {
await saveAndUnfocusForModal();
}
@@ -247,6 +253,7 @@ extension HandleAiScribeInComposerExtension on ComposerController {
preferredPlacement: ModalPlacement.top,
crossAxisAlignment: ModalCrossAxisAlignment.start,
onSelectAiScribeSuggestionAction: handleAiScribeSuggestionAction,
isScribeMobile: isScribeMobile,
);
}
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:core/utils/platform_info.dart';
import 'package:scribe/scribe/ai/presentation/widgets/overlay/ai_selection_overlay.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart';
@@ -34,7 +33,7 @@ class ComposerAiScribeSelectionOverlay extends StatelessWidget {
controller.clearFocusRecipients();
controller.clearFocusSubject();
if (PlatformInfo.isMobile) {
if (controller.isScribeMobile) {
await controller.saveAndUnfocusForModal();
}
}
+1
View File
@@ -22,6 +22,7 @@ export 'scribe/ai/presentation/model/modal/modal_placement.dart';
export 'scribe/ai/presentation/model/text_selection_model.dart';
export 'scribe/ai/presentation/styles/ai_scribe_styles.dart';
export 'scribe/ai/presentation/utils/ai_scribe_constants.dart';
export 'scribe/ai/presentation/utils/ai_scribe_mobile_utils.dart';
export 'scribe/ai/presentation/utils/context_menu/hover_submenu_controller.dart';
export 'scribe/ai/presentation/utils/context_menu/context_submenu_controller.dart';
export 'scribe/ai/presentation/utils/modal/ai_scribe_modal_manager.dart';
@@ -0,0 +1,8 @@
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart';
class AiScribeMobileUtils {
static bool isScribeInMobileMode(BuildContext? context) {
return context != null && ResponsiveUtils().isMobile(context);
}
}
@@ -1,5 +1,4 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:scribe/scribe.dart';
@@ -8,6 +7,7 @@ class AiScribeModalManager {
AiScribeModalManager._();
static Future<void> showAIScribeMenuModal({
required bool isScribeMobile,
required ImagePaths imagePaths,
required List<AIScribeMenuCategory> availableCategories,
required OnSelectAiScribeSuggestionAction onSelectAiScribeSuggestionAction,
@@ -19,7 +19,7 @@ class AiScribeModalManager {
}) async {
final AIAction? aiAction;
if (PlatformInfo.isMobile) {
if (isScribeMobile) {
aiAction = await showMobileAIScribeMenuModal(
imagePaths: imagePaths,
content: content,
@@ -46,6 +46,7 @@ class AiScribeModalManager {
if (aiAction != null) {
await showAIScribeSuggestionModal(
aiAction: aiAction,
isScribeMobile: isScribeMobile,
imagePaths: imagePaths,
content: content,
buttonPosition: buttonPosition,
@@ -59,6 +60,7 @@ class AiScribeModalManager {
static Future<void> showAIScribeSuggestionModal({
required AIAction aiAction,
required bool isScribeMobile,
required ImagePaths imagePaths,
required OnSelectAiScribeSuggestionAction onSelectAiScribeSuggestionAction,
String? content,
@@ -67,7 +69,7 @@ class AiScribeModalManager {
ModalPlacement? preferredPlacement,
ModalCrossAxisAlignment crossAxisAlignment = ModalCrossAxisAlignment.center,
}) async {
if (PlatformInfo.isMobile) {
if (isScribeMobile) {
await showMobileAIScribeSuggestionModal(
aiAction: aiAction,
imagePaths: imagePaths,
@@ -45,7 +45,12 @@ class InlineAiAssistButton extends StatelessWidget {
await onTapFallback?.call();
if (!context.mounted) return;
final isScribeMobile = AiScribeMobileUtils.isScribeInMobileMode(context);
await AiScribeModalManager.showAIScribeMenuModal(
isScribeMobile: isScribeMobile,
imagePaths: imagePaths,
availableCategories: AIScribeMenuCategory.values,
buttonPosition: position,