flutter bloc doesn't update the ui? - flutter

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 {}

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 button doesn't work when passing variables between files

I'm building a workout app with a sign out button and a delete exercise button. I've made a single file instead of 2 and passed variable. I did this so That I don't have to make 2 files.
the problem is with function; in the onPressed call back in dialog.instance.dart
if I don't pass the variables it works fine. but I don't wanna make 2 separate files.
I tried this but it didn't work to plan:
dialog_instance.dart
Future<void> DialogInstance(BuildContext context, void Function()? function,
String name, String description) {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
backgroundColor: Colors.blueGrey,
title: Text(
name,
style: const TextStyle(color: Colors.white),
),
actions: [
Row(
children: [
const SizedBox(width: 16.0),
Text(
'Are you sure $description',
style: const TextStyle(color: Colors.white),
)
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {
function;
},
style:
OutlinedButton.styleFrom(backgroundColor: Colors.red),
child: const Text('Yes',
style: TextStyle(color: Colors.white)),
),
),
],
),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Cancel',
style: TextStyle(color: Colors.white)),
),
),
],
),
],
);
});
}
workout_page.dart
class WorkoutPage extends StatefulWidget {
const WorkoutPage({Key? key}) : super(key: key);
#override
State<WorkoutPage> createState() => _WorkoutPageState();
}
User user = FirebaseAuth.instance.currentUser!;
String signOutText = 'Sign Out';
const signOutDescription = 'you want to sign out?';
class _WorkoutPageState extends State<WorkoutPage> {
#override
Widget build(BuildContext context) {
void signOutFunction() {
AuthService.signOutMethod();
Navigator.of(context)
.pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);
}
return Scaffold(
backgroundColor: backgroundColor,
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(user.email!, style: const TextStyle(fontSize: 14)),
backgroundColor: backgroundColor,
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: GradientElevatedButton(
onPressed: () {
DialogInstance(context, signOutFunction, signOutText,
signOutDescription);
},
child: const Text('Sign out')),
)
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.cyan,
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const ExercisePage()));
},
child: const Icon(
Icons.add,
color: Colors.black,
),
),
);
}
}
cardiovascular_card.dart
class CardiovascularCard extends StatefulWidget {
AsyncSnapshot<QuerySnapshot> snapshot;
int index;
CardiovascularCard(this.snapshot, this.index, {Key? key}) : super(key: key);
#override
State<CardiovascularCard> createState() => _CardiovascularCardState();
}
String deleteExerciseText = 'Delete exercise';
final uid = FirebaseAuth.instance.currentUser?.uid;
TextEditingController _calorieController = TextEditingController();
TextEditingController _timeController = TextEditingController();
String deleteExerciseDescription = 'you want to delete this exercise?';
class _CardiovascularCardState extends State<CardiovascularCard> {
#override
Widget build(BuildContext context) {
String deleteExerciseText = 'Delete exercise';
final uid = FirebaseAuth.instance.currentUser?.uid;
final data = widget.snapshot.data;
final exerciseId = data!.docs[widget.index].reference.id;
void deleteExerciseFunction() {
FirebaseFirestore.instance
.runTransaction((Transaction myTransaction) async {
myTransaction.delete(data.docs[widget.index].reference);
});
}
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(children: [
Card(
elevation: 8,
color: const Color.fromARGB(255, 81, 108, 122),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
data.docs[widget.index]['exerciseName'],
style: const TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
const Divider(thickness: 1.0),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Text(
'Calories',
style: TextStyle(color: Colors.white),
),
Text(
'Time',
style: TextStyle(color: Colors.white),
),
],
),
Slidable(
endActionPane: ActionPane(
motion: const ScrollMotion(),
children: [
SlidableAction(
onPressed: (context) {
DialogInstance(context, deleteExerciseFunction,
deleteExerciseText, deleteExerciseDescription);
},
label: 'Delete',
backgroundColor: Colors.red,
icon: Icons.delete,
)
],
),
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.145,
child: TextField(
style: const TextStyle(fontWeight: FontWeight.bold),
cursorColor: Colors.white,
onSubmitted: (value) async {
FirebaseFirestore.instance.runTransaction(
(Transaction myTransaction) async {
FirebaseFirestore.instance
.collection('users')
.doc(uid)
.collection('workout')
.doc(exerciseId)
.update({'caloriesBurnt': value});
});
},
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
controller: _calorieController,
decoration: InputDecoration(
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
hintText: data.docs[widget.index]['caloriesBurnt']
.toString()),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.145,
child: TextField(
style: const TextStyle(fontWeight: FontWeight.bold),
cursorColor: Colors.white,
onSubmitted: (value) async {
FirebaseFirestore.instance.runTransaction(
(Transaction myTransaction) async {
FirebaseFirestore.instance
.collection('users')
.doc(uid)
.collection('workout')
.doc(exerciseId)
.update({'time': value});
});
},
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
controller: _timeController,
decoration: InputDecoration(
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
hintText:
data.docs[widget.index]['time'].toString()),
),
),
],
),
),
),
],
),
),
]),
);
}
}
If i understand correctly - function named function is not called.
You have to call the function with function() or tear-off
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {
function();
},
or
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed:function,

Can't save the right image url on Firestore

Actually I am getting data by user, saving it in a map and adding this item to a list. When user has added all items in the list, it press the floating action button to add this list to an existing list on the firestore.
All data is being saved successfully except the imageUrl. First item in the list has null imageUrl at firestore however the second item is assigned the imageUrl of first Item. And the sequence goes on... I don't know what am I missing! I have subtracted most of code to be specific. I think the problem is being caused by the variable itemImageUrl that is being overridden. Help!
This is the code:
class RetrieveShop extends StatefulWidget {
String nameShop;String docId;
RetrieveShop(this.nameShop,this.docId);
#override
_RetrieveShopState createState() => _RetrieveShopState();
}
class _RetrieveShopState extends State<RetrieveShop> {
var result;
bool isLoading = false;
bool isLoadingNow = false;
var _price = TextEditingController();
var _itemName = TextEditingController();
/* var _id = TextEditingController();
var _category = TextEditingController();*/
var _desc = TextEditingController();
File _image;
File _image2;
String itemImageUrl;
bool _showDg = false;
bool condition = true;
bool isPopular = false;
bool savingAllDataToFirestore = false;
List itemo=[];
Future getImageFromGallery() async {
var image = await ImagePicker()
.getImage(source: ImageSource.gallery, imageQuality: 80);
setState(() {
_image = File(image.path);
print('Image Path $_image');
});
}
Future getImageFromCamera() async {
var image = await ImagePicker().getImage(source: ImageSource.camera);
setState(() {
_image = File(image.path);
print('Image Path $_image');
});
}
Future uploadItemOfShop(BuildContext context) async {
Reference ref = storage.ref().child(
"${this.widget.nameShop}'s ${_itemName.text} Price ${_price.text}" +
DateTime.now().toString());
if (_image.toString() == '') {
Flushbar(
title: "Menu Item Image is empty",
message: "Please Add some Image first",
backgroundColor: Colors.red,
boxShadows: [
BoxShadow(
color: Colors.red[800],
offset: Offset(0.0, 2.0),
blurRadius: 3.0,
)
],
duration: Duration(seconds: 3),
)
..show(context);
} else {
setState(() {
isLoadingNow=true;
});
debugPrint('wah');
UploadTask uploadTask = ref.putFile(_image);
uploadTask.then((res) async {
itemImageUrl = await res.ref.getDownloadURL();
}).then((value){
setState(() {
isLoadingNow=false;
});
debugPrint("Nullifing the Image object");
_image=_image2; //Trying to null the file object after it is used so thinking that might
//the problem is being caused here
});
}
}
Widget listTile(BuildContext context,String doc) {
return !isLoadingNow?SingleChildScrollView(
child: ListTile(
title: Wrap(
// mainAxisAlignment: MainAxisAlignment.start,
direction: Axis.horizontal,
children: [
Text(
"Enter details of Item",
style: TextStyle(fontSize: 22, color: Colors.black87),
),
Stack(
children: [
SizedBox(
width: MediaQuery
.of(context)
.size
.width,
height: MediaQuery
.of(context)
.size
.height / 2.5,
child: (_image != null)
? Image.file(
_image,
fit: BoxFit.cover,
)
: Image.network(
"https://images.unsplash.com/photo-1502164980785-f8aa41d53611?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
fit: BoxFit.fill,
),
),
Container(
alignment: Alignment.topLeft,
color: Colors.white38,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(
Icons.add_a_photo,
size: 30.0,
color: Colors.black,
),
onPressed: () {
getImageFromCamera();
},
),
SizedBox(
width: 10,
),
IconButton(
icon: Icon(
Icons.create_new_folder_rounded,
size: 30.0,
color: Colors.black,
),
onPressed: () {
getImageFromGallery();
},
),
],
),
)
],
),
],
),
subtitle: Column(
children: [
TextField(
controller: _itemName,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Enter Item name',
icon: Icon(Icons.fastfood),
alignLabelWithHint: true,
hintText: "Zinger Burger etc"),
autofocus: true,
),
TextField(
controller: _price,
autofocus: false,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Enter Price',
icon: Icon(Icons.attach_money),
alignLabelWithHint: true,
hintText: "70 etc"),
),
SwitchListTile(
title: condition ? Text("Fresh") : Text("Used"),
value: condition,
onChanged: _onConditionChanged,
),
SwitchListTile(
title: isPopular ? Text("Popular") : Text("Not Popular"),
value: isPopular,
onChanged: _onPopularityChanged,
),
TextField(
autofocus: false,
maxLength: 150,
controller: _desc,
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: InputDecoration(
labelText: 'Enter Description',
icon: Icon(Icons.description),
alignLabelWithHint: true,
hintText:
"This item contains cheez and paneer with delicious mayonees etc.."),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(
child: Text(
"Save",
style: TextStyle(color: Colors.white, fontSize: 16),
),
color: Colors.red,
onPressed: () {
if(_image !=null){
int price=int.parse(_price.text);
String itemName=_itemName.text;
String itemDesc=_desc.text;
String categoryO=this.categoryToSave;
String imageUrl=this.itemImageUrl;
uploadItemOfShop(context).then((value){
String idO=getRandomString(3);
var item = {
'itemName': itemName,
'itemPrice': price,
'itemDesc': itemDesc,
'category': categoryO,
'condition': condition,
'imageUrl': imageUrl,
'isPopular': this.isPopular,
'id': idO,
};
setState(() {
itemo.add(item);
});
});
setState(() {
_showDg = false;
});
_price.clear();
_desc.clear();
_itemName.clear();
/* imageUrl='';
itemImageUrl='';*/
}else{
Fluttertoast.showToast(msg: 'Please select some image first');
}
}
),
],
),
],
),
selectedTileColor: Colors.red.shade300,
),
):Padding(
padding: const EdgeInsets.all(40.0),
child: Center(
child:CircularProgressIndicator()
),
);
}
Widget myList(String nameOfButton2, {BuildContext buildContext}) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
StreamBuilder(
stream: FirebaseFirestore.instance.collection('shops').where(
'name', isEqualTo: this.widget.nameShop).snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.hasData){
DocumentSnapshot list=snapshot.data.docs.single;
return isLoadingNow
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: list.data()['menu'].length,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context,int index){
return Card(
shadowColor: Colors.red,
//color: Colors.black,
elevation: 8.0,
//borderOnForeground: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
margin: EdgeInsets.only(
bottom: 10, right: 10),
child: ListTile(
leading: CachedNetworkImage(
fit: BoxFit.cover,
//height: 100,
placeholderFadeInDuration:
Duration(seconds: 2),
fadeOutDuration: Duration(seconds: 2),
imageUrl: list
.data()['menu'][index]['imageUrl'],
progressIndicatorBuilder: (context, url,
downloadProgress) =>
Center(
child:
CircularProgressIndicator(
value: downloadProgress.progress,
color: kPrimaryColor,
)),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
title:Text('Name: ${list.data()['menu'][index]['itemName']}'),
subtitle: Column(
crossAxisAlignment:CrossAxisAlignment.start,
children:[
Text(
"Price: ${list.data()['menu'][index]['itemPrice']} Rs",
style: TextStyle(
color: Colors.black54,
fontSize: 18),
),
Text(
"Description: ${list.data()['menu'][index]['itemDesc']}",
style: TextStyle(
color: Colors.black87, fontSize: 20),
),
list.data()['menu'][index]['condition']
? Text("Condition: Fresh")
: Text("Condition: Used"),
]
),
),
);
},
);
}
if(snapshot.hasError){
return Text('Please try again');
}
return Center(
child: CircularProgressIndicator(),
);
},
),
]
,
);
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("${this.widget.nameShop}"),
centerTitle: false,
actions: [
IconButton(
icon: Icon(Icons.add_comment),
onPressed: () {
setState(() {
_showDg = !_showDg;
});
})
],
),
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
_showDg ? listTile(context,this.widget.docId) : Text(""),
myList(this.widget.nameShop),
],
),
),
),
floatingActionButton: FloatingActionButton(
child: Text("Items ${itemo.length.toString()}"),
onPressed: (){
if(itemo.length==0){
Fluttertoast.showToast(msg: 'Please add some items first');
}else{
FirebaseFirestore.instance.collection('shops').doc(this.widget.docId).update({
"menu": FieldValue.arrayUnion(itemo),
});
setState(() {
itemo=[];
});
}
},
),
);
}
}
Was just missing await before the object of uploadtask.

How to validate a form in Flutter

I am trying to validate my fields before submitting in flutter. But somehow it doesn't validate as the validate always comes true even if the fields are empty.
This is what I tried. Can someone help me to identify what I have done wrong?
as you can see below, I have even set the validators and controller. But still the Submission happens even when the fields are empty
class _AddNewsState extends State<AddNews> {
GlobalKey<FormState> _key = GlobalKey<FormState>();
TextEditingController _headlineController;
TextEditingController _descriptionController;
String _dropDownActivity;
// get current date
static var now = new DateTime.now();
static var formatter = new DateFormat('yyyy-MM-dd');
String formattedDate = formatter.format(now);
// get current timie
dynamic currentTime = DateFormat.jm().format(DateTime.now());
#override
void initState() {
super.initState();
_headlineController = TextEditingController();
_descriptionController = TextEditingController();
_dropDownActivity = "";
}
#override
Widget build(BuildContext context) {
File _image;
String image_url = "";
FileImage _getImage() {
var img = (File(widget.imgPath));
setState(() {
_image = img;
});
return FileImage(_image);
}
Future _showToastMsg(String msgType, String msg) {
if (msgType == "success") {
return Fluttertoast.showToast(
msg: msg,
textColor: Colors.white,
toastLength: Toast.LENGTH_SHORT,
timeInSecForIosWeb: 1,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.green,
);
} else if (msgType == "error") {
return Fluttertoast.showToast(
msg: msg,
textColor: Colors.white,
toastLength: Toast.LENGTH_SHORT,
timeInSecForIosWeb: 1,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.red,
);
} else {
return Fluttertoast.showToast(
msg: msg,
textColor: Colors.white,
toastLength: Toast.LENGTH_SHORT,
timeInSecForIosWeb: 1,
gravity: ToastGravity.BOTTOM,
backgroundColor: Colors.black,
);
}
}
get_image_url_from_uploadPicture(String url) {
image_url = url;
return image_url;
}
showLoadingWhileSaving(BuildContext context) {
AlertDialog alert = AlertDialog(
content: new Row(
children: [
CircularProgressIndicator(),
Container(margin: EdgeInsets.only(left: 5), child: Text("Loading")),
],
),
);
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Future _uploadPicture(BuildContext context) async {
String fileName = basename(_image.path);
StorageReference storageReference =
FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask storageUploadTask = storageReference.putFile(_image);
showLoadingWhileSaving(context);
StorageTaskSnapshot storageTaskSnapshot =
await storageUploadTask.onComplete;
image_url =
await (await storageUploadTask.onComplete).ref.getDownloadURL();
get_image_url_from_uploadPicture(image_url);
Navigator.pop(context);
setState(() {
_showToastMsg("success", "News Successfully Saved!");
});
}
return Scaffold(
appBar: AppBar(
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(null),
color: Colors.white,
onPressed: () {},
);
},
),
centerTitle: true,
title: Text(
"Report a News",
),
backgroundColor: Colors.blueGrey,
),
body: Container(
child: SingleChildScrollView(
padding: const EdgeInsets.all(26.0),
child: Form(
key: _key,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.center,
child: GFImageOverlay(
border: Border.all(color: Colors.blueGrey, width: 4.0),
height: 200,
width: 200,
color: Colors.red,
shape: BoxShape.circle,
boxFit: BoxFit.fill,
image: (widget.imgPath != null)
? _getImage()
: AssetImage("images/default_news_image.png"),
)),
SizedBox(
height: 30.0,
),
TextFormField(
textInputAction: TextInputAction.next,
controller: _headlineController,
validator: (headline) {
if (headline == null || headline.isEmpty) {
_showToastMsg("error", "Please enter a Headline");
}
},
decoration: InputDecoration(
labelText: "Headline",
hintText: "Covid-19 new stats",
border: OutlineInputBorder(),
icon: Icon(Icons.add_box),
),
),
SizedBox(
height: 16.0,
),
TextFormField(
maxLines: 5,
textInputAction: TextInputAction.next,
controller: _descriptionController,
validator: (description) {
if (description == null || description.isEmpty) {
_showToastMsg("error", "Please provide a Headline");
}
},
decoration: InputDecoration(
labelText: "Description",
hintText: "Covid-19 new stats are sky-rock...",
border: OutlineInputBorder(),
icon: Icon(Icons.message),
),
),
SizedBox(
height: 16.0,
),
DropDownFormField(
titleText: 'Priority',
value: _dropDownActivity,
hintText: 'Select the priority',
onSaved: (value) {
setState(() {
_dropDownActivity = value;
});
},
onChanged: (value) {
setState(() {
_dropDownActivity = value;
});
},
validator: (value) {
if (value == null || value == "") {
_showToastMsg("error", "Please select a priority");
}
},
dataSource: [
{
"display": "High",
"value": "High",
},
{
"display": "Medium",
"value": "Medium",
},
{
"display": "Low",
"value": "Low",
},
],
textField: 'display',
valueField: 'value',
),
SizedBox(
height: 16.0,
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
GFButtonBadge(
size: GFSize.SMALL,
onPressed: () {
_showToastMsg(
"other", "Today is : ${formattedDate}");
},
icon: Icon(
Icons.calendar_today,
size: 16.0,
color: Colors.white,
),
text: '',
),
SizedBox(
width: 10.0,
),
Text(
"- ${formattedDate}",
style: TextStyle(fontSize: 18.0),
),
],
),
SizedBox(
height: 10.0,
),
Row(
children: <Widget>[
GFButtonBadge(
size: GFSize.SMALL,
onPressed: () {
_showToastMsg("other", "Time is : ${currentTime}");
},
icon: Icon(
Icons.alarm,
size: 16.0,
color: Colors.white,
),
text: '',
),
SizedBox(
width: 10.0,
),
Text(
"- ${currentTime}",
style: TextStyle(fontSize: 18.0),
),
],
),
SizedBox(
height: 14.0,
),
],
),
Align(
alignment: Alignment.center,
child: Text(
"Date and time will be saved automaticallt on \"Save\"",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey,
),
),
),
SizedBox(
height: 20.0,
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton.icon(
icon: Icon(Icons.refresh),
color: Colors.orange,
textColor: Colors.white,
label: Text("Retake"),
onPressed: () async {
Navigator.of(context).pop();
},
),
RaisedButton.icon(
icon: Icon(Icons.add_a_photo),
color: Colors.green,
textColor: Colors.white,
label: Text("Snap"),
onPressed: () async {
try {
// first upload the photo
if (_key.currentState.validate()) {
_showToastMsg("other",
get_image_url_from_uploadPicture("cool"));
} else {
_showToastMsg("other",
get_image_url_from_uploadPicture("empty"));
}
// await FireStoreServiceApi().add_news(News(
// headline: _headlineController.text,
// description: _descriptionController.text,
// imageUrl: image_url,
// timeNews: currentTime.toString(),
// timeDate: formattedDate.toString(),
// priority: _dropDownActivity.toString(),
// ));
} catch (e) {
print(e);
}
},
),
],
),
],
),
),
),
),
);
}
}
Tell me where I have gone wrong and how to fix that
Thank you.
You must return a String in the validator whenever you want to show an input error.
TextFormField(
textInputAction: TextInputAction.next,
controller: _headlineController,
validator: (headline) {
if (headline == null || headline.isEmpty) {
return "Please enter a Headline";
}
return null;
},
decoration: InputDecoration(
labelText: "Headline",
hintText: "Covid-19 new stats",
border: OutlineInputBorder(),
icon: Icon(Icons.add_box),
),
),

Popupmenu setstate doesnt update Flutter

currently I am trying to update a text in my popupmenu, in between the add and reduce icon button, when i click on add button. Value increases but it does not update when i setstate it. I have to close the popupmenu and reopen it to see the new updated value. Any tips to improve my code would be greatly appreciated. Thank you for your help.
This is my code:
class SelectMedicalItems extends StatefulWidget {
final Function callBack;
SelectMedicalItems({this.callBack});
#override
_SelectMedicalItemsState createState() => _SelectMedicalItemsState();
}
class _SelectMedicalItemsState extends State<SelectMedicalItems>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
double _scale;
int tempCount = 0;
String tempName = '';
List<CartItems> totalItem = [];
TextEditingController textController = TextEditingController();
void _onTap() {
_animationController.forward();
}
void _onTapReverse() {
_animationController.reverse();
}
void _onTapUp(TapUpDetails details) {
_animationController.reverse();
}
void _onTapDown(TapDownDetails details) {
_animationController.forward();
}
List items = List<String>();
List<String> tempMedical = medicalItems;
void filteredSearch(String query) {
items = tempMedical
.where((txt) => query.isEmpty || txt.toUpperCase().contains(query))
.toList();
setState(() {});
}
GlobalKey<ScaffoldState> _scaffoldState = GlobalKey<ScaffoldState>();
void _showBar(String newValue) async {
_scaffoldState.currentState.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
content: Text('You have selected: $newValue'),
),
);
await showDialog(
barrierDismissible: false,
context: context,
child: StatefulBuilder(builder: (context, setState) {
return AlertDialog(
elevation: 30,
backgroundColor: Color(0xFFE6F0F9),
contentPadding: EdgeInsets.all(10),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: Text(
'How many do you need?',
style: TextStyle(
color: Color(0xFF67696F),
),
),
content: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.all(15.0),
child: TextField(
autofocus: true,
keyboardType: TextInputType.numberWithOptions(),
onSubmitted: (value) {
setState(() {
tempCount = int.parse(value);
});
},
onChanged: (value) {
setState(() {
tempCount = int.parse(value);
});
},
decoration: InputDecoration(
hintText: 'e.g 10', suffixText: 'pcs'),
),
),
),
],
),
actions: <Widget>[
FlatButton(
onPressed: () {
setState(() {
tempCount = 0;
tempName = '';
});
Navigator.pop(context);
},
child: Text(
'Cancel',
style: TextStyle(color: Colors.red),
)),
FlatButton(
onPressed: () {
setState(() {
totalItem.add((CartItems(
cartItem: tempName, itemQuantity: tempCount)));
tempName = '';
tempCount = 0;
});
Navigator.pop(context);
},
child: Text(
'Okay',
style: TextStyle(color: Colors.blue),
)),
],
);
}));
setState(() {});
}
#override
void initState() {
items = tempMedical;
_animationController = AnimationController(
vsync: this,
upperBound: 0.1,
lowerBound: 0.0,
duration: Duration(milliseconds: 100))
..addListener(() {
setState(() {});
});
super.initState();
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
_scale = 1 - _animationController.value;
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xFFE6F0F9),
resizeToAvoidBottomPadding: false,
key: _scaffoldState,
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
GestureDetector(
onTapUp: _onTapUp,
onTapDown: _onTapDown,
onTap: () {
_onTap();
_onTapReverse();
Future.delayed(Duration(milliseconds: 500), () {
Navigator.pop(context);
});
},
child: Transform.scale(
scale: _scale,
child: Container(
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFE6F0F9),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
offset: Offset(5, 5),
blurRadius: 8,
),
BoxShadow(
color: Colors.white.withOpacity(0.5),
offset: Offset(-5, -5),
blurRadius: 8,
)
]),
child: Icon(
Icons.arrow_back_ios,
color: Color(0xFF67696F),
),
),
),
),
Spacer(),
Badge(
elevation: 5,
position: BadgePosition.topRight(top: -1, right: -5),
animationDuration: Duration(seconds: 1),
toAnimate: true,
animationType: BadgeAnimationType.slide,
badgeContent: Text(
totalItem.length.toString(),
style: TextStyle(color: Colors.white),
),
child: PopupMenuButton(
color: Color(0xFFE6F0F9),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
itemBuilder: (context) {
return totalItem
.map((item) => PopupMenuItem(
value: item.cartItem,
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Text(
'${item.cartItem}',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.w500),
),
),
Spacer(),
GestureDetector(
onTap: () {
setState(() {
item.itemQuantity++;
});
},
child: Icon(
Icons.add_circle,
color: Colors.green,
),
),
Text(
item.itemQuantity.toString(),
style: TextStyle(color: Colors.black),
),
GestureDetector(
onTap: () {
setState(() {
item.itemQuantity--;
});
},
child: Icon(
Icons.remove_circle,
color: Colors.red,
),
),
],
),
))
.toList();
},
child: Container(
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFE6F0F9),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
offset: Offset(5, 5),
blurRadius: 8,
),
BoxShadow(
color: Colors.white.withOpacity(0.5),
offset: Offset(-5, -5),
blurRadius: 8,
)
]),
child: Icon(
Icons.shopping_cart,
color: Color(0xFF67696F),
)),
),
),
],
),
),
Padding(
padding: EdgeInsets.all(15.0),
child: TextField(
controller: textController,
decoration: InputDecoration(
hintText: 'Search',
labelText: 'Search',
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0))),
suffix: GestureDetector(
child: Icon(Icons.clear),
onTap: () {
textController.clear();
setState(() {
items = tempMedical;
});
},
)),
onChanged: (value) {
filteredSearch(value.toUpperCase());
},
),
),
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Material(
color: Color(0xFFE6F0F9),
child: InkWell(
child: ListTile(
onTap: () {
SystemSound.play(SystemSoundType.click);
_showBar('${items[index]}');
widget.callBack(items[index]);
tempName = '${items[index]}';
},
title: Text(
'${items[index]}',
style: TextStyle(color: Color(0xFF67696F)),
),
trailing: Icon(
Icons.add_circle_outline,
color: Colors.green,
size: 30,
),
),
),
);
})),
],
),
),
);
}
}
class CartItems {
final String cartItem;
int itemQuantity;
CartItems({this.cartItem, this.itemQuantity: 1});
}
You can copy-paste run full code below
You can use StatefulBuilder as child of PopupMenuItem and return Row
Code Snippet:
PopupMenuItem(
value: item.cartItem,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Row(
mainAxisSize: MainAxisSize.min,
Working Demo:
Full Code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SelectMedicalItems(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class SelectMedicalItems extends StatefulWidget {
final Function callBack;
SelectMedicalItems({this.callBack});
#override
_SelectMedicalItemsState createState() => _SelectMedicalItemsState();
}
class _SelectMedicalItemsState extends State<SelectMedicalItems>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
double _scale;
int tempCount = 0;
String tempName = '';
List<CartItems> totalItem = [CartItems(cartItem: "apple", itemQuantity: 2)];
TextEditingController textController = TextEditingController();
void _onTap() {
_animationController.forward();
}
void _onTapReverse() {
_animationController.reverse();
}
void _onTapUp(TapUpDetails details) {
_animationController.reverse();
}
void _onTapDown(TapDownDetails details) {
_animationController.forward();
}
List items = List<String>();
List<String> tempMedical = ["medical"]; //medicalItems;
void filteredSearch(String query) {
items = tempMedical
.where((txt) => query.isEmpty || txt.toUpperCase().contains(query))
.toList();
setState(() {});
}
GlobalKey<ScaffoldState> _scaffoldState = GlobalKey<ScaffoldState>();
void _showBar(String newValue) async {
_scaffoldState.currentState.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
content: Text('You have selected: $newValue'),
),
);
await showDialog(
barrierDismissible: false,
context: context,
child: StatefulBuilder(builder: (context, setState) {
return AlertDialog(
elevation: 30,
backgroundColor: Color(0xFFE6F0F9),
contentPadding: EdgeInsets.all(10),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: Text(
'How many do you need?',
style: TextStyle(
color: Color(0xFF67696F),
),
),
content: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.all(15.0),
child: TextField(
autofocus: true,
keyboardType: TextInputType.numberWithOptions(),
onSubmitted: (value) {
setState(() {
tempCount = int.parse(value);
});
},
onChanged: (value) {
setState(() {
tempCount = int.parse(value);
});
},
decoration: InputDecoration(
hintText: 'e.g 10', suffixText: 'pcs'),
),
),
),
],
),
actions: <Widget>[
FlatButton(
onPressed: () {
setState(() {
tempCount = 0;
tempName = '';
});
Navigator.pop(context);
},
child: Text(
'Cancel',
style: TextStyle(color: Colors.red),
)),
FlatButton(
onPressed: () {
setState(() {
totalItem.add((CartItems(
cartItem: tempName, itemQuantity: tempCount)));
tempName = '';
tempCount = 0;
});
Navigator.pop(context);
},
child: Text(
'Okay',
style: TextStyle(color: Colors.blue),
)),
],
);
}));
setState(() {});
}
#override
void initState() {
items = tempMedical;
_animationController = AnimationController(
vsync: this,
upperBound: 0.1,
lowerBound: 0.0,
duration: Duration(milliseconds: 100))
..addListener(() {
setState(() {});
});
super.initState();
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
_scale = 1 - _animationController.value;
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xFFE6F0F9),
resizeToAvoidBottomPadding: false,
key: _scaffoldState,
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
GestureDetector(
onTapUp: _onTapUp,
onTapDown: _onTapDown,
onTap: () {
_onTap();
_onTapReverse();
Future.delayed(Duration(milliseconds: 500), () {
Navigator.pop(context);
});
},
child: Transform.scale(
scale: _scale,
child: Container(
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFE6F0F9),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
offset: Offset(5, 5),
blurRadius: 8,
),
BoxShadow(
color: Colors.white.withOpacity(0.5),
offset: Offset(-5, -5),
blurRadius: 8,
)
]),
child: Icon(
Icons.arrow_back_ios,
color: Color(0xFF67696F),
),
),
),
),
Spacer(),
Container(
/* elevation: 5,
position: BadgePosition.topRight(top: -1, right: -5),
animationDuration: Duration(seconds: 1),
toAnimate: true,
animationType: BadgeAnimationType.slide,
badgeContent: Text(
totalItem.length.toString(),
style: TextStyle(color: Colors.white),
),*/
child: PopupMenuButton(
color: Color(0xFFE6F0F9),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
itemBuilder: (context) {
return totalItem
.map((item) => PopupMenuItem(
value: item.cartItem,
child: StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Text(
'${item.cartItem}',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.w500),
),
),
Spacer(),
GestureDetector(
onTap: () {
setState(() {
item.itemQuantity++;
});
},
child: Icon(
Icons.add_circle,
color: Colors.green,
),
),
Text(
item.itemQuantity.toString(),
style: TextStyle(color: Colors.black),
),
GestureDetector(
onTap: () {
setState(() {
item.itemQuantity--;
});
},
child: Icon(
Icons.remove_circle,
color: Colors.red,
),
),
],
);
})))
.toList();
},
child: Container(
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Color(0xFFE6F0F9),
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
offset: Offset(5, 5),
blurRadius: 8,
),
BoxShadow(
color: Colors.white.withOpacity(0.5),
offset: Offset(-5, -5),
blurRadius: 8,
)
]),
child: Icon(
Icons.shopping_cart,
color: Color(0xFF67696F),
)),
))
],
),
),
Padding(
padding: EdgeInsets.all(15.0),
child: TextField(
controller: textController,
decoration: InputDecoration(
hintText: 'Search',
labelText: 'Search',
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0))),
suffix: GestureDetector(
child: Icon(Icons.clear),
onTap: () {
textController.clear();
setState(() {
items = tempMedical;
});
},
)),
onChanged: (value) {
filteredSearch(value.toUpperCase());
},
),
),
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Material(
color: Color(0xFFE6F0F9),
child: InkWell(
child: ListTile(
onTap: () {
//SystemSound.play(SystemSoundType.click);
_showBar('${items[index]}');
widget.callBack(items[index]);
tempName = '${items[index]}';
},
title: Text(
'${items[index]}',
style: TextStyle(color: Color(0xFF67696F)),
),
trailing: Icon(
Icons.add_circle_outline,
color: Colors.green,
size: 30,
),
),
),
);
})),
],
),
),
);
}
}
class CartItems {
final String cartItem;
int itemQuantity;
CartItems({this.cartItem, this.itemQuantity: 1});
}
The popmenu itself has no state, so the setState doesn't affect it. The easiest way to fix that is making each item of the menu a Stateful Widget. Something like this:
class CartSelector extends StatefulWidget {
CartSelector({Key key, this.item}) : super(key: key);
final CartItems item;
#override
_CartSelectorState createState() => _CartSelectorState();
}
class _CartSelectorState extends State<CartSelector> {
CartItems item;
#override
void initState() {
super.initState();
item = widget.item;
}
#override
Widget build(BuildContext context) {
return Container(
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Text(
'${item.cartItem}',
style: TextStyle(color: Colors.grey, fontWeight: FontWeight.w500),
),
),
Spacer(),
GestureDetector(
onTap: () {
setState(() {
item.itemQuantity++;
});
},
child: Icon(
Icons.add_circle,
color: Colors.green,
),
),
Text(
item.itemQuantity.toString(),
style: TextStyle(color: Colors.black),
),
GestureDetector(
onTap: () {
setState(() {
item.itemQuantity--;
});
},
child: Icon(
Icons.remove_circle,
color: Colors.red,
),
),
],
),
);
}
}
And then replace it in the PopMenu builder.
return totalItem.map((item) => PopupMenuItem(
value: item.cartItem,
child: CartSelector(item: item),
)).toList();
This code probably need some polish, but I think it will do the work. Hope this helps.
You have to assign PopupMenuButton.initialValue,
check the simple example:
PopupMenuButton<int>(
itemBuilder: (context) => [
PopupMenuItem(
value: 1,
child: Text("First"),
),
PopupMenuItem(
value: 2,
child: Text("Second"),
),
],
initialValue: 2,
onCanceled: () {
print("You have canceled the menu.");
},
onSelected: (value) {
print("value:$value");
},
icon: Icon(Icons.list),
);
For more information follow this link:
Widgets 14 | PopupMenuButton