Unverified Commit 40b33e23 authored by J-P Nurmi's avatar J-P Nurmi Committed by GitHub

Autocomplete: support asynchronous options (#88193)

parent 13b38add
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
...@@ -22,7 +24,7 @@ import 'shortcuts.dart'; ...@@ -22,7 +24,7 @@ import 'shortcuts.dart';
/// See also: /// See also:
/// ///
/// * [RawAutocomplete.optionsBuilder], which is of this type. /// * [RawAutocomplete.optionsBuilder], which is of this type.
typedef AutocompleteOptionsBuilder<T extends Object> = Iterable<T> Function(TextEditingValue textEditingValue); typedef AutocompleteOptionsBuilder<T extends Object> = FutureOr<Iterable<T>> Function(TextEditingValue textEditingValue);
/// The type of the callback used by the [RawAutocomplete] widget to indicate /// The type of the callback used by the [RawAutocomplete] widget to indicate
/// that the user has selected an option. /// that the user has selected an option.
...@@ -293,8 +295,8 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>> ...@@ -293,8 +295,8 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
} }
// Called when _textEditingController changes. // Called when _textEditingController changes.
void _onChangedField() { Future<void> _onChangedField() async {
final Iterable<T> options = widget.optionsBuilder( final Iterable<T> options = await widget.optionsBuilder(
_textEditingController.value, _textEditingController.value,
); );
_options = options; _options = options;
......
...@@ -647,6 +647,67 @@ void main() { ...@@ -647,6 +647,67 @@ void main() {
); );
}); });
testWidgets('support asynchronous options builder', (WidgetTester tester) async {
final GlobalKey fieldKey = GlobalKey();
final GlobalKey optionsKey = GlobalKey();
late FocusNode focusNode;
late TextEditingController textEditingController;
Iterable<String>? lastOptions;
Duration? delay;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: RawAutocomplete<String>(
optionsBuilder: (TextEditingValue textEditingValue) async {
final Iterable<String> options = kOptions.where((String option) {
return option.contains(textEditingValue.text.toLowerCase());
});
if (delay == null) {
return options;
}
return Future<Iterable<String>>.delayed(delay, () => options);
},
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
focusNode = fieldFocusNode;
textEditingController = fieldTextEditingController;
return TextField(
key: fieldKey,
focusNode: focusNode,
controller: textEditingController,
);
},
optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<String> onSelected, Iterable<String> options) {
lastOptions = options;
return Container(key: optionsKey);
},
),
),
)
);
// Enter text to build the options with delay.
focusNode.requestFocus();
delay = const Duration(milliseconds: 500);
await tester.enterText(find.byKey(fieldKey), 'go');
await tester.pumpAndSettle();
// The options have not yet been built.
expect(find.byKey(optionsKey), findsNothing);
expect(lastOptions, isNull);
// Await asynchronous options builder.
await tester.pumpAndSettle(delay);
expect(find.byKey(optionsKey), findsOneWidget);
expect(lastOptions, <String>['dingo', 'flamingo', 'goose']);
// Enter text to rebuild the options without delay.
delay = null;
await tester.enterText(find.byKey(fieldKey), 'ngo');
await tester.pump();
expect(lastOptions, <String>['dingo', 'flamingo']);
});
testWidgets('can navigate options with the keyboard', (WidgetTester tester) async { testWidgets('can navigate options with the keyboard', (WidgetTester tester) async {
final GlobalKey fieldKey = GlobalKey(); final GlobalKey fieldKey = GlobalKey();
final GlobalKey optionsKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment