inset_services/process_text.rs
1//! Flutter counterpart: `services/process_text.dart`.
2
3use inset_foundation::App;
4
5/// A data structure describing text processing actions.
6#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7pub struct ProcessTextAction {
8 /// The action unique id.
9 pub id: String,
10 /// The action localized label.
11 pub label: String,
12}
13
14impl ProcessTextAction {
15 /// Creates text processing actions based on those returned by the engine.
16 pub fn new(id: impl Into<String>, label: impl Into<String>) -> ProcessTextAction {
17 ProcessTextAction {
18 id: id.into(),
19 label: label.into(),
20 }
21 }
22}
23
24/// Determines how to interact with the text processing feature.
25pub trait ProcessTextService {
26 /// Returns a [`Vec`] of [`ProcessTextAction`]s containing all text processing
27 /// actions available.
28 ///
29 /// If there are no actions available, an empty list will be returned.
30 fn query_text_actions(&self, app: &App) -> Vec<ProcessTextAction>;
31
32 /// Returns a [`String`] when the text action returns a transformed text or
33 /// [`None`] when the text action did not return a transformed text.
34 ///
35 /// The `id` parameter is the text action unique identifier returned by
36 /// [`query_text_actions`](Self::query_text_actions).
37 ///
38 /// The `text` parameter is the text to be processed.
39 ///
40 /// The `read_only` parameter indicates that the transformed text, if it exists,
41 /// will be used as read-only.
42 fn process_text_action(
43 &self,
44 app: &App,
45 id: &str,
46 text: &str,
47 read_only: bool,
48 ) -> Option<String>;
49}
50
51/// The service used by default for the text processing feature.
52///
53/// Any widget may use this service to get a list of text processing actions
54/// and send requests to activate these text actions.
55///
56/// This is currently only supported on Android and it requires adding the
57/// following '<queries>' element to the Android manifest file:
58///
59/// ```text
60/// <manifest ...>
61/// <application ...>
62/// ...
63/// </application>
64/// <!-- Required to query activities that can process text, see:
65/// https://developer.android.com/training/package-visibility and
66/// https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
67///
68/// In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
69/// <queries>
70/// <intent>
71/// <action android:name="android.intent.action.PROCESS_TEXT"/>
72/// <data android:mimeType="text/plain"/>
73/// </intent>
74/// </queries>
75/// </manifest>
76/// ```
77///
78/// The '<queries>' element is part of the Android manifest file generated when
79/// running the 'flutter create' command.
80///
81/// If the '<queries>' element is not found, [`query_text_actions`](ProcessTextService::query_text_actions) will return an
82/// empty list of [`ProcessTextAction`].
83///
84/// See also:
85///
86/// * [`ProcessTextService`], the service that this implements.
87#[derive(Clone, Debug, Default)]
88pub struct DefaultProcessTextService;
89
90impl DefaultProcessTextService {
91 /// Creates the default service to interact with the platform text processing
92 /// feature.
93 pub fn new() -> DefaultProcessTextService {
94 DefaultProcessTextService
95 }
96}
97
98impl ProcessTextService for DefaultProcessTextService {
99 fn query_text_actions(&self, app: &App) -> Vec<ProcessTextAction> {
100 let _ = app;
101 Vec::new()
102 }
103
104 /// On Android, the readOnly parameter might be used by the targeted activity, see:
105 /// https://developer.android.com/reference/android/content/Intent#EXTRA_PROCESS_TEXT_READONLY.
106 fn process_text_action(
107 &self,
108 app: &App,
109 id: &str,
110 text: &str,
111 read_only: bool,
112 ) -> Option<String> {
113 let _ = (app, id, text, read_only);
114 None
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use inset_foundation::AppCell;
121
122 use super::*;
123
124 #[test]
125 fn action_equality() {
126 let action = ProcessTextAction::new("id", "Translate");
127 assert_eq!(action, ProcessTextAction::new("id", "Translate"));
128 assert_ne!(action, ProcessTextAction::new("id", "Share"));
129 }
130
131 #[test]
132 fn default_service_is_empty() {
133 let cell = AppCell::new();
134 let app = cell.borrow_mut();
135 let service = DefaultProcessTextService::new();
136 assert!(service.query_text_actions(&app).is_empty());
137 assert!(
138 service
139 .process_text_action(&app, "id", "hello", false)
140 .is_none()
141 );
142 }
143}