How to update the amount value when the user add data and store it to list view flutter - flutter

Hi guys I'm new in flutter and need your help. In this case, i'm able to add the budget and retrieve it to list view. but now I'm trying show only 1 list for each category but count for the amount? so if the user add the new budget, the amount will be count and updated to the list view (with the same currency). Anyone can help me how to list the the same category but with updated amount if the user add the budget in the budget code? Please help. Thank you. For the database, I'm using Firestore in the firebase
choose budget category
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/detail.dart';
import 'package:monger_app/theme/colors.dart';
class BudgetSettings extends StatefulWidget {
#override
_BudgetSettingsState createState() => _BudgetSettingsState();
}
class _BudgetSettingsState extends State<BudgetSettings> {
List<Container> categorylist = new List();
var character=[
{"name":"Food", "image":"food.png"},
{"name":"Social-Life", "image":"travel.png"},
{"name":"Transportation", "image":"transportation.png"},
{"name":"Beauty", "image":"makeup.png"},
{"name":"Household", "image":"household.png"},
{"name":"Education", "image":"education.png"},
{"name":"Health", "image":"health.png"},
{"name":"Gift", "image":"gift.png"},
{"name":"Other", "image":"other.png"},
];
_makelist() async {
for (var i = 0; i < character.length; i++) {
final newcharacter = character[i];
final String image = newcharacter["image"];
categorylist.add(
new Container(
padding: new EdgeInsets.all(20.0),
child: new Card( child:
SingleChildScrollView(
child: new Column(
children: <Widget>[
new Hero(
tag: newcharacter['name'],
child: new Material(
child: new InkWell(
onTap: ()=> Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context)=> new Detail(name: newcharacter['name'], image: image,),
)),
child:
new Image.asset("assets/$image", fit: BoxFit.contain,),
)
),
),
//new Image.asset('assets/$image', fit: BoxFit.cover,),
new Padding(padding: new EdgeInsets.all(5.0),),
new Text(newcharacter['name'], style: new TextStyle(fontSize: 18.0),),
],
),
),
),
),
);
}
}
#override
void initState() {
_makelist();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: primary,
title: Text(getTranslated((context), "budget_settings"),
),),
body: new GridView.count(
crossAxisCount: 2,
children: categorylist,
),
);
}
}
Add budget code
import 'package:dropdownfield/dropdownfield.dart';
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/account.dart';
import 'package:monger_app/page/budgetsettings.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Detail extends StatefulWidget {
Detail({this.name, this.image});
final String name;
final String image;
#override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(getTranslated((context), "budget_settings"),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Account()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: new ListView(
children: <Widget>[
new Container(
height: 250.0,
child:
new Hero(tag: widget.name,
child: new Material(
child: new InkWell(
child: new Image.asset("assets/${widget.image}", fit: BoxFit.contain,),
)
))
),
new Name(name: widget.name,),
],
),
);
}
}
class Name extends StatefulWidget {
Name({this.name});
final String name;
#override
_NameState createState() => _NameState();
}
class _NameState extends State<Name> {
#override
String selectCurrency;
final currencySelected = TextEditingController();
var _formKey = GlobalKey<FormState>();
List <String> currencycategories = [
"IDR",
"MYR",
"USD",
"CNY"
];
Widget build(BuildContext context) {
final amount = TextEditingController();
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference collect= firestore.collection("Budget");
final FirebaseAuth _auth = FirebaseAuth.instance;
final User user =_auth.currentUser;
final uid = user.uid;
return Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Text(
widget.name,
textAlign: TextAlign.center,
style: new TextStyle(
fontSize: 25.0,
color: primary,
fontWeight: FontWeight.bold,
),
),
),
Row(
children: <Widget> [
new Expanded(child: new DropDownField(
controller: currencySelected,
labelText: getTranslated((context), "currency_hint"),
enabled: true,
itemsVisibleInDropdown: 4,
items: currencycategories,
onValueChanged: (dynamic value) {
selectCurrency = value;
},
value: selectCurrency,
required: false,
),
flex: 2,
),
new SizedBox(
width: 10.0,
),
new Expanded(child: TextFormField(
validator: (input) {
if (input.isEmpty) return 'Please fill up the text fields';
},
controller: amount,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: getTranslated((context), "budget_enter"),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
),
),
flex: 2,
)],
),
Padding(
padding: EdgeInsets.all(20.0),
child: ElevatedButton(
onPressed: () async {
final FirebaseAuth _auth = FirebaseAuth
.instance;
final User user = _auth.currentUser;
final uid = user.uid;
if(!_formKey.currentState.validate()){
return;
}
_formKey.currentState.save();
collect.add({
'name': this.widget.name,
'currency': selectCurrency,
'amount': amount.text,
});
amount.text = "";
Navigator.pop(context);
},
child: Text(getTranslated((context), "save_button").toUpperCase(), style: TextStyle (
fontSize: 14,
)),
style: ButtonStyle(
padding: MaterialStateProperty.all<EdgeInsets>(EdgeInsets.all(20.0)),
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
backgroundColor: MaterialStateProperty.all<Color>(Colors.pink),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: BorderSide(color: secondary)
),
),
),
),
)
],
),
)
)
],
),
)
);
}
}
Retrieve it to list view code
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/transaction.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import './transaction.dart' as expense;
import './transaction.dart' as income;
class TransactionMonthly extends StatefulWidget {
#override
_TransactionMonthlyState createState() => _TransactionMonthlyState();
}
class _TransactionMonthlyState extends State<TransactionMonthly> with SingleTickerProviderStateMixin {
TabController controller;
#override
void initState() {
controller = new TabController(vsync: this, length: 2);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(getTranslated(context, 'budget_title'),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Transactions()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('Budget').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data.docs.map((document) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
SizedBox(width: 10,),
Text(document.get('name'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 10,),
Row(children: [
SizedBox(width: 10,),
Text(document.get('currency'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
SizedBox(width: 10,),
Text(document.get('amount'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 8,),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: (){
Widget cancelButton = FlatButton(child: Text("Cancel"),
onPressed: (){
Navigator.pop(context);
},
);
Widget deleteButton = FlatButton(child: Text("Delete"),
onPressed: (){
FirebaseFirestore.instance.collection('Budget').doc(document.id).delete();
Navigator.pop(context);
},
);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Delete Budget'),
content: Text('Are you sure want to delete it?'),
actions: [
cancelButton,
deleteButton,
],
),
);
//_showDeleteDialog();
//_showDeleteDialog(document: document);
},
child: Row(
children: [
Icon(Icons.delete_forever_outlined,
color: Colors.red,
),
SizedBox(width: 6,),
Text('Delete', style: TextStyle(fontSize: 16,
color: Colors.red,
fontWeight: FontWeight.w600
), ),
],
),
)
],
)
],)
);
}).toList(),
);
}
return Center(
child: CircularProgressIndicator(),
);
}
),
);
}
}

I think what you want is a sort of group by name so that you show the food category with 160 in your example instead of two times the same category (Correct me if i am wrong). What i suggest is to first create a class named Budget with your three attributes name, currency and amount. When you receive your data in TransactionMonthly Streambuilder you need to group your snapshot data by name. Once you done that you create a list of budgets List<Budget> budgets so that you add the sum of amount per name of budgets.
Here is a sample code that you can use, you can simply copy paste it and try on DartPad by yourself:
import 'package:collection/collection.dart';
//DATA coming from your Firebase collection
Map<String, dynamic> data1 = {
'name':"Food",
'currency': "IDR",
'amount': 100,
};
Map<String, dynamic> data2 = {
'name':"Food",
'currency': "IDR",
'amount': 60,
};
Map<String, dynamic> data3 = {
'name':"Beauty",
'currency': "USD",
'amount': 120,
};
//Your Budget class
class Budget{
String currency;
String name;
int amount;
#override
String toString(){
return "Budget: {currency: $currency, name: $name, amount: $amount}";
}
Budget({required this.currency, required this.name, required this.amount});
}
void main(){
List<Map<String, dynamic>> snapshot = [data1, data2, data3];
List<Budget> budgets = [];
//you group your budgets by name so you will have: {'Food': [data1, data2], 'Beauty':[data3]}
final groupByName = groupBy(snapshot, (Map<String, dynamic> doc)=>doc['name']);
print(groupByName);
int totalAmount = 0;
String currency = "";
groupByName.forEach((name, value){
//because we grouped by name every value will have same currency
currency = value[0]['currency'];
//Here we calculate the sum of all Food
totalAmount = value.map((e)=>e['amount']).reduce((v, e)=> v+e);
budgets.add(Budget(currency: currency, amount: totalAmount, name: name));
});
//budgets is your final list to use in your listView
print(budgets);
}

Related

How to select multiple checkboxes in flutter in checkboxlisttile

Can anyone please tell me how do I select multiple options in checkboxlisttile.
Here I am able to click only one option. I want to set the status column in note table in database as completed when i check the particular item.
(Actually I want to select the item as completed and display it under another tab called completed. checkboxlisttile is created dynamically i.e from database. When a new note is added it is displayed in this listview.)
note_info.dart //this is the screen where notes are displayed i.e listview
import 'dart:io';
import 'package:vers2cts/models/note_model.dart';
import 'package:vers2cts/models/customer_model.dart';
import 'package:vers2cts/services/db_service.dart';
import 'package:vers2cts/utils/db_helper.dart';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'new_note.dart';
class Note_Info extends StatefulWidget{
final String appBarTitle;
final CustomerModel customer;
//Note_Info();
Note_Info(this. customer, this.appBarTitle);
#override
State<StatefulWidget> createState() {
//return Note_InfoState();
return Note_InfoState(this. customer,this.appBarTitle);
}
}
class Note_InfoState extends State<Note_Info> {
DBService dbService = DBService();
List<NoteModel> noteList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
NoteModel note=NoteModel();
String appBarTitle;
CustomerModel customer=new CustomerModel();
Note_InfoState(this.customer, this.appBarTitle);
bool rememberMe = false;
DateTime _date = DateTime.now();
TextEditingController custfNameController = TextEditingController();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
updateListView();
if (noteList == null) {
noteList = List<NoteModel>();
updateListView();
}
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
var height = MediaQuery.of(context).size.height;
var name=customer.first_name+" "+customer.last_name;
custfNameController.text = name;
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
Icons.add,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewNote(customer,note)));
},
)
],
),
body: Container(
child: Column(
children: <Widget>[
TextField(controller: custfNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(children: [
ImageProfile(customer.cust_photo),
Padding(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
icon: Icon(
Icons.call,
color: Colors.green,
size: 45,
),
onPressed: () {
},
),
),
],),
),
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
text: "All",
),
Tab(
text: "Pending",
),
Tab(
text: "Cancelled",
),
Tab(
text: "Completed",
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
child: getNotecheckList()
),
// second tab bar view widget
Container(
),
Container(
child: Center(
child: Text(
'Cancelled',
),
),
),
Container(
child: Center(
child: Text(
'Completed',
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme
.of(context)
.primaryColorDark,
textColor: Colors.white,
child: Text('Save', textScaleFactor: 1.5,),
onPressed: () {
setState(() {
//_reset();
});
},
),
),
),
]
),
)
));
}
Widget ImageProfile(String fileName) {
return Center(
child: CircleAvatar(
radius: 80.0,
backgroundImage: fileName == null
?AssetImage('images/person_icon.jpg')
:FileImage(File(customer.cust_photo))),
);
}
Future<void> updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
int cid=customer.cust_id;
Future<List<NoteModel>> noteListFuture = dbService.getCustomerNotes(cid);
noteListFuture.then((noteList) {
setState(() {
this.noteList = noteList;
this.count = noteList.length;
});
});
});
}
int _isChecked=-1;
ListView getNotecheckList() {
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: CheckboxListTile(
title: Text(this.noteList[position].note),
subtitle: Text(this.noteList[position].actn_on),
//secondary: const Icon(Icons.web),
value: position== _isChecked,
onChanged: (bool value) {
setState(() {
_isChecked = value?position:-1;
});
},
controlAffinity: ListTileControlAffinity.leading,
),
);
},
);
}
}
new_note.dart //this is where new note is added.
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
import 'package:intl/intl.dart';
import 'package:vers2cts/models/customer_model.dart';
import 'package:vers2cts/models/note_model.dart';
import 'package:vers2cts/services/db_service.dart';
import 'package:vers2cts/utils/form_helper.dart';
class NewNote extends StatefulWidget{
final NoteModel note;
final CustomerModel customer;
NewNote(this.customer,this. note);
//Dropdown
/*
final String label;
final Function(Color) onChanged;
final double height;
final double width;
NewNote.fordropdwn({
Key key,
this.onChanged,
this.height = 25,
this.width = 150,
this.label,
}) : super(key: key);*/
#override
State<StatefulWidget> createState() {
//return New_NoteState(this.customer);
return New_NoteState(this.customer,this.note);
}
}
class New_NoteState extends State<NewNote> with SingleTickerProviderStateMixin{
New_NoteState(this.customer,this.note);
NoteModel note=new NoteModel();
CustomerModel customer=new CustomerModel();
TextEditingController NoteController=TextEditingController();
TextEditingController custfNameController = TextEditingController();
DateTime _reminderDate = DateTime.now();
DBService dbService=new DBService();
SpeedDial _speedDial(){
return SpeedDial(
// child: Icon(Icons.add),
animatedIcon: AnimatedIcons.add_event,
animatedIconTheme: IconThemeData(size: 24.0),
backgroundColor: Colors.yellow,
curve: Curves.easeInCirc,
children: [
SpeedDialChild(
child: Icon(Icons.location_on,color: Colors.yellow,),
//backgroundColor: Theme.of(context).primaryColor,
label: 'Add Location',
//labelBackgroundColor:Theme.of(context).primaryColor,
),
SpeedDialChild(
child: Icon(Icons.keyboard_voice),
//backgroundColor: Colors.yellow,
label: 'Add voice',
//labelBackgroundColor: Colors.yellow
),
SpeedDialChild(
child: Icon(Icons.attachment_outlined,color :Colors.redAccent),
//backgroundColor:Theme.of(context).primaryColorLight,
label: 'Add File',
// labelBackgroundColor: Theme.of(context).primaryColorLight
),
SpeedDialChild(
child: Icon(Icons.image,color: Colors.lightBlue,),
//backgroundColor: Colors.yellow,
label: 'Add Image',
// labelBackgroundColor: Colors.yellow,
),
],
);
}
//for DropDownMenu
Color value=Colors.red;
final List<Color> colors = [
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow,
Colors.pink,
Colors.purple,
Colors.brown,
];
//for Switch
bool isSwitched = false;
var textValue = 'Switch is OFF';
void toggleSwitch(bool value) {
if(isSwitched == false)
{
setState(() {
isSwitched = true;
note.rmnd_ind=1;
//this.note.remindOn = _reminderDate.toString();
});
}
else
{
setState(() {
isSwitched = false;
note.rmnd_ind=0;
});
}
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
var name=customer.first_name+customer.last_name;
custfNameController.text = name;
return WillPopScope(
onWillPop: () {
// Write some code to control things, when user press Back navigation button in device navigationBar
moveToLastScreen();
},
child: Scaffold(
appBar:AppBar(),
body:ListView(
children: <Widget>[
SizedBox(
height: 2.0,
),
TextField(controller: custfNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Align(
alignment: Alignment.centerLeft,
child: Text("Add New",textAlign: TextAlign.left,
style: TextStyle(fontSize: 22,fontWeight: FontWeight.bold),),
),
SizedBox(
height: 2.0,
),
Divider(),
SizedBox(
height: 2.0,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: NoteController,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(width: 2.0),)),
keyboardType: TextInputType.multiline,
minLines: 5,//Normal textInputField will be displayed
maxLines: 5, // when user presses enter it will adapt to it
onChanged: (value) {
this.note.note = value;
},
),
),
TableCalendar(
selectedDayPredicate: (day) {
return isSameDay(_reminderDate, day);
},
onDaySelected: (selectedDay, focusedDay) {
setState(() {
String _reminderDate = DateFormat('dd-MM-yyyy').format(selectedDay);
note.actn_on=_reminderDate.toString();
});
},// Set initial date
focusedDay: DateTime.now(),
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),),
SizedBox(
height: height*0.03,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(//mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Remind me",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: Switch(
onChanged: toggleSwitch,
value: isSwitched,
//activeColor: Colors.blue,
//activeTrackColor: Colors.yellow,
//inactiveThumbColor: Colors.redAccent,
//inactiveTrackColor: Colors.orange,
),
),
),
],),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children:<Widget>[
Text("Priority",style: TextStyle(fontSize: 20.0),),
Padding(
padding: const EdgeInsets.only(left:20.0),
child: Container(
child: SmoothStarRating(
size: height=50.0,
allowHalfRating: false,
onRated: (value) {
this.note.prty=value;
print("rating value -> $value");
},
),
),
)]),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Color",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: DropdownButton<Color>(
value: value,
//hint: Text(widget.label ?? ''),
onChanged: (color) {
setState(() => value = color);
//widget.onChanged(color);
},
items: colors.map((e) => DropdownMenuItem(
value: e,
child: Container(
// width: 60.0,
//height: 10.0,
width: 60.0,
// height: widget.height,
color: e,
),
),
)
.toList(),
),
),
),
],),
),
SizedBox(
height: height*0.08,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme.of(context).primaryColorDark,
textColor: Colors.white,
child: Text('Save',textScaleFactor: 1.5,),
onPressed: (){
setState(() {
_save();
});
},
),
),
),
],
),
floatingActionButton:_speedDial(),
));
}
void moveToLastScreen() {
Navigator.pop(context, true);
}
void _save() async {
moveToLastScreen();
note.cust_id=customer.cust_id;
print(customer.cust_id);
print(note.cust_id);
int result;
if (note.note_id != null) { // Case 1: Update operation
result = await dbService.updateNote(note);
} else { // Case 2: Insert Operation
result = await dbService.insertNote(note);
}
if (result != 0) { // Success
FormHelper.showAlertDialog(context,'Status', 'Note Saved Successfully');
} else { // Failure
FormHelper.showAlertDialog(context,'Status', 'Problem Saving Note');
}
}
}
db_service.dart
import 'package:vers2cts/models/customer_model.dart';
import 'package:vers2cts/models/languages_model.dart';
import 'package:vers2cts/models/note_model.dart';
import 'package:vers2cts/models/user_model.dart';
import 'package:vers2cts/utils/db_helper.dart';
class DBService {
Future<int> insertNote(NoteModel note) async {
await DB.init();
var result = await DB.insert(NoteModel.table, note);
return result;
}
Future<List<NoteModel>> getCustomerNotes(int customer) async {
await DB.init();
var res = await DB.rawQuery("note WHERE cust_id = '$customer'");
int count = res.length;
List<NoteModel> notelist = List<NoteModel>();
// For loop to create a 'Note List' from a 'Map List'
for (int i = 0; i < count; i++) {
notelist.add(NoteModel.fromMap(res[i]));
}
return notelist;
}
}
note_model.dart
import 'model.dart';
class NoteModel extends Model {
static String table = 'note';
bool isSelected=false;
int note_id;
int cust_id;
String note;
String actn_on;
int rmnd_ind;
double prty;
String colr;
String sts;
int id;
String cre_date;
String cre_by;
String mod_date;
String mod_by;
int txn_id;
int delete_ind;
NoteModel({
this.note_id,
this.cust_id,
this.note,
this.actn_on,
this.rmnd_ind,
this.prty,
this.colr,
this.sts,
this.id,
this.cre_date,
this.cre_by,
this.mod_date,
this.mod_by,
this.txn_id,
this.delete_ind
});
static NoteModel fromMap(Map<String, dynamic> map) {
return NoteModel(
note_id: map["note_id"],
cust_id: map['cust_id'],
note: map['note'].toString(),
actn_on: map['actn_on'].toString(),
rmnd_ind: map['rmnd_ind'],
prty: map['prty'],
colr: map['colr'].toString(),
sts: map['sts'].toString(),
id: map['id'],
cre_date: map['cre_date'].toString(),
cre_by: map['cre_by'].toString(),
mod_date: map['mod_date'].toString(),
mod_by: map['mod_by'].toString(),
txn_id: map['txn_id'],
delete_ind: map['delete_ind'],
);
}
Map<String, dynamic> toMap() {
Map<String, dynamic> map = {
'note_id': note_id,
'cust_id': cust_id,
'note':note,
'actn_on': actn_on,
'rmnd_ind': rmnd_ind,
'prty': prty,
'colr': colr,
'sts':sts,
'id': id,
'cre_date': cre_date,
'cre_by': cre_by,
'mod_date':mod_date,
'mod_by':mod_by,
'txn_id':txn_id,
'delete_ind': delete_ind
};
if (note_id != null) {
map['note_id'] = note_id;
}
return map;
}
}
db_helper.dart
import 'dart:async';
import 'package:vers2cts/models/model.dart';
import 'package:path/path.dart' as p;
import 'package:sqflite/sqflite.dart';
abstract class DB {
static Database _db;
static int get _version => 1;
static Future<Database> init() async {
if (_db != null) {
return _db;
}
try {
var databasesPath = await getDatabasesPath();
String _path = p.join(databasesPath, 'CTS.db');
_db = await openDatabase(_path, version: _version, onCreate: onCreate);
print('db location:'+_path);
} catch (ex) {
print(ex);
}
}
static void onCreate(Database db, int version) async {
await db.execute(
'CREATE TABLE note (note_id INTEGER PRIMARY KEY,cust_id INTEGER, '
'note TEXT, '
'actn_on TEXT, rmnd_ind INTEGER, prty REAL, colr TEXT,'
'sts TEXT,'
'id INTEGER, cre_date TEXT,cre_by TEXT, mod_date TEXT,mod_by TEXT, txn_id INTEGER, delete_ind INTEGER)');
}
static Future<List<Map<String, dynamic>>> query(String table) async =>
_db.query(table);
static Future<int> insert(String table, Model model) async =>
await _db.insert(table, model.toMap());
static Future<Batch> batch() async => _db.batch();
static Future<List<Map<String, dynamic>>> rawQuery(String table) async =>
_db.query(table);
}
You need to store what all values are selected from user and then play with it.
For example -
var selectedIndexes = [];
ListView getNotecheckList() {
return ListView.builder(
itemCount: count,
itemBuilder: (_, int index) {
return Card(
color: Colors.white,
elevation: 2.0,
child: CheckboxListTile(
title: Text(this.noteList[position].note),
subtitle: Text(this.noteList[position].actn_on),
value: selectedIndexes.contains(index),
onChanged: (_) {
if (selectedIndexes.contains(index)) {
selectedIndexes.remove(index); // unselect
} else {
selectedIndexes.add(index); // select
}
},
controlAffinity: ListTileControlAffinity.leading,
),
);
},
);
}
store only index or whole array and play around
Output :-
Code :-
import 'package:flutter/material.dart';
class CheckBoxExample extends StatefulWidget {
const CheckBoxExample({Key? key}) : super(key: key);
#override
State<CheckBoxExample> createState() => _CheckBoxExampleState();
}
class _CheckBoxExampleState extends State<CheckBoxExample> {
List multipleSelected = [];
List checkListItems = [
{
"id": 0,
"value": false,
"title": "Sunday",
},
{
"id": 1,
"value": false,
"title": "Monday",
},
{
"id": 2,
"value": false,
"title": "Tuesday",
},
{
"id": 3,
"value": false,
"title": "Wednesday",
},
{
"id": 4,
"value": false,
"title": "Thursday",
},
{
"id": 5,
"value": false,
"title": "Friday",
},
{
"id": 6,
"value": false,
"title": "Saturday",
},
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 64.0),
child: Column(
children: [
Column(
children: List.generate(
checkListItems.length,
(index) => CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
dense: true,
title: Text(
checkListItems[index]["title"],
style: const TextStyle(
fontSize: 16.0,
color: Colors.black,
),
),
value: checkListItems[index]["value"],
onChanged: (value) {
setState(() {
checkListItems[index]["value"] = value;
if (multipleSelected.contains(checkListItems[index])) {
multipleSelected.remove(checkListItems[index]);
} else {
multipleSelected.add(checkListItems[index]);
}
});
},
),
),
),
const SizedBox(height: 64.0),
Text(
multipleSelected.isEmpty ? "" : multipleSelected.toString(),
style: const TextStyle(
fontSize: 22.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}

Flutter - unable to produce variable from data in Cloud Firestore - undefined name error

I am trying to use a list from a Cloud Firestore document field (called 'a_ge_vi') to populate my DropdownMenu options. This takes the form of an array of strings (see attached image).
However, when I try to produce the List<String> with data from Cloud Firestore and put it in the variable _partyList2, I get the error in the console of Undefined name '_partyList2'. I created a version of the list in Flutter and this works fine - it is shown as _partyList. But really I want to use the data from Cloud Firestore so I can change the values when I need to.
Can anyone help with why this isn't working?
PS. It is worth noting that this text widget Text(snapshot.data.documents[0]['q01'] does show q01, which is also a field in my Cloud Firestore document so I am connecting to the database.
I have the following code:
import 'package:flutter/material.dart';
import 'package:rewardpolling/pages/login_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
final responseInstance = Firestore.instance;
final _auth = FirebaseAuth.instance;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
List<String> _partyList = <String>[
"Conservatives",
"Labour",
"Liberal Democrats",
"SNP",
"Plaid Cymru",
"The Brexit Party",
"Other",
"I would not vote"
];
class TestSurvey extends StatefulWidget {
static const String id = 'TestSurvey';
#override
_TestSurveyState createState() => _TestSurveyState();
}
class _TestSurveyState extends State<TestSurvey> {
var selectedParty, submittedParty, userid;
#override
void initState() async {
super.initState();
await Firestore.instance
.collection('MySurveys')
.document('FirestoreTestSurvey')
.get()
.then((DocumentSnapshot document) {
List<String> _partyList2 = document.data['a_ge_vi'];
print(_partyList2);
});
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xffEEEEEE),
appBar: AppBar(
backgroundColor: Color(0xff303841),
title: Center(child: Text('Test Survey')),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, LoginScreen.id);
}),
],
leading: Padding(padding: EdgeInsets.only(left: 12), child: Text(' ')),
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: FormBuilder(
key: _fbKey,
child: ListView(
children: <Widget>[
Padding(padding: EdgeInsets.all(16.0)),
StreamBuilder(
stream:
Firestore.instance.collection('MySurveys').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading data');
return Column(
children: <Widget>[
Text(
snapshot.data.documents[0]['q01'],
textAlign: TextAlign.left,
overflow: TextOverflow.visible,
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "Roboto",
fontSize: 20),
),
DropdownButton(
items: _partyList2
.map((value) => DropdownMenuItem<dynamic>(
child: Text(
value,
style:
TextStyle(color: Color(0xff303841)),
),
value: value,
))
.toList(),
onChanged: (selectedParty) {
setState(() {
submittedParty = selectedParty;
});
},
value: submittedParty,
isExpanded: true,
hint: Text(
'Please choose an option',
style: TextStyle(color: Color(0xff303841)),
),
),
SizedBox(
width: double.infinity,
child: RaisedButton(
child: Text('Submit Survey'),
onPressed: () async {
final FirebaseUser user =
await _auth.currentUser();
final String userid = user.uid;
responseInstance
.collection("testSurvey08052020")
.add({
"user_id": userid,
"ge_vi": submittedParty,
"submission_time": DateTime.now()
});
})),
],
);
},
),
],
),
)),
);
}
}
I see that you have defined the List<String> _partyList2 = document.data['a_ge_vi']; in the initState.Its an issue of scope as the rest of code doesn't have access to the variable _partyList2;
What you can do is define the variable in the state and then assign it in initState
Hope this answers your question.
As mentioned by Shubham this issue is due to scope, as _partyList2 is only accessible in method initState the solution to this is add a variable that is accesible in other parts of the code and setting it to this value on initState.
I corrected the code and added below:
import 'package:flutter/material.dart';
import 'package:rewardpolling/pages/login_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
final responseInstance = Firestore.instance;
final _auth = FirebaseAuth.instance;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
List<String> _partyList = <String>[
"Conservatives",
"Labour",
"Liberal Democrats",
"SNP",
"Plaid Cymru",
"The Brexit Party",
"Other",
"I would not vote"
];
class TestSurvey extends StatefulWidget {
static const String id = 'TestSurvey';
#override
_TestSurveyState createState() => _TestSurveyState();
}
class _TestSurveyState extends State<TestSurvey> {
var selectedParty, submittedParty, userid, usablePartyList;
#override
void initState() async {
super.initState();
await Firestore.instance
.collection('MySurveys')
.document('FirestoreTestSurvey')
.get()
.then((DocumentSnapshot document) {
List<String> _partyList2 = document.data['a_ge_vi'];
print(_partyList2);
usablePartyList = _partyList2;
});
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xffEEEEEE),
appBar: AppBar(
backgroundColor: Color(0xff303841),
title: Center(child: Text('Test Survey')),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, LoginScreen.id);
}),
],
leading: Padding(padding: EdgeInsets.only(left: 12), child: Text(' ')),
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: FormBuilder(
key: _fbKey,
child: ListView(
children: <Widget>[
Padding(padding: EdgeInsets.all(16.0)),
StreamBuilder(
stream:
Firestore.instance.collection('MySurveys').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading data');
return Column(
children: <Widget>[
Text(
snapshot.data.documents[0]['q01'],
textAlign: TextAlign.left,
overflow: TextOverflow.visible,
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "Roboto",
fontSize: 20),
),
DropdownButton(
items: usablePartyList
.map((value) => DropdownMenuItem<dynamic>(
child: Text(
value,
style:
TextStyle(color: Color(0xff303841)),
),
value: value,
))
.toList(),
onChanged: (selectedParty) {
setState(() {
submittedParty = selectedParty;
});
},
value: submittedParty,
isExpanded: true,
hint: Text(
'Please choose an option',
style: TextStyle(color: Color(0xff303841)),
),
),
SizedBox(
width: double.infinity,
child: RaisedButton(
child: Text('Submit Survey'),
onPressed: () async {
final FirebaseUser user =
await _auth.currentUser();
final String userid = user.uid;
responseInstance
.collection("testSurvey08052020")
.add({
"user_id": userid,
"ge_vi": submittedParty,
"submission_time": DateTime.now()
});
})),
],
);
},
),
],
),
)),
);
}
}
flutter dart google-cloud-firestore

how to display data in flutter firestore provider

I want to display data from firestore using provider in flutter. i got stuck please help. below are my codes
//product display page
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
class Product extends StatefulWidget {
#override
_ProductState createState() => _ProductState();
}
class _ProductState extends State<Product> {
#override
Widget build(BuildContext context) {
final product = Provider.of<AppProvider>(context);
return GridView.builder(
itemCount: productList.length,
gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
itemBuilder: (BuildContext context, int index){
return Padding(
padding:const EdgeInsets.all(4.0),
child:SingleProd(
//where i want to get the product details
prodName: product.featuredProducts[index].name.toString(),
),
);
}
);
}
}
class SingleProd extends StatelessWidget {
final prodName;
final prodPicture;
final prodOldPrice;
final prodPrice;
SingleProd({this.prodName, this.prodPicture,this.prodOldPrice,this.prodPrice});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(tag: new Text("hero 1"),
child:
Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
//here we are passing the value of the products to Product detail page
productDetailName:prodName,
)
)
),
child:GridTile(
footer: Container(
color: Colors.white,
child: new Row(
children: <Widget>[
new Expanded(
child: new Text(prodName, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
),
new Text(
"\$$prodPrice", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
],
)
),
child: Image.asset(prodPicture,
fit: BoxFit.cover,),
),
),
),
),
);
}
}
//product class
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
class Product{
static const ID = "id";
static const CATEGORY = "category";
static const NAME = "name";
static const PRICE = "price";
static const BRAND = "brand";
static const COLORS = "colors";
static const QUANTITY = "quantity";
static const SIZES = "sizes";
static const SALE = "sale";
static const FEATURED = "featured";
static const PICTURE = "picture";
String _id;
String _name;
String _brand;
String _category;
String _picture;
double _price;
int _quantity;
List _colors;
List _sizes;
bool _onSale;
bool _featured;
// getters
String get name => _name;
String get id => _id;
String get category => _category;
String get brand => _brand;
String get picture => _picture;
double get price => _price;
int get quantity => _quantity;
List get colors => _colors;
List get sizes => _sizes;
bool get onSale => _onSale;
bool get featured => _featured;
// named constructure
Product.fromSnapshot(DocumentSnapshot snapshot){
Map data = snapshot.data;
_name = data[NAME];
_id = data[ID];
_category = data[CATEGORY];
_brand = data[BRAND];
_price = data[PRICE];
_quantity = data[QUANTITY];
_colors = data[COLORS];
_onSale = data[SALE];
_featured = data[FEATURED];
_picture = data[PICTURE];
}
}
//provider page for the product
import 'package:flutter/material.dart';
import 'package:shopping/db/product.dart';
import 'package:shopping/models/product.dart';
class AppProvider with ChangeNotifier {
List<Product>_fearturedProducts=[];
//method
void _getFeaturedProducts()async{
_fearturedProducts=await _productService.getFeaturedProducts();
notifyListeners();
}
}
//connection to Firestore to collect data
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/models/product.dart';
class ProductService{
Firestore _firestore=Firestore.instance;
String collection="Products";
Future<List<Product>>getFeaturedProducts(){
_firestore.collection(collection).where('featured', isEqualTo:true).getDocuments()
.then((snap){
List<Product>featuredProducts=[];
snap.documents.map((snapshot)=> featuredProducts.add(Product.fromSnapshot(snapshot)));
return featuredProducts;
});
}
}
guys, I have managed to solve the question. The answer is as follow //product page
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
import 'package:shopping/models/product.dart';
class Products extends StatefulWidget {
#override
ProductsState createState() => ProductsState();
}
class ProductsState extends State<Products> {
List<Product> products;
#override
Widget build(BuildContext context) {
final productProvider = Provider.of<CRUDModel>(context);
return StreamBuilder<QuerySnapshot>(
stream: productProvider.fetchProductsAsStream(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
products = snapshot.data.documents
.map((doc) => Product.fromMap(doc.data, doc.documentID))
.toList();
return GridView.builder(
itemCount: products.length,
gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
itemBuilder: (BuildContext context, index){
return Padding(
padding:const EdgeInsets.all(4.0),
child:SingleProd(
product:products[index]
// prodPicture: productList[index]['picture'],
//prodOldPrice: productList[index]['oldPrice'],
//prodPrice: productList[index]['price'],
),
);
}
);
}
else {
return Text('fetching');
}
}
);
}
}
class SingleProd extends StatelessWidget {
//final prodName;
//final prodPicture;
//final prodOldPrice;
//final prodPrice;
final Product product;
SingleProd({ #required this.product});
//SingleProd({product.picture});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(tag: product.id,
child:
Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
//here we are passing the value of the products to Product detail page
productDetailName:product.name,
productDetailNewPrice:product.price,
productDetailPicture:product.picture,
//productDetailOldPrice:prodOldPrice,
//productDetailNewPrice:prodPrice,
//productDetailPicture: prodPicture,
)
)
),
child:GridTile(
footer: Container(
color: Colors.white,
child: new Row(
children: <Widget>[
new Expanded(
child: new Text(product.name, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
),
new Text(
'${product.price} \$', style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
],
)
),
child: Image.asset('assets/${product.picture}.jpg',
fit: BoxFit.cover,),
),
),
),
),
);
}
}
//product class
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:ui';
class Product {
String id;
String name;
String brand;
String category;
String picture;
double price;
int quantity;
List colors;
List sizes;
bool sale;
bool featured;
Product(
{this.id, this.name, this.brand,
this.category, this.picture,this.price,
this.quantity,this.colors,this.sizes,this.sale,this.featured}
);
Product.fromMap(Map snapshot,String id) :
id = id ?? '',
name= snapshot['name'] ?? '',
brand = snapshot['brand'] ?? '',
category = snapshot['category'] ?? '',
picture= snapshot['picture'] ?? '',
price= snapshot['price'] ?? '',
quantity= snapshot['quantity'] ?? '',
colors= snapshot['colors'] ?? '',
sizes= snapshot['sizes'] ?? '',
sale= snapshot['sale'] ?? '',
featured= snapshot['featured'] ?? '';
toJson() {
return {
"name": name,
"brand": brand,
"category": category,
"picture": picture,
"price": price,
"quantity": quantity,
"colors": colors,
"sizes": sizes,
"sale": sale,
"featured": brand,
};
}
}
//provider class for the product
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/db/Api.dart';
import 'package:shopping/models/product.dart';
class CRUDModel extends ChangeNotifier {
//Api _api = locator<Api>();
String path="Products";
Api _api= Api();
List<Product> products;
Future<List<Product>> fetchProducts() async {
var result = await _api.getDataCollection();
products = result.documents
.map((doc) => Product.fromMap(doc.data, doc.documentID))
.toList();
notifyListeners();
return products;
}
Stream<QuerySnapshot> fetchProductsAsStream() {
notifyListeners();
return _api.streamDataCollection();
}
Future<Product> getProductById(String id) async {
var doc = await _api.getDocumentById(id);
notifyListeners();
return Product.fromMap(doc.data, doc.documentID) ;
}
}
//connection to firestore
import 'package:cloud_firestore/cloud_firestore.dart';
class Api{
final Firestore _db = Firestore.instance;
String ref="Products";
//CollectionReference ref;
/*Api({this.path } ) {
ref = _db.collection(path);
}*/
Future<QuerySnapshot> getDataCollection() {
//return ref.getDocuments() ;
return _db.collection(ref).where('featured', isEqualTo:true).getDocuments();
}
Stream<QuerySnapshot> streamDataCollection() {
// return ref.snapshots() ;
//return _db.snapshots(ref).getDocuments();
return _db.collection(ref).snapshots();
}
Future<DocumentSnapshot> getDocumentById(String id) {
// return ref.document(id).get();
return _db.document(id).get();
}
Future<void> removeDocument(String id){
//return ref.document(id).delete();
return _db.document(id).delete();
}
Future<DocumentReference> addDocument(Map data) {
// return ref.add(data);
return _db.collection(ref).add(data);
}
Future<void> updateDocument(Map data , String id) {
//return ref.document(id).updateData(data) ;
return _db.document(ref).updateData(data);
}
}
//homepage where i displayed the products
import 'package:flutter/material.dart';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:shopping/commons/common.dart';
import 'package:provider/provider.dart';
import 'package:shopping/provider/app_provider.dart';
import '../provider/user_provider.dart';
//My packages imports
import 'package:shopping/componets/horizontal_listview.dart';
import 'package:shopping/componets/product.dart';
import 'package:shopping/pages/cart.dart';
import 'package:shopping/pages/login.dart';
class HomePage extends StatefulWidget {
// List<Product> products;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController _searchController = new TextEditingController();
//final FirebaseAuth _firebaseAuth=FirebaseAuth.instance;
#override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context);
final productProvider=Provider.of<CRUDModel>(context);
Widget image_carousel = new Container(
height: 200.0,
child: new Carousel(
boxFit: BoxFit.cover,
images: [
AssetImage('images/c1.jpg'),
AssetImage('images/m1.jpeg'),
AssetImage('images/m2.jpg'),
AssetImage('images/w1.jpeg'),
AssetImage('images/w3.jpeg'),
AssetImage('images/w4.jpeg'),
],
autoplay:true,
animationCurve: Curves.fastOutSlowIn,
animationDuration: Duration(milliseconds:1000 ),
dotSize: 4.0,
indicatorBgPadding: 8.0,
dotBgColor: Colors.transparent,
),
);
return Scaffold(
appBar: new AppBar(
iconTheme: IconThemeData(color: blue),
elevation: 0.1,
backgroundColor: white,
title: Material(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[50],
elevation: 0.0,
child: TextFormField(
controller: _searchController,
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
validator: (value) {
if (value.isEmpty) {
return "The Search field cannot be empty";
}
return null;
}),
),
actions: <Widget>[
new IconButton(
icon: Icon(
Icons.search,
color: blue,
),
onPressed: () {},
),
new IconButton(
icon: Icon(
Icons.shopping_cart,
color: blue,
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => new Cart()));
}),
],
),
drawer: new Drawer(
child: new ListView(
children: <Widget>[
//drawer header
new UserAccountsDrawerHeader(
accountName: Text("Afolabi"),
accountEmail: Text("mtreal62#gmail.com"),
currentAccountPicture: GestureDetector(
child: new CircleAvatar(
backgroundColor: Colors.grey,
child: Icon(
Icons.person,
color: Colors.white,
),
),
),
decoration: BoxDecoration(
color: blue,
),
),
//body
InkWell(
onTap: () {},
child: ListTile(
title: Text("Home Page"),
leading: Icon(
Icons.home,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("My Account"),
leading: Icon(
Icons.person,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("My Orders"),
leading: Icon(
Icons.shopping_basket,
color: blue,
),
),
),
InkWell(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => new Cart()));
},
child: ListTile(
title: Text("Shopping Cart"),
leading: Icon(
Icons.shopping_cart,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("Favourites"),
leading: Icon(
Icons.favorite,
color: blue,
),
),
),
Divider(),
InkWell(
onTap: () {},
child: ListTile(
title: Text("Settings"),
leading: Icon(
Icons.settings,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("About"),
leading: Icon(
Icons.help,
),
),
),
InkWell(
onTap: () {
user.signOut();
// changeScreenReplacement(context, Login());
},
child: ListTile(
title: Text("Log Out"),
leading: Icon(
Icons.transit_enterexit,
),
),
),
],
),
),
body: new Column(
children: <Widget>[
//Image Carousel for the home Page Banner
image_carousel,
//padding widget after carousel
new Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.centerLeft,
child: new Text("Categories"),
),
),
//Horizontal layout start from here
HorizontalList(),
//End of the horizontal layout
//padding widget for Recent products categories
new Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.centerLeft,
child: new Text("Recent Products"),
),
),
// Text(appProvider.featuredProducts.length.toString(),
//style: TextStyle(color: Colors.black),),
Flexible(
child: Products(),
),
//Horizontal layout start from here
],
),
);
}
}
Future _signOut() async {
try {
await FirebaseAuth.instance.signOut();
} catch (e) {
print(e); // TODO: show dialog with error
}
}
You are never calling _getFeaturedProducts() from your AppProvider class. So _fearturedProducts will always be null
In class AppProvider you are calling method on undefined name:
_productService.getFeaturedProducts()
Every IDE should show you this error ex. In my Android Studio it looks like this:

having an problem designing Provider design to flutter application

The main reason i want to change the design is that when i scan a product and then scan the same one i get the same product twice while it is the same one so basically i just need to increase the quantity of the product by one.
I have used Provider before but I still can't manage to arrange the classes the right way to make it work.
first i have tried to make a Productobject(which extenes ChangeNotifier) inside ProductCard class and use provider.of(context) and retrieve the quantity of the prodcut.
plus,at the main before the material I used ChangeNotifierProvider
I have a mess in my head and i would love to see someone arranging the code with explanation of how the things works
main
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sally_smart/utilities/product_notifier.dart';
import 'screens/checkout_screen.dart';
import 'screens/login_screen.dart';
import 'screens/registration_screen.dart';
import 'screens/welcome_screen.dart';
import 'package:provider/provider.dart';
//void main() => runApp(Sally());
void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(new Sally());
});
}
class Sally extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
backgroundColor: Colors.teal,
cardColor: Color(0xFF068194),
),
initialRoute: LoginScreen.id,
routes: {
WelcomeScreen.id: (context) => WelcomeScreen(),
RegistrationScreen.id: (context) => RegistrationScreen(),
LoginScreen.id: (context) => LoginScreen(),
CheckoutScreen.id: (context) => CheckoutScreen()
},
);
}
}
ProductCard
import 'package:flutter/material.dart';
import 'package:sally_smart/utilities/constants.dart';
import 'package:sally_smart/utilities/product.dart';
import 'package:sally_smart/utilities/round_icon_button.dart';
class ProductCard extends StatefulWidget {
final Product prodcut;
ProductCard(Product product);
#override
_ProductCardState createState() => _ProductCardState();
}
class _ProductCardState extends State<ProductCard> {
double finalPrice;
// static int quantity = 1;
#override
Widget build(BuildContext context) {
finalPrice = widget.prodcut.quantity * widget.prodcut.productPrice;
return Card(
elevation: 5.0,
child: ListTile(
leading: Padding(
padding: EdgeInsets.only(
left: 2.0,
),
child: Icon(
widget.prodcut.productIcon,
size: 35,
),
),
title: Text(
widget.prodcut.productName,
style: kProductNameTextStyle,
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RoundIconButton(
icon: Icons.add,
color: Colors.green,
function: () {
setState(() {
widget.prodcut.quantity++;
});
}),
Text(
'$widget.prodcut.quantity',
),
RoundIconButton(
icon: Icons.remove,
color: Colors.red,
function: () {
setState(() {
widget.prodcut.quantity--;
if ( widget.prodcut.quantity == 0) {
widget.prodcut.quantity++;
}
});
}),
],
),
),
Text(
'${finalPrice.toStringAsFixed(2)} ₪',
style: TextStyle(fontSize: 15),
),
],
),
),
);
}
}
Prodcut
import 'package:flutter/cupertino.dart';
class Product extends ChangeNotifier{
String productName;
double productPrice;
IconData productIcon;
String id;
String barCode;
int quantity;
Product(this.productName, this.productPrice, this.productIcon, this.id,
this.barCode,this.quantity);
}
welcome screen
import 'package:audioplayers/audio_cache.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
import 'package:sally_smart/screens/login_screen.dart';
import 'package:sally_smart/screens/registration_screen.dart';
import 'package:sally_smart/utilities/constants.dart';
import 'package:sally_smart/utilities/product.dart';
import 'package:sally_smart/utilities/product_card.dart';
import 'package:sally_smart/utilities/scan_button_const.dart';
import 'package:sally_smart/utilities/scan_methods.dart';
//import 'package:sally_smart/utilities/scan_pageML.dart';
//import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart';
//import 'package:firebase_ml_vision/firebase_ml_vision.dart';
//working version
//List<ProductCard> shoppingList = [];
final sallyDatabase = Firestore.instance;
class WelcomeScreen extends StatefulWidget {
static const String id = 'welcome_screen';
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> {
final _auth = FirebaseAuth.instance;
final textEditorController = TextEditingController();
String _scanBarcode = 'Unknown';
String productName = 'Product Test';
double productPrice;
String productBarCode;
IconData productIcon = Icons.add_shopping_cart;
final List<ProductCard> shoppingList = [];
int productId = 0;
static AudioCache barcodeSound = AudioCache();
// saves barcodes data
List<String> data = [];
Future<void> initPlatformState() async {
String barcodeScanRes;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
barcodeScanRes =
await FlutterBarcodeScanner.scanBarcode("#ff6666", "Cancel", true);
} 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;
setState(() {
_scanBarcode = barcodeScanRes;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF21bacf),
appBar: AppBar(
elevation: 3,
backgroundColor: Colors.black54,
leading: Icon(
Icons.shopping_basket,
size: 30,
),
title: Text(
'Sally',
textAlign: TextAlign.end,
style: kHeaderTextStyle,
),
actions: <Widget>[
IconButton(icon: Icon(Icons.settings), onPressed: () {}),
VerticalDivider(
color: Color(0x8CFFFFFF),
width: 3,
),
IconButton(
icon: Icon(Icons.power_settings_new),
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, LoginScreen.id);
}),
VerticalDivider(
color: Color(0x8CFFFFFF),
width: 3,
),
IconButton(icon: Icon(Icons.share), onPressed: () {}),
VerticalDivider(
color: Color(0x8CFFFFFF),
width: 3,
),
// PopupMenuButton(itemBuilder: ),
],
),
body: Container(
decoration: kBackgroundGradientScan,
child: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'ברוכה הבאה, סאלי',
textAlign: TextAlign.right,
style: kHeaderTextStyle,
),
Padding(
padding: EdgeInsets.only(top: 5, right: 15),
child: Hero(
tag: 'Sally',
child: CircleAvatar(
backgroundImage:
AssetImage('images/missing_avatar_F.png'),
maxRadius: 25,
),
),
)
],
),
Padding(
padding: EdgeInsets.symmetric(vertical: 3, horizontal: 15),
child: TextField(
textAlign: TextAlign.center,
onChanged: (value) async {
_scanBarcode = value;
productPrice = await getProductPrice(_scanBarcode);
productName = await getProductName(_scanBarcode);
},
decoration: kTextFieldDecoration.copyWith(
prefixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: () {
_scanBarcode = '';
textEditorController.clear();
try {
setState(() {
textEditorController.clear();
//checking if a product was already scanned
//adding a ProductCard to the shopping list with the ProductCard const. Works on scan
shoppingList.add(ProductCard( new Product(productName, productPrice, productIcon, shoppingList.length.toString(),
productBarCode, 1)));
});
} catch (e) {
print(e);
}
},
),
// prefix: IconButton(
// icon: Icon(Icons.search),
// onPressed: () {
//
// }),
hintText: '...הכנס ברקוד או שם מוצר ידנית'),
),
),
DividerSally(),
shoppingListBuilder(),
DividerSally(),
Container(
child: Padding(
padding: EdgeInsets.only(bottom: 15.0),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: Column(
children: <Widget>[
ScanMainButton(
iconData: Icons.flip,
buttonText: 'סרוק מוצר',
onPressed: () async {
//Navigator.pushNamed(context, ScanScreen.id);
await initPlatformState();
barcodeSound.play('barcode_sound.mp3');
//Changes the product name by referencing to the database
productBarCode = _scanBarcode;
productPrice =
await getProductPrice(_scanBarcode);
productName =
await getProductName(_scanBarcode);
setState(() {
//checking if a product was already scanned
//adding a ProductCard to the shopping list with the ProductCard const. Works on scan
shoppingList.add(ProductCard( new Product(productName, productPrice, productIcon, shoppingList.length.toString(),
productBarCode, 1)));
});
},
color: Colors.teal,
),
ScanMainButton(
iconData: Icons.check,
buttonText: 'מעבר לתשלום',
color: Colors.green,
onPressed: () {
Navigator.pushNamed(
context, RegistrationScreen.id);
}),
],
),
),
),
)
],
),
),
),
));
}
Expanded shoppingListBuilder() {
return Expanded(
child: Container(
color: Colors.black38,
child: ListView.builder(
reverse: true,
itemCount: shoppingList.length,
itemBuilder: (context, index) {
ProductCard item = shoppingList[index];
return Dismissible(
key: Key(item.prodcut.id),
direction: DismissDirection.startToEnd,
onDismissed: (direction) {
setState(() {
shoppingList.removeAt(index);
});
},
background: Container(
child: Icon(
Icons.restore_from_trash,
size: 40,
),
margin: EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
Color(0x8C650223),
Color(0x8CB9013E),
],
stops: [0.1, 0.9],
),
),
),
child: item //ListTile(title: Text('${item.productName}.')),
);
},
),
));
}
}

How to pass data back from a widget?

I have a screen where users can add a location. Here, I have separated all my widgets into there own files as illustrated below;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttershare/pages/location/location_help_screen.dart';
import 'package:fluttershare/widgets/common_widgets/customDivider.dart';
import 'package:uuid/uuid.dart';
import '../../widgets/camp_type_select.dart';
import '../../widgets/extra_location_notes.dart';
import '../../widgets/location_input.dart';
import '../../widgets/opening_times.dart';
import '../../widgets/post_media.dart';
import '../../widgets/space_avalibility.dart';
import '../../widgets/utility_type_select.dart';
import '../../widgets/width_restriction.dart';
import '../../widgets/height_restriction.dart';
import '../../models/locations.dart';
import '../../models/user.dart';
import '../home.dart';
class AddNewLocation extends StatefulWidget {
static const routeName = '/add-new-location';
final User currentUser;
AddNewLocation({this.currentUser});
_AddNewLocationState createState() => _AddNewLocationState();
}
class _AddNewLocationState extends State<AddNewLocation> {
String postId = Uuid().v4();
final _scaffoldKey = GlobalKey<ScaffoldState>();
PlaceLocation _pickedLocation;
int storyPostCount = 0;
bool isLoading = false;
void _selectPlace(double lat, double lng) {
_pickedLocation = PlaceLocation(lattitude: lat, longitude: lng);
}
getLocationPostCount() async {
setState(() {
isLoading = true;
});
QuerySnapshot snapshot = await locationPostRef
.document(currentUser.id)
.collection('user_location_posts')
.getDocuments();
setState(() {
storyPostCount = snapshot.documents.length;
});
}
createLocationPostInFirestore(
{String mediaUrl,
String description,
double heightRestriction,
double widthRestriction}) {
locationPostRef
.document(currentUser.id)
.collection("user_location_posts")
.document(postId)
.setData({
"postId": postId,
"ownerId": currentUser.id,
"username": currentUser.username,
"description": description,
"timestamp": timestamp,
"lattitude": _pickedLocation.lattitude,
"longitude": _pickedLocation.longitude,
"max_height": heightRestrictionValue.toStringAsFixed(0),
"max_width": widthRestrictionValue.toStringAsFixed(0),
});
}
handlePostSubmit() {
createLocationPostInFirestore(
heightRestriction: heightRestrictionValue,
widthRestriction: widthRestrictionValue,
);
SnackBar snackbar = SnackBar(
content: Text("Profile Updated"),
);
_scaffoldKey.currentState.showSnackBar(snackbar);
setState(() {
postId = Uuid().v4();
});
}
buildUploadUserHeader() {
return Container(
margin: EdgeInsets.only(bottom: 10),
height: 200,
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage:
CachedNetworkImageProvider(currentUser.photoUrl)),
),
],
),
),
),
Expanded(
flex: 6,
child: Container(
color: Colors.pink,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(currentUser.displayName),
],
),
),
),
],
),
);
}
buildCampUploadForm() {
return Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
//buildUploadUserHeader(), //TODO: This is the profile header that is dissabled for now. Work on possibly a header in the future.
Container(
padding: EdgeInsets.all(15),
child: Column(
children: <Widget>[
CampTypeSelect(),
CustomDivider(),
LocationInput(_selectPlace),
CustomDivider(),
HeightRestriction(),
WidthRestriction(),
SpaceAvalibility(),
OpeningTimes(),
CustomDivider(),
PostMedia(),
CustomDivider(),
UtilityServices(),
CustomDivider(),
ExtraLocationNotes(),
Container(
height: 80,
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Row(
children: <Widget>[
Expanded(
child: FlatButton(
color: Colors.black,
onPressed: () => handlePostSubmit(),
child: Text(
"SUBMIT",
style: Theme.of(context).textTheme.display2,
),
padding: EdgeInsets.all(20),
),
)
],
),
),
],
),
),
],
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text(
'Add New Location',
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
// action button
IconButton(
icon: Icon(Icons.info_outline),
color: Colors.black,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => LocationSubmitHelpScreen()),
);
},
),
// action button
IconButton(
icon: Icon(Icons.close),
color: Colors.black,
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
body: buildCampUploadForm(),
backgroundColor: Colors.white,
);
}
}
What I am trying to do is pass the data back from the widget ExtraLocationNotes()
to the function createLocationPostInFirestore().
For context, this is what my widget looks like;
import 'package:flutter/material.dart';
import 'common_widgets/custom_form_card.dart';
class ExtraLocationNotes extends StatefulWidget {
_ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}
class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
TextEditingController descriptionController = TextEditingController();
#override
Widget build(BuildContext context) {
return CustomFormCard(
child: Column(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Text(
"EXTRA INFORMATION",
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.w400,
letterSpacing: 2.0,
),
),
],
),
),
SizedBox(height: 20),
TextFormField(
controller: descriptionController,
maxLines: 6,
maxLength: 250,
maxLengthEnforced: true,
style:
new TextStyle(fontSize: 18.0, height: 1.3, color: Colors.black),
decoration: const InputDecoration(
hintText:
"Please write a description of this location for fellow travellers.",
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.only(),
borderSide: BorderSide(color: Colors.black),
),
),
),
],
),
);
}
}
How do I pass the data back to the parent widget?
You need a callback, which will be triggered in the child widget then the value will be updated in the parent widget:
// 1- Define a pointers to executable code in memory, which is the callback.
typedef void MyCallback(String val);
class ExtraLocationNotes extends StatefulWidget {
// 2- You will pass it to this widget with the constructor.
final MyCallback cb;
// 3- ..pass it to this widget with the constructor
ExtraLocationNotes({this.cb});
_ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}
class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
//..
//...
RaisedButton(
//..
// 4- in any event inside the child you can call the callback with
// the data you want to send back to the parent widget:
onPressed: () {
widget.cb("Hello from the other side!");
}
),
}
Then inside the parent widget you need to catch the data which sent form the child:
class AddNewLocation extends StatefulWidget {
//...
_AddNewLocationState createState() => _AddNewLocationState();
}
class _AddNewLocationState extends State<AddNewLocation> {
// 1- Global var to store the data that we're waiting for.
String _dataFromMyChild = "";
buildCampUploadForm() {
return Container(
//...
//...
// 2- Pass the callback with the constructor of the child, this
// will update _dataFromMyChild's value:
ExtraLocationNotes(cb: (v) => setState(() => _dataFromMyChild = v)),
//..
}
// then
createLocationPostInFirestore() {
// Use _dataFromMyChild's value here
}
}
You can use the BuildContext object to get the context widget (might no be the parent!) couldn't read it all but as i understand that you need to pass the info from the child to the parent ,and you can do it with some like this :-
(context.widget as MyType).doStuff();
Note.
please check first with
print(context.widget.runtimeType);
but to make a better solution make a mutable data object that is passed from parent to the child so when changes happens it reflect's on the parent so you can separate business logic from ui logic.