From c8253551b19999d8ddc47c73bf03d8a29c1fae85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Poizat?= Date: Wed, 4 Feb 2026 15:20:15 +0100 Subject: [PATCH] Add a toolbar to execute quick actions to Scribe suggestion Actions : - copy - regenerate --- scribe/lib/scribe.dart | 1 + scribe/lib/scribe/ai/l10n/intl_ar.arb | 12 +++ scribe/lib/scribe/ai/l10n/intl_de.arb | 12 +++ scribe/lib/scribe/ai/l10n/intl_en.arb | 12 +++ scribe/lib/scribe/ai/l10n/intl_fr.arb | 12 +++ scribe/lib/scribe/ai/l10n/intl_it.arb | 12 +++ scribe/lib/scribe/ai/l10n/intl_messages.arb | 14 +++- scribe/lib/scribe/ai/l10n/intl_ru.arb | 12 +++ scribe/lib/scribe/ai/l10n/intl_vi.arb | 12 +++ .../localizations/scribe_localizations.dart | 15 ++++ .../ai_scribe_suggestion_state_mixin.dart | 1 + .../ai_scribe_suggestion_success.dart | 3 + ...cribe_suggestion_success_list_actions.dart | 79 ++++++++++--------- .../ai_scribe_suggestion_success_toolbar.dart | 45 +++++++++++ 14 files changed, 205 insertions(+), 37 deletions(-) create mode 100644 scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_toolbar.dart diff --git a/scribe/lib/scribe.dart b/scribe/lib/scribe.dart index bc420893b..9e9327048 100644 --- a/scribe/lib/scribe.dart +++ b/scribe/lib/scribe.dart @@ -45,6 +45,7 @@ export 'scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_hea export 'scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_loading.dart'; export 'scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success.dart'; export 'scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_list_actions.dart'; +export 'scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_toolbar.dart'; export 'scribe/ai/presentation/widgets/overlay/ai_selection_overlay.dart'; export 'scribe/ai/presentation/widgets/search/ai_scribe_bar.dart'; export 'scribe/ai/presentation/widgets/mobile/ai_scribe_mobile_actions_bottom_sheet.dart'; diff --git a/scribe/lib/scribe/ai/l10n/intl_ar.arb b/scribe/lib/scribe/ai/l10n/intl_ar.arb index 480afda86..22d04af50 100644 --- a/scribe/lib/scribe/ai/l10n/intl_ar.arb +++ b/scribe/lib/scribe/ai/l10n/intl_ar.arb @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "نسخ", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "إعادة المحاولة", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } diff --git a/scribe/lib/scribe/ai/l10n/intl_de.arb b/scribe/lib/scribe/ai/l10n/intl_de.arb index 60728c4b4..3fac7b8d3 100644 --- a/scribe/lib/scribe/ai/l10n/intl_de.arb +++ b/scribe/lib/scribe/ai/l10n/intl_de.arb @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "Kopieren", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "Erneut versuchen", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } diff --git a/scribe/lib/scribe/ai/l10n/intl_en.arb b/scribe/lib/scribe/ai/l10n/intl_en.arb index 743b56bb8..539732622 100644 --- a/scribe/lib/scribe/ai/l10n/intl_en.arb +++ b/scribe/lib/scribe/ai/l10n/intl_en.arb @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "Copy", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "Retry", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/scribe/lib/scribe/ai/l10n/intl_fr.arb b/scribe/lib/scribe/ai/l10n/intl_fr.arb index ad9abd004..0537deb0a 100644 --- a/scribe/lib/scribe/ai/l10n/intl_fr.arb +++ b/scribe/lib/scribe/ai/l10n/intl_fr.arb @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "Copier", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "Réessayer", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } diff --git a/scribe/lib/scribe/ai/l10n/intl_it.arb b/scribe/lib/scribe/ai/l10n/intl_it.arb index 8586cc45c..0ab3e93d4 100644 --- a/scribe/lib/scribe/ai/l10n/intl_it.arb +++ b/scribe/lib/scribe/ai/l10n/intl_it.arb @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "Copia", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "Riprova", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } diff --git a/scribe/lib/scribe/ai/l10n/intl_messages.arb b/scribe/lib/scribe/ai/l10n/intl_messages.arb index 075499f20..6ec7af566 100644 --- a/scribe/lib/scribe/ai/l10n/intl_messages.arb +++ b/scribe/lib/scribe/ai/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-26T09:26:56.495094", + "@@last_modified": "2026-02-04T15:15:31.191557", "categoryCorrectGrammar": "Correct", "@categoryCorrectGrammar": { "type": "text", @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "Copy", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "Retry", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/scribe/lib/scribe/ai/l10n/intl_ru.arb b/scribe/lib/scribe/ai/l10n/intl_ru.arb index bbf385559..eb54a66f4 100644 --- a/scribe/lib/scribe/ai/l10n/intl_ru.arb +++ b/scribe/lib/scribe/ai/l10n/intl_ru.arb @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "Копировать", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "Повторить", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } diff --git a/scribe/lib/scribe/ai/l10n/intl_vi.arb b/scribe/lib/scribe/ai/l10n/intl_vi.arb index f6615fa06..7d520cca9 100644 --- a/scribe/lib/scribe/ai/l10n/intl_vi.arb +++ b/scribe/lib/scribe/ai/l10n/intl_vi.arb @@ -125,5 +125,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "copy": "Sao chép", + "@copy": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "retry": "Thử lại", + "@retry": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } diff --git a/scribe/lib/scribe/ai/localizations/scribe_localizations.dart b/scribe/lib/scribe/ai/localizations/scribe_localizations.dart index f838e3e38..36efcbdb1 100644 --- a/scribe/lib/scribe/ai/localizations/scribe_localizations.dart +++ b/scribe/lib/scribe/ai/localizations/scribe_localizations.dart @@ -177,6 +177,21 @@ class ScribeLocalizations { name: 'insert', ); } + + // Suggestion Success Toolbar + String get copy { + return Intl.message( + 'Copy', + name: 'copy', + ); + } + + String get retry { + return Intl.message( + 'Retry', + name: 'retry', + ); + } } class _ScribeLocalizationsDelegate diff --git a/scribe/lib/scribe/ai/presentation/utils/modal/ai_scribe_suggestion_state_mixin.dart b/scribe/lib/scribe/ai/presentation/utils/modal/ai_scribe_suggestion_state_mixin.dart index 26095b0e1..078874867 100644 --- a/scribe/lib/scribe/ai/presentation/utils/modal/ai_scribe_suggestion_state_mixin.dart +++ b/scribe/lib/scribe/ai/presentation/utils/modal/ai_scribe_suggestion_state_mixin.dart @@ -107,6 +107,7 @@ mixin AiScribeSuggestionStateMixin on State { suggestionText: suggestionText, hasContent: hasContent, onSelectAction: onSelectAction, + onLoadSuggestion: loadSuggestion, ); } diff --git a/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success.dart b/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success.dart index 4f15b0754..5eed49f3a 100644 --- a/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success.dart +++ b/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success.dart @@ -7,12 +7,14 @@ class AiScribeSuggestionSuccess extends StatelessWidget { final String suggestionText; final bool hasContent; final OnSelectAiScribeSuggestionAction onSelectAction; + final VoidCallback onLoadSuggestion; const AiScribeSuggestionSuccess({ super.key, required this.imagePaths, required this.suggestionText, required this.onSelectAction, + required this.onLoadSuggestion, this.hasContent = false, }); @@ -42,6 +44,7 @@ class AiScribeSuggestionSuccess extends StatelessWidget { suggestionText: suggestionText, hasContent: hasContent, onSelectAction: onSelectAction, + onLoadSuggestion: onLoadSuggestion, ), ], ), diff --git a/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_list_actions.dart b/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_list_actions.dart index 7482eb3e3..7b4873c47 100644 --- a/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_list_actions.dart +++ b/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_list_actions.dart @@ -14,12 +14,14 @@ class AiScribeSuggestionSuccessListActions extends StatelessWidget { final String suggestionText; final bool hasContent; final OnSelectAiScribeSuggestionAction onSelectAction; + final VoidCallback onLoadSuggestion; const AiScribeSuggestionSuccessListActions({ super.key, required this.imagePaths, required this.suggestionText, required this.onSelectAction, + required this.onLoadSuggestion, this.hasContent = false, }); @@ -27,45 +29,50 @@ class AiScribeSuggestionSuccessListActions extends StatelessWidget { Widget build(BuildContext context) { final localizations = ScribeLocalizations.of(context); - return Row( - mainAxisAlignment: MainAxisAlignment.end, - spacing: 8, + return Column( children: [ - if (hasContent) - Flexible( - child: Container( - constraints: const BoxConstraints(minWidth: 67), - height: 36, - child: ConfirmDialogButton( - label: AiScribeSuggestionActions.replace.getLabel(localizations), - textColor: AppColor.primaryMain, - onTapAction: () { - Navigator.of(context).pop(); - onSelectAction( - AiScribeSuggestionActions.replace, - suggestionText, - ); - }, + AiScribeSuggestionSuccessToolbar(suggestionText: suggestionText, onLoadSuggestion: onLoadSuggestion, imagePaths: imagePaths), + Row( + mainAxisAlignment: MainAxisAlignment.end, + spacing: 8, + children: [ + if (hasContent) + Flexible( + child: Container( + constraints: const BoxConstraints(minWidth: 67), + height: 36, + child: ConfirmDialogButton( + label: AiScribeSuggestionActions.replace.getLabel(localizations), + textColor: AppColor.primaryMain, + onTapAction: () { + Navigator.of(context).pop(); + onSelectAction( + AiScribeSuggestionActions.replace, + suggestionText, + ); + }, + ), + ), + ), + Flexible( + child: Container( + constraints: const BoxConstraints(minWidth: 72), + height: 36, + child: ConfirmDialogButton( + label: AiScribeSuggestionActions.insert.getLabel(localizations), + backgroundColor: AppColor.blueD2E9FF, + textColor: AppColor.primaryMain, + onTapAction: () { + Navigator.of(context).pop(); + onSelectAction( + AiScribeSuggestionActions.insert, + suggestionText, + ); + }, + ), ), ), - ), - Flexible( - child: Container( - constraints: const BoxConstraints(minWidth: 72), - height: 36, - child: ConfirmDialogButton( - label: AiScribeSuggestionActions.insert.getLabel(localizations), - backgroundColor: AppColor.blueD2E9FF, - textColor: AppColor.primaryMain, - onTapAction: () { - Navigator.of(context).pop(); - onSelectAction( - AiScribeSuggestionActions.insert, - suggestionText, - ); - }, - ), - ), + ], ), ], ); diff --git a/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_toolbar.dart b/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_toolbar.dart new file mode 100644 index 000000000..bd7cf62e2 --- /dev/null +++ b/scribe/lib/scribe/ai/presentation/widgets/modal/suggestion/ai_scribe_suggestion_success_toolbar.dart @@ -0,0 +1,45 @@ +import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:scribe/scribe.dart'; +import 'package:core/presentation/resources/image_paths.dart'; + +class AiScribeSuggestionSuccessToolbar extends StatelessWidget { + final String suggestionText; + final VoidCallback onLoadSuggestion; + final ImagePaths imagePaths; + + const AiScribeSuggestionSuccessToolbar({ + super.key, + required this.suggestionText, + required this.onLoadSuggestion, + required this.imagePaths, + }); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + TMailButtonWidget.fromIcon( + icon: imagePaths.icCopy, + iconSize: AIScribeSizes.icon, + iconColor: AIScribeColors.secondaryIcon, + backgroundColor: Colors.transparent, + tooltipMessage: ScribeLocalizations.of(context).copy, + onTapActionCallback: () { + Clipboard.setData(ClipboardData(text: suggestionText)); + }, + ), + TMailButtonWidget.fromIcon( + icon: imagePaths.icRefresh, + iconSize: AIScribeSizes.icon, + iconColor: AIScribeColors.secondaryIcon, + backgroundColor: Colors.transparent, + tooltipMessage: ScribeLocalizations.of(context).retry, + onTapActionCallback: onLoadSuggestion, + ), + ], + ); + } +} \ No newline at end of file