From c75abff9336007385b25a7c190a021ede7694b36 Mon Sep 17 00:00:00 2001 From: Amir Panahandeh Date: Sun, 9 Jun 2024 09:17:53 +0330 Subject: [PATCH] Add enable suggestions --- packages/fleather/lib/src/widgets/editor.dart | 28 +++++++++ .../widgets/editor_input_client_mixin.dart | 33 ++++++---- packages/fleather/lib/src/widgets/field.dart | 11 ++++ .../editor_input_client_mixin_test.dart | 60 +++++++++++++------ 4 files changed, 100 insertions(+), 32 deletions(-) diff --git a/packages/fleather/lib/src/widgets/editor.dart b/packages/fleather/lib/src/widgets/editor.dart index 3b2d36be..f0f357a6 100644 --- a/packages/fleather/lib/src/widgets/editor.dart +++ b/packages/fleather/lib/src/widgets/editor.dart @@ -160,6 +160,15 @@ class FleatherEditor extends StatefulWidget { /// Defaults to `true`. final bool autocorrect; + /// Whether to show input suggestions as the user types. + /// + /// This flag only affects Android. On iOS, suggestions are tied directly to + /// [autocorrect], so that suggestions are only shown when [autocorrect] is + /// true. On Android autocorrection and suggestion are controlled separately. + /// + /// Defaults to true. + final bool enableSuggestions; + /// Whether to enable user interface affordances for changing the /// text selection. /// @@ -289,6 +298,7 @@ class FleatherEditor extends StatefulWidget { this.showCursor = true, this.readOnly = false, this.autocorrect = true, + this.enableSuggestions = true, this.enableInteractiveSelection = true, this.minHeight, this.maxHeight, @@ -460,6 +470,7 @@ class _FleatherEditorState extends State autocorrect: widget.autocorrect, showCursor: widget.showCursor, readOnly: widget.readOnly, + enableSuggestions: widget.enableSuggestions, enableInteractiveSelection: widget.enableInteractiveSelection, minHeight: widget.minHeight, maxHeight: widget.maxHeight, @@ -559,6 +570,7 @@ class RawEditor extends StatefulWidget { bool? showCursor, this.readOnly = false, this.autocorrect = true, + this.enableSuggestions = true, this.enableInteractiveSelection = true, this.minHeight, this.maxHeight, @@ -615,6 +627,15 @@ class RawEditor extends StatefulWidget { /// Defaults to `true`. final bool autocorrect; + /// Whether to show input suggestions as the user types. + /// + /// This flag only affects Android. On iOS, suggestions are tied directly to + /// [autocorrect], so that suggestions are only shown when [autocorrect] is + /// true. On Android autocorrection and suggestion are controlled separately. + /// + /// Defaults to true. + final bool enableSuggestions; + /// Callback which is triggered when the user wants to open a URL from /// a link in the document. final ValueChanged? onLaunchUrl; @@ -1405,6 +1426,13 @@ class RawEditorState extends EditorState } else { if (oldWidget.readOnly && _hasFocus) { openConnectionIfNeeded(); + } else if (oldWidget.autocorrect != widget.autocorrect || + oldWidget.enableSuggestions != widget.enableSuggestions || + oldWidget.keyboardAppearance != widget.keyboardAppearance || + oldWidget.textCapitalization != widget.textCapitalization || + oldWidget.enableInteractiveSelection != + widget.enableInteractiveSelection) { + updateConnectionConfig(); } } } diff --git a/packages/fleather/lib/src/widgets/editor_input_client_mixin.dart b/packages/fleather/lib/src/widgets/editor_input_client_mixin.dart index 17d38454..1a3765bc 100644 --- a/packages/fleather/lib/src/widgets/editor_input_client_mixin.dart +++ b/packages/fleather/lib/src/widgets/editor_input_client_mixin.dart @@ -51,19 +51,7 @@ mixin RawEditorStateTextInputClientMixin on EditorState if (!hasConnection) { _lastKnownRemoteTextEditingValue = textEditingValue; - _textInputConnection = TextInput.attach( - this, - TextInputConfiguration( - inputType: TextInputType.multiline, - readOnly: widget.readOnly, - obscureText: false, - autocorrect: widget.autocorrect, - enableDeltaModel: true, - inputAction: TextInputAction.newline, - keyboardAppearance: widget.keyboardAppearance, - textCapitalization: widget.textCapitalization, - ), - ); + _textInputConnection = TextInput.attach(this, _configuration); _updateSizeAndTransform(); _textInputConnection!.setEditingState(_lastKnownRemoteTextEditingValue!); @@ -71,6 +59,25 @@ mixin RawEditorStateTextInputClientMixin on EditorState _textInputConnection!.show(); } + void updateConnectionConfig() { + if (hasConnection) { + _textInputConnection!.updateConfig(_configuration); + } + } + + TextInputConfiguration get _configuration => TextInputConfiguration( + inputType: TextInputType.multiline, + readOnly: widget.readOnly, + obscureText: false, + enableDeltaModel: true, + autocorrect: widget.autocorrect, + enableSuggestions: widget.enableSuggestions, + inputAction: TextInputAction.newline, + enableInteractiveSelection: widget.enableInteractiveSelection, + keyboardAppearance: widget.keyboardAppearance, + textCapitalization: widget.textCapitalization, + ); + /// Closes input connection if it's currently open. Otherwise does nothing. void closeConnectionIfNeeded() { if (hasConnection) { diff --git a/packages/fleather/lib/src/widgets/field.dart b/packages/fleather/lib/src/widgets/field.dart index 96debfe8..172af00b 100644 --- a/packages/fleather/lib/src/widgets/field.dart +++ b/packages/fleather/lib/src/widgets/field.dart @@ -70,6 +70,15 @@ class FleatherField extends StatefulWidget { /// Defaults to `true`. final bool autocorrect; + /// Whether to show input suggestions as the user types. + /// + /// This flag only affects Android. On iOS, suggestions are tied directly to + /// [autocorrect], so that suggestions are only shown when [autocorrect] is + /// true. On Android autocorrection and suggestion are controlled separately. + /// + /// Defaults to true. + final bool enableSuggestions; + /// Whether to enable user interface affordances for changing the /// text selection. /// @@ -181,6 +190,7 @@ class FleatherField extends StatefulWidget { this.showCursor = true, this.readOnly = false, this.autocorrect = true, + this.enableSuggestions = true, this.enableInteractiveSelection = true, this.minHeight, this.maxHeight, @@ -252,6 +262,7 @@ class _FleatherFieldState extends State { showCursor: widget.showCursor, readOnly: widget.readOnly, autocorrect: widget.autocorrect, + enableSuggestions: widget.enableSuggestions, enableInteractiveSelection: widget.enableInteractiveSelection, minHeight: widget.minHeight, maxHeight: widget.maxHeight, diff --git a/packages/fleather/test/widgets/editor_input_client_mixin_test.dart b/packages/fleather/test/widgets/editor_input_client_mixin_test.dart index b07e94cb..3f60684e 100644 --- a/packages/fleather/test/widgets/editor_input_client_mixin_test.dart +++ b/packages/fleather/test/widgets/editor_input_client_mixin_test.dart @@ -299,28 +299,50 @@ void main() { }); }); - group('send editor options to TextInputConnection', () { - testWidgets('send autocorrect option', (tester) async { - Map? textInputClientProperties; - tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( - SystemChannels.textInput, (MethodCall methodCall) async { - if (methodCall.method == 'TextInput.setClient') { - textInputClientProperties = methodCall.arguments[1]; - } - return null; - }); + testWidgets('send editor options to TextInputConnection', (tester) async { + Map? textInputSetClientProperties; + Map? textInputUpdateConfigProperties; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.textInput, (MethodCall methodCall) async { + if (methodCall.method == 'TextInput.setClient') { + textInputSetClientProperties = methodCall.arguments[1]; + } else if (methodCall.method == 'TextInput.updateConfig') { + textInputUpdateConfigProperties = methodCall.arguments; + } + return null; + }); - final editor = - EditorSandBox(tester: tester, document: ParchmentDocument()); - await editor.pump(); - await editor.tap(); + final controller = FleatherController(); + Future pumpEditor(bool enable) async { + final editor = MaterialApp( + home: FleatherField( + controller: controller, + enableSuggestions: enable, + autocorrect: enable, + )); + await tester.pumpWidget(editor); + await tester.tapAt(tester.getCenter(find.byType(RawEditor))); tester.binding.scheduleWarmUpFrame(); await tester.pumpAndSettle(); + } - expect( - textInputClientProperties?['autocorrect'], - true, - ); - }); + await pumpEditor(true); + expect(textInputSetClientProperties?['autocorrect'], true); + expect(textInputSetClientProperties?['enableSuggestions'], true); + expect(textInputUpdateConfigProperties, isNull); + + await tester.pumpWidget(const SizedBox()); + await tester.pumpAndSettle(); + + await pumpEditor(false); + expect(textInputSetClientProperties?['autocorrect'], false); + expect(textInputSetClientProperties?['enableSuggestions'], false); + expect(textInputUpdateConfigProperties, isNull); + + textInputSetClientProperties = null; + await pumpEditor(true); + expect(textInputUpdateConfigProperties?['autocorrect'], true); + expect(textInputUpdateConfigProperties?['enableSuggestions'], true); + expect(textInputSetClientProperties, isNull); }); }