| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/foundation.dart'; |
| |
| import 'system_channels.dart'; |
| |
| /// A data structure describing text processing actions. |
| @immutable |
| class ProcessTextAction { |
| /// Creates text processing actions based on those returned by the engine. |
| const ProcessTextAction(this.id, this.label); |
| |
| /// The action unique id. |
| final String id; |
| |
| /// The action localized label. |
| final String label; |
| |
| @override |
| bool operator ==(Object other) { |
| if (identical(this, other)) { |
| return true; |
| } |
| |
| return other is ProcessTextAction && |
| other.id == id && |
| other.label == label; |
| } |
| |
| @override |
| int get hashCode => Object.hash(id, label); |
| } |
| |
| /// Determines how to interact with the text processing feature. |
| abstract class ProcessTextService { |
| /// Returns a [Future] that resolves to a [List] of [ProcessTextAction]s |
| /// containing all text processing actions available. |
| /// |
| /// If there are no actions available, an empty list will be returned. |
| Future<List<ProcessTextAction>> queryTextActions(); |
| |
| /// Returns a [Future] that resolves to a [String] when the text action |
| /// returns a transformed text or null when the text action did not return |
| /// a transformed text. |
| /// |
| /// The `id` parameter is the text action unique identifier returned by |
| /// [queryTextActions]. |
| /// |
| /// The `text` parameter is the text to be processed. |
| /// |
| /// The `readOnly` parameter indicates that the transformed text, if it exists, |
| /// will be used as read-only. |
| Future<String?> processTextAction(String id, String text, bool readOnly); |
| } |
| |
| /// The service used by default for the text processing feature. |
| /// |
| /// Any widget may use this service to get a list of text processing actions |
| /// and send requests to activate these text actions. |
| /// |
| /// This is currently only supported on Android and it requires adding the |
| /// following '<queries>' element to the Android manifest file: |
| /// |
| /// <manifest ...> |
| /// <application ...> |
| /// ... |
| /// </application> |
| /// <!-- Required to query activities that can process text, see: |
| /// https://developer.android.com/training/package-visibility?hl=en and |
| /// https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT. |
| /// |
| /// In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --> |
| /// <queries> |
| /// <intent> |
| /// <action android:name="android.intent.action.PROCESS_TEXT"/> |
| /// <data android:mimeType="text/plain"/> |
| /// </intent> |
| /// </queries> |
| /// </manifest> |
| /// |
| /// The '<queries>' element is part of the Android manifest file generated when |
| /// running the 'flutter create' command. |
| /// |
| /// If the '<queries>' element is not found, `queryTextActions()` will return an |
| /// empty list of `ProcessTextAction`. |
| /// |
| /// See also: |
| /// |
| /// * [ProcessTextService], the service that this implements. |
| class DefaultProcessTextService implements ProcessTextService { |
| /// Creates the default service to interact with the platform text processing |
| /// feature via communication over the text processing [MethodChannel]. |
| DefaultProcessTextService() { |
| _processTextChannel = SystemChannels.processText; |
| } |
| |
| /// The channel used to communicate with the engine side. |
| late MethodChannel _processTextChannel; |
| |
| /// Set the [MethodChannel] used to communicate with the engine text processing |
| /// feature. |
| /// |
| /// This is only meant for testing within the Flutter SDK. |
| @visibleForTesting |
| void setChannel(MethodChannel newChannel) { |
| assert(() { |
| _processTextChannel = newChannel; |
| return true; |
| }()); |
| } |
| |
| @override |
| Future<List<ProcessTextAction>> queryTextActions() async { |
| final Map<Object?, Object?> rawResults; |
| |
| try { |
| final Map<Object?, Object?>? result = |
| await _processTextChannel.invokeMethod( |
| 'ProcessText.queryTextActions', |
| ) as Map<Object?, Object?>?; |
| |
| if (result == null) { |
| return <ProcessTextAction>[]; |
| } |
| |
| rawResults = result; |
| } catch (e) { |
| return <ProcessTextAction>[]; |
| } |
| |
| return <ProcessTextAction>[ |
| for (final Object? id in rawResults.keys) |
| ProcessTextAction(id! as String, rawResults[id]! as String), |
| ]; |
| } |
| |
| @override |
| /// On Android, the readOnly parameter might be used by the targeted activity, see: |
| /// https://developer.android.com/reference/android/content/Intent#EXTRA_PROCESS_TEXT_READONLY. |
| Future<String?> processTextAction(String id, String text, bool readOnly) async { |
| final String? processedText = await _processTextChannel.invokeMethod( |
| 'ProcessText.processTextAction', |
| <dynamic>[id, text, readOnly], |
| ) as String?; |
| |
| return processedText; |
| } |
| } |