diff --git a/example/lib/example_expansion.dart b/example/lib/example_expansion.dart new file mode 100644 index 0000000..1a2e288 --- /dev/null +++ b/example/lib/example_expansion.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:searchable_listview/searchable_listview.dart'; + +class ExampleExpansion extends StatelessWidget { + const ExampleExpansion({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SearchableList.expansion( + expansionListData: const {}, + expansionTitleBuilder: (context) { + return const Text('Example Expansion'); + }, + filterExpansionData: filterFunction, + expansionListBuilder: (_, __) { + return const Text('Example Expansion Item'); + }, + ), + ); + } + + Map> filterFunction(String filter) { + return {}; + } +} diff --git a/lib/searchable_listview.dart b/lib/searchable_listview.dart index 86845e6..588c970 100644 --- a/lib/searchable_listview.dart +++ b/lib/searchable_listview.dart @@ -271,7 +271,7 @@ class SearchableList extends StatefulWidget { /// Callback invoked when filtring the searchable list /// used when providing [asyncListCallback] /// can't be null when [asyncListCallback] isn't null - late List Function(String, List)? asyncListFilter; + late List Function(String query, List list)? asyncListFilter; /// Loading widget displayed when [asyncListCallback] is loading /// if nothing is provided in [loadingWidget] searchable list will display a [CircularProgressIndicator] @@ -316,7 +316,7 @@ class SearchableList extends StatefulWidget { final TextInputType textInputType; /// Callback function invoked when submiting the search text field - final Function(String?)? onSubmitSearch; + final Function(String? search)? onSubmitSearch; /// The search type on submiting text field or when changing the text field value /// ```dart @@ -409,11 +409,11 @@ class SearchableList extends StatefulWidget { /// Callback used when filtering the expansion list /// required when using [expansion] constructor - late Map> Function(String)? filterExpansionData; + late Map> Function(String query)? filterExpansionData; /// The expansion list title widget builder /// required when using [expansion] constructor - late Widget Function(dynamic) expansionTitleBuilder; + late Widget Function(dynamic header) expansionTitleBuilder; /// Physics attributes used in listview widget late ScrollPhysics? physics; diff --git a/test/expansion_searchable_listview_test.dart b/test/expansion_searchable_listview_test.dart new file mode 100644 index 0000000..1a4e89d --- /dev/null +++ b/test/expansion_searchable_listview_test.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:searchable_listview/searchable_listview.dart'; + +void main() { + group('ExpansionSearchableListView Display', () { + testWidgets(''' + Veryfing expansion searchable listview default display + ''', (test) async { + final dataMap = { + 'Fruits': ['Apple', 'Banana', 'Orange'], + 'Vegetables': ['Carrot', 'Broccoli', 'Spinach'], + }; + + final expansionListView = SearchableList.expansion( + expansionListData: dataMap, + expansionListBuilder: (expansionGroupIndex, listItem) { + return ListTile( + title: Text(listItem), + ); + }, + expansionTitleBuilder: (header) { + return Text(header); + }, + filterExpansionData: (_) { + return {}; + }, + initiallyExpanded: true, + ); + + await test.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: expansionListView, + ), + ), + ), + ); + + expect(find.text('Fruits'), findsOneWidget); + expect(find.text('Vegetables'), findsOneWidget); + expect(find.text('Apple'), findsOneWidget); + expect(find.text('Carrot'), findsOneWidget); + + final searchField = find.byType(TextField); + await test.enterText(searchField, '2'); + await test.pumpAndSettle(); + + expect(find.text('Apple'), findsNothing); + }); + + testWidgets(''' + Veryfing expansion searchable listview display when not expanded + ''', (test) async { + final dataMap = { + 'Fruits': ['Apple', 'Banana', 'Orange'], + 'Vegetables': ['Carrot', 'Broccoli', 'Spinach'], + }; + + final expansionListView = SearchableList.expansion( + expansionListData: dataMap, + expansionListBuilder: (expansionGroupIndex, listItem) { + return ListTile( + title: Text(listItem), + ); + }, + expansionTitleBuilder: (header) { + return Text(header); + }, + filterExpansionData: (_) { + return {}; + }, + ); + + await test.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: expansionListView, + ), + ), + ), + ); + + expect(find.text('Fruits'), findsOneWidget); + expect(find.text('Vegetables'), findsOneWidget); + expect(find.text('Apple'), findsNothing); + expect(find.text('Carrot'), findsNothing); + }); + + testWidgets(''' + Veryfing expansion searchable listview display and tap to expand + ''', (test) async { + final dataMap = { + 'Fruits': ['Apple', 'Banana', 'Orange'], + 'Vegetables': ['Carrot', 'Broccoli', 'Spinach'], + }; + + final expansionListView = SearchableList.expansion( + expansionListData: dataMap, + expansionListBuilder: (expansionGroupIndex, listItem) { + return ListTile( + title: Text(listItem), + ); + }, + expansionTitleBuilder: (header) { + return Text(header); + }, + filterExpansionData: (_) { + return {}; + }, + ); + + await test.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: expansionListView, + ), + ), + ), + ); + + expect(find.text('Fruits'), findsOneWidget); + expect(find.text('Vegetables'), findsOneWidget); + + final fruitsHeader = find.text('Fruits'); + await test.tap(fruitsHeader); + await test.pumpAndSettle(); + + expect(find.text('Apple'), findsOneWidget); + }); + + testWidgets(''' + Veryifing empty widget display when search yields no results + ''', (test) async { + final dataMap = { + 'Fruits': ['Apple', 'Banana', 'Orange'], + 'Vegetables': ['Carrot', 'Broccoli', 'Spinach'], + }; + + final expansionListView = SearchableList.expansion( + expansionListData: dataMap, + expansionListBuilder: (expansionGroupIndex, listItem) { + return ListTile( + title: Text(listItem), + ); + }, + expansionTitleBuilder: (header) { + return Text(header); + }, + filterExpansionData: (_) { + return {}; + }, + emptyWidget: const Text('No items found'), + ); + + await test.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: expansionListView, + ), + ), + ), + ); + + expect(find.text('Fruits'), findsOneWidget); + expect(find.text('Vegetables'), findsOneWidget); + + final searchField = find.byType(TextField); + await test.enterText(searchField, '2'); + await test.pumpAndSettle(); + + expect(find.text('Apple'), findsNothing); + expect(find.text('No items found'), findsOneWidget); + }); + }); +}