Can't make a single select with a Switch or a RadioListTile flutter - flutter

i'm trying to make an Extra Food Items List it's for a Delivery App. The module of restaurants requiere these , but my issue is when I use a RadioListTile or a SwitchListTile it is possible to select more than one option, all the data is from an API where the Admin of some restaurant put the products. What i try to do is to make a ListView. separated for the Extra Groups (eg."Presa") and my Extras are the products or toppings that some product can have
Widget build(BuildContext context) {
return SwitchListTile.adaptive(
activeColor: Theme.of(context).accentColor,
// checkColor: Theme.of(context).primaryColor,
value: widget.extra.checked,
onChanged:(value) {
setState(() {
//widget.extra.checked = value;
widget.extra.checked = !widget.extra.checked;
widget.onChanged();
Future.delayed(Duration(milliseconds: 200),(){
Navigator.pop(context);
});
widget.onSelectedExtra;
});
},
title: Text(
widget.extra?.name,
style: Theme.of(context).textTheme.headline3.merge(TextStyle(
color: Theme.of(context).shadowColor,
fontSize: 16
)),
textAlign: TextAlign.start,
),
subtitle: widget.extra.price == 'null' || widget.extra.price == null || widget.extra.price == '0' || widget.extra.price == 0
? Helper.getPrice(0, context, style: Theme.of(context).textTheme.headline4.merge(TextStyle(
color: Theme.of(context).accentColor
)),)
:Helper.getPrice(widget.extra.price, context, style: Theme.of(context).textTheme.headline4.merge(TextStyle(
color: Theme.of(context).accentColor
)),),
);
}
}
In this section i'm calling just one Extra Food so i can return inside a list in the other section
if (_con.product.extraGroups == null)
CircularLoadingWidget(height: 100)
else
ListView.separated(
padding: EdgeInsets.all(0),
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
controller: ScrollController(initialScrollOffset: 600),
itemBuilder: (context, extraGroupIndex) {
var extraGroup = _con.product.extraGroups.elementAt(extraGroupIndex);
return Wrap(
children: <Widget>[
ListTile(
dense: true,
contentPadding: EdgeInsets.symmetric(vertical: 0),
leading: Icon(
Icons.add_circle_outline,
color: Theme.of(context).accentColor
),
title: Text(
extraGroup?.name ?? '',
style: Theme.of(context).textTheme.subtitle1.merge(TextStyle(
color: Theme.of(context).accentColor,
fontWeight: FontWeight.w600,
fontSize: 16
)),
),
),
Container(
decoration: BoxDecoration(
),
child: ListTile(
title:Text('Seleccione su ${extraGroup.name}',
style: Theme.of(context).textTheme.caption.merge(TextStyle(
color: Theme.of(context).shadowColor,
//fontWeight: FontWeight.w600,
fontSize: 13
)),
),
trailing: FlatButton(
color: Theme.of(context).focusColor.withOpacity(0.4),
shape:RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)
),
onPressed:(){
showModalBottomSheet(
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(30),topRight: Radius.circular(30))
),
context: context,
builder: (context){
return Wrap(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
child: ListView.separated(
padding: EdgeInsets.all(0),
itemBuilder: (context, extraIndex) {
return ExtraItemWidget(
extra: _con.product.extras.where((extra) => extra.extraGroupId == extraGroup.id && extra.multiple_selection == true ).elementAt(extraIndex),
onChanged: _con.calculateTotal,
);
},
separatorBuilder: (context, index) {
return SizedBox(height: 0);
},
itemCount: _con.product.extras.where((extra) => extra.extraGroupId == extraGroup.id && extra.multiple_selection == true).length,
primary: false,
shrinkWrap: true,
),
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: ListView.builder(
itemBuilder: (context, extraIndex) {
return ExtraSingleItemWidget(
extra: _con.product.extras.where((extra) => extra.extraGroupId == extraGroup.id && extra.multiple_selection == false).elementAt(extraIndex),
onChanged: _con.calculateTotal,
onSelectedExtra: _con.SelectedExtra,
);
},
itemCount: _con.product.extras.where((extra) => extra.extraGroupId == extraGroup.id && extra.multiple_selection == false).length,
primary: false,
shrinkWrap: true,
),
),
],
);
});
},
child: Wrap(
children: [
Text(
'Seleccionar',
style: Theme.of(context).textTheme.button.merge(TextStyle(
color: Theme.of(context).shadowColor
)),
),
],
),
),
),
),
],
);
},
separatorBuilder: (context, index) {
return Divider(thickness:1.5,height: 20);
},
itemCount: _con.product.extraGroups.length,
primary: false,
shrinkWrap: true,
),
I'm calling like ExtraSingleItemWidget, once the user select an extra it add to the base price but if the user want to select another extra from the modal bottom sheet it select more than one and I just need one at a time.enter image description here
enter image description here

Related

Flutter - How to search in List and display in ListView?

I'm coding a search system for the Flutter application I've developed. I'm having a problem with the back-end. First I pull the data from Firebase Firestore. Then I convert it to Model structure.
The code of the search system:
StreamBuilder(
stream: db.collection("DebrisPeoples").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
final List<DebrisPeopleModel> data = snapshot.data!.docs
.map((e) => DebrisPeopleModel.fromDocument(e))
.toList(); // To Model code
return Column(
children: [
const SizedBox(height: 10),
SizedBox(
width: MediaQuery.of(context).size.width * 0.95,
child: TextFormField(
decoration: InputDecoration(
prefixIcon: const Icon(Icons.search),
contentPadding: const EdgeInsets.only(),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
),
onChanged: (value) {
final find = data.where(
(element) => data.contains(element.nameSurname));
print(find); // PROBLEM - NOT WORKING
},
),
),
SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.8,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: data.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(
data[index].personSize == 1
? Icons.person
: Icons.people,
),
title: Text(data[index].nameSurname.toString()),
subtitle: Text(
"${data[index].city} / ${data[index].district}",
),
trailing: IconButton(
icon: const Icon(Icons.info),
onPressed: () {
Get.to(const UnderRublePeopleDetailPage(),
arguments: data[index]);
print(data[index].nameSurname);
},
),
),
);
},
),
),
],
);
}
},
),
I'm having the problem in the query part. My goal is, for example, if there is a record in the form of ABC, I want it to appear in the results even if the user searches for A or AB.
Then I want the results to be displayed in the list. I will be grateful for your help :)
To change search results:
final find = data.where((element) => element
.nameSurname!
.toLowerCase()
.contains(value.toLowerCase()));
print(find);
setState(() {
data = find.toList();
print(data);
});
I tried to make such a search system. However, the results in the ListView do not change as I enter the TextFormField.
Your onChanged code should be as following.
onChanged: (value) {
final find = data.where(
(element) => element.nameSurname.toLowerCase().contains(value.toLowerCase()));
print(find);
}
Make sure you are managing the state to reflect the changes on UI.
Edited
final controller = TextEditingController();//Keep this as a field
StreamBuilder(
stream: db.collection("DebrisPeoples").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
final searchText = controller.text.trim().toLowerCase();
final List<DebrisPeopleModel> data = snapshot.data!.docs
.map((e) => DebrisPeopleModel.fromDocument(e))
.where((e) => searchText.isEmpty || e.nameSurname!
.toLowerCase().contains(searchText))
.toList(); // To Model code
return Column(
children: [
const SizedBox(height: 10),
SizedBox(
width: MediaQuery
.of(context)
.size
.width * 0.95,
child: TextFormField(
controller: controller,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.search),
contentPadding: const EdgeInsets.only(),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
),
onChanged: (value) {
setState((){ });
},
),
),
SizedBox(
width: double.infinity,
height: MediaQuery
.of(context)
.size
.height * 0.8,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: data.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(
data[index].personSize == 1
? Icons.person
: Icons.people,
),
title: Text(data[index].nameSurname.toString()),
subtitle: Text(
"${data[index].city} / ${data[index].district}",
),
trailing: IconButton(
icon: const Icon(Icons.info),
onPressed: () {
Get.to(const UnderRublePeopleDetailPage(),
arguments: data[index]);
print(data[index].nameSurname);
},
),
),
);
},
),
),
],
);
}
},
)

How to show loading indicator on only one list item in Flutter?

I have a list of items with buttons. By clicking on one element on the button, I get a CircularProgressIndicator. I ran into a problem that when I click on one card per button, I get a loading indicator on all cards. How can I make the loading indicator appear on only one card that I click on?
bool isApprovedLoading = false;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: Padding(
padding: const EdgeInsets.only(top: 10, bottom: 18),
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: list.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 7.0, sigmaY: 7.0),
child: Container(
height: 152,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color:
constants.Colors.greyXDark.withOpacity(0.8),
),
child: Row(
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
isApprovedLoading
? const CircularProgressIndicator(
color: constants
.Colors.purpleMain)
: OrderButton(
text: 'Approved',
svgIcon:
SvgPicture.asset(
constants.Assets
.enable,
color: constants
.Colors
.purpleMain),
textStyle: const TextStyle(
fontFamily: constants
.FontFamily
.AvenirLtStd,
fontSize: 12,
fontWeight:
FontWeight.w800,
color: constants
.Colors
.purpleMain),
borderColor: constants
.Colors.purpleMain,
buttonColor: constants
.Colors.greyXDark
.withOpacity(0.5),
onTap: () {
setState(() {
isApprovedLoading =
true;
});
_confirmOrder(
context,
list[index].id,
poyntBookingsCubit,
user,
);
},
),
],
),
),
],
),
),
),
),
],
),
),
),
),
);
},
)
),
),
);
you need define new variable like:
int selectedItem = -1;
and change your asdasd to this:
onTap: () {
setState(() {
isApprovedLoading = true;
selectedItem = index;
});
_confirmOrder(
context,
list[index].id,
poyntBookingsCubit,
user,
);
},
then use it like this:
isApprovedLoading && selectedItem == index
? const CircularProgressIndicator(
color: constants.Colors.purpleMain)
: OrderButton(...),

Dynamic listview in flutter

I'm new to Flutter, but I'm trying to make an app with a ListView. The ListView is a list of exercises, within each exercise the number of sets can be added. The problem comes when i press the button add exercise. The above exercise with sets is just copied. I would like a new exercise tab with 0 sets. Below the code can be found.
Here is a picture of the list.
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "null",
);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
titleSection,
// ignore: unnecessary_new
new TextField(
controller: eCtrl,
onSubmitted: (text) {
litems.add(text);
eCtrl.clear();
setState(() {});
},
),
Expanded(
// ignore: unnecessary_new
child: new ListView.builder(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Card(
child: Padding(
padding: EdgeInsets.all(10),
child: ExpansionTile(
initiallyExpanded: true,
title: Text(
litems[Index],
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(child: Text(" ")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
],
),
// ignore: sort_child_properties_last
children: <Widget>[
ListView.builder(
shrinkWrap: true,
itemCount: sets.length,
itemBuilder:
(BuildContext context, int Index1) {
return Dismissible(
key: UniqueKey(),
// only allows the user swipe from right to left
direction:
DismissDirection.endToStart,
// Remove this product from the list
// In production enviroment, you may want to send some request to delete it on server side
onDismissed: (_) {
setState(() {
sets.removeAt(Index1);
});
},
// ignore: sort_child_properties_last
child: Card(
elevation: 0,
child: Padding(
padding: EdgeInsets.all(1),
child: ListTile(
title: Text(
" ",
style: const TextStyle(
fontSize: 10,
fontWeight:
FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(
child: Text(" "),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
],
),
))),
background: Container(
color: Colors.red,
margin:
const EdgeInsets.symmetric(
horizontal: 15,
),
alignment: Alignment.centerRight,
child: const Text(
"Delete",
style: TextStyle(
color: Colors.white,
),
)));
}),
Padding(
padding: EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () {
sets.add('sets-test');
setState(() {});
},
child: const Text('+ Add Set')),
),
const SizedBox(height: 5),
],
leading: IconButton(
icon: const Icon(
Icons.close,
color: Colors.red,
),
onPressed: () {
litems.removeAt(Index);
setState(() {});
},
),
)));
})),
ElevatedButton(
onPressed: () {
litems.add("new");
setState(() {});
},
child: const Text('Add Exercises')),
ElevatedButton(
onPressed: () {
createUser(user1, "5");
exercise.setExerciseTotals();
//saveExercise(exercise);
final workout = Workout([exercise, exercise1], "Det gik fint",
"10", 60, "type", "name", true, 0, 0, 0);
//workout.setWorkoutTotals();
saveWorkout(workout, userID);
},
child: const Text('pop')),
bottomSection,
],
),
));
}
You are not copy the item, you logic is that add new Item with null value, change decoratedField to this:
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "0",
);

I need create Switch from snapshot response in Flutter

I would like to get the name of each item coming from snapshot.data!.sections![i].checklists! .map((e) => e.quesito and transform it into Text (' ') for each item, but I didn't find a solution at this moment and I can't get the title for my SwitchListTile...
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 6,
itemBuilder: (context, i) {
return Column(
children: <Widget>[
Container(
width: double.infinity,
padding:
const EdgeInsets.only(left: 15),
color: Colors.grey[200],
child: Row(
children: [
Text(
'${snapshot.data!.secoes![i].nome}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold),
),
const SizedBox(
height: 30,
),
],
),
),
...snapshot.data!.secoes![i].checklists!
.map<Widget>(
(e) => SwitchListTile(
title: Text(''),
value: true,
onChanged: (bool newValue) {},
),
),
],
);
},
),
If you are sure you have the data parsed, you can simply call the data from the map.
...snapshot.data!.secoes![i].checklists!
.map<Widget>(
(e) => SwitchListTile(
title: Text(e.quesito),
value: true,
onChanged: (bool newValue) {},
),
),

Flutter combo box item in list view

I'm trying to make a combobox and when I select an item, I want it to be added in a listview when a button is pressed.
I tried multiple solutions, but none seems to work, as far as I did, I could make a input field and add the items manually, but I can't do it with a combobox ( without letting the user write them manually ).
Here is what I did:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:searchable_dropdown/searchable_dropdown.dart';
class LocationTab extends StatefulWidget {
#override
_LocationTabState createState() => _LocationTabState();
}
class _LocationTabState extends State<LocationTab> {
List<String> mylist = List();
List<ParentCategoryComboBox> _visibility =
ParentCategoryComboBox.getParentCategory();
List<DropdownMenuItem<ParentCategoryComboBox>> _dropdownMenuItems;
List<PlatformReachComboBox> _platformReach =
PlatformReachComboBox.getPlatformReach();
List<DropdownMenuItem<PlatformReachComboBox>> _dropdownPlatformReach;
PlatformReachComboBox _selectedPlatformReach;
ParentCategoryComboBox _selectedVisibility;
#override
void initState() {
_dropdownMenuItems = buildDropDownMenuItems(_visibility);
_selectedVisibility = _dropdownMenuItems[0].value;
_dropdownPlatformReach =
buildDropdownMenuItemsPlatformReach(_platformReach);
_selectedPlatformReach = _dropdownPlatformReach[0].value;
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10.0, left: 20.0, right: 20.0),
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
SizedBox(
height: 20,
),
Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
"Select visibility:",
style: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
],
),
DropdownButton(
icon: Icon(
Icons.visibility,
color: Colors.black45,
),
isExpanded: true,
value: _selectedVisibility,
items: _dropdownMenuItems,
onChanged: (ParentCategoryComboBox selectedVisibility) {
setState(() {
_selectedVisibility = selectedVisibility;
});
},
),
SizedBox(
height: 35,
),
Container(
padding: new EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
borderRadius: BorderRadius.circular((10))),
child: Column(
children: <Widget>[
SizedBox(
height: 10,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Select platform reach:",
style: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
SizedBox(
height: 20,
),
Row(
children: <Widget>[
Expanded(
child: SearchableDropdown(
isExpanded: true,
value: _selectedPlatformReach,
items: _dropdownPlatformReach,
isCaseSensitiveSearch: false,
onChanged:
(PlatformReachComboBox selectedPlatformReach) {
setState(() {
_selectedPlatformReach = selectedPlatformReach;
});
},
),
flex: 2,
),
Expanded(
child: Container(
height: 50.0,
width: 80,
child: Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Colors.blue,
color: Colors.deepPurpleAccent,
elevation: 0.0,
child: GestureDetector(
onTap: () {
setState(() {
mylist.add(_selectedPlatformReach.toString());
});
},
child: Center(
child: Text(
'ADD',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
flex: 0,
),
],
),
SizedBox(
height: 10,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Added:",
style: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
SizedBox(
height: 10,
),
ListView.builder(
padding: EdgeInsets.only(left: 10),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: mylist.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Text(
mylist[Index]
);
},
),
// ListView.builder(
// padding: EdgeInsets.only(left: 10),
// scrollDirection: Axis.vertical,
// shrinkWrap: true,
// itemCount: _platformReach.length,
// itemBuilder: (BuildContext ctxt, int Index) {
// return Text(
// "Galati"
// );
//// return DropdownButton(
//// value: _selectedPlatformReach.toString(),
//// items: _dropdownPlatformReach,
//// onChanged: (value) {
//// _selectedPlatformReach = value;
//// setState(() {});
//// },
//// hint: Text('Select drowdown'),
//// );
//// return new Text(_dropdownPlatformReach[Index].value);
// },
// ),
],
),
),
],
),
),
);
}
}
Mock data class:
import 'package:flutter/material.dart';
class PlatformReachComboBox {
String name;
String hint;
PlatformReachComboBox(this.name, this.hint);
static List<PlatformReachComboBox> getPlatformReach() {
return <PlatformReachComboBox>[
PlatformReachComboBox('Jud Galati', '(RO, [Galati] County)'),
PlatformReachComboBox('Jud Braila', '(RO, [Braila] County)'),
PlatformReachComboBox('Jud Prahova', '(RO, [Ploiesti] County)'),
PlatformReachComboBox('Jud Maramures', '(RO, [Baia Mare] County)'),
];
}
}
List<DropdownMenuItem<PlatformReachComboBox>>
buildDropdownMenuItemsPlatformReach(List platforms) {
List<DropdownMenuItem<PlatformReachComboBox>> items = List();
for (PlatformReachComboBox platform in platforms) {
items.add(
DropdownMenuItem(
value: platform,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
platform.name,
style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
),
Text(
platform.hint,
style:
TextStyle(fontWeight: FontWeight.normal, color: Colors.grey),
textAlign: TextAlign.end,
)
],
),
),
);
}
return items;
}
And this is where I encounter the problem, I don't know what to return in ListView for me pressing the button, and then the item to be added in there:
ListView.builder(
padding: EdgeInsets.only(left: 10),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: _platformReach.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Text(
"Galati"
);
},
),
please try this way ... define a list
List<String> mylist = List();
and use it below
ListView.builder(
padding: EdgeInsets.only(left: 10),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: mylist.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Text(
mylist[Index]
);
},
),
and After button Clicked
setState(() {
mylist.add(_selectedVisibility.name);
});