diff --git a/example/lib/widgets/async_searchable_listview.dart b/example/lib/widgets/async_searchable_listview.dart index cf65364..a58e92f 100644 --- a/example/lib/widgets/async_searchable_listview.dart +++ b/example/lib/widgets/async_searchable_listview.dart @@ -20,7 +20,7 @@ class AsyncSearchableListview extends StatelessWidget { }, asyncListFilter: (query, list) async { await Future.delayed(const Duration(seconds: 3)); - var result = actors + var result = list .where((element) => element.name.contains(query) || element.lastName.contains(query)) diff --git a/lib/searchable_listview.dart b/lib/searchable_listview.dart index 657c00e..a600d38 100644 --- a/lib/searchable_listview.dart +++ b/lib/searchable_listview.dart @@ -519,6 +519,7 @@ class _SearchableListState extends State> { CancelableOperation?>? _activeOperation; late Debouncer? _debouncer; List expansionTileControllers = []; + bool isAsyncCallBackRunning = true; @override void initState() { @@ -541,7 +542,7 @@ class _SearchableListState extends State> { if (widget.asyncListCallback != null) { // Load the initial list for the async constructor WidgetsBinding.instance.addPostFrameCallback((_) async { - _asyncFilter(""); + await _asyncInitialList(); if (mounted) setState(() {}); }); _debouncer = Debouncer(milliseconds: widget.asyncDebounceTime); @@ -612,7 +613,7 @@ class _SearchableListState extends State> { if (asyncError) { return widget.errorWidget ?? const DefaultErrorWidget(); } - if (_activeOperation != null) { + if (_activeOperation != null || isAsyncCallBackRunning) { return widget.loadingWidget ?? const DefaultLoadingWidget(); } return renderSearchableListView(); @@ -799,8 +800,9 @@ class _SearchableListState extends State> { } else if (widget.asyncListCallback != null) { // Debouncer always has a value in this case _debouncer!.run(() async { + if (mounted) setState(() {}); _activeOperation?.cancel(); - _asyncFilter(value); + await _asyncFilter(value); if (mounted) setState(() {}); }); } else { @@ -862,6 +864,11 @@ class _SearchableListState extends State> { } Future _asyncFilter(String value) async { + if (isAsyncCallBackRunning) { + // Wait for the initial list before filtering + return; + } + final operation = CancelableOperation.fromFuture( widget.asyncListFilter!( value, @@ -879,11 +886,34 @@ class _SearchableListState extends State> { asyncError = true; } } finally { - // Make sure to not interrupt an other operation + // Make sure to not interrupt another operation if (_activeOperation == operation) { _activeOperation = null; } } - setState(() {}); + } + + Future _asyncInitialList() async { + isAsyncCallBackRunning = true; + // First get the initial list + try { + final initialData = await widget.asyncListCallback!(); + if (initialData != null) { + asyncListResult = initialData; + } else { + asyncError = true; + } + } catch (e) { + asyncError = true; + return; + } + isAsyncCallBackRunning = false; + // Then check if a query was typed during the initial list loading to filter if needed + if ((widget.searchTextController?.text ?? "") != "") { + await _asyncFilter(widget.searchTextController!.text); + } else { + filtredAsyncListResult.clear(); + filtredAsyncListResult.addAll(asyncListResult); + } } }