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 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
......@@ -22,7 +24,7 @@ import 'shortcuts.dart';
/// See also:
///
/// * [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
/// that the user has selected an option.
......@@ -293,8 +295,8 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
}
// Called when _textEditingController changes.
void _onChangedField() {
final Iterable<T> options = widget.optionsBuilder(
Future<void> _onChangedField() async {
final Iterable<T> options = await widget.optionsBuilder(
_textEditingController.value,
);
_options = options;
......
......@@ -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 {
final GlobalKey fieldKey = 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