No such method error while calling a function - firebase

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.

Related

How to check loggedinuser email in firestore database? Flutter

Here is my code;
class TaskList extends StatefulWidget {
#override
_TaskListState createState() => _TaskListState();
}
class _TaskListState extends State<TaskList> {
final _auth = FirebaseAuth.instance;
void getCurrentUser() async {
try {
final user = await _auth.currentUser;
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
getCurrentUser();
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: _firestore.collection('tasks').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Padding(
padding: EdgeInsets.only(top: 50, bottom: 50),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"There is nothing to show for now!",
style: GoogleFonts.poppins(fontSize: 20),
),
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddTask()),
);
},
child: Container(
height: 80,
width: 80,
decoration: BoxDecoration(
color: Colors.blueAccent,
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomRight,
colors: [Colors.blue, Colors.blueAccent],
),
shape: BoxShape.circle,
),
child: Center(
child: Icon(
Icons.add,
size: 35,
color: Colors.white,
),
),
),
),
],
),
);
} else {
return Padding(
padding:
EdgeInsets.only(top: 50, bottom: 50, left: 20, right: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: ListView(
children:
snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return Card(
child: Padding(
padding: EdgeInsets.only(
top: 10, bottom: 10, left: 10, right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(data['title'],
style: kNormalTextStyle),
Text(
data['text'],
style: kNormalTextStyle,
),
Text(
data['date'],
style: kNormalTextStyle,
),
Text(
data['time'],
style: kNormalTextStyle,
),
],
),
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {},
)
],
),
),
);
}).toList(),
),
),
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddTask()),
);
},
child: Container(
height: 80,
width: 80,
decoration: BoxDecoration(
color: Colors.blueAccent,
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomRight,
colors: [Colors.blue, Colors.blueAccent],
),
shape: BoxShape.circle,
),
child: Center(
child: Icon(
Icons.add,
size: 35,
color: Colors.white,
),
),
),
),
],
),
);
}
});
}
}
What I'm tryin to do is if there is a task with email as same as loggedInUser, I want to show it AllTasks page.
return StreamBuilder(
stream: _firestore.collection('tasks').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData)
In this code part, I can check if there is any data in snapshot however, I want to check if there is a task with mail as same as loggedInUser.email. Is there a way to check if there is a task with email as same as loggedInUser?
loggedInUser implementation:
User? loggedInUser;
Also how I add data to firestore database:
ElevatedButton(
child: Text("Add Task"),
onPressed: () {
String formatedDate =
DateFormat("MM-dd-yyyy").format(_selectedDate!);
String formattedTime =
DateFormat("HH:mm").format(_dateTime!);
_firestore.collection("tasks").add({
'title': _titleController.text,
'text': _textController.text,
'date': formatedDate,
'time': formattedTime,
'email': loggedInUser!.email,
});
Navigator.pop(context, _firestore);
},
),
If you only want to show the tasks for the logged in user, it is best to use a query to only read those tasks from the database.
stream: _firestore.collection('tasks').where('email', isEqualTo: loggedInUser!.email).snapshots(),
Also see the FlutterFire documentation on filtering data through queries.

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
});```

How can I update note NoteScreen widget when I add an item in AddNote widget?

In set state I call _notes to fetch notes from firebase to be updated.
But when I add a note in the widget AddNote and press save button, and then go back to NoteScreen, it is not been updated automatically. I must tu swipe down to refresh, and then _notes get again called and the data is up to date.
And I also need feedback on my code, I am a beginner and an opinion about clean code practices will be of high value.
class NoteScreen extends StatefulWidget {
static const routeName = '/noteScreen';
#override
_NoteScreenState createState() => _NoteScreenState();
}
class _NoteScreenState extends State<NoteScreen> {
Widget currentPage;
String search;
bool isLoading = false;
Future<void> _notes() async {
try {
final authData = Provider.of<Auth>(context, listen: false);
await Provider.of<NoteList>(context, listen: false)
.fetchAndSetNotes(search, authData.userId);
print('Note Screen FetchAndSetNotes');
} catch (err) {
print(err.toString());
}
}
#override
void initState() {
_notes();
super.initState();
}
#override
Widget build(BuildContext context) {
final note = Provider.of<NoteList>(context);
print(note.items.length);
SystemChrome.setEnabledSystemUIOverlays([]);
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(alignment: Alignment.topCenter, children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.teal, Colors.purple])),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.of(context).pushNamed(AddNote.routeName);
},
),
IconButton(
icon: Icon(Icons.logout),
onPressed: () {
Provider.of<Auth>(context, listen: false).logout();
})
],
title: Text(
'NoteApp',
style: TextStyle(fontSize: 20),
),
elevation: 0.0,
backgroundColor: Colors.transparent),
body: SingleChildScrollView(
child: Column(children: [
Align(
alignment: Alignment.topCenter,
child: Container(
height: MediaQuery.of(context).size.height * 0.10,
width: MediaQuery.of(context).size.width,
child: FloatingSearchBar(
borderRadius: BorderRadius.all(Radius.circular(20)),
hint: 'Search',
actions: [],
onQueryChanged: (query) {
setState(() {
try {
search = query;
} catch (err) {
print(err.toString());
}
_notes();
});
},
builder: (context, transition) {
return ClipRRect();
},
),
)),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: MediaQuery.of(context).size.height * 0.80,
width: MediaQuery.of(context).size.width,
child: FutureBuilder(
builder: (context, snapshot) =>
snapshot.connectionState == ConnectionState.waiting
? CircularProgressIndicator()
: RefreshIndicator(
onRefresh: () => _notes(),
child: ListView.builder(
padding: EdgeInsets.all(10),
itemCount: note.items.length,
itemBuilder: (context, i) => Column(
children: [
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
NoteDisplay(
noteItem: note.items[i],
),
),
);
},
child: note.items[i] != null
? Padding(
padding: EdgeInsets.all(5),
child: NoteItem(
note.items[i].content,
note.items[i].dateTime,
note.items[i].title,
note.items[i].id),
)
: Container(
child: Center(
child: Text(
'No notes Available'),
),
),
),
],
),
),
),
),
),
),
]),
),
)),
]),
);
}
}
**AddNote widget **
class AddNote extends StatefulWidget {
static const routeName = '/addNotes';
#override
_AddNoteState createState() => _AddNoteState();
}
class _AddNoteState extends State<AddNote> {
final _form = GlobalKey<FormState>();
TextEditingController titleControler = new TextEditingController();
var _newNotes = Notes(id: null, title: '', content: '', dateTime: '');
Future<void> _saveNote() async {
final isvalid = _form.currentState.validate();
if (!isvalid) {
return;
}
_form.currentState.save();
Navigator.of(context).pop();
try {
await Provider.of<NoteList>(context, listen: false).addNotes(_newNotes);
print('add_note');
} catch (err) {
print('add_note');
print(err.toString());
}
}
#override
Widget build(BuildContext context) {
final DateTime dateTime = DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd – kk:mm').format(dateTime);
Size size = MediaQuery.of(context).size;
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.teal, Colors.purple])),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
elevation: 0.0,
backgroundColor: Colors.transparent,
title: Text('Add notes '),
actions: [IconButton(icon: Icon(Icons.save), onPressed: _saveNote)],
),
body: Center(
child: Form(
key: _form,
child: Container(
height: size.height * 0.7,
margin: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30))),
child: Card(
margin: EdgeInsets.all(30),
elevation: 20,
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter a Title';
}
return null;
},
controller: titleControler,
decoration: InputDecoration(
hintText: 'Title',
),
onSaved: (value) {
_newNotes = Notes(
title: value,
id: _newNotes.id,
content: _newNotes.content,
dateTime: formattedDate);
print(value.toString());
},
textInputAction: TextInputAction.next,
),
SizedBox(
height: 20,
),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "The content cannon't be empty";
}
return null;
},
onSaved: (value) {
_newNotes = Notes(
title: _newNotes.title,
content: value,
id: _newNotes.id,
dateTime: formattedDate);
print(value.toString());
},
maxLines: null,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(hintText: 'Note content'),
),
SizedBox(
height: 10,
),
Text('$formattedDate')
],
),
),
),
),
),
),
),
),
);
}
}
I believe what is want is a stream instead of a future. i don't know what your fetchAndSetNotes() function looks like but Instead of doing
FirebaseFirestore.instance.collection(collectionName).doc(id).get() you should do Firestore.instance.collection("collectionName").doc(id).snapshots() which will give you a stream. you use a StreamBuilder (considering you are using provider, you should use stream provider) instead of FutureBuilder.

How do i add cart page for my ecommerce app on flutter?

Im using firebase as a backend. I retrieved products from firebase using stream builder .I looked into providers but all the tutorials used providers for the products page too.Can i use provviders only for cart?How do i do it?Or is there any other way to implement cart page?
here's the code for the products page.
class Shop extends StatefulWidget {
final User currentUser;
final String prodId;
final String onwerId;
Shop({ this.currentUser,
this.prodId,
this.onwerId});
#override
_ShopState createState() => _ShopState( prodId: this.prodId,ownerId:this.onwerId);
}
class _ShopState extends State<Shop> {
final _firestore = Firestore.instance;
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
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:StreamBuilder(
stream: Firestore.instance.collectionGroup("userProducts").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
} else {
return new ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return new ShopItem(
shopmediaUrl: ds['shopmediaUrl'],
productname: ds['productname'],
price: ds['price'],
photoUrl: ds['photoUrl'],
username: ds['username'],
prodId: ds['prodId'],
userId: ds['userId'],
ownerId: ds['ownerId'],
);
}
);
}
}
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black38,
onPressed: ()
async{ Navigator.push(context, MaterialPageRoute(builder: (context) =>Uploadecom(currentUser: currentUser, )));
},
child: Icon(Icons.add_box),
),
);
}
}
class ShopItem extends StatelessWidget {
final String username;
final String prodId;
final String ownerId;
final String photoUrl;
final String shopmediaUrl;
final String productname;
final String price;
final String userId;
ShopItem({
this.ownerId,
this.prodId,
this.shopmediaUrl,
this.username,
this.photoUrl,
this.price,
this.productname,
this.userId,
});
showProduct(context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductScreen(
prodId: prodId,
userId: ownerId,
),
),
);
}
#override
Widget build(BuildContext context) {
// configureshopmediaPreview(context);
return
//
Column( children: <Widget>[
Stack(
children: <Widget>[
Container(
child:Row(
children: <Widget>[
Expanded(
child: Container(
// width: 360,
height: 400.0,
child:AspectRatio(
aspectRatio: 16 / 9,
child:Container(
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
shopmediaUrl),
fit: BoxFit.cover),
),
),
),
),
),
)],
),
),
Positioned(
bottom: 10,
left: 10,
child: Container(
height: 40,
width: 40,
child: cachedNetworkImage(photoUrl),
),
),
Positioned(
bottom: 20,
left: 60,
child: Container(
child: Text(username,style: TextStyle(color: Colors.white,fontWeight:FontWeight.bold),),
),
),
Container(
alignment: Alignment.bottomRight,
child: 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(productname,style: TextStyle(color: kText,fontSize: 30.0,fontWeight:FontWeight.bold),),
),
],
),
Row(
children: <Widget>[
Container( child: Text('₹',style: TextStyle(color: kText,)),
),
Container(
child: Text(price,style: TextStyle(color: kText,fontSize: 20.0,fontWeight:FontWeight.bold),),
),
],
),
Divider(color: kGrey,),
],
);
}
}
Yes, you can use provider(or any state management solution) for the cart page only, but you have to persist those cart products so when the user logs out or exit your app and returns he will find his cart products still available, for persisting I suggest creating a carts collection in your Firestore and for every user create a cart.

Resources