Multiple select options in flutter - flutter

I want to create a choice chip list of options and select multiple choices in that. I also want to change the colour when the options are selected. the options are dynamic.
I tried using the below function but the onselectionchanged displays null error and the color doesn't change when tapped. Any suggestions please??
_buildChoiceList() {
List<Widget> choices = [];
options.forEach((item) {
choices.add(Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
selected: selectedOptions.contains(item),
backgroundColor: Color(0xffff08222),
onSelected: (selected) {
setState(() {
selectedOptions.contains(item)
? selectedOptions.remove(item)
: selectedOptions.add(item);
widget.onSelectionChanged(selectedOptions);
});
},
),
));
});
return choices;
}

List<String> hobbyList = [
'Shopping',
'Comedy',
'Brunch',
'Music',
'Road Trips',
'Tea',
'Trivia',
'Comedy',
'Clubbing',
'Drinking',
'Wine',
'Hiking',
'Yoga',
'Volleyball',
'Craft Beer',
'Dogs',
'Cats',
'Activism',
'Vlogging',
'Museum',
'Dancing',
'Running',
'Singing',
'Make-Up',
'Concert',
'Cafe',
'Theater',
'Baking',
'Gardening',
'Cooking',
'Video Games',
'Camping'
];
List<String>? selectedHobby = [];
Wrap(children: hobbyList.map(
(hobby) {
bool isSelected = false;
if (selectedHobby!.contains(hobby)) {
isSelected = true;
}
return GestureDetector(
onTap: () {
if (!selectedHobby!.contains(hobby)) {
if (selectedHobby!.length < 5) {
selectedHobby!.add(hobby);
setState(() {});
print(selectedHobby);
}
} else {
selectedHobby!
.removeWhere((element) => element == hobby);
setState(() {});
print(selectedHobby);
}
},
child: Container(
margin: EdgeInsets.symmetric(
horizontal: 5, vertical: 4),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 5, horizontal: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(18),
border: Border.all(
color: isSelected
? kActiveColor
: Colors.grey,
width: 2)),
child: Text(
hobby,
style: TextStyle(
color:
isSelected ? kActiveColor : Colors.grey,
fontSize: 14),
),
)),
);
},
).toList(),
),

use this plugin here
this is the sample code from a project
Expanded(
child: MultiSelectDialogField(
initialValue:
profileImage['height'] ?? [],
searchable: true,
listType: MultiSelectListType.CHIP,
buttonText: heightList.isEmpty
? Text(
"No Hieght",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
)
: Text(
"Height",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
title: Text('Height'),
items: HeightList().height.map((e) => MultiSelectItem(e, e))
.toList(),
decoration: BoxDecoration(color:Colors.white.withOpacity(0.2),
borderRadius:BorderRadius.circular(10),),
buttonIcon: Icon(Icons.arrow_drop_down_outlined,
color:Colors.white.withOpacity(0.7),),
onConfirm: (values) {
heightList = values;
setState(() {
heightLenght = heightList.length;
});
},
chipDisplay: MultiSelectChipDisplay( onTap: (value) {
setState(() {
heightList.remove(value);
});
},
),
)),

Related

Product list is not Showing in this flutter screen

My product has been added to Firebase, but there is a problem with the dashboard's list not appearing. No errors are displayed on the console or the screen.I'm not sure where the problem is appearing in the code or firebase. I'm basically developing an e-commerce app that users should use to sell their goods.
class _SellerDashBoardState extends State<SellerDashBoard> {
MaterialColor active = Colors.red;
MaterialColor notActive = Colors.grey;
List<SellerProductItem> products = [
const SellerProductItem(),
];
#override
Widget build(BuildContext context) {
print(parentIdGlobal);
print(FirebaseAuth.instance.currentUser!.uid);
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Text(
'Seller Dashboard',
style: TextStyle(
fontSize: ResponsiveWidget.isSmallScreen(context) ? 17.0 : 25.0),
),
actions: [
IconButton(
icon: const Icon(Icons.add_circle),
iconSize: 27.0,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => AddProductForm(),
),
);
},
),
IconButton(
icon: WebsafeSvg.asset(
'assets/images/sold-out.svg',
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => SoldItemScreens(),
),
);
},
),
],
),
body: Column(
children: <Widget>[
const SizedBox(
height: 10.0,
),
Container(
color: const Color(0xffF7F7F7),
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("items")
.where('seller', isEqualTo: parentIdGlobal)
.where('isSold', isEqualTo: true)
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final List<QueryDocumentSnapshot<Map<String, dynamic>>>
docSnapList = snapshot.data?.docs ?? [];
if (docSnapList.isEmpty) {
return Center(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: WebsafeSvg.asset(
'assets/images/empty_dashboard.svg',
fit: BoxFit.cover,
height: MediaQuery.of(context).size.height / 5,
),
),
);
}
final List<Map<String, dynamic>> docList = docSnapList
.map((QueryDocumentSnapshot<Map<String, dynamic>>
queryDocumentSnapshot) =>
queryDocumentSnapshot.data())
.toList();
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: docList.length,
itemBuilder: (context, index) {
bool isSold = docList[index]['isSold'] ?? true;
bool isLiked = docList[index]['isLiked'] ?? true;
String itemId = docList[index]['itemId'] ?? '';
String seller = docList[index]['seller'] ?? '';
String sellerName = docList[index]['sellerName'] ?? '';
String title = docList[index]['title'] ?? '';
String desc = docList[index]['desc'] ?? '';
String price = docList[index]['price'] ?? '';
String condition = docList[index]['condition'] ?? '';
String category = docList[index]['category'] ?? '';
String location = docList[index]['location'] ?? '';
String itemImage =
docList[index]['imageDownloadUrl'] ?? '';
return SellerProductItem(
itemId: itemId,
seller: seller,
sellerName: sellerName,
title: title,
desc: desc,
price: price,
itemImage: itemImage,
isLiked: isLiked,
isSold: isSold,
category: category,
condition: condition,
location: location,
);
},
);
},
add product screen
class _AddProductFormState extends State<AddProductForm> {
TextEditingController controllerTitle = TextEditingController();
TextEditingController controllerPrice = TextEditingController();
TextEditingController controllerDescription = TextEditingController();
TextEditingController controllerlocation = TextEditingController();
GlobalKey<FormState> _formKey = GlobalKey();
String selectedCondition = 'New';
String selectedCategory = 'Cosmetic Aids';
bool isReadOnly = true;
File? pickedImage;
bool imgStatus = false;
List<String> conditionList = [
'New',
'Like New',
'Good',
'Fair',
'Poor',
];
List<String> categoryList = [
'Cosmetic Aids',
'Mobility Products',
'Bath Safety Products',
'Others',
];
bool _switchValue = false;
Future<void> addGroceryItemToToDb() async {
final itemId = Uuid().v4();
String? url;
if (pickedImage != null) {
print(parentIdGlobal);
print(FirebaseAuth.instance.currentUser!.uid);
Reference storage = FirebaseStorage.instance
.ref()
.child('users/${FirebaseAuth.instance.currentUser!.uid}/$itemId/item_pic');
UploadTask uploadTask = storage.putFile(pickedImage!);
final temp = await (await uploadTask).ref.getDownloadURL();
url = temp.toString();
}
FirebaseFirestore.instance.collection('items').doc(itemId).set(
{
'itemId': itemId,
'timestamp': DateTime.now(),
'seller': parentIdGlobal,
'sellerName': userNameGlobal,
'title': controllerTitle.text,
'price': controllerPrice.text,
'desc': controllerDescription.text,
'condition': selectedCondition,
'category': selectedCategory,
'location': controllerlocation.text,
'isSold': false,
'imageDownloadUrl': url,
},
);
} // adds grocery item to db
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 1.0,
centerTitle: true,
title: Text(
'Add a Product',
),
),
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
_selectImageButton(context),
_writeTitle(),
_writePrice(),
_giveitfree(),
_conditionDropDown(),
_writeDescription(),
_categoryDropDown(),
_writeLocation(),
Align(
alignment: Alignment.bottomCenter,
child: _addProductButton(context)),
],
),
),
),
);
}
_selectImageButton(BuildContext context) {
return GestureDetector(
onTap: () async {
await Permission.photos.request();
var status = await Permission.photos.status;
if (status.isGranted) {
try {
XFile? _pickedImage = await ImagePicker().pickImage(
source: ImageSource.gallery,
maxWidth: 100,
maxHeight: 100,
imageQuality: 100
) ;
if(_pickedImage !=null){
pickedImage = File(_pickedImage.path);
setState(() {
imgStatus = true;
});
} }catch (e) {
print(e.toString());
}
} else if (status.isDenied || status.isRestricted) {
print('Permission Denied');
showDialog(
context: context,
builder: (context) {
if (Platform.isAndroid)
return AlertDialog(
title: Text('Permission Not Granted'),
content:
Text('The permission for photo library is not granted'),
actions: [
ElevatedButton(
onPressed: () => openAppSettings(),
child: Text('Ok'),
),
],
);
return CupertinoAlertDialog(
title: Text('Permission Not Granted'),
content:
Text('The permission for photo library is not granted'),
actions: [
ElevatedButton(
onPressed: () => openAppSettings(),
child: Text('Ok'),
),
],
);
});
} else if (status.isDenied) {
print('Permission Undetermined');
}
},
child: Padding(
padding: EdgeInsets.only(
top: 10.0,
bottom: 10.0,
),
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.transparent,
border: Border.all(
style: BorderStyle.solid,
color: Colors.red,
),
),
child: pickedImage == null
? Icon(
Icons.add,
color: Colors.red,
)
: Image.file(
pickedImage!,
fit: BoxFit.contain,
),
),
),
);
}
ButtonTheme _addProductButton(BuildContext context) {
return ButtonTheme(
minWidth: MediaQuery.of(context).size.width / 1.1,
child: ElevatedButton(
onPressed: imgStatus
? () async {
if (_formKey.currentState?.validate() == true) {
try {
Navigator.pop(context);
await addGroceryItemToToDb();
} catch (error) {
print(error);
}
}
}
: null,
child: Text(
'Add Product',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
);
}
Padding _writeDescription() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
controller: controllerDescription,
maxLines: 5,
inputFormatters: [
new LengthLimitingTextInputFormatter(
1450,
),
],
maxLength: 1450,
decoration: InputDecoration(
alignLabelWithHint: true,
isDense: true,
labelText: 'Description',
helperText: "Describe what you're selling in detail",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
);
}
Padding _conditionDropDown() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: conditionDropdownbuttonStyle(),
);
}
Widget conditionDropdownbuttonStyle() {
List<Text> pickerItems = [];
for (String condition in conditionList) {
pickerItems.add(Text(condition));
}
if (Platform.isIOS) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Condition',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 10,
),
CupertinoPicker(
backgroundColor: Colors.white70,
useMagnifier: true,
itemExtent: 32.0,
diameterRatio: 2,
scrollController: FixedExtentScrollController(initialItem: 0),
magnification: 1.2,
onSelectedItemChanged: (selectedIndex) {
print(selectedIndex);
selectedCondition = conditionList[selectedIndex];
print(selectedCondition);
},
children: pickerItems,
),
],
);
}
List<DropdownMenuItem<String>> dropDownItem = [];
for (String condition in conditionList) {
print(condition);
var newItem = DropdownMenuItem<String>(
child: Text(condition),
value: condition,
);
dropDownItem.add(newItem);
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'Condition',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
width: 10.0,
),
Expanded(
child: DropdownButton<String>(
items: dropDownItem,
isExpanded: true,
value: selectedCondition,
hint: Text(
'Condition',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
onChanged: (value) {
setState(() {
if (value != null) {
selectedCondition = value;
}
});
},
),
)
],
);
}
Padding _categoryDropDown() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: categoryDropdownbuttonStyle(),
);
}
Widget categoryDropdownbuttonStyle() {
List<Text> pickerItems1 = [];
for (String category in categoryList) {
pickerItems1.add(Text(category));
}
if (Platform.isIOS) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Category',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 10,
),
CupertinoPicker(
backgroundColor: Colors.white70,
useMagnifier: true,
itemExtent: 32.0,
diameterRatio: 2,
scrollController: FixedExtentScrollController(initialItem: 0),
magnification: 1,
onSelectedItemChanged: (selectedIndex) {
print(selectedIndex);
selectedCategory = categoryList[selectedIndex];
print(selectedCategory);
},
children: pickerItems1,
),
],
);
}
List<DropdownMenuItem<String>> dropDownItem = [];
for (String category in categoryList) {
print(category);
var newItem = DropdownMenuItem<String>(
child: Text(category),
value: category,
);
dropDownItem.add(newItem);
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'Category',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
width: 10.0,
),
Expanded(
child: DropdownButton<String>(
items: dropDownItem,
isExpanded: true,
value: selectedCategory,
hint: Text(
'Category',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
onChanged: (value) {
setState(() {
if (value != null) {
selectedCategory = value;}
});
},
),
)
],
);
}
Padding _giveitfree() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Give it away for free',
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.w600,
),
),
switchButtonType(),
],
),
);
}
Widget _writePrice() {
if (_switchValue) {
return Container(
width: 0.0,
height: 0.0,
);
}
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
controller: controllerPrice,
maxLines: 1,
inputFormatters: [
new LengthLimitingTextInputFormatter(
5,
),
FilteringTextInputFormatter.digitsOnly,
],
decoration: InputDecoration(
prefixIcon: Icon(Icons.attach_money),
isDense: true,
labelText: 'Price',
helperText: 'Set your Price',
hintText: 'Default Price: 0 \u0024',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
);
}
Padding _writeTitle() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
validator: (value) {
if (value != null) {
if (value.length < 5) {
return 'The title should be at least 5 characters';
}
return null;
};
return null;},
controller: controllerTitle,
maxLines: 1,
inputFormatters: [
new LengthLimitingTextInputFormatter(
50,
),
],
decoration: InputDecoration(
prefixIcon: Icon(
Icons.title,
),
isDense: true,
labelText: 'Title*',
labelStyle: TextStyle(
color: Colors.red,
),
helperText: 'Describe your Product in few words',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
8.0,
),
),
),
),
);
}
Padding _writeLocation() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
controller: controllerlocation,
maxLines: 1,
inputFormatters: [
new LengthLimitingTextInputFormatter(
50,
),
],
decoration: InputDecoration(
prefixIcon: Icon(
Icons.location_on,
),
suffixIcon: IconButton(
icon: Icon(Icons.near_me),
onPressed: getLocation,
),
isDense: true,
labelText: 'Location',
helperText: 'Eg: Austin,Texas',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
);
}
getLocation() async {
try {
await Permission.location.request();
var status = await Permission.location.status;
if (status.isGranted) {
print('Permission Granted');
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
print(position);
double latitude = position.latitude;
double longitude = position.longitude;
print('latitude: $latitude \n longitude: $longitude');
List<Placemark> placemark = await placemarkFromCoordinates(
latitude,
longitude,
);
setState(() {
print(placemark[0]);
controllerlocation.text =
('${placemark[0].locality},${placemark[0].administrativeArea},${placemark[0].country}')
.toString();
});
} else if (status.isDenied || status.isRestricted) {
print('Permission Denied');
Widget switchButtonType() {
if (Platform.isAndroid) {
return Switch(
value: _switchValue,
onChanged: (value) {
setState(
() {
_switchValue = value;
isReadOnly = _switchValue;
controllerPrice.text = '0';
print(_switchValue);
},
);
},
);
}
return CupertinoSwitch(
value: _switchValue,
onChanged: (value) {
setState(
() {
_switchValue = value;
isReadOnly = _switchValue;
controllerPrice.text = '0';
print(_switchValue);
},
You are filtering items that have isSold set to true but when adding you are adding with isSold set to false. Maybe you should change your filter to .where('isSold', isEqualTo: false)?

flutter bloc doesn't update the ui?

when i navigate from NewSales screen to CreateItem screen and add item and press the add button
the item is added to sqflite database then it navigates back to new sales but the state is not updated , it's updated only if i restarted the app
the NewSales screen
class _NewSalesState extends State<NewSales> {
final controller = TextEditingController();
showAlertDialog(BuildContext context,String name) {
// Create button
// Create AlertDialog
AlertDialog alert = AlertDialog(
title: const Text("Alert"),
content: const Text("you want to delete this item?"),
actions: [
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green)),
child: const Text("CANCEL", style: TextStyle(color: Colors.white)),
onPressed: () {
Navigator.of(context).pop();
},
),
BlocBuilder<SalesCubit, SalesState>(
builder: (context, state) {
final bloc=BlocProvider.of<SalesCubit>(context);
return TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red)),
child: const Text(
"DELETE",
style: TextStyle(color: Colors.white),
),
onPressed: () {
Navigator.of(context).pop();
bloc.deleteItem(name).then((value) {
bloc.getAllItems();
});
},
);
},
)
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
// #override
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery
.of(context)
.size;
return BlocConsumer<SalesCubit, SalesState>(
listener: (context, state) {},
builder: (context, state) {
final bloc = BlocProvider.of<SalesCubit>(context);
if (state is SalesInitial) {
bloc.getAllItems();
}
return Scaffold(
drawer: const navDrawer(),
appBar: AppBar(
title: const Text("Ticket"),
actions: [
IconButton(
onPressed: () async {
String barcodeScanRes;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
barcodeScanRes = await FlutterBarcodeScanner.scanBarcode(
'#ff6666', 'Cancel', true, ScanMode.BARCODE);
print('barcodeScanRes $barcodeScanRes');
print(bloc.bsResult);
} on PlatformException {
barcodeScanRes = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
bloc.toggleSearch();
controller.text = barcodeScanRes;
bloc.filterItems(barcodeScanRes);
},
icon: const Icon(Icons.scanner),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
onPressed: () {
Navigator.of(context).pushNamed(Routes.addCustomerRoute);
},
icon: Icon(Icons.person_add)),
),
],
),
body: Column(
children: [
// the first button
Container(
width: double.infinity,
height: deviceSize.height * .1,
color: Colors.grey,
child: GestureDetector(
onTap: ()=>displayMessage("an item was charged successfully", context),
child: Padding(
padding: const EdgeInsets.all(10),
child: Container(
color: Colors.green,
child: const Center(
child: Text("charge",style: TextStyle(color: Colors.white),),
),
),
),
),
),
// the second container
SizedBox(
width: deviceSize.width,
height: deviceSize.height * .1,
child: Row(
children: [
DecoratedBox(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: SizedBox(
width: deviceSize.width * .8,
child: bloc.isSearch
? TextFormField(
autofocus: true,
controller: controller,
decoration:
const InputDecoration(hintText: "Search"),
onChanged: (value) {
bloc.filterItems(controller.text);
},
)
: DropdownButtonFormField<String>(
// underline: Container(),
// value: "Discounts",
hint: const Padding(
padding: EdgeInsets.only(left: 10),
child: Text('Please choose type'),
),
items: <String>['Discounts', 'All Items']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
),
),
DecoratedBox(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: SizedBox(
width: deviceSize.width * .2,
child: IconButton(
onPressed: () {
bloc.toggleSearch();
if (!bloc.isSearch) {
bloc.filterItems('');
}
},
icon: Icon(
!bloc.isSearch ? Icons.search : Icons.close)),
),
)
],
),
),
// the third container
if (state is IsLoading || state is SalesInitial)
const Center(
child: CircularProgressIndicator(
color: Colors.green,
backgroundColor: Colors.green,
),
),
if (state is Loaded || state is IsSearch || state is SearchDone)
bloc.items.isEmpty
? const Center(
child: Text("no items added yet"),
)
: Expanded(
child: bloc.filteredItems.isEmpty
? const Center(
child: Text(
"no items found with this name",
style: TextStyle(color: Colors.green),
),
)
: ListView.builder(
itemCount: bloc.filteredItems.length,
itemBuilder: (context, i) {
final item = bloc.filteredItems[i];
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green,
radius: 20,
child: Text(item.price),
),
title: Text(item.name),
subtitle: Text(item.barcode),
trailing: Column(
children: [
IconButton(
onPressed: () {
showAlertDialog(context,item.name);
// bloc.deleteItem(item.name).then((value) {
// bloc.getAllItems();
// });
},
icon: const Icon(
Icons.delete,
color: Colors.red,
))
],
)),
);
}))
],
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: ()async {
Navigator.of(context).pushNamed(Routes.createItemRoute);
},
),
);
},
);
}
}
the CreateItem screen
class _CreateItemState extends State<CreateItem> {
final nameController = TextEditingController();
final priceController = TextEditingController();
final costController = TextEditingController();
final skuController = TextEditingController();
final barcodeController = TextEditingController();
final inStockController = TextEditingController();
bool each = true; // bool variable for check box
bool isColor = true;
bool switchValue = false;
File? file;
String base64File = "";
String path = "";
final _formKey = GlobalKey<FormState>();
#override
void dispose() {
nameController.dispose();
priceController.dispose();
costController.dispose();
skuController.dispose();
barcodeController.dispose();
inStockController.dispose();
super.dispose();
}
Future pickImage(ImageSource source) async {
File? image1;
XFile imageFile;
final imagePicker = ImagePicker();
final image = await imagePicker.pickImage(source: source);
imageFile = image!;
image1 = File(imageFile.path);
List<int> fileUnit8 = image1.readAsBytesSync();
setState(() {
base64File = base64.encode(fileUnit8);
});
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return BlocProvider(
create: (BuildContext context) => CreateItemCubit(),
child: Builder(builder: (context){
final bloc=BlocProvider.of<CreateItemCubit>(context);
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil(Routes.newSalesRoute, (route) => false),
icon: const Icon(Icons.arrow_back)),
title: const Text("Create Item"),
actions: [TextButton(onPressed: () {}, child: const Text("SAVE"))],
),
body: Padding(
padding: const EdgeInsets.all(10),
child: Form(
key: _formKey,
child: ListView(
children: [
TextFormField(
controller: nameController,
cursorColor: ColorManager.black,
decoration: const InputDecoration(hintText: "Name"),
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return "name can't be less than 5 chars";
}
return null;
},
),
gapH24,
Text(
"Category",
style: TextStyle(color: ColorManager.grey),
),
SizedBox(
width: deviceSize.width,
child: DropdownButtonFormField<String>(
// value: "Categories",
hint: const Padding(
padding: EdgeInsets.only(left: 10),
child: Text('No Category'),
),
items: <String>['No Category', 'Create Category']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
),
gapH24,
const Text(
"Sold by",
style: TextStyle(color: Colors.black),
),
gapH24,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: each,
onChanged: (inputValue) {
setState(() {
each = !each;
});
},
),
gapW4,
const Text(
"Each",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
gapH24,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: !each,
onChanged: (inputValue) {
setState(() {
each = !each;
});
},
),
gapW4,
const Text(
"Weight",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
TextFormField(
controller: priceController,
decoration: InputDecoration(
hintText: "Price",
hintStyle: TextStyle(color: ColorManager.grey)),
validator: (value) {
if (value!.isEmpty) {
return "price can,t be empty";
}
return null;
},
),
gapH4,
Text(
"leave the field blank to indicate price upon sale",
style: TextStyle(color: ColorManager.grey),
),
gapH20,
Text(
"Cost",
style: TextStyle(color: ColorManager.grey),
),
TextFormField(
controller: costController,
decoration: InputDecoration(
hintText: "cost",
hintStyle: TextStyle(color: ColorManager.black)),
validator: (value) {
if (value!.isEmpty) {
return "cost can't be empty";
}
return null;
},
),
gapH20,
Text(
"SKU",
style: TextStyle(color: ColorManager.grey),
),
TextFormField(
controller: skuController,
decoration: InputDecoration(
hintText: "Sku",
hintStyle: TextStyle(color: ColorManager.black)),
validator: (value) {
if (value!.isEmpty) {
return "Sku can't be empty";
}
return null;
},
),
gapH30,
TextFormField(
controller: barcodeController,
decoration: InputDecoration(
hintText: "Barcode",
hintStyle: TextStyle(color: ColorManager.grey)),
validator: (value) {
if (value!.isEmpty) {
return "Barcode can't be empty";
}
return null;
},
),
gapH30,
// Divider(thickness: 1,color: ColorManager.black,),
Text(
"Inventory",
style: TextStyle(
color: ColorManager.green,
fontSize: 15,
fontWeight: FontWeight.bold),
),
// ListTile(
// title: Text("TrackStock",style: TextStyle(color: ColorManager.green,fontSize: 15,fontWeight: FontWeight.bold)),
// trailing: Switch(value: switchValue, onChanged: (bool value) {
// setState(() {
// switchValue=!switchValue;
// });
// },),
// ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("TrackStock",
style: TextStyle(
color: ColorManager.grey,
fontSize: 15,
fontWeight: FontWeight.bold)),
Switch(
value: switchValue,
onChanged: (bool value) {
setState(() {
switchValue = !switchValue;
});
},
),
],
),
gapH10,
if (switchValue)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"in stock",
style:
TextStyle(color: ColorManager.grey, fontSize: 15),
),
TextFormField(
keyboardType: TextInputType.number,
controller: inStockController,
decoration: const InputDecoration(hintText: "0"),
validator: (value) {
if (value!.isEmpty) {
return "value can't be empty";
}
return null;
},
)
],
),
gapH20,
Text(
"Representation in POS",
style: TextStyle(
color: ColorManager.green,
fontSize: 15,
fontWeight: FontWeight.bold),
),
gapH15,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: isColor,
onChanged: (inputValue) {
setState(() {
if (!isColor) {
isColor = !isColor;
}
});
},
),
gapW4,
const Text(
"Color and Shape",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
gapH10,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: !isColor,
onChanged: (inputValue) {
setState(() {
if (isColor) {
isColor = !isColor;
}
});
},
),
gapW4,
const Text(
"Image",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
isColor
? GridView.builder(
physics:
const NeverScrollableScrollPhysics(), // to disable GridView's scrolling
shrinkWrap: true, // You won't see infinite size error
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: containers().length,
itemBuilder: (BuildContext context, int index) {
return containers()[index];
},
)
: Padding(
padding: const EdgeInsets.all(10),
child: Row(
children: [
Expanded(
flex: 1,
child: base64File == ""
? const Icon(Icons.person)
: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(5)),
child: Image.memory(
base64.decode(base64File)))),
gapW4,
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
onPressed: () =>
pickImage(ImageSource.camera),
child: Row(
children: [
Icon(
Icons.camera_alt,
color: ColorManager.black,
),
gapW8,
Text(
"Take a photo",
style: TextStyle(
color: ColorManager.black,
),
)
],
),
),
const Divider(
thickness: 1,
color: Colors.grey,
),
TextButton(
onPressed: () =>
pickImage(ImageSource.gallery),
child: Row(
children: [
Icon(Icons.camera_alt,
color: ColorManager.black),
gapW8,
Text(
"Choose from gallery",
style: TextStyle(
color: ColorManager.black,
),
)
],
),
)
],
),
)
],
),
)
],
),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.save,color: Colors.white,),
onPressed: () async {
bool isValid = _formKey.currentState!.validate();
if (isValid) {
FocusScope.of(context).unfocus();
ItemModel? item=await bloc.checkItem(nameController.text);
if(item!=null){
displayMessage("this item was inserted before", context);
}else{
int? res=await bloc.saveItem(ItemModel(
nameController.text,
priceController.text,
costController.text,
skuController.text,
barcodeController.text));
if(res!=null){
displayMessage("an item was inserted successfully", context);
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context)=>const NewSales()), (route) => false);
}
}
}
},
),
);
}
),
);
}
}
this is the SaleCubit
class SalesCubit extends Cubit<SalesState> {
SalesCubit() : super(SalesInitial());
bool isSearch=false;
ItemDBHelper db=ItemDBHelper();
List<ItemModel> items=[];
List<ItemModel> filteredItems=[];
String bsResult='Unknown'; //barcode search result
void toggleSearch(){
isSearch=!isSearch;
emit(IsSearch());
}
void setBarcodeResult(String value){
bsResult=value;
emit(SearchDone());
}
void filterItems(String query){
// emit(Searching());
query.isEmpty?
filteredItems=items:
filteredItems=items.where((item) => item.name.toLowerCase().contains(query.toLowerCase())).toList();
emit(SearchDone());
}
Future<List<ItemModel>?> getAllItems()async{
try{
emit(IsLoading());
items=await db.getAllItems();
filteredItems=items;
print(items);
return items;
}finally{
emit(Loaded());
}
}
Future<void> deleteItem(String name)async{
await db.deleteItem(name);
emit(SearchDone());
}
}
this is the SalesState
part of 'sales_cubit.dart';
#immutable
abstract class SalesState {}
class SalesInitial extends SalesState {}
class IsSearch extends SalesState {}
class IsLoading extends SalesState {}
class Loaded extends SalesState {}
class Searching extends SalesState {}
class SearchDone extends SalesState {}

Showing and Hiding Widget give SetState() or markNeedsBuild() called during build error

I have some trouble with hiding and showing widget. So, I have an OTP verification page to verify the code that sent to the user. In that page, when a user click a text button to resend otp code, the button will be hidden and replaced by countdown timer.
showCountdown ?
Center(
child: CountdownTimer(
textStyle: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
endTime: endTime,
onEnd: () {
setState(() {
showCountdown = false;
});
},
),
)
:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Tidak Menerima Kode Verifikasi? ",
style: TextStyle(color: Colors.black54, fontSize: 15),
),
TextButton(
onPressed: () {
// userService.resendOtp(widget.phoneNumber.toString()).then((value) => snackBar(value));
setState(() {
showCountdown = true;
clicked++;
});
},
child: Text(
"Kirim Ulang",
style: TextStyle(
color: Constant.color,
fontWeight: FontWeight.bold,
fontSize: 16),
)
)
],
),
First click is okay, but when clicked for second time, it give this error
The following assertion was thrown building NotificationListener<KeepAliveNotification>:
setState() or markNeedsBuild() called during build.
It shows that the error maybe on this part
onEnd: () {
setState(() {
showCountdown = false;
});
},
Full Code for build method
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/Background.png"),
alignment: Alignment.center,
fit: BoxFit.cover
)
),
child: ListView(
children: <Widget>[
// SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'Verifikasi Nomor HP',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
textAlign: TextAlign.center,
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 30.0, vertical: 8),
child: RichText(
text: TextSpan(
text: "Kode Dikirim Ke Nomor ",
children: [
TextSpan(
text: "${widget.phoneNumber}",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15)),
],
style: TextStyle(color: Colors.black54, fontSize: 15)),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 20,
),
Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
appContext: context,
pastedTextStyle: TextStyle(
color: Constant.color,
fontWeight: FontWeight.bold,
),
length: 6,
obscureText: false,
obscuringCharacter: '*',
blinkWhenObscuring: true,
animationType: AnimationType.fade,
validator: (v) {
if (v!.length < 6) {
return "Harap Masukan Kode OTP Yang Benar";
} else {
return null;
}
},
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(5),
fieldHeight: 50,
fieldWidth: 40,
activeFillColor: Colors.white,
),
cursorColor: Colors.black,
animationDuration: Duration(milliseconds: 300),
errorAnimationController: errorController,
controller: textEditingController,
keyboardType: TextInputType.number,
boxShadows: [
BoxShadow(
offset: Offset(0, 1),
color: Colors.black12,
blurRadius: 10,
)
],
onCompleted: (v) {
print("Completed");
},
onChanged: (value) {
print(value);
setState(() {
currentText = value;
});
},
enablePinAutofill: true,
beforeTextPaste: (text) {
print("Allowing to paste $text");
//if you return true then it will show the paste confirmation dialog. Otherwise if false, then nothing will happen.
//but you can show anything you want here, like your pop up saying wrong paste format or etc
return true;
},
)),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text(
hasError ? "*Please fill up all the cells properly" : "",
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w400),
),
),
SizedBox(
height: 20,
),
showCountdown ?
Center(
child: CountdownTimer(
textStyle: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
endTime: endTime,
onEnd: () {
setState(() {
showCountdown = false;
});
},
),
)
:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Tidak Menerima Kode Verifikasi? ",
style: TextStyle(color: Colors.black54, fontSize: 15),
),
TextButton(
onPressed: () {
// userService.resendOtp(widget.phoneNumber.toString()).then((value) => snackBar(value));
setState(() {
showCountdown = true;
clicked++;
});
},
child: Text(
"Kirim Ulang",
style: TextStyle(
color: Constant.color,
fontWeight: FontWeight.bold,
fontSize: 16),
)
)
],
),
SizedBox(
height: 14,
),
Container(
margin:
const EdgeInsets.symmetric(vertical: 16.0, horizontal: 30),
child: ButtonTheme(
height: 50,
child: TextButton(
onPressed: () {
formKey.currentState!.validate();
// conditions for validating
if (currentText.length != 6 ) {
errorController!.add(ErrorAnimationType.shake); // Triggering error shake animation
setState(() => hasError = true);
} else {
userService.verifyOtp(widget.phoneNumber.toString(), currentText).then((value) {
if(value == "Kode OTP Salah") {
errorController!.add(ErrorAnimationType.shake);
textEditingController.clear();
setState(() {
hasError = true;
snackBar(value);
});
} else {
setState(() {
hasError = false;
snackBar(value);
});
Future.delayed(Duration(seconds: 3)).then( (value) =>
Navigator.of(context).pushReplacement(
new MaterialPageRoute(builder: (context) => new SignIn()))
);
}
});
}
},
child: Center(
child: Text(
"Verifikasi Kode OTP".toUpperCase(),
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
decoration: BoxDecoration(
color: Constant.color,
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(
color: Colors.green.shade200,
offset: Offset(1, -2),
blurRadius: 5),
BoxShadow(
color: Colors.green.shade200,
offset: Offset(-1, 2),
blurRadius: 5)
]),
),
],
),
),
),
);
}
I dont have any idea why this is happened, so I need help for this. Thank you.
This error means that the Flutter Engine is instructed to build something (using setState for example), but at the very moment another build is already in progress.
So you have to find out which of your setState statements causes this error, it could be the one at onEnd, you can debug your code to be sure. Than you can add a callback, which will be executed after the current build is completed:
WidgetsBinding.instance.addPostFrameCallback((_){
setState(() {
});
});
If you haven't already done, include this in your main function:
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp()); // or whatever you app class name is
}

Radio Button while using in List builder

I faced problem of separating value of radio button . As I use multiple radio buttons in multiple list that i get from APi. so every time , when i select one radio button ,it selects all radio button of this type in all list. for example: radio 1 = check , radio 2 = unchecked in list 1 and list 2. i select radio 1 of list 1 but both radio 1 of list 1 and list 2 selected.
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import 'package:http/http.dart' as http;
import 'package:progress_dialog/progress_dialog.dart';
import 'package:project40/Constants/APIConstants.dart';
import 'package:project40/Constants/styleConstant.dart';
import 'package:project40/screens/home_screen.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:project40/api/add_filter_api.dart';
import 'package:project40/provider/add_post_provider.dart';
import 'package:provider/provider.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:project40/Constants/globals.dart' as globals;
class FilterScreen extends StatefulWidget {
#override
_FilterScreenState createState() => _FilterScreenState();
}
class _FilterScreenState extends State<FilterScreen> {
var jsonData;
//String filterVariable;
int school_everyone = 0;
bool all_Feed = true;
AddPostProvider _addPostProvider;
int length = 0;
int v = 0;
Future mySchools() async {
print("test");
//loading dialog appears
ProgressDialog pr;
pr = new ProgressDialog(context, showLogs: true);
pr.style(
progressWidget: Container(
width: 50,
child: Lottie.asset("assets/json/360-loader.json"),
),
message: 'Please wait...');
pr.show();
//api link
String url = baseURL + mySchoolURL;
//getting user token
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString("token");
print(token);
//create post request
http.Response response = await http.get(url, headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer $token',
}).catchError((e) => print(e));
print('successs');
pr.hide();
if (response == null) {
//appear dialog if any error will be occured
Alert(
context: context,
title: "",
type: AlertType.none,
desc: "Something went wrong. Please try again",
buttons: [
DialogButton(
child: Text(
"OK",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () {
Navigator.pop(context);
pr.hide();
},
width: 120,
)
],
).show();
} else {
jsonData = jsonDecode(response.body);
if (jsonData["status_code"] == 200) {
print(jsonData);
// if (all_Feed == true) {
// filterVariable = "All School";
// }
// print(filterVariable);
pr.hide();
//store the no of institutions
length = jsonData["data"].length;
setState(() {});
} else {
pr.hide();
//if error occured
Alert(
context: context,
type: AlertType.none,
title: "",
desc: jsonData["message"],
buttons: [
DialogButton(
child: Text(
"OK",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () {
Navigator.pop(context);
pr.hide();
},
width: 120,
)
],
).show();
}
}
return jsonDecode(response.body);
}
#override
void initState() {
super.initState();
mySchools();
if (all_Feed == true) {
school_everyone = 0;
}
if (school_everyone == 1) {
all_Feed = false;
}
// if (all_Feed == false) {
// setState(() {
// selectedRadio(2);
// });
// }
// if (school_everyone == 1) {
// setState(() {
// all_school = 0;
// });
// }
}
void selectedRadio(int value) {
setState(() {
all_Feed = false;
school_everyone = value;
});
}
#override
Widget build(BuildContext context) {
_addPostProvider = Provider.of<AddPostProvider>(context, listen: false);
return Material(
child: Scaffold(
backgroundColor: Colors.grey,
body: Stack(
//alignment: AlignmentDirectional.topCenter,
children: [
Container(
padding: EdgeInsets.only(top: 5),
decoration: BoxDecoration(
//borderRadius: BorderRadius.circular(50),
),
child: Padding(
padding: const EdgeInsets.only(top: 45),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
color: Colors.white,
),
child: Column(
children: [
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.arrow_back),
),
onTap: () {
Navigator.pop(context);
},
),
Text(
"Feed Filter",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Roboto",
fontSize: 20,
fontWeight: FontWeight.bold),
),
Container(width: 32.0),
],
),
Divider(
thickness: 1,
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: GestureDetector(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomeScreen()));
},
child: allFilter(
Checkbox(
value: all_Feed,
activeColor: Colors.black,
onChanged: (value) {
setState(() {
all_Feed = value;
if (all_Feed == true) {
school_everyone = 0;
} else {
school_everyone = 1;
}
});
}),
Text(
"All school",
style: DayMoodRobotoStyle.heading5c,
)),
),
),
Expanded(
child: ListView.builder(
itemCount: length,
itemBuilder: (context, index) {
return SingleChildScrollView(
child: Container(
child: schoolUseage(
jsonData["data"][index]["institution"]
["name"] ??
"",
jsonData["data"][index]["institution"]
["none"] ??
"",
jsonData["data"][index]["institution"]
["_id"] ??
"",
jsonData["data"][index]["year"]["year"] ??
"",
jsonData["data"][index]["year"]["_id"] ??
"",
jsonData["data"][index]["program"] == null
? ""
: jsonData["data"][index]["program"]
["title"],
jsonData["data"][index]["program"] == null
? ""
: jsonData["data"][index]["program"]
["_id"],
index),
),
);
}),
),
InkWell(
onTap: () async {
// var response =
// await GetFilterPostAPI().getFilterPostApi(
// ids: globals.filterVariable,
// );
// print('add filter response$response');
// if (response['status_code'] == 200) {
// _addPostProvider.addPostProgress = false;
Navigator.pop(context);
Fluttertoast.showToast(
msg: 'Filter Add Successfully..');
// _addPostProvider.addPostProgress = false;
// } else {
// Fluttertoast.showToast(msg: response['message']);
// _addPostProvider.addPostProgress = false;
// }
},
hoverColor: Colors.transparent,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: 55.0,
margin: EdgeInsets.symmetric(
horizontal: 20,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(28.0),
color: const Color(0xff0188ba),
boxShadow: [
BoxShadow(
color: const Color(0x333F51B5).withOpacity(0.2),
offset: Offset(0, 20),
blurRadius: 20,
),
],
),
child: Text(
'Filter',
style: DayMoodRobotoStyle.heading5,
textAlign: TextAlign.center,
),
),
),
SizedBox(
height: 20,
),
],
),
),
),
),
],
),
),
);
}
Widget schoolInfo(Radio icon, Expanded schoolname) {
return Row(
children: [icon, schoolname],
);
}
Widget allFilter(Checkbox icon, Text schoolname) {
return Row(
children: [icon, schoolname],
);
}
Widget schoolUseage(
String schooolName,
String school_id,
String _id,
String classOf,
String classof_id,
String department,
String department_id,
int index) {
String s1 = index.toString();
String s2 = school_everyone.toString();
String s = s1 + s2;
v = int.parse(s);
return Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(
schooolName,
style: TextStyle(
color: all_Feed == true ? Colors.grey : Colors.blue,
fontSize: 17,
fontFamily: "Ubuntu",
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
),
),
SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
ignoring: true,
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: null,
groupValue: index,
onChanged: (value) {
selectedRadio(value);
globals.filterVariable =
"all_" + school_id + "program_" + _id;
}),
Expanded(
child: Text(
"Everyone",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 1,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s1 + s2;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "all_$_id";
});
}),
Expanded(
child: Text(
"Everyone",
style: DayMoodRobotoStyle.heading5c,
),
)),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: 2,
groupValue: school_everyone,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
"None",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 2,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s1 + s2;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "none_" + _id;
});
}),
Expanded(
child: Text(
"None",
style: DayMoodRobotoStyle.heading5c,
),
)),
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: 2,
groupValue: school_everyone,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
department + " Only",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
maxLines: 2,
),
),
),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 3,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s2 + s1;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "program_" + _id;
});
}),
Expanded(
child: Text(
department + " Only",
style: DayMoodRobotoStyle.heading5c,
maxLines: 2,
),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: classof_id,
groupValue: school_id,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
"Class of " + classOf + " Only",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 4,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s2 + s1;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "year_" + _id;
//classOf + "_" + school_id;
});
}),
Expanded(
child: Text(
"Class of " + classOf + " Only",
style: DayMoodRobotoStyle.heading5c,
),
)),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: all_Feed == true ? 0 : department_id,
groupValue: school_id,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
department + " - " + classOf,
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 5,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s2 + s1;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "programyear_" + _id;
// department + classOf + "_" + school_id;
});
}),
Expanded(
child: Text(
department + " - " + classOf,
style: DayMoodRobotoStyle.heading5c,
),
)),
),
SizedBox(
height: 20,
),
],
);
}
}
Here is the minimum implementation of 2Radio button groups.
class _TestState extends State<Test> {
int group1Value;
int group2Value;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Radio"),
),
body: Column(
children: [
//Let suppose this is group 1
Row(
children: [
Radio(
value: 0,
groupValue: group1Value,
onChanged: (value) {
setState(() {
group1Value = value;
});
},
),
Expanded(child: Text("Radio1")),
],
),
Row(
children: [
Radio(
value: 1,
groupValue: group1Value,
onChanged: (value) {
setState(() {
group1Value = value;
});
},
),
Expanded(child: Text("Radio2")),
],
),
Row(
children: [
Radio(
value: 2,
groupValue: group1Value,
onChanged: (value) {
setState(() {
group1Value = value;
});
},
),
Expanded(child: Text("Radio3")),
],
),
SizedBox(height: 20),
Text(
"Second Group",
style: Theme.of(context).textTheme.subtitle1.copyWith(
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
//suppose this is group 2
Row(
children: [
Radio(
value: 0,
groupValue: group2Value,
onChanged: (value) {
setState(() {
group2Value = value;
});
},
),
Expanded(child: Text("Radio1")),
],
),
Row(
children: [
Radio(
value: 1,
groupValue: group2Value,
onChanged: (value) {
setState(() {
group2Value = value;
});
},
),
Expanded(child: Text("Radio2")),
],
),
Row(
children: [
Radio(
value: 2,
groupValue: group2Value,
onChanged: (value) {
setState(() {
group2Value = value;
});
},
),
Expanded(child: Text("Radio3")),
],
),
],
),
);
}
}
Here are the results

When routing to another page I get "There are multiple heroes that share the same tag within a subtree"

I am trying to navigate from one screen to another with route. When I hit the button for the page to move to the route provided I get the error:
I/flutter ( 8790): Another exception was thrown: There are multiple heroes that share the same tag within a subtree.
Sharing with you the source code:
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_counter/flutter_counter.dart';
import 'package:gender_selection/gender_selection.dart';
import 'package:group_chats/addContactUI.dart';
import 'package:group_chats/addPhone.dart';
import 'package:group_chats/letGoUI.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Animation/FadeAnimation.dart';
import 'Model/insertUserModel.dart';
class AddProfileUI extends StatefulWidget {
final List<String> listFriends;
final String phone;
AddProfileUI(this.listFriends, this.phone);
#override
_AddProfileUIState createState() => _AddProfileUIState();
}
class _AddProfileUIState extends State<AddProfileUI> {
File _image;
final picker = ImagePicker();
final _formKey = GlobalKey<FormState>();
String name = "";
String city = "";
TextEditingController dobController = TextEditingController();
bool single = false;
Gender gender;
final _scaffoldKey = GlobalKey<ScaffoldState>();
int defaultValue = 18;
List<String> selectedContact;
SharedPreferences prefs;
bool _loading = true;
Future initPrefs() async {
prefs = await SharedPreferences.getInstance();
}
uploadImage(String userId) async {
try {
FormData formData = new FormData.fromMap({
"file":
await MultipartFile.fromFile(_image.path, filename: "$userId.jpg"),
});
var response = await Dio().post(
"https://us-central1-app-backend-fc090.cloudfunctions.net/webApi/api/v1/upload_profile/$userId",
data: formData);
if (response.statusCode == 200)
return response.data;
else
return null;
} catch (e) {
print(e.toString());
return null;
}
}
Future<InsertUserModel> insertData() async {
try {
for (int i = 0; i < selectedContact.length; i++) {
if (selectedContact[i][0] == "0") {
selectedContact[i] = selectedContact[i].replaceRange(0, 1, "+972");
}
}
var body = jsonEncode({
"gender": gender.index == 0 ? "male" : "female",
"city": city,
"last_login": {},
"friends": selectedContact ?? [],
"single": single,
"name": name,
"phone_number": widget.phone,
"age": defaultValue
});
final String apiUrl =
"https://us-central1-app-backend-fc090.cloudfunctions.net/webApi/api/v1/users/${AddPhoneUI.uid}";
final response = await http.post(apiUrl,
headers: {"content-type": "application/json"}, body: body);
if (response.statusCode == 200) {
final responseString = response.body;
return insertUserModelFromJson(responseString);
}
} catch (e) {
setState(() {
_loading = false;
});
}
}
getUserData() async {
try {
final String apiUrl =
"https://us-central1-app-backend-fc090.cloudfunctions.net/webApi/api/v1/users/";
final response = await http.get(apiUrl);
if (response.statusCode == 200) {
final responseString = response.body;
return insertUserModelFromJson(responseString);
}
} catch (e) {
setState(() {
_loading = false;
});
Scaffold.of(context).showSnackBar(SnackBar(
backgroundColor: Colors.red,
content: Text('Error: ${e.toString()}'),
duration: Duration(milliseconds: 2500),
));
}
}
Future<void> _selectStartingDate(BuildContext context) async {
DateTime selectedDate = DateTime.now();
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950),
lastDate: DateTime(
DateTime.now().year, DateTime.now().month, DateTime.now().day),
);
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
dobController.text = selectedDate.year.toString() +
"-" +
selectedDate.month.toString() +
"-" +
selectedDate.day.toString();
});
}
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
}
showPopUp(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape:
OutlineInputBorder(borderRadius: BorderRadius.circular(14.0)),
content: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 20.0,
),
Text(
"My Profile",
style: TextStyle(
fontSize: 27.0, fontWeight: FontWeight.w600),
),
SizedBox(
height: 30.0,
),
RichText(
text: TextSpan(
text: "Your friends will be able to\nsee ",
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
children: <TextSpan>[
TextSpan(
text: 'only',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500)),
TextSpan(text: 'your picture and\name.'),
],
)),
SizedBox(
height: 10.0,
),
RichText(
text: TextSpan(
text: "Other fields are used for\n",
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
children: <TextSpan>[
TextSpan(
text: 'research issues',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500)),
TextSpan(text: "only."),
],
)),
SizedBox(
height: 10.0,
),
RichText(
text: TextSpan(
text: "Please fill all the fields.",
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
)),
SizedBox(
height: 80.0,
),
MaterialButton(
shape: OutlineInputBorder(
borderSide: BorderSide(width: 1.0)),
color: Colors.white38,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 20.0),
child: Text(
"Ok, got it",
style: TextStyle(fontSize: 18.0),
),
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
));
}
#override
void initState() {
super.initState();
selectedContact = widget.listFriends;
initPrefs();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {},
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddContactUI(),
)).then((value) {
setState(() {
selectedContact = value;
});
});
},
child: Column(
children: [
Icon(
Icons.supervisor_account,
size: 40.0,
),
Text("Add Friends"),
],
),
)
],
),
),
Container(
child: GestureDetector(
onTap: () async {
await getImage();
},
child: CircleAvatar(
radius: 60.0,
backgroundImage: _image != null
? Image.file(_image).image
: Image.asset("assets/empty.png").image,
backgroundColor: Colors.transparent,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: FadeAnimation(
1.7,
Form(
key: _formKey,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Color(0xff5E17EB).withOpacity(0.3),
blurRadius: 20,
offset: Offset(0, 10),
)
]),
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey[200]))),
child: TextFormField(
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) =>
FocusScope.of(context).nextFocus(),
onChanged: (val) {
setState(() {
name = val;
});
},
validator: (val) =>
val.isEmpty ? "Enter Name" : null,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Name",
hintStyle: TextStyle(color: Colors.grey)),
),
),
Container(
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey[200]))),
padding: EdgeInsets.all(10),
child: TextFormField(
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
onChanged: (val) {
setState(() {
city = val;
});
},
validator: (val) {
if (val.isEmpty) return "Enter City";
// if (val.length < 6)
// return "Password should be at least 6 characters";
return null;
},
decoration: InputDecoration(
border: InputBorder.none,
hintText: "City",
hintStyle: TextStyle(color: Colors.grey)),
),
),
Container(
height: 140.0,
padding: EdgeInsets.all(10),
child: GenderSelection(
selectedGender: gender,
maleText: "", //default Male
femaleText: "", //default Female
linearGradient: LinearGradient(colors: [
Colors.indigo,
Colors.black
]), //List: [Colors.indigo, Colors.black]
selectedGenderIconBackgroundColor:
Colors.indigo, // default red
checkIconAlignment:
Alignment.centerRight, // default bottomRight
selectedGenderCheckIcon:
null, // default Icons.check
onChanged: (Gender gender) {
this.gender = gender;
print(this.gender);
},
equallyAligned: true,
animationDuration: Duration(milliseconds: 400),
isCircular: true, // default : true,
isSelectedGenderIconCircular: true,
opacityOfGradient: 0.6,
padding: const EdgeInsets.all(3),
size: 120, //default : 120
),
),
SizedBox(
height: 10.0,
),
Row(
children: [
Checkbox(
value: single,
onChanged: (value) {
setState(() {
single = !single;
});
},
),
Text(
"Are you Single?",
style: TextStyle(fontSize: 16.0),
)
],
),
Padding(
padding: const EdgeInsets.all(14.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
"Age:",
style: TextStyle(fontSize: 18.0),
),
Counter(
initialValue: defaultValue,
buttonSize: 35.0,
textStyle: TextStyle(fontSize: 25.0),
minValue: 0,
color: Colors.black,
maxValue: 80,
step: 1,
decimalPlaces: 0,
onChanged: (value) {
// get the latest value from here
setState(() {
defaultValue = value;
});
},
),
],
),
),
],
),
),
),
),
),
SizedBox(
height: 20.0,
),
FadeAnimation(
1.9,
MaterialButton(
shape: OutlineInputBorder(borderSide: BorderSide(width: 1.0)),
color: Colors.black,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 20.0),
child: Text(
"Next",
style: TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
InsertUserModel result = await insertData();
// var imageResult = await uploadImage(result.id);
print(result.data[0].id);
if (_image != null) {
await uploadImage(result.data[0].id);
}
setState(() {
_loading = false;
});
if (result != null) {
await prefs.setString("userID", result.data[0].id);
final snackBar = SnackBar(
content: Text(
result.message,
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.green,
duration: Duration(milliseconds: 2000),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LetGoUI(result.data[0].id),
));
} else {
final snackBar = SnackBar(
content: Text(
"Here is some error, please try again later!",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.red,
duration: Duration(milliseconds: 2000),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
}
}
},
),
)
],
),
),
),
);
}
}
I really don't understand what is the problem because I'm not using any Heros and not have double FloatingActionButton.
How do I solve this?
Thanks
There might be problem with showing snackbar while navigating. you should remove that problem by calling following method before navigating.
void removeSnackBarCallsBeforeNavigation() {
ScaffoldMessenger.of(context).removeCurrentSnackBar();
}