@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
88import 'package:flutter/rendering.dart' ;
99import 'package:flutter/scheduler.dart' ;
1010import 'package:flutter/services.dart' ;
11+ import 'package:meta/meta.dart' ;
1112
1213import '../common/utils/platform.dart' ;
1314import '../controller/quill_controller.dart' ;
@@ -19,6 +20,7 @@ import 'config/editor_config.dart';
1920import 'embed/embed_editor_builder.dart' ;
2021import 'raw_editor/config/raw_editor_config.dart' ;
2122import 'raw_editor/raw_editor.dart' ;
23+ import 'raw_editor/raw_editor_state.dart' ;
2224import 'widgets/box.dart' ;
2325import 'widgets/cursor.dart' ;
2426import 'widgets/delegate.dart' ;
@@ -196,6 +198,71 @@ class QuillEditorState extends State<QuillEditor>
196198 QuillEditorConfig get configurations => widget.config;
197199 QuillEditorConfig get config => widget.config;
198200
201+ /// The native context menu items (e.g., `Translate` , `Search` ).
202+ /// This is Android-specific and is always `null` on other platforms.
203+ List <ProcessTextAction >? _nativeTextProcessActions;
204+
205+ // Always `null` on platforms other than Android.
206+ @visibleForTesting
207+ @internal
208+ ProcessTextService ? processTextService;
209+
210+ /// Query the engine to initialize the list of text processing actions to show
211+ /// in the text selection toolbar on Android.
212+ Future <void > _initAndroidNativeTextProcessActions () async {
213+ if (isAndroidApp && config.displayNativeContextMenuItems) {
214+ processTextService ?? = DefaultProcessTextService ();
215+ _nativeTextProcessActions = [
216+ ...await processTextService! .queryTextActions ()
217+ ];
218+ }
219+ }
220+
221+ // For the original method, refer to: https://github.com/flutter/flutter/blob/9e211cabbd72de59d79decacfe0ad6f707c61366/packages/flutter/lib/src/widgets/editable_text.dart#L3059-L3091
222+ List <ContextMenuButtonItem > _buildTextProcessingActionButtonItems (
223+ QuillRawEditorState rawEditorState,
224+ ) {
225+ final buttonItems = < ContextMenuButtonItem > [];
226+
227+ final textEditingValue = controller.plainTextEditingValue;
228+ final selection = textEditingValue.selection;
229+ if (! selection.isValid || selection.isCollapsed) {
230+ return buttonItems;
231+ }
232+
233+ for (final action in _nativeTextProcessActions ?? []) {
234+ buttonItems.add (
235+ ContextMenuButtonItem (
236+ label: action.label,
237+ onPressed: () async {
238+ final selectedText =
239+ controller.selection.textInside (textEditingValue.text);
240+ if (selectedText.isEmpty) {
241+ return ;
242+ }
243+
244+ final processedText = await processTextService! .processTextAction (
245+ action.id,
246+ selectedText,
247+ controller.readOnly,
248+ );
249+
250+ // If an activity does not return a modified version, just hide the toolbar.
251+ // Otherwise use the result to replace the selected text.
252+ final allowPaste =
253+ ! controller.readOnly && textEditingValue.selection.isValid;
254+ if (processedText != null && allowPaste) {
255+ // TODO: Paste the processedText
256+ } else {
257+ rawEditorState.hideToolbar ();
258+ }
259+ },
260+ ),
261+ );
262+ }
263+ return buttonItems;
264+ }
265+
199266 @override
200267 void initState () {
201268 super .initState ();
@@ -218,6 +285,22 @@ class QuillEditorState extends State<QuillEditor>
218285 _editorKey.currentState? .hideToolbar ();
219286 }
220287 });
288+ _initAndroidNativeTextProcessActions ();
289+ }
290+
291+ Widget _defaultContextMenuBuilder (
292+ BuildContext context,
293+ QuillRawEditorState rawEditorState,
294+ ) {
295+ return TextFieldTapRegion (
296+ child: AdaptiveTextSelectionToolbar .buttonItems (
297+ buttonItems: [
298+ ...rawEditorState.contextMenuButtonItems,
299+ ..._buildTextProcessingActionButtonItems (rawEditorState)
300+ ],
301+ anchors: rawEditorState.contextMenuAnchors,
302+ ),
303+ );
221304 }
222305
223306 @override
@@ -277,8 +360,7 @@ class QuillEditorState extends State<QuillEditor>
277360 placeholder: config.placeholder,
278361 onLaunchUrl: config.onLaunchUrl,
279362 contextMenuBuilder: showSelectionToolbar
280- ? (config.contextMenuBuilder ??
281- QuillRawEditorConfig .defaultContextMenuBuilder)
363+ ? config.contextMenuBuilder ?? _defaultContextMenuBuilder
282364 : null ,
283365 showSelectionHandles: isMobile,
284366 showCursor: config.showCursor ?? true ,
0 commit comments