From 4bb045bbf64478fe1274f5b300c11c9e5bfd6647 Mon Sep 17 00:00:00 2001 From: lcuis Date: Fri, 24 Feb 2023 10:03:45 +0100 Subject: [PATCH] (2.2.4 WIP) added searchResultDisplayFn ; thanks @ramioooz https://github.com/lcuis/search_choices/issues/109 --- CHANGELOG.md | 4 ++ README.md | 66 +++++++++++++++++++ example/lib/main.dart | 44 +++++++++++++ lib/src/dropdown/dropdown_dialog.dart | 22 +++++++ lib/src/search_choices.dart | 93 +++++++++++++++++++++++++++ pubspec.yaml | 2 +- 6 files changed, 230 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c17da3c..c8424c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.4 + +* added searchResultDisplayFn. Thanks @ramioooz https://github.com/lcuis/search_choices/issues/109 + ## 2.2.3 * added buildFutureFilterOrOrderButton to customize future filter and order button. Thanks @agustin-garcia https://github.com/lcuis/search_choices/issues/107 diff --git a/README.md b/README.md index b00eae2..de9cd21 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,16 @@ Search choices Widget with a single choice that opens a dialog or a menu to let String? orderBy, })? buildFutureFilterOrOrderButton, + Widget Function({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, T value, bool itemSelected) itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + })? + searchResultDisplayFn, }) ``` @@ -239,6 +249,7 @@ Search choices Widget with a single choice that opens a dialog or a menu to let ** nbFilters is set to the number of filters applied if any. ** orderAsc true when the applied order is ascending. ** orderBy is the string by which the search is sorted. +* searchResultDisplayFn to customize the display of the search result items within the dialog or menu. #### Multiple choice constructor @@ -336,6 +347,16 @@ Search choices Widget with a multiple choice that opens a dialog or a menu to le String? orderBy, })? buildFutureFilterOrOrderButton, + Widget Function({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, T value, bool itemSelected) itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + })? + searchResultDisplayFn, }) ``` @@ -401,6 +422,7 @@ Search choices Widget with a multiple choice that opens a dialog or a menu to le ** nbFilters is set to the number of filters applied if any. ** orderAsc true when the applied order is ascending. ** orderBy is the string by which the search is sorted. +* searchResultDisplayFn to customize the display of the search result items within the dialog or menu. #### Example app usage @@ -2734,6 +2756,50 @@ SearchChoices.single( )), ); }, + // Here, searchResultDisplayFn doesn't change anything. + // This is a way to make sure this parameter still works with automated + // integration testing. + searchResultDisplayFn: ({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, dynamic value, bool itemSelected) + itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + }) { + return Expanded( + child: Scrollbar( + controller: scrollController, + thumbVisibility: thumbVisibility, + child: itemsToDisplay.length == 0 + ? emptyListWidget + : ListView.builder( + controller: scrollController, + itemBuilder: (context, index) { + int itemIndex = itemsToDisplay[index].item1; + DropdownMenuItem item = itemsToDisplay[index].item2; + bool isItemSelected = itemsToDisplay[index].item3; + return InkWell( + onTap: () { + itemTapped( + itemIndex, + item.value, + isItemSelected, + ); + }, + child: displayItem( + item, + isItemSelected, + ), + ); + }, + itemCount: itemsToDisplay.length, + ), + ), + ); + }, ) ``` ### Single dialog custom field presentation diff --git a/example/lib/main.dart b/example/lib/main.dart index b912d03..2a31c66 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2282,6 +2282,50 @@ class MyAppState extends State { )), ); }, + // Here, searchResultDisplayFn doesn't change anything. + // This is a way to make sure this parameter still works with automated + // integration testing. + searchResultDisplayFn: ({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, dynamic value, bool itemSelected) + itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + }) { + return Expanded( + child: Scrollbar( + controller: scrollController, + thumbVisibility: thumbVisibility, + child: itemsToDisplay.length == 0 + ? emptyListWidget + : ListView.builder( + controller: scrollController, + itemBuilder: (context, index) { + int itemIndex = itemsToDisplay[index].item1; + DropdownMenuItem item = itemsToDisplay[index].item2; + bool isItemSelected = itemsToDisplay[index].item3; + return InkWell( + onTap: () { + itemTapped( + itemIndex, + item.value, + isItemSelected, + ); + }, + child: displayItem( + item, + isItemSelected, + ), + ); + }, + itemCount: itemsToDisplay.length, + ), + ), + ); + }, ), "Single dialog custom field presentation": SearchChoices.single( items: items, diff --git a/lib/src/dropdown/dropdown_dialog.dart b/lib/src/dropdown/dropdown_dialog.dart index 20a99a4..8624d97 100644 --- a/lib/src/dropdown/dropdown_dialog.dart +++ b/lib/src/dropdown/dropdown_dialog.dart @@ -155,6 +155,17 @@ class DropdownDialog extends StatefulWidget { String? orderBy, })? buildFutureFilterOrOrderButton; + /// See SearchChoices class. + final Widget Function({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, T value, bool itemSelected) itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + })? searchResultDisplayFn; + DropdownDialog({ Key? key, this.items, @@ -198,6 +209,7 @@ class DropdownDialog extends StatefulWidget { this.clearSearchIcon, this.listValidator, this.buildFutureFilterOrOrderButton, + this.searchResultDisplayFn, }) : super(key: key); _DropdownDialogState createState() => _DropdownDialogState(); @@ -715,6 +727,16 @@ class _DropdownDialogState extends State { /// [int] as the index in the [selectedItems] list. Widget listDisplay( List, bool>> itemsToDisplay) { + if (widget.searchResultDisplayFn != null) { + return widget.searchResultDisplayFn!( + itemsToDisplay: itemsToDisplay, + scrollController: widget.listScrollController, + thumbVisibility: widget.itemsPerPage == null ? false : true, + emptyListWidget: emptyList(), + itemTapped: itemTapped as Function(int, dynamic, bool), + displayItem: displayItem, + ); + } return Expanded( child: Scrollbar( controller: widget.listScrollController, diff --git a/lib/src/search_choices.dart b/lib/src/search_choices.dart index 48504a6..3662b3b 100644 --- a/lib/src/search_choices.dart +++ b/lib/src/search_choices.dart @@ -323,6 +323,71 @@ class SearchChoices extends FormField { String? orderBy, })? buildFutureFilterOrOrderButton; + /// [searchResultDisplayFn] to customize the display of the search result + /// items within the dialog or menu. + /// Example: + /// searchResultDisplayFn: ({ + /// required List> itemsToDisplay, + /// required ScrollController scrollController, + /// required bool thumbVisibility, + /// required Widget emptyListWidget, + /// required void Function(int index, dynamic value, bool itemSelected) + /// itemTapped, + /// required Widget Function(DropdownMenuItem item, bool isItemSelected) + /// displayItem, + /// }) { + /// return Expanded( + /// child: itemsToDisplay.length == 0 + /// ? emptyListWidget + /// : SingleChildScrollView( + /// child: Wrap( + /// spacing: 10, + /// children: itemsToDisplay.map( + /// (Tuple3 item) { + /// return Padding( + /// padding: + /// const EdgeInsets.symmetric(vertical: 8.0), + /// child: InkWell( + /// onTap: () { + /// itemTapped( + /// item.item1, + /// item.item2.value, + /// item.item3, + /// ); + /// }, + /// child: Container( + /// decoration: BoxDecoration( + /// border: Border.all( + /// color: Colors.grey, + /// width: 5, + /// )), + /// child: Row( + /// mainAxisSize: MainAxisSize.min, + /// children: [ + /// Padding( + /// padding: const EdgeInsets.symmetric( + /// horizontal: 8.0), + /// child: item.item2, + /// ), + /// ], + /// ), + /// ), + /// ), + /// ); + /// }, + /// ).toList()), + /// )); + /// }, + final Widget Function({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, T value, bool itemSelected) itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + })? searchResultDisplayFn; + /// Search choices Widget with a single choice that opens a dialog or a menu /// to let the user do the selection conveniently with a search. /// @@ -459,6 +524,8 @@ class SearchChoices extends FormField { /// ** [nbFilters] is set to the number of filters applied if any. /// ** [orderAsc] true when the applied order is ascending. /// ** [orderBy] is the string by which the search is sorted. + /// * [searchResultDisplayFn] to customize the display of the search result + /// items within the dialog or menu. factory SearchChoices.single({ Key? key, List>? items, @@ -550,6 +617,16 @@ class SearchChoices extends FormField { String? orderBy, })? buildFutureFilterOrOrderButton, + Widget Function({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, T value, bool itemSelected) itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + })? + searchResultDisplayFn, }) { return (SearchChoices._( key: key, @@ -610,6 +687,7 @@ class SearchChoices extends FormField { restorationId: restorationId, giveMeThePop: giveMeThePop, buildFutureFilterOrOrderButton: buildFutureFilterOrOrderButton, + searchResultDisplayFn: searchResultDisplayFn, )); } @@ -748,6 +826,8 @@ class SearchChoices extends FormField { /// ** [nbFilters] is set to the number of filters applied if any. /// ** [orderAsc] true when the applied order is ascending. /// ** [orderBy] is the string by which the search is sorted. + /// * [searchResultDisplayFn] to customize the display of the search result + /// items within the dialog or menu. factory SearchChoices.multiple({ Key? key, List>? items, @@ -840,6 +920,16 @@ class SearchChoices extends FormField { String? orderBy, })? buildFutureFilterOrOrderButton, + Widget Function({ + required List> itemsToDisplay, + required ScrollController scrollController, + required bool thumbVisibility, + required Widget emptyListWidget, + required void Function(int index, T value, bool itemSelected) itemTapped, + required Widget Function(DropdownMenuItem item, bool isItemSelected) + displayItem, + })? + searchResultDisplayFn, }) { return (SearchChoices._( key: key, @@ -902,6 +992,7 @@ class SearchChoices extends FormField { restorationId: restorationId, giveMeThePop: giveMeThePop, buildFutureFilterOrOrderButton: buildFutureFilterOrOrderButton, + searchResultDisplayFn: searchResultDisplayFn, )); } @@ -971,6 +1062,7 @@ class SearchChoices extends FormField { this.restorationId, this.giveMeThePop, this.buildFutureFilterOrOrderButton, + this.searchResultDisplayFn, }) : assert(!multipleSelection || doneButton != null), assert(menuConstraints == null || !dialogBox), assert(itemsPerPage == null || currentPage != null, @@ -1341,6 +1433,7 @@ class _SearchChoicesState extends FormFieldState { clearSearchIcon: widget.clearSearchIcon, listValidator: widget.listValidator, buildFutureFilterOrOrderButton: widget.buildFutureFilterOrOrderButton, + searchResultDisplayFn: widget.searchResultDisplayFn, )); }); } diff --git a/pubspec.yaml b/pubspec.yaml index 8bff62c..42e29d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: search_choices description: Highly versatile Widget to search through a single or multiple choices list in a dialog box or a menu. Supports pagination and future/API/webservice searches with sort and filter. -version: 2.2.3 +version: 2.2.4 homepage: https://github.com/lcuis/search_choices repository: https://github.com/lcuis/search_choices issue_tracker: https://github.com/lcuis/search_choices/issues