Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE REQUEST] - Wrap items of SearchChoices.multiple() widget #109

Closed
ramioooz opened this issue Feb 23, 2023 · 11 comments
Closed

[FEATURE REQUEST] - Wrap items of SearchChoices.multiple() widget #109

ramioooz opened this issue Feb 23, 2023 · 11 comments
Labels
enhancement New feature or request waiting for customer response The team needs more information from the user

Comments

@ramioooz
Copy link

Hello developers.

First I would like to thank you very much for providing such a nice and smart widget.
I have a suggestion for a feature here.

for the SearchChoices.multiple() widget.
we wanted to be able to have the items in the multichoice list to be displayed in a wrap/grid.
the only available option now is to have the items displayed in a list.

please have a look over my attached image to give you an idea about what we want.
IMG_20230223_034306

we would like to have the items of SearchChoices.multiple() to be displayed in a wrap. something similar to what is shown in the second drawing in the image attached.

My regards.
Rami

@lcuis
Copy link
Owner

lcuis commented Feb 23, 2023

Hello @ramioooz ,

Thank you very much for your message and request!

I believe this is covered by the selectedAggregateWidgetFn parameter. There is an example called "Multi dialog with count and wrap" as follows:

SearchChoices.multiple(
        items: items,
        selectedItems: selectedItemsMultiDialogWithCountAndWrap,
        hint: "Select items",
        searchHint: "Select items",
        onChanged: (value) {
          setState(() {
            selectedItemsMultiDialogWithCountAndWrap = value;
          });
        },
        isExpanded: true,
        selectedValueWidgetFn: (item) {
          return (Container(
            margin: const EdgeInsets.all(15.0),
            padding: const EdgeInsets.all(3.0),
            decoration:
                BoxDecoration(border: Border.all(color: Colors.blueAccent)),
            child: Text(
              item,
              overflow: TextOverflow.ellipsis,
            ),
          ));
        },
        selectedAggregateWidgetFn: (List<Widget> list) {
          return (Column(children: [
            Text("${list.length} items selected"),
            Wrap(children: list),
          ]));
        },
      )

With this result:
https://searchchoices.jod.li/Multi%20dialog%20with%20count%20and%20wrap.gif

Cheers!

@ramioooz
Copy link
Author

ramioooz commented Feb 23, 2023

Hello @lcuis ,
Thank you very much for your reply.

selectedAggregateWidgetFn parameter helps us show already-selected items in Wrap which is great.
but I am not talking about that...
I am talking about the stage (before selecting the items) where you open a dialog to search and select your choices.
items in that popup dialog are listed vertically. we wanted to be able to have the items in a grid/wrap.

My Regards.

@lcuis
Copy link
Owner

lcuis commented Feb 23, 2023

Oh, indeed, sorry, let me check.

@lcuis
Copy link
Owner

lcuis commented Feb 23, 2023

Indeed, for this to work easily, there would need to be an additional callback to replace the listDisplay method in _DropdownDialogState class:

/// Builds the list display from the given list of [DropdownMenuItem] along
/// with the [bool] indicating whether the item is selected or not and the
/// [int] as the index in the [selectedItems] list.
Widget listDisplay(
List<Tuple3<int, DropdownMenuItem<dynamic>, bool>> itemsToDisplay) {
return Expanded(
child: Scrollbar(
controller: widget.listScrollController,
thumbVisibility: widget.itemsPerPage == null ? false : true,
child: itemsToDisplay.length == 0
? emptyList()
: ListView.builder(
controller: widget.listScrollController,
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,
),
),
);
}

Thanks for mentioning this!

I hope this can be done soon.

@lcuis lcuis added the enhancement New feature or request label Feb 23, 2023
@Macacoazul01
Copy link
Collaborator

@lcuis there is something like this being done here:
https://pub.dev/packages/multi_dropdown
@ramioooz correct me if this isn't what you are expecting

@ramioooz
Copy link
Author

@lcuis there is something like this being done here: https://pub.dev/packages/multi_dropdown @ramioooz correct me if this isn't what you are expecting

not really. the example display selected items in a wrap. we can do that in your widget using selectedAggregateWidgetFn parameter. but again this is not the issue.
we are talking about the items displayed inside the popup dialog or menu. the dialog shows search results vertically which is fine in most cases. but sometimes we want to show search results in a wrap. (as an inventory of items a user can select from)
we are using buildDropDownDialog to customize the dialog but we can not put list items in a wrap.
check this snippet of our menu code:

buildDropDownDialog: (
          Widget titleBar,
          Widget searchBar,
          Widget list,
          Widget closeButton,
          BuildContext dropDownContext,
        ) {
          return (AnimatedContainer(
            padding: MediaQuery.of(dropDownContext).viewInsets,
            duration: const Duration(milliseconds: 300),
            child: Card(
              color: Colors.grey[100],
              margin: const EdgeInsets.symmetric(vertical: 80, horizontal: 80),
              child: Container(
                padding:
                    const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    searchBar,
                    list, // <-- we want to have this as a wrap. right now it is an Expanded widget
                    // closeButton,
                  ],
                ),
              ),
            ),
          ));
        },

the photos attaches show the current result and the wanted result.
A. current result
111
B. wanted result
222

Thank you.

@lcuis
Copy link
Owner

lcuis commented Feb 24, 2023

Thanks @Macacoazul01 for the link. This is an interesting project.

Thanks @ramioooz for the additional explanation and examples.

@lcuis
Copy link
Owner

lcuis commented Feb 24, 2023

Hi @ramioooz ,

Here is an example with the upcoming new parameter searchResultDisplayFn:

        searchResultDisplayFn: ({
          required List<Tuple3<int, DropdownMenuItem, bool>> 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<int, DropdownMenuItem, bool> 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()),
                    ));
        },

With this result:
image

I will commit and publish as soon as possible.

@lcuis
Copy link
Owner

lcuis commented Feb 24, 2023

Release 2.2.4 has just been published to pub.dev with the previously mentioned new parameter.

@lcuis lcuis added the waiting for customer response The team needs more information from the user label Feb 24, 2023
@ramioooz
Copy link
Author

Hello @lcuis

I can't thank you enough for putting the effort into bringing the idea into the material world.
You just exceeded my expectations.
I updated your plugin in my project and added the new parameter searchResultDisplayFn to my code as you suggested with slight modifications and here is the end result.

searchResultDisplayFn: ({
          required List<Tuple3<int, DropdownMenuItem, bool>> 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.isEmpty
                ? emptyListWidget
                : SingleChildScrollView(
                    child: Wrap(
                      spacing: 10,
                      // runSpacing: 10,
                      children: itemsToDisplay.map(
                        (Tuple3<int, DropdownMenuItem, bool> item) {
                          return Padding(
                            padding: const EdgeInsets.symmetric(vertical: 5),
                            child: InkWell(
                              onTap: () {
                                itemTapped(
                                  item.item1,
                                  item.item2.value,
                                  item.item3,
                                );
                              },
                              child: Container(
                                decoration: BoxDecoration(
                                  border: Border.all(color: Colors.grey),
                                  borderRadius: const BorderRadius.all(
                                    Radius.circular(5),
                                  ),
                                ),
                                child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                    // Checkbox(
                                    //     value: item.item3, onChanged: null),
                                    item.item3
                                        ? Icon(
                                            Icons.check_box,
                                            color:
                                                Theme.of(context).primaryColor,
                                          )
                                        : const Icon(
                                            Icons.check_box_outline_blank,
                                            color: Colors.grey,
                                          ),
                                    item.item2,
                                  ],
                                ),
                              ),
                            ),
                          );
                        },
                      ).toList(),
                    ),
                  ),
          );
        },

555

Thank you very much
👏👏👏👏👏

@lcuis
Copy link
Owner

lcuis commented Feb 26, 2023

Thanks a lot @ramioooz for the confirmation and for your message!

Enjoy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request waiting for customer response The team needs more information from the user
Projects
None yet
Development

No branches or pull requests

3 participants