Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions example/lib/example_expansion.dart
Original file line number Diff line number Diff line change
@@ -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<dynamic, List<dynamic>> filterFunction(String filter) {
return {};
}
}
8 changes: 4 additions & 4 deletions lib/searchable_listview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class SearchableList<T> extends StatefulWidget {
/// Callback invoked when filtring the searchable list
/// used when providing [asyncListCallback]
/// can't be null when [asyncListCallback] isn't null
late List<T> Function(String, List<T>)? asyncListFilter;
late List<T> Function(String query, List<T> list)? asyncListFilter;

/// Loading widget displayed when [asyncListCallback] is loading
/// if nothing is provided in [loadingWidget] searchable list will display a [CircularProgressIndicator]
Expand Down Expand Up @@ -316,7 +316,7 @@ class SearchableList<T> 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
Expand Down Expand Up @@ -409,11 +409,11 @@ class SearchableList<T> extends StatefulWidget {

/// Callback used when filtering the expansion list
/// required when using [expansion] constructor
late Map<dynamic, List<T>> Function(String)? filterExpansionData;
late Map<dynamic, List<T>> 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;
Expand Down
180 changes: 180 additions & 0 deletions test/expansion_searchable_listview_test.dart
Original file line number Diff line number Diff line change
@@ -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<String>.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<String>.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<String>.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<String>.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);
});
});
}