Want to pass the total price in the bottom navigation bar in flutter - firebase

How can i show the total amount in the bottom navigation bar... The app uses firebase backend... I have a filed in my database name total price of each item... Now I want to fetch the total price of each item and then add it and display in the bottom navigation bar..
I have attach my firebase backend screen shot.. what i need is to get all the value of the field 'total' add it up and show it in the bottom bar below the Total which is hardcoded as 999 currently section...
It would be helpful if some let me know how to do it.. I am new to app development and flutter as well
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
import 'dart:async';
import 'package:fluttertoast/fluttertoast.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final myController = TextEditingController(); ///Alert Dialog box input text myController will be use to store the number of qty
String id;
var qty;
var price;
var total;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home:Scaffold(
bottomNavigationBar: new Container( //// Bottom Naviagtion Bar for check out and Total price
color: Colors.white,
child: Row(
children: <Widget>[
Expanded(child: ListTile(
title: Text("Total"),
subtitle: Text("Rs 999"),
),),
Expanded(
child: MaterialButton(onPressed:() {},
child: Text("Check Out",style: TextStyle(color: Colors.white),),
color: Colors.red,) ,
)
],
),
),
appBar: AppBar(title: Text('MyKart'),
),
body: (
StreamBuilder(
stream: Firestore.instance.collection('KartDetails').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot kartDetails = snapshot.data.documents[index];
return Container(
height: 150,
child: Card(
elevation: 10,
child: Container(
height: 100,
width: 100,
child: Row(
children: <Widget>[
Container(
width: 100,
height: 100,
child: Image.network(kartDetails['img']),
),
Container(
child: (Text(kartDetails['item'])),
),
Container(
width: 50,
child: (Text('Rs '+kartDetails['price'].toString(),textAlign: TextAlign.end,)),
),
Container(
margin: EdgeInsets.only(left: 20),
height: 120,
width: 50,
color: Colors.white10,
child: Column(
children: <Widget>[
RaisedButton(
color: Colors.grey,
onPressed: (){
showDialog(context: context,
builder: (BuildContext context){
return Dialog(
child: Container(
height: 250,
color: Colors.white10,
child: Container(
margin: EdgeInsets.all(40.0),
child: Column(
children: <Widget>[
TextField(
controller: myController,
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: 'Enter the Quantity'),
),
Container(
height: 50,
),
RaisedButton(
color: Colors.blue,
child: Text('Submit'),
onPressed: () async{
qty = myController.text;
//==================================================================Total Number of QTY ENTERED==========================================//
if (int.parse(qty)>0 && int.parse(qty)>=5) {
CollectionReference collectionRefernce = Firestore
.instance.collection(
'KartDetails');
QuerySnapshot querySnapshot = await collectionRefernce
.getDocuments();
querySnapshot
.documents[index]
.reference
.updateData(
{"quantity": qty});
//==================================================================Calculate price for each product==========================================//
price = kartDetails['price'];
total=int.parse(qty)*price;
querySnapshot
.documents[index]
.reference
.updateData(
{"total": total});
print(myController
.toString());
Navigator.of(context)
.pop();
myController.clear();
Fluttertoast.showToast(msg: "Quantity Updated",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 20.0
);
}
else if(int.parse(qty) < 5 || int.parse(qty)<0) {
Fluttertoast.showToast(msg: "Minimum 5 quanity",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 20.0
);
myController.clear();
}
else {
Fluttertoast.showToast(msg: "Please enter valid quantity",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 20.0
);
myController.clear();
}
//Firebase query
},
)
],
),
),
),
);
});
},
child: Icon(Icons.shopping_basket),
),
Container(
height: 20,
),
RaisedButton(
color: Colors.grey,
child: Icon(Icons.delete,color: Colors.black87,),
)
],
),
),
Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 3),
height: 50,
width: 70,
child: Center(child: Text('Quantity')),
),
Container(
width: 70,
child: Center(child: Text((kartDetails['quantity']).toString())),
),
Container(
margin: EdgeInsets.only(top: 25),
child: Center(child: Text('Total Price')),),
Container(
margin: EdgeInsets.only(left: 3),
width: 70,
child: Center(child: Text(("Rs " + (kartDetails['total']).toString()))),
),
],
),
],
),
),
),
);
},
);
}
else{
return Center(
child: Container(),
);;
}
},
)
),
),
);
}
}

You can easily do it with this method:
var totalCartValue = 0;
String getCartTotal() async {
QuerySnapshot snapshot = await Firestore.instance
.collection('KartDetails')
.getDocuments();
snapshot.documents.forEach((doc) {
setState((){
totalCartValue += doc.data['total'];
});
});
return totalCartValue.toString();
}
P.S: This method will give you the total of all values in the KartDetails collection not the total for the current user, for the current user it should be like this:
var totalCartValue = 0;
String getCartTotal() async {
QuerySnapshot snapshot = await Firestore.instance
.collection('KartDetails')
.where("UID", isEqualTo: FirebaseAuth.instance.currentUser().toString())
.getDocuments();
snapshot.documents.forEach((doc) {
setState((){
totalCartValue += doc.data['total'];
});
});
return totalCartValue.toString();
}
And use it in the UI that way:
class YourClassName extends StatefulWidget {
#override
_YourClassNameState createState() => _YourClassNameState();
}
class _YourClassNameState extends State<YourClassName> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: //your body code,
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.cart_shopping),
title: new Text(totalCartValue),
),
]
)
);
}
}
You should call it inside your initState so it gets executed whenever app starts:
#override
initState(){
super.initState();
getCartTotal();
}

This is a very vague question, so I will give a shot at one method of solving this. In order to do this you will need some sort of state management solution. I suggest using provider. Flutter has a tutorial on provider here. Essentially you will have to create a ChangeNotifier that every time would onAddItem and onDeleteItem and call notifyListeners() whenever you add or delete items. Then your bottom bar would simply use a Consumer to get the values from your ChangeNotifier. As I said this is just one approach, but since you did not give a replicable example this is the best I can do.

Related

Cant Figure Out How To display Only the post details for the post I have clicked on

So I have this code here and I would like to display post details from firebase for the post which I have clicked on, but instead, it lists post details for every single post in the database one after another.
Can anyone help me figure out how I can make it so that when A post is clicked, details will show for only the post which was clicked, and not for all of the posts? Any help would be greatly appreciated, thank you.
The Info I would like to display on the post is
postTitle
postDesc
postAuthor
Here is what the firebase looks like
Code Here:
import 'package:tennis_event_app/services/crud.dart';
import 'package:tennis_event_app/views/create_blog.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot? blogSnapshot;
#override
void initState() {
crudMethods.getData()?.then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList() {
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 24),
itemCount: blogSnapshot!.docs.length,
itemBuilder: (context, index) {
return BlogTile(
author: blogSnapshot!.docs[index].get('author'),
title: blogSnapshot!.docs[index].get('title'),
desc: blogSnapshot!.docs[index].get('desc'),
imgUrl: blogSnapshot!.docs[index].get('imgUrl'),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Flutter",
style: TextStyle(fontSize: 22),
),
Text(
"Blog",
style: TextStyle(fontSize: 22, color: Colors.blue),
)
],
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Container(
child: blogSnapshot != null
? blogsList()
: Container(
child: Center(
child: CircularProgressIndicator(),
))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateBlog()));
},
),
);
}
}
class BlogTile extends StatelessWidget {
final String imgUrl, title, desc, author;
BlogTile(
{required this.author,
required this.desc,
required this.imgUrl,
required this.title});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 16, right: 16, left: 16),
child: Stack(
children: <Widget>[
Container(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(8)),
child: Image.network(
imgUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
height: 170,
),
),
),
Container(
height: 170,
decoration: BoxDecoration(
color: Colors.black45.withOpacity(0.3),
borderRadius: BorderRadius.circular(6)),
),
Container(
height: 170,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
SizedBox(height: 4),
Text(
'$desc',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
SizedBox(
height: 4,
),
Text(author),
],
)),
Container(
child: SizedBox(
height: 170,
width: MediaQuery.of(context).size.width,
child: TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(fontSize: 20),
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage()));
},
child: const Text(''),
),
),
),
],
),
);
}
}
class DetailPage extends StatefulWidget {
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot? blogSnapshot;
#override
void initState() {
crudMethods.getData()?.then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList2() {
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 24),
itemCount: blogSnapshot!.docs.length,
itemBuilder: (context, index) {
return PageContent(
postAuthor: blogSnapshot!.docs[index].get('postAuthor'),
postTitle: blogSnapshot!.docs[index].get('postTitle'),
postDesc: blogSnapshot!.docs[index].get('postDesc'),
imgUrl: blogSnapshot!.docs[index].get('imgUrl'),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Flutter",
style: TextStyle(fontSize: 22),
),
Text(
"Blog",
style: TextStyle(fontSize: 22, color: Colors.blue),
)
],
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Container(
child: blogSnapshot != null
? blogsList2()
: Container(
child: Center(
child: CircularProgressIndicator(),
))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateBlog()));
},
),
);
}
}
class PageContent extends StatelessWidget {
final String imgUrl, postTitle, postDesc, postAuthor;
PageContent(
{required this.postAuthor,
required this.postDesc,
required this.imgUrl,
required this.postTitle});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 16, right: 16, left: 16),
child: Card(
child: ListTile(
title: Text(
postTitle,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
subtitle: Text(
'$postDesc',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
)
)
);
}
}
I also reference crud.dart in that code, so incase you need it, here it is:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:collection';
class CrudMethods {
Future<void> addData(blogData) async {
print(blogData);
FirebaseFirestore.instance
.collection("blogs")
.add(blogData)
.then((value) => print(value))
.catchError((e) {
print(e);
});
}
getData() async {
return await FirebaseFirestore.instance
.collection("blogs")
.orderBy("ts", descending: true)
.get();
}
}
Thank you again for any help!
First I would recommend to modelize your data in an object for exemple a class Article that is easier to serialize and manipulate.
Then instead of requesting another time the database you should save your data in a List<Article> for example then you only update this list on refresh from your main page. That way you don'y manipulate a QuerySnapshot or Future but just your list of objects.
Finally and to answer your question, you could simply pass the clicked item Article to your details page and only display its content. Because here, you have the same construction as your main page with the same request that is resent.
Usually you can build your route like that (adding a parameter to your details with the index you clicked on for example)
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage(article: _data[i])));
},
Here is an article on serialization from Flutter docs, it shows how to build your model with the toMap, toJson and fromJson methods.

How can I make that the on ttap button only be pressed one time? - Flutter

I have an issue with flutter, and the isComplet bool are not working well. When I press it twice in the app, it make the task as may times as you tap on there. How can I solve it? This is the entire code. The todos list is a list of tasks to do in a task app, but it works fine:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:mrplan/loading.dart';
import 'package:mrplan/services/database_services.dart';
import 'package:mrplan/src/models/todo.dart';
import 'package:mrplan/src/pages/graficas_circulares_page.dart';
import 'package:mrplan/src/widgets/appbar.dart';
bool isComplet = false;
TextEditingController todoTitleController = TextEditingController();
class Todolist extends StatefulWidget {
#override
_TodolistState createState() => _TodolistState();
}
class _TodolistState extends State<Todolist> {
TextEditingController todoTitleController = TextEditingController();
#override
Widget build(BuildContext context) {
setState(() {
});
return Scaffold(
body: SafeArea(
child: StreamBuilder<List<Todo>>(
stream: DatabaseService().listTodos(),
builder: (context, snapshot) {
if(!snapshot.hasData){
return Loading();
}
List<Todo> todos = snapshot.data;
if(todos.length == 0){
return Center(child: Text('No hay tareas agregadas!'));
}
return Padding(
padding:EdgeInsets.all(0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
Expanded(
child: ListView.separated(
separatorBuilder: (context, index)=> Divider(color: Colors.white),
shrinkWrap: true,
itemCount: todos.length,
itemBuilder: (context, index){
return Dismissible(
key: UniqueKey(),
background: Container(padding: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: Icon(Icons.delete),
color: Colors.red),
onDismissed: (direction) async {
await DatabaseService().removeTodo(todos[index].uid);
quitar();
},
child: StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection('Todos').doc().snapshots(),
builder: (context, snapshot) {
var todoss = snapshot.data;
return ListTile(
onTap: (){
isComplet = !isComplet;
if (Todo().isComplet = true)
{DatabaseService().completTask(todos[index].uid);}
if (Todo().isComplet = false)
{DatabaseService().uncompletTask(todos[index].uid);}},
leading: Container(
padding: EdgeInsets.all(2),
height: 30,
width: 30,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
shape: BoxShape.circle
),
child: todos[index].isComplet
? Icon(
Icons.check,
color: Colors.white,)
: Container(),
),
title: Text(
todos[index].title,
style: todos[index].isComplet
? TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
decoration: TextDecoration.lineThrough,
decorationColor: Colors.red,
)
: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
decoration: null
)
),
);
}
),
);
}
),
)
],
),
);
}
)
),
);
}
}
class Appbar extends StatefulWidget {
#override
_AppbarState createState() => _AppbarState();
}
class _AppbarState extends State<Appbar> {
#override
Widget build(BuildContext context) {
bool isbuttondisabled = false;
setState(() {
});
return StreamBuilder<Object>(
stream: null,
builder: (context, snapshot) {
return Container(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 0,
child: Container(
height: MediaQuery.of(context).size.height * 0.05,
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Container(
decoration: BoxDecoration(
color:Colors.grey[100],
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(5.0),
)
),
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.symmetric(horizontal: 10.0),
width: MediaQuery.of(context).size.width * 0.835,
child: Center(
child: TextFormField(
controller: todoTitleController,
autofocus: true,
decoration: InputDecoration(
hintStyle: TextStyle(color: Colors.blue[800]),
hintText: "Inserte una tarea...",
border: InputBorder.none
),
),
),
),
TextButton(
child: Container(
height: MediaQuery.of(context).size.height,
child: Center(child: Icon(Icons.add))),
style: TextButton.styleFrom(
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: const Radius.circular(10.0),
)
),
backgroundColor: Theme.of(context).primaryColor
),
onPressed: isbuttondisabled ? null : ()async {
if(todoTitleController.text.isNotEmpty){
await DatabaseService().createNewTodo(todoTitleController.text.trim());
FocusScope.of(context).unfocus();
anadir();
todoTitleController.clear();
isComplet = !isComplet;
}
}
)
],
),
)
)
);
}
);
}
}
The relevant code where I am stucked is this:
onTap: (){
isComplet = !isComplet;
if (Todo().isComplet = true)
{DatabaseService().completTask(todos[index].uid);}
if (Todo().isComplet = false)
{DatabaseService().uncompletTask(todos[index].uid);}},
Thanks a lot!
It would be better if you could refactor the code a little bit. But heres the problem
remove this code inside the build method
bool isbuttondisabled = false;
setState(() {
});
add bool isbuttondisabled = false;
outside the build method.
where ever your button is,
in the onPressed parameter
setState(() {
isbuttondisabled=true;
//Todo add your code
});```

read number of children from the firebase realtime database using flutter

I'm new to flutter and really need help with my problem regarding reading/calculating the number of children from the firebase real-time database.
The database I use has several categories.
Each category has several cases.
What I want, is to extract the information from the database, how many cases each category has and to show this information in a list. That means - to show the name of the category AND how many children (cases) this category has (totalCases)...
Here is my code, I'm struggling with:
import '../components/category_list_tile.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import '../constants.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
import 'dart:async';
class ScreenCategoryList extends StatefulWidget {
static String id = 'screen_category_list';
final FirebaseApp app;
ScreenCategoryList({this.app});
#override
_ScreenCategoryListState createState() => _ScreenCategoryListState();
}
class _ScreenCategoryListState extends State<ScreenCategoryList> {
final referenceDatabase = FirebaseDatabase.instance;
final _dbRef = FirebaseDatabase.instance.reference().child("de");
static int number = 100;
bool showSpinner = false;
DatabaseReference _databaseReference;
#override
void initState() {
final FirebaseDatabase database = FirebaseDatabase(app: widget.app);
_databaseReference = database.reference().child("de");
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white, Colors.white],
),
image: const DecorationImage(
image: AssetImage("images/background.png"), fit: BoxFit.cover),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
toolbarHeight: 60.0,
elevation: 0.0,
backgroundColor: Colors.black12,
leading: Padding(
padding: EdgeInsets.only(left: 12.0, top: 12.0, bottom: 12.0),
child: Image(image: AssetImage('images/lexlogo_black.png'))),
title: Center(
child: Column(
children: [
Text(
'Kategorien',
style: TextStyle(
color: kMainDarkColor,
fontFamily: 'Roboto',
fontSize: 21.0,
fontWeight: FontWeight.bold),
),
],
),
),
actions: [
Padding(
padding: EdgeInsets.only(right: 8.0),
child: IconButton(
icon: Icon(Icons.more_vert_rounded),
iconSize: 30.0,
color: kMainDarkColor,
onPressed: () {},
//onPressed: onPressMenuButton,
),
),
],
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: FirebaseAnimatedList(
query: _databaseReference.child('category'),
itemBuilder: (
BuildContext context,
DataSnapshot snapshot,
Animation<double> animation,
int index,
) {
Future<int> getNumberOfNodes() async {
final response = await FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
.child('$index')
.child('cases')
.once();
var nodes = [];
response.value.forEach((v) => nodes.add(v));
return nodes.length;
}
var myNumber = getNumberOfNodes();
int myInt = 99;
myNumber.then((value) {
myInt = value;
});
number = myInt;
return CategoryListTile(
title: snapshot.value['name'].toString(),
successfulCases: 1,
totalCases: number,
onTitleClick: () {},
onInfoButtonClick: () {},
);
},
reverse: false,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
),
),
),
);
}
}
Since you declare Future<int> getNumberOfNodes() async, you need to FutureBuilder to display that value.
Something like this:
child: FutureBuilder<int>(
future: FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
.child('$index')
.child('cases')
.once();
var nodes = [];
response.value.forEach((v) => nodes.add(v));
return nodes.length;
}
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
return Text("Case count: "+snapshot.data);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}'),
} else {
return CircularProgressIndicator();
}
},
)
I did not compile or run this code, so please treat it as a pseudo-code. If you get any errors while using this, try to fix them by searching for the error message before reporting back.
So the future is the code that determines the value, and then the builder renders the correct UI based on whether the value is available yet. You'll want to replace the Text("Case count: "+snapshot.data) with your own UI, so the CategoryListTile(...).
Thank you #Frank van Puffelen for your suggestion. Finally could read the number of children of at least one category.
The code had to be changed like this:
class _ScreenCategoryListState extends State<ScreenCategoryList> {
final referenceDatabase = FirebaseDatabase.instance;
bool showSpinner = false;
DatabaseReference _databaseReference;
#override
void initState() {
final FirebaseDatabase database = FirebaseDatabase(app: widget.app);
_databaseReference = database.reference().child("de");
super.initState();
}
Future<Map<int, int>> getNumberOfNodes() async {
Map<int, int> caseNumbers = new Map<int, int>();
// read number of category nodes
final categoriesNumbersResponse = await FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
// .child('0')
// .child('cases')
.once();
var categoryNodes = [];
categoriesNumbersResponse.value.forEach((v) => categoryNodes.add(v));
int numberOfCategories = categoryNodes.length;
//read number of cases in category
for (int i = 0; i < numberOfCategories; i++) {
final caseResponse = await FirebaseDatabase.instance
.reference()
.child('de')
.child('category')
.child('$i')
.child('cases')
.once();
var caseNodes = [];
caseResponse.value.forEach((v) => caseNodes.add(v));
int numberOfCases = caseNodes.length;
caseNumbers[i] = numberOfCases;
}
return caseNumbers;
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white, Colors.white],
),
image: const DecorationImage(
image: AssetImage("images/background.png"), fit: BoxFit.cover),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
toolbarHeight: 60.0,
elevation: 0.0,
backgroundColor: Colors.black12,
leading: Padding(
padding: EdgeInsets.only(left: 12.0, top: 12.0, bottom: 12.0),
child: Image(image: AssetImage('images/lexlogo_black.png'))),
title: Center(
child: Column(
children: [
Text(
'Kategorien',
style: TextStyle(
color: kMainDarkColor,
fontFamily: 'Roboto',
fontSize: 21.0,
fontWeight: FontWeight.bold),
),
],
),
),
actions: [
Padding(
padding: EdgeInsets.only(right: 8.0),
child: IconButton(
icon: Icon(Icons.more_vert_rounded),
iconSize: 30.0,
color: kMainDarkColor,
onPressed: () {},
//onPressed: onPressMenuButton,
),
),
],
),
body: FutureBuilder<Map<int, int>>(
future: getNumberOfNodes(),
builder: (BuildContext context,
AsyncSnapshot<Map<int, int>> casesSnapshot) {
if (casesSnapshot.hasData) {
return FirebaseAnimatedList(
reverse: false,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
query: _databaseReference.child('category'),
itemBuilder: (
BuildContext context,
DataSnapshot categorySnapshot,
Animation<double> animation,
int index,
) {
int numberOfCases = casesSnapshot.data[index];
//print('number of cases $_counter, $numberOfCases');
return CategoryListTile(
title: categorySnapshot.value['name'].toString(),
successfulCases: 10,
totalCases: numberOfCases,
onTitleClick: () {},
onInfoButtonClick: () {},
);
},
);
} else if (casesSnapshot.hasError) {
return Center(
child: Column(
children: <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${casesSnapshot.error}'),
)
],
),
);
} else {
return Center(
child: Column(
children: <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
],
),
);
}
},
),
),
);
}
}

No such method error while calling a function

I retrieved products data from Firebase for my E-commerce homepage through future builder. I've created another screen that displays more information on a product when the user clicks on a product from the E-commerce homepage.To navigate to more information screen i created a function called showProduct and called it with a button, but when the button id pressed it shows
NoSuchMethodError: The method '[]' was called on null.Receiver: null Tried calling .
The showProduct function ] was also used on the vendor profile page where the products shown are shown in gridview and when clicked on any product from the vendors's profile.The showProduct function works and open more information screen.
E-commerce Homepage:
c
lass Shop extends StatefulWidget {
final Prod products;
final User currentUser;
final String prodId;
final String onwerId;
Shop({ this.currentUser,
this.prodId,
this.products,
this.onwerId});
#override
_ShopState createState() => _ShopState( prodId: this.prodId,products: this.products,ownerId:this.onwerId);
}
class _ShopState extends State<Shop> {
String postOrientation = "grid";
String shopOrientation = "grid";
bool isFollowing = false;
bool isLoading = false;
String uid="";
String prodId;
String ownerId;
Prod products;
_ShopState({
this.prodId, this.products,this.ownerId,
});
#override
void initState() {
super.initState();
showProduct;
}
Future getProducts()async {
var firestore = Firestore.instance;
QuerySnapshot snap = await firestore.collectionGroup("userProducts").getDocuments();
return snap.documents;
}
Future<Null>getRefresh()async{
await Future.delayed(Duration (seconds : 3));
setState(() {
getProducts();
});
}
showProduct(context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductScreen(
prodId: prodId,
userId: ownerId,
),
),
);
}
#override
Widget build(BuildContext context) {
return
Scaffold(
appBar: AppBar(backgroundColor: kSecondaryColor,
title: Text( 'Shop',
style: TextStyle(
fontFamily :"MajorMonoDisplay",
fontSize: 35.0 ,
color: Colors.white),),
iconTheme: new IconThemeData(color: kSecondaryColor),
),
backgroundColor: kPrimaryColor,
body:FutureBuilder(
future: getProducts(),
builder: (context,snapshot)
{
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: circularProgress(),);
} else {
return
RefreshIndicator(
onRefresh: getRefresh,
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
var ourdata = snapshot.data[index];
return
Container(
height: 500,
margin: EdgeInsets.only(
top: 1.0, left: 10.0, right: 10.0, bottom: 1.0),
child: Column( children: <Widget>[
SizedBox( height:1.0,),
Stack(
children: <Widget>[
Container(
child:Row(
children: <Widget>[
Expanded(
child: Container(
height: 400.0,
child: ClipRRect(borderRadius: BorderRadius.circular(20.0),
child: cachedNetworkImage(ourdata.data['shopmediaUrl'],
),
),
),
),
],
),
),
Expanded(
child: Positioned(
bottom: 10,
left: 10,
child: Container(
height: 40,
width: 40,
child: ClipRRect(
borderRadius: BorderRadius.circular(40.0),
child: Image.network(ourdata.data['photoUrl'],)),
),
),
),
Expanded(
child: Positioned(
bottom: 20,
left: 60,
child: Container(
child: Text(ourdata.data['username'],style: TextStyle(color: Colors.white,fontWeight:FontWeight.bold),),
),
),
),
Container(
alignment: Alignment.bottomRight,
child: GFButton(
onPressed: () => showProduct(context) ,
text: "More",
icon: Icon(Icons.card_travel),
shape: GFButtonShape.pills,
),
),
],
),
Row(
children: <Widget>[
Container(
child: Text(ourdata.data['productname'],style: TextStyle(color: kText,fontSize: 30.0,fontWeight:FontWeight.bold),),
),
],
),
Row(
children: <Widget>[
Container( child: Text('₹',style: TextStyle(color: kText,)),
),
Container(
child: Text(ourdata.data['price'],style: TextStyle(color: kText,fontSize: 20.0,fontWeight:FontWeight.bold),),
),
],
),
Divider(color: kGrey,),
],
),
);
}
)
);
}
}
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black38,
onPressed: ()
async{ Navigator.push(context, MaterialPageRoute(builder: (context) =>Uploadecom(currentUser: currentUser, )));
},
child: Icon(Icons.add_box),
),
);
}
}
This is the gridview on the vendor's profile.
class ProductTile extends StatelessWidget {
final Prod products;
ProductTile(this.products);
showProduct(context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductScreen(
prodId: products.prodId,
userId: products.ownerId,
),
),
);
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => showProduct(context),
child: cachedNetworkImage(products.shopmediaUrl),
);
}
}
If you need more codes please ask me.

Flutter Passing Document ID in Firestore Query

I am trying to figure out how to do this.
If I pass the document ID hardcoded it works. But Since I have multiple pages, I am trying to figure out how to pass it and then query it..
My main page has the following.
import 'package:flutter/material.dart';
import 'package:onlytag2/pages/category.dart';
import 'package:onlytag2/widget/maincard.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
Query collectionReference = Firestore.instance.collection("mainCategories").orderBy("title");
void initState() {
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
#override
void dispose() {
subscription.cancel(); //Streams must be closed when not needed
super.dispose();
}
passData(DocumentSnapshot snap, String cat, String title) {
print(cat);
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Category(snapshot: snap, category: cat, title: title,)));
}
#override
Widget build(BuildContext context) {
if (snapshot == null) return Center(
child: Container(
color: Colors.black,
alignment: AlignmentDirectional(0.0, 0.0),
child: Container(
color: Colors.black,
constraints: BoxConstraints(
maxHeight: 300.0,
maxWidth: 200.0,
minWidth: 150.0,
minHeight: 150.0
),
child: CircularProgressIndicator(),
),
),
);
return Scaffold(
backgroundColor: Color(0xff0E0E0F),
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"#",
style: TextStyle(
fontSize: 25, color: Color(0xffff9900), fontFamily: 'Dokyo'),
),
Text(
"onlytags",
style: TextStyle(color: Colors.white, fontFamily: 'Dokyo'),
)
],
),
),
body: Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return InkWell(
onTap: () => passData(snapshot[index], snapshot[index].documentID.toString(), snapshot[index].data["title"] ),
child: MainCard(
title: snapshot[index].data["title"],
subtitle: snapshot[index].data["subTitle"],
image: snapshot[index].data["image"],
),
);
}),
),
],
),
),
],
),
);
}
}
The category widget is where I am having the problem.
Comment Listed where I am having the problem.
import 'package:flutter/material.dart';
import 'package:onlytag2/widget/sub.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class Category extends StatefulWidget {
DocumentSnapshot snapshot;
final String category;
final String title;
Category({this.snapshot, this.category, this.title});
#override
_CategoryState createState() => _CategoryState();
}
class _CategoryState extends State<Category>{
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
//How do I get the category passed properly? I know it is the Document ID, but since it changes based on what button is pressed before,
//I cant figure out how to pass it..
Query collectionReference = Firestore.instance.collection("mainCategories").document(widget.category).collection("subCategories").orderBy("title");
void initState() {
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
#override
void dispose() {
subscription.cancel(); //Streams must be closed when not needed
super.dispose();
}
#override
Widget build(BuildContext context) {
if (snapshot == null) return Center(
child: Container(
color: Colors.black,
alignment: AlignmentDirectional(0.0, 0.0),
child: Container(
color: Colors.black,
constraints: BoxConstraints(
maxHeight: 300.0,
maxWidth: 200.0,
minWidth: 150.0,
minHeight: 150.0
),
child: CircularProgressIndicator(),
),
),
);
return Scaffold(
backgroundColor: Color(0xff0E0E0F),
appBar: AppBar(
iconTheme: IconThemeData(
color: Color(0xffff9900),
),
centerTitle: true,
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
"#", style: TextStyle(fontSize: 25, color: Color(0xffff9900), fontFamily: 'Dokyo'),
),
Text(widget.title.toLowerCase(), style: TextStyle(color: Colors.white, fontFamily: 'Dokyo'),)
],
),
),
body: Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return Sub(
title: snapshot[index].data["title"],
subtitle: snapshot[index].data["subTitle"],
image: snapshot[index].data["image"],
);
}),
),
Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 15),)
],
),
),
],
),
);
}
}
I have realised that the code looks shady on the comment so let me make an answer.
What you are trying to do is currently not supported in flutter as can be seen at these GitHub issues 1 and 2.
Change your code to,
class _CategoryState extends State<Category>{
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
Query collectionReference;
void initState() {
collectionReference = Firestore.instance.collection("mainCategories").document(widget.category).collection("subCategories").orderBy("title");
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
...
Hope this helps.

Resources