Flutter Firebase: data updating in Firebase, but not showing the counter update on the screen automatically - firebase

I am holding a counter in my Firebase which holds the total upvotes for a picture. When the upvote button is pressed, the database should update the counter of that specified counter by 1, which it does. However, it doesn't show the update on the app screen. For example if an image has 8 upvotes, and the button is pressed to upvote, it will still show 8 upvotes on the screen but in the database it will now be 9 upvotes. When I hot refresh the value changes. How can I make both things happen asynchronously? I tried playing around with it and it's always that either it updates the database and the screen stays unchanged, or the screen changes and the database doesn't.
For the functions below, they behave as expected but just not asynchronously on the screen.
The relevant function that increments the followers in the database:
// likedposts is a list of posts that have already been liked and is initalised earlier
// even if I remove the if statement here, the behaviour is the same
void incrementFollowers(int index) async {
if (!likedposts.contains(posts[index])) {
likedposts.add(posts[index]);
addLikedPost();
FirebaseFirestore.instance
.collection('uploads')
.doc(usernames[index])
.collection('images')
.where('caption', isEqualTo: captions[index])
.get()
.then((querySnapshot) {
querySnapshot.docs.forEach((result) async {
FirebaseFirestore.instance
.collection('uploads')
.doc(usernames[index])
.collection('images')
.doc(result.id)
.update({'upvotes': upvotes[index]+1,});
setState(() {
getUpvotes(index);
});
});
});
}
}
The function that displays the upvotes:
getUpvotes(int index) {
return RichText(
text: TextSpan(
style:
TextStyle(color: Colors.black, fontSize: 20.0),
children: <TextSpan>[
TextSpan(
text: upvotes[index].toString() + ' upvotes',
style: TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
print(
'This will take to upvoters of the photo');
}),
]));
}
The widget that displays everything in my app (to find where I'm calling the incrementFollowers button, just do ctrl+F for incrementFollowers and you'll find it):
Widget _getPost() {
Size size = MediaQuery.of(context).size;
if (url!= null) {
return new ListView.builder(
itemCount: images.length,
itemBuilder: (BuildContext context, int userIndex) {
return Container(
child: Column(
children: <Widget>[
Container(
//Includes dp + username + report flag
margin: EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(right: 8),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserProfile(usernames[userIndex])
),
);
},
child: CircleAvatar(
backgroundImage: displayPic[1],
))),
RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: usernames[userIndex],
style: TextStyle(
color: Colors.black, fontSize: 15.0),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserProfile(usernames[userIndex])
),
);
})
]),
)
],
),
IconButton(
icon: Image.asset('assets/pictures/ICON_flag.png'),
iconSize: 25,
onPressed: () {
reportUser(userIndex, context);
},
),
],
),
),
Stack(children: <Widget>[
Container(
//the post picture
child: GestureDetector(
//This is to handle the tagged users raised button
onTap: () {
if (isVisible == false)
setState(() {
isVisible = true;
});
else
setState(() {
isVisible = false;
});
},
),
height: size.height * 0.5,
width: returnWidth(),
padding: EdgeInsets.only(
left: 16,
right: 16,
top: 0,
bottom: 24,
),
// constraints: BoxConstraints(maxHeight: 50),
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill, image: NetworkImage(images[userIndex])),
)
),
Positioned(
top: 25,
left: 50,
child: returnTaggedUsers(userIndex),)
]),
Row(
mainAxisAlignment: returnAlignment(),
// upvote + downvote + comment + send + save icons
children: <Widget>[
Container(
color: upVoted ? Colors.blue : Colors.white,
margin: EdgeInsets.only(right: 8),
child: IconButton(
icon: Image.asset('assets/pictures/ICON_upvote.png'),
iconSize: 25,
onPressed: () async {
setState(() {
incrementFollowers(userIndex);
});
getUpvotes(userIndex);
},
)
),
Container(
color: downVoted ? Colors.blue : Colors.white,
margin: EdgeInsets.only(right: 8),
child: IconButton(
icon: Image.asset('assets/pictures/ICON_downvote.png'),
iconSize: 25,
onPressed: () {
setState(() {
downVoted = true;
upVoted = false;
});
},
)),
Container(
margin: EdgeInsets.only(right: 8),
child: IconButton(
icon: Image.asset('assets/pictures/ICON_comment.png'),
iconSize: 25,
onPressed: () {
commentPopUp(userIndex, context);
},
)),
Container(
margin: EdgeInsets.only(right: 8),
child: IconButton(
icon: Image.asset('assets/pictures/ICON-send.png'),
iconSize: 25,
onPressed: () {
print(
'This will let a user send the post to another user');
},
)),
Container(
margin: EdgeInsets.only(right: 8),
child: IconButton(
icon: Image.asset('assets/pictures/ICON_save.png'),
iconSize: 25,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ReportPanel()
),
);
},
)),
],
),
Column(
mainAxisAlignment: returnAlignment(),
//This column contains username, upload description and total upvotes
children: <Widget>[
Container(
//The person who posted along with photo description
alignment: returnCommentAlignment(),
margin: EdgeInsets.only(left: 10, right: 10),
child: RichText(
text: TextSpan(
style:
TextStyle(color: Colors.black, fontSize: 20.0),
children: <TextSpan>[
TextSpan(
text: usernames[userIndex] + ': ',
style: TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserProfile(usernames[userIndex])
),
);
}),
TextSpan(text: captions[userIndex]),
])),
),
Container(
//The total upvotes of post
alignment: returnCommentAlignment(),
margin: EdgeInsets.only(left: 10, right: 10),
child: getUpvotes(userIndex),
)
],
),
Column(
mainAxisAlignment: returnAlignment(),
//This column contains username and comment of commenters
children: <Widget>[
Container(
//First comment
alignment: returnCommentAlignment(),
margin: EdgeInsets.only(left: 10, right: 10),
child: RichText(
text: TextSpan(
style:
TextStyle(color: Colors.black, fontSize: 20.0),
children: <TextSpan>[
TextSpan(
text:
'HarperEvans1: ', //will be a username from firebase
style: TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
print(
'This will take to profile of that person');
}),
TextSpan(text: 'Nice photo!'),
])),
),
Container(
//Second comment
alignment: returnCommentAlignment(),
margin: EdgeInsets.only(left: 10, right: 10),
child: RichText(
text: TextSpan(
style:
TextStyle(color: Colors.black, fontSize: 20.0),
children: <TextSpan>[
TextSpan(
text:
'trevorwilkinson: ', //will be a username from firebase
style: TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
print(
'This will take to profile of that person');
}),
TextSpan(
text:
'Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda'),
])),
),
Container(
//view more comments
alignment: returnCommentAlignment(),
margin: EdgeInsets.only(left: 10, right: 10),
child: RichText(
text: TextSpan(
style:
TextStyle(color: Colors.grey, fontSize: 20.0),
children: <TextSpan>[
TextSpan(
text:
'view more comments', //will take to the comments
style: TextStyle(color: Colors.grey),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CommentPage(posts[userIndex], usernames[userIndex])
),
);
}),
])),
)
],
)
],
));
});
}
}
Thank you!

Currently you have nothing triggering a rebuild from Firebase. You need to return a FutureBuilder or StreamBuilder in your getUpvotes function. That will get notified of changes in the cloud and trigger a re-build.
Here's something to get you started. Return this instead in your getUpvotes method and complete the stream portion of the StreamBuilder
StreamBuilder(
stream: Firestore.instance.collection...// finish this part to get your snapshot of total upvotes from your collection,
builder: (context, snapshot) {
if(snapshot.hasData) {
return RichText(
text: TextSpan(
style: TextStyle(color: Colors.black, fontSize: 20.0),
children: <TextSpan>[
TextSpan(
text: upvotes[index].toString() + ' upvotes',
style: TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
print('This will take to upvoters of the photo');
}),
],
),
);
}
else {
// handle no data
}
},
);

Related

How to update and delete a data in a list according to it's document id - flutter, firebase 2021

I am trying to delete and update a list of details in flutter. For that i used doc('document_id') which was given as a solution in another stackoverflow question. I tried some another solutions given in stacker flow too. But nothing fork for me. But if I give a specific documentID I am able to delete that. Also how can I pass the selected data to update page too.
class addressProfile extends StatefulWidget {
const addressProfile({Key? key}) : super(key: key);
#override
_addressProfileState createState() => _addressProfileState();
}
class _addressProfileState extends State<addressProfile> {
var Default = 'unDefault';
delete() async {
try {
FirebaseFirestore.instance
.collection("address")
.doc('document_id')
.delete();
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade100,
appBar: AppBar(
centerTitle: true,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text(
'My Addresses',
style: TextStyle(color: Colors.black),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: Colors.black,
),
onPressed: () {
Navigator.of(context).pushNamed('/profilePage');
},
),
),
body: ListView(
padding: EdgeInsets.all(16),
children: [
StreamBuilder<QuerySnapshot>(
stream:
FirebaseFirestore.instance.collection("address").snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Expanded(
child: SizedBox(
height: 700,
child: ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
QueryDocumentSnapshot x = snapshot.data!.docs[index];
return Container(
child: Card(
child: Padding(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(x['firstName']),
Text(' '),
Text(x['lastName']),
],
),
Text(""),
Row(
children: [
Text(x['primaryPhone']),
Text(" / "),
Text(x['secondaryPhone']),
],
),
Text(''),
Row(
children: [
Text(x['address1']),
Text(', '),
Text(x['address2']),
Text(', '),
Text(x['city']),
Text(', '),
Text(x['region']),
],
),
Divider(
color: Colors.black,
),
Row(
children: [
Container(
child: Radio(
value: 'default',
groupValue: Default,
onChanged: (String? val) {
setState(() {
if (val != null)
Default = val;
});
}),
),
Container(
child: Text("Default"),
),
Container(
padding: EdgeInsets.only(left: 60),
child: Align(
child: ElevatedButton.icon(
onPressed: () {
if (snapshot.data!.docs.length >
1) {
delete();
Fluttertoast.showToast(
msg:
"Address deleted successfully",
toastLength:
Toast.LENGTH_SHORT,
gravity:
ToastGravity.BOTTOM,
textColor: Colors.black,
backgroundColor:
Colors.green.shade400,
);
} else {
Fluttertoast.showToast(
msg:
"Main address cannot be deleted",
toastLength:
Toast.LENGTH_SHORT,
gravity:
ToastGravity.BOTTOM,
textColor: Colors.black,
backgroundColor:
Colors.green.shade400,
);
}
},
label: Text('Delete'),
style: ElevatedButton.styleFrom(
fixedSize: Size(90, 20),
primary: Colors.red.shade500,
padding: EdgeInsets.symmetric(
horizontal: 5,
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
10))),
icon: Icon(
Icons.delete_outline_sharp),
),
),
),
Container(
padding: EdgeInsets.only(left: 14),
child: Align(
child: ElevatedButton.icon(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (builder) =>
updateAddress(),
),
);
},
label: Text('Update'),
style: ElevatedButton.styleFrom(
fixedSize: Size(90, 20),
primary:
Colors.green.shade500,
padding: EdgeInsets.symmetric(
horizontal: 5,
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
10))),
icon: Icon(Icons.edit),
),
),
),
],
),
],
),
),
),
);
},
),
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
Align(
alignment: AlignmentDirectional.bottomCenter,
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamed('/addNewAddress');
},
child: Text(
"Add New Address",
style: TextStyle(
fontSize: 15,
letterSpacing: 2,
color: Colors.black,
),
),
style: ElevatedButton.styleFrom(
fixedSize: Size(250, 40),
primary: Colors.green.shade500,
padding: EdgeInsets.symmetric(
horizontal: 50,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10))),
),
),
],
),
);
}
}
This is so far I did. Please help me to continue.
I don't know how you have saved the data. But I got an issue like this and what I did was, I added a variable as "id" to database while saving the data. There is an auto generated id plugin for flutter (nanoid). You can add that and save the data as following.
var id = nanoid(10) //10 is the length of the id. You can give as you wish
create() async {
try {
FirebaseFirestore.instance
.collection("address")
.doc(id)
.set({
"id":id,
//other inputs
});
} catch (e) {
print(e);
}
}
Then you can use that id as a key to update ad delete.
For example according to you code to delete you can use like this in the onPress(){} of delete button,
FirebaseFirestore.instance.collection("address").doc(x['id']).delete();
So the data related to id will be deleted.
Also better to use proper name rather than "x".
Can you please try this
delete(String docId) async {
try {
FirebaseFirestore.instance
.collection("address")
.doc(docId)
.delete();
} catch (e) {
print(e);
}
}
Your delete function call
delete(snapshot.data!.docs[index].id);
Update document
void update(String docId){
FirebaseFirestore.instance.collection("address").doc(docId) .update({"field1":"fieldValue1","field2":"fieldValue2"});
}
Let me know if you find any issues in comment

type 'Future<dynamic>' is not a subtype of type 'Widget?'

IM trying to call on Tap method, what I want now is change it to a future method because on Tap the method is not ready because im calling a firebase query . So heres first my method
where the onTap function is
child: InkWell(
onTap: () async {
setState(() {
israting = true;
});
},
child: israting
? buildBody(videos.data()['likes'], videos.data()['id'])
: Icon(
Icons.star,
size: 37,
color: videos.data()['likes'].contains(uid)
? Colors.yellow
: Colors.white,
),
),
So im giving the buildBody 2 parameters from a streambuilder
and then thats the function
buildBody(videoid, video) async {
if (videoid.contains(uid)) {
await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get()
.then((value) {
votefromfirebase = value.data()["rating"];
});
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: votefromfirebase,
itemBuilder: (context, index) => InkWell(
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
print(video);
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
));
} else {
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: _userRating,
itemBuilder: (context, index) => InkWell(
onTap: () {
setState(() {
_userRating = index + 1.toDouble();
});
likevideo(video, _userRating);
},
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
),
);
}
}
buildprofile(String url) {
return Container(
width: 50,
height: 50,
child: Stack(
children: [
Positioned(
left: (50 / 2) - (50 / 2),
child: Container(
width: 50,
height: 50,
padding: EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
),
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(60),
child: Container(
height: 110,
width: 110,
decoration: BoxDecoration(
color: Colors.white,
),
child: url != null && url != "profilepictureer"
? Image.network(
url,
fit: BoxFit.cover,
)
: Image.asset(
'assets/profilepictureer.png') // Your widget is here when image is no available.
),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(color: Colors.black, width: 4)),
),
),
),
],
),
);
}
}
At the moment im getting this error
The following _TypeError was thrown building:
type 'Future<dynamic>' is not a subtype of type 'Widget?'
When the exception was thrown, this was the stack
#0 _VideopageofcurrentuserState.build.<anonymous closure>.<anonymous closure> (package:wichtigdenyady/taking%20videos/currentuservideos.dart:310:47)
#1 SliverChildBuilderDelegate.build
package:flutter/…/widgets/sliver.dart:455
#2 SliverMultiBoxAdaptorElement._build
package:flutter/…/widgets/sliver.dart:1201
#3 SliverMultiBoxAdaptorElement.performRebuild.processElement
package:flutter/…/widgets/sliver.dart:1145
#4 Iterable.forEach (dart:core/iterable.dart:257:30)
The error throws in the onTap function
The buildBody function cannot be an async function.
You should move the call to Firebase out of this function and use the result of it in state, instead.
An async function always returns a Future. Because the return type isn't defined, it assumes it will return a Future<dynamic>. If you defined the return type as Widget buildBody(videoid, video) async, the IDE would show an error.
In your onTap function, you can make the call:
onTap: () async {
setState(() {
israting = true;
});
if(!videos.data()['likes'].contains(uid)) return; // don't call firebase if uid is not in videoid
final value = await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get();
setState(() {
votefromfirebase = value.data()["rating"];
});
},
Next, change the buildBody function to a non-async function and check if votefromfirebase is in the state
Widget buildBody(videoid, video) {
if (votefromfirebase == null) {
return Container(); // return empty container, progress indicator, or anything else
}
// else return the normal body
return Container(
child: Stack(
// rest of this widget

flutter and firestore : change price and size dynamicly

hello iam using flutter and firebase in my project , i have a product and evert product have a price , every product have a list of sizes , i want the product to change its price when the size changes .
here is my product document :
i know that i have to change the prices into list but how to link them together in firebase or flutter .
this is my code :
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: CustomText(
text: "Select a Size",
color: Colors.white,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: DropdownButton<String>(
value: _size,
style: TextStyle(color: Colors.white),
items: widget.product.sizes
.map<DropdownMenuItem<String>>(
(value) => DropdownMenuItem(
value: value,
child: CustomText(
text: value,
color: Colors.red,
)))
.toList(),
onChanged: (value) {
setState(() {
_size = value;
});
}),
)
],
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"${widget.product.description}",
style: TextStyle(color: Colors.white)),
),
),
Padding(
padding: const EdgeInsets.all(9),
child: Material(
borderRadius: BorderRadius.circular(15.0),
color: Colors.white,
elevation: 0.0,
child: MaterialButton(
onPressed: () async {
appProvider.changeIsLoading();
bool success = await userProvider.addToCart(
product: widget.product,
size: _size);
if (success) {
toast("Added to Cart!");
userProvider.reloadUserModel();
appProvider.changeIsLoading();
return;
} else {
toast("Not added to Cart!");
appProvider.changeIsLoading();
return;
}
},
minWidth: MediaQuery.of(context).size.width,
child: appProvider.isLoading
? Loading()
: Text(
"Add to cart",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20.0),
),
)),
),
SizedBox(
height: 20,
)
],
),
),
)
],
There is trigger for widget :
onChanged: (value) {
setState(() {
_size = value;
reference.setData({quantity : value}, merge: true)
});
}),
Just change the reference to document path.

How to add "this user/account does not exist" error in Flutter, using Firebase?

I am trying to make a login page in Flutter. I have used Firebase as well for user authentication and logging in. The problem is, while I can login successfully with the correct information, I am unable to display anything like a pop up error box or message that the account does not exist. This is my code :
class _LoginPageState extends State<LoginPage> {
String _email, _password;
final auth = FirebaseAuth.instance;
bool hidepwd = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
brightness: Brightness.light,
backgroundColor: Colors.transparent,
elevation: 0,
leading: Container(
margin: EdgeInsets.all(5),
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Color(0xffe9eefa),
),
child: IconButton(
onPressed: (){Navigator.pop(context);},
icon: Icon(
Icons.keyboard_arrow_left_rounded,
color: Color(0xff2657ce),
),
),
),
),
body: ListView(
children: <Widget>[
Container(
child: IconButton(
icon: Icon(
Icons.account_circle_rounded,
color: Color(0xff2657ce),
size:100,
),
),
),
SizedBox(height: 50,),
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.only(right: 240),
child: Text('Email Address', style: TextStyle(
fontSize: 15,),),
),
SizedBox(height: 10,),
Container(
padding: EdgeInsets.symmetric(vertical: 2, horizontal: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Colors.grey.withOpacity(0.2),
),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'Email',
),
onChanged: (value) {
setState(() {
_email = value.trim();
});
},
),
),
SizedBox(height: 20,),
Container(
padding: EdgeInsets.only(right: 270),
child: Text('Password', style: TextStyle(
fontSize: 15,
),),
),
SizedBox(height: 10,),
Container(
padding: EdgeInsets.symmetric(vertical: 2, horizontal: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Colors.grey.withOpacity(0.2),
),
child: Row(
children: <Widget>[
Expanded(
child: TextFormField(
obscureText: hidepwd,
decoration: InputDecoration(hintText: 'Password'),
onChanged: (value) {
setState(() {
_password = value.trim();
});
},
),
),
Container(
height: 50,
width: 50,
child: IconButton(
onPressed: togglepwdVisibility,
icon: IconButton(
icon: hidepwd == true ? Icon(
Icons.visibility_off
): Icon(Icons.visibility),
),
),
)
],
),
),
SizedBox(height: 20,),
RaisedButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
color: Color(0xff5178D7),
child: Text("Log In", style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 15
),),
onPressed: (){
auth.signInWithEmailAndPassword(email: _email, password: _password).then((_){
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => frontpage()));
});
}
),
SizedBox(height: 20,),
Container(
child: Center(
child: Text('---- or ----'),
),
),
SizedBox(height: 20,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Don't have an account? "),
InkWell(
onTap: openSignUpPage,
child: Text("Sign Up", style: TextStyle(
color: Color(0xff1A3C90),
fontWeight: FontWeight.w700
),),
)
],
)
],
),
),
),
],
),
);
}
Any ideas/suggestions on what I could add or change in my code to have that error message included when I am unable to login overall?
In your login onPressed: (){ ... }, catch the FirebaseAuthException.
Source: https://firebase.flutter.dev/docs/auth/usage/#sign-in
try {
UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: "barry.allen#example.com",
password: "SuperSecretPassword!"
);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
If you need alerts to pop on each login error you can try using the following function but only if you are using TextEdittingController:
signIn() async {
if (_loginFormKey.currentState!.validate()) {
_loginFormKey.currentState!.save();
try {
await FirebaseAuth.instance
.signInWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text)
.then((currentUser) => FirebaseFirestore.instance
.collection("users")
.doc(currentUser.user!.uid)
.get()
.then((conext) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage())))
.catchError((err) => print(err)));
} on FirebaseAuthException catch (error) {
if (error.code == 'user-not-found') {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Auth Exception!"),
content: Text("This User Does Not Exist."),
actions: <Widget>[
Row(
children: [
ElevatedButton(
child: Text("Sign In Again"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
)
],
);
});
} else if (error.code == 'wrong-password') {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Auth Exception!"),
content: Text("The Password Entered is Invalid."),
actions: <Widget>[
Row(
children: [
ElevatedButton(
child: Text("Sign In Again"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
)
],
);
});
}
}
}
}

Error while returning the number of count of collections in firebase flutter?

i'm developing an admin app in that i'm tired to return the number of users from firebase, i got few help from stackoverflow and was able to print in the terminal but its returning null on the app can someone please help me.this my code
class _AdminState extends State<Admin> {
Future<String> getUsersCount() async{
var length = -1;
await Firestore.instance.collection('users').getDocuments().then((myDocuments){
print("${myDocuments.documents.length}");
length = myDocuments.documents.length;
});
return Future.value(length.toString());
}
Page _selectedPage = Page.dashboard;
MaterialColor active = Colors.indigo;
MaterialColor notActive = Colors.grey;
final databaseReference = Firestore.instance;
bool isDelete= true;
var values;
TextEditingController categoryController = TextEditingController();
TextEditingController brandController = TextEditingController();
GlobalKey<FormState> _categoryFormKey = GlobalKey();
//GlobalKey<FormState> _brandFormKey = GlobalKey();
// BrandService _brandService = BrandService();
CategoryService _categoryService = CategoryService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: <Widget>[
Expanded(
child: FlatButton.icon(
onPressed: () {
setState(() => _selectedPage = Page.dashboard);
},
icon: Icon(
Icons.dashboard,
color: _selectedPage == Page.dashboard
? active
: notActive,
),
label: Text('Dashboard'))),
Expanded(
child: FlatButton.icon(
onPressed: () {
setState(() => _selectedPage = Page.manage);
},
icon: Icon(
Icons.sort,
color:
_selectedPage == Page.manage ? active : notActive,
),
label: Text('Manage'))),
],
),
elevation: 0.0,
backgroundColor: Colors.white,
),
body: _loadScreen());
}
Widget _loadScreen() {
switch (_selectedPage) {
case Page.dashboard:
return FutureBuilder(
future: getUsersCount(),
builder: (BuildContext context, AsyncSnapshot<String> text) {
print(text);
if(text== "-1"){
return CircularProgressIndicator();
} else {
return Column(
children: <Widget>[
ListTile(
subtitle: Text('Admin View', textAlign: TextAlign.center,
style: TextStyle(fontSize: 29.0,
color: Colors.indigo,
fontWeight: FontWeight.bold),),
),
Expanded(child: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,),
children: <Widget>[
Padding(
padding: const EdgeInsets.all(18.0), child: Card(
child: ListTile(title: FlatButton.icon(
onPressed: null,
icon: Icon(
Icons.directions_boat, color: Colors.black,),
label: Text("Boats", style: TextStyle(
fontSize: 9, color: Colors.indigo),)),
subtitle: Text('3', textAlign: TextAlign.center,
style: TextStyle(
color: active, fontSize: 50.0),)),
),
),
Padding(padding: const EdgeInsets.all(18.0),
child: Card(child: ListTile(
title: FlatButton.icon(
onPressed: null,
icon: Icon(
Icons.people, color: Colors.black,),
label: Text("Users", style: TextStyle(
fontSize: 9, color: Colors.indigo),)),
subtitle: Text(text.data != null ? text.data : '',
textAlign: TextAlign.center,
style: TextStyle(color: active, fontSize: 50.0),
)),
),
),
Padding(
padding: const EdgeInsets.all(22.0),
child: Card(
child: ListTile(
title: FlatButton.icon(
onPressed: null,
icon: Icon(
Icons.bookmark, color: Colors.black,),
label: Text("Bookings", style: TextStyle(
fontSize: 8, color: Colors.indigo),)),
subtitle: Text(
'120',
textAlign: TextAlign.center,
style: TextStyle(
color: active, fontSize: 50.0),
)),
),
),
],
),
),
],
);
} })
i was returning a null string value but when include this set of lines Text(text.data??'default value') i was able to clear that error but still not able to clear my issue someone please help me
You need to add await before getting data from Firestore, since it is and async and you are not waiting for the result and returning the value which is initialized to 0
Future<String> getUsersCount() async {
var length = 0;
await Firestore.instance.collection('users').getDocuments().then((myDocuments){
print("${myDocuments.documents.length}");
length = myDocuments.documents.length;
});
return Future.value(length.toString());
}
As you can see the value of users count(36) is getting printed but it is not return because the return gets called before the async execution is getting finish..
Initialize your length to -1 in getUsersCount method and then in build method before returning the cloumn widget check the text (snapshot value) :
if (text == "-1"){
return Center(
child: CircularProgressIndicator(backgroundColor: Colors.red,)
);
} else{
return Column(....)
}

Resources