How to assign a Future variable to a class getter in Flutter - firebase

I'm trying to read user data from Firebase via Streamer and assign them into properties of my User class. I have a FirabaseActions class doing firebase stuff. Here is the method that I use streamer to get data. It works perfectly, and print(user.data['userName']); give me the right result.
static Future<User> userDataStream(loggedInUserEmail) async {
final databaseReference = Firestore.instance;
User currentUser;
await for (var snapshot in databaseReference
.collection('users')
.where('email', isEqualTo: loggedInUserEmail)
.snapshots()) {
for (var user in snapshot.documents) {
print(user.data['userName']);
currentUser.userName = user.data['userName'];
currentUser.email = user.data['email'];
currentUser.userID = user.data['userID'];
currentUser.level = user.data['level'];
}
}
return currentUser;
}
The problem begin when I try to assign these user info to my class properties. Here is my User class. I got an error like below. It is about Future type but I can't handle it. What should I do?
Class 'Future' has no instance getter 'email'.
Receiver: Instance of 'Future'
Tried calling: email
class User {
String userName;
String userID;
String email;
int level;
User({this.userName, this.userID, this.level, this.email});
}

The first problem is that you cant assign an username like this
currentUser.userName = user.data['userName'];
Because currentUser is null. A simple solution to that is to replace
User currentUser; with User currentUser = User();
Second problem :
I think you should never search user by his email, rather by the UID that you get from
FirebaseUser user = await FirebaseAuth.instance.currentUser(),
So you would query for the user like this :
static Future<User> userDataStream() async {
final firestore = Firestore.instance;
final currentFirestoreUser = await FirebaseAuth.instance.currentUser();
User currentUser;
var query = await firestore
.collection('users')
.where('uid', isEqualTo: currentFirestoreUser.uid)
.getDocuments();
var user = query.documents.first.data;
currentUser = User(
userName: user['userName'],
userID: user['userID'],
level: user['level'],
email: user['email']);
return currentUser;
}
You could add UID as a method's parameter, or leave it inside the method.

Related

Failed to get uid to use within DatabaseService class in flutter

I face a problem where I can't get the current user ID from my firebase. I've already make that every new user will have their own collection based on the UID like this:
void addImagetoFirestore() async {
final CollectionReference imageData = Firestore.instance.collection(uid);
This is my DatabaseService class
class DatabaseService {
final String uid;
DatabaseService({this.uid});
String useruid;
final FirebaseAuth auth = FirebaseAuth.instance;
//Collection reference
final CollectionReference warrantyCollection =
Firestore.instance.collection('user id here');
List<Picture> _warrantyListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return Picture(
name: doc.data['product name'],
info: doc.data['info'],
url: doc.data['url'],
uid: doc.data['uid']);
}).toList();
}
Future updateUserData(String name) async {
return await warrantyCollection.document(uid).setData({'name': name});
}
Stream<List<Picture>> get picture {
return warrantyCollection.snapshots().map(_warrantyListFromSnapshot);
}
}
I've tried referring to this,
but it seem like I can't just make something like
final CollectionReference warrantyCollection = Firestore.instance.collection(useridmethod());
are there any other alternative that I can try?
Instead of getting uid as a parameter to class, fetch it in constructor because in your case final FirebaseAuth auth = FirebaseAuth.instance; is useless as I see.
try this;
DatabaseService(){
userId = auth.currentUser.uid;
}

Store array from cloud firestore into variable

I have a collection called users. Each document has the ids of posts they have saved in an array. Is it possible to put this array into a variable and have it in a Text() widget? Essentially the text widget output would look like this on screen oMqSYa97CteaDr19lZ5Ga6WO4jn8oPJREOcJWLI2.
I have searched for this solution, but haven't found any luck.
I've tried a few things, but usually end up with Instance of 'Future DocomentSnapshot'
you should share your code for us to learn what you did and why do you face with that oMqSYa97CteaDr19lZ5Ga6WO4jn8oPJREOcJWLI2. However, firstly, you should create a model like that
class UserData {
final String uid;
final String name;
final String sugars;
final int strength;
UserData({ this.uid, this.sugars, this.strength, this.name });
}
and an instance;
final CollectionReference UsersCollection =
FirebaseFirestore.instance.collection('users');
and you can use it like that ;
UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
return UserData(
uid: uid,
name: snapshot.data()['name'],
sugars: snapshot.data()['sugars'],
strength: snapshot.data()['strength'],
);
}
Stream<UserData> get userData {
return UsersCollection.doc(uid).snapshots().map(_userDataFromSnapshot);
}
finally;
UserData userData = snapshot.data.sugars;

Unable to Return Queried Data From Firebase (Flutter/Dart)

Context: I'm trying to query and return a String (imgUrl) from Firebase. I'm always able to print the string inside the query, but the returned value is always null. I'm wondering if my query is wrong and am not sure what best practices are.
Database Outline:
Query Function:
This is the code under our DatabaseService() class, which contains all database queries and updating functions.
String getImageUrl(String _uid) {
String _imgUrl;
Firestore.instance
.document('users/$_uid')
.get()
.then((value) => _imgUrl = value['imgUrl']);
return _imgUrl;
}
Main:
getImageUrl() is called under setImage(). The toast under setImage always returns null and so does the code under it.
String _uid;
// Sets variable '_uid' to the uid of the current user
// Gets called in initstate
Future _getUid() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
_uid = user.uid;
}
// Sets the profile photo. If there is no existing profile photo online,
// grab the image on the device. If there is no image online OR on the device,
// Display the default image
void setImage(String url) {
// Get the url that's stored in the db
String _tempUrl = DatabaseService().getImageUrl(_uid); // always ends up being null
Fluttertoast.showToast(msg: "_tempUrl: $_tempUrl");
// Rest of the function
}
#override
void initState() {
super.initState();
_getUid();
}
Please let me know what to do to fix this as it's driving me crazy. Thanks in advance.
Change the method to the following:
Future<String> getImageUrl(String _uid) async {
String _imgUrl;
DocumentSnapshot value =
await Firestore.instance.document('users/$_uid').get();
_imgUrl = value['imgUrl'];
return _imgUrl;
}
use async/await to wait for the future to finish, and then call it like the following:
void setImage(String url) async{
// Get the url that's stored in the db
String _tempUrl = await DatabaseService().getImageUrl(_uid); // always ends up being null
Fluttertoast.showToast(msg: "_tempUrl: $_tempUrl");
// Rest of the function
}

Firestore query to variable to populate shared preferences

New to Flutter, and although I've been around code for many years, this is my first time actually developing. I've been trying to figure out how to query the Cloud Firestore and map one of those properties to a shared preference. Since my app is talking to the cloud firestore when a user logs in anyway, I feel like I can update my shared preferences with a few fields that will save me from having to call firestore everytime I want to retrieve that piece of information.
I created a class that represents the collection layout in the firestore
class FirestoreUser {
FirestoreUser(this.aboutMe, this.nickname);
final String aboutMe;
final String nickname;
factory FirestoreUser.fromMap(Map<String, dynamic> data) {
if (data == null) {
return null;
}
final String aboutMe = data['aboutMe'];
final String nickname = data['nickname'] ?? '';
return FirestoreUser(aboutMe, nickname);
}
Map<String, dynamic> toMap() {
return {
'aboutMe': aboutMe,
'nickname': nickname,
};
}
}
I also have a function that writes data to the Firestore collection. That works just fine.
What I'm having a hard time with is how do I query for "aboutMe" in the collection above? I'm using
a provider to get the uid, but how do I do something like this:
aboutMe = Firestore.query.tothatdocument
Here's what I have been working on so far:
final user = Provider.of<User>(context, listen: false);
final firestore = Provider.of<FirestoreService>(context, listen:false);
final firebaseUser = await FirebaseAuth.instance.currentUser();
final QuerySnapshot result = await Firestore.instance.collection('users').where('id', isEqualTo: firebaseUser.uid).getDocuments();
final List<DocumentSnapshot> documents = result.documents;
SharedPreferences prefs = await SharedPreferences.getInstance();
And I want to do something like this:
prefs.setString('aboutMe', 'thatAboutMeVariable);
Is this possible? I think I'm missing capturing the stream as a snapshot? but not to sure.
Thanks again!
I ended up creating a new class with functions to retrieve the fields that I wanted. I then assigned a variable to the results of that function.
Here's the call:
aboutMe = await FirestoreUserService(id: widget.id).getAboutMeFromFirestore();
Here's the class and function:
class FirestoreUserService {
FirestoreUserService({#required this.id});
final FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference users;
String aboutMe;
Future getAboutMeFromFirestore() async {
DocumentSnapshot ds = await FirebaseFirestore.instance.collection('users').doc(id).get();
aboutMe = ds.data()['aboutMe'];
//print('\nFirestore aboutMe is value: $aboutMe');
return aboutMe;
}
}

How to connect specific user to specific product

I've product class that contain
String id;
String address;
String image;
bool isFavourite;
String userEmail;
I've also google sign in method that in the end return this:
FirebaseUser user = await _auth.signInWithCredential(credential);
print(user.displayName);
return user;
How do i connect specific user to specific product?
For example in this method:
final Map<String, dynamic> responseData = json.decode(response.body);
final Product addedProduct = Product(
id: responseData['name'],
address: address,
image: image,
userEmail: userEmail //the problem
);
I expect to get here 3 arguments, currently 2 hard coded and the user name should be dynamic based on which email login is currently use through the sign in method, but i can't get access to the user.displayName/email etc
onPressed: () => model.addProduct('USA',
'https://cdn.pixabay.com/photo/2019/01/27/22/31/girl-3959203__340.jpg',),
You can use email property of FirebaseUser. Check API docs or simply dive in to the source code on your IDE.
FirebaseUser _user;
void _signIn() async {
_user = await _auth.signInWithCredential(credential);
print(_user.displayName);
}
void addProduct (String address, String image){
final Map<String, dynamic> responseData = json.decode(response.body);
final Product addedProduct = Product(
id: responseData['name'],
address: address,
image: image,
userEmail: _user.email //the problem
);
}

Resources