Flutter + Dart : my class stop after i get the data from firebase - flutter

I do not know what happened but after the line where I get my data from firebase the class stops
final DocumentSnapshot doc = await userRef.document(user.id).get();
i tried to print something after that line but it won't run, no idea why...
i want my class to redirected the user to create an account
createUserInFireStore() async {
final GoogleSignInAccount user = googleSignIn.currentUser;
final DocumentSnapshot doc = await userRef.document(user.id).get();
if (!doc.exists) {
final username = await Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateAccount()));
userRef.document(user.id).setData({
'id': user.id,
'username': username,
'photoURL': user.photoUrl,
'email': user.email,
'displayName': user.displayName,
'bio': '',
'timeStamp': timeStamp,
});
}}
but everything stops after the lined I mentioned
the console show this
E/flutter (26482): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(error, FirebaseOptions.getProjectId() cannot be null, null)

in your 'CreateUserinFireStore' function, change the code inside the If condition to following,
if (!doc.exists) {
await userRef.document(user.id).setData({
"id": user.id,
"userNAme": userName,
"photoUrl": user.photoUrl,
"email": user.email,
"displayName": user.displayName,
"bio": "",
"timeStamp": timestamp
});
Navigator.of(context)
.push(MaterialPageRoute(builder: (conetext) => CreateAccount()));
}
I think this link will help you
https://firebase.google.com/docs/database/unity/retrieve-data

Maybe the Future userRef.document(user.id).get() just never returns, try a timeout:
final DocumentSnapshot doc = await userRef.document(user.id).get().timeout(Duration(seconds:5));
if you get a timeout error, check the network connection, or if anything else is blocking your request to firebase.

Related

Cloud Firestore Database is not displaying users after authentication?

I am trying to do authentication using createUserWithEmailAndPassword .The user iis getting created since I can signin using the email and password which created using createUserWithEmailAndPassword .But my firestore database is not showing the document which I have created using createUserWithEmailAndPassword().
This is my code:
onPressed: () async {
try {
final newuser = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email ?? 'error',
password: password ?? 'error',
);
if (newuser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => home()),
);
}
} catch (e) {
print(e);
}
I have created 3 users with this method and I'm able to login with these credential but these users are not showing in my Firestore Database.
As #ashish already mentioned, you need to store all your extra parameters in the firestore as documents. A better way to implement this is to use different function to register user and create a user document related to that registered user.
Below is an example I created to help out!
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
void main() {
String email = "test#test.com";
String password = "123456";
String firstName = "test";
String lastName = "test";
String phoneNumber = "09876543456";
/// This is the function to create new user
Future<void> createUser(
email,
password,
firstName,
lastName,
phoneNumber,
/*... and any other params you wish to collect */
) async {
// firebase auth
final FirebaseAuth auth = FirebaseAuth.instance;
// firestore db
FirebaseFirestore db = FirebaseFirestore.instance;
// try-catch creation process to accurate exception
try {
final credential = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
// get user id
String userID = credential.user!.uid;
// creating user profile on db
await db.collection("users").doc(userID).set({
"id": userID,
"firstName": firstName,
"lastName": lastName,
"phoneNumber": phoneNumber,
// ... other params
});
print("Signed up successfully!");
} on FirebaseAuthException catch (error) {
print("Something is wrong: $error");
}
}
/// this is the create button
TextButton(
onPressed: () async {
await createUser(
email,
password,
firstName,
lastName,
phoneNumber,
/*... and any other params you wish to collect */
);
},
child: const Text("Create test user"),
);
}
Let me know if you need anything else :). BYE!!!
To store the data in the database you need to use a Firestore instance to store data in firebase Firestore.
onPressed: () async {
try {
final newuser = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email ?? 'error',
password: password ?? 'error',
);
await FirebaseFirestore.instance.collection('Users').doc(newuser!.uid).set({
email: newuser.email
});
if (newuser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => home()),
);
}
} catch (e) {
print(e);
}
}
You need to put the data which you want to store in firestore in set() function.
Firebase Authentication data are show into the login into firebase then on tap of Authentication options menu -> user section , you can view store 3 users data in this section

The body might complete normally, causing 'null' to be returned, but the return type, 'FutureOr<UserCredential>', is a potentially non-nullable type

I am building a flutter app and I am trying to create a method that will enable users to be registered in Firebase as well as storing their data in Firestore. I am getting an error where the body is returning null. I know the method has to return Usercredential somehow but I am a bit stuck. Please may anyone assist.
Here's my code:
void validateAndSubmit() async {
if (validateAndSave()) {
try {
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: _email, password: _password)
.then((userCredential) {
FirebaseFirestore.instance.collection('users').doc(userCredential.user!.uid).set({
"uid": userCredential.user!.uid,
'Name': _name,
'userName': _userName,
'email': _email,
});
}
);
Navigator.pushNamed(context, '/home');
print('Registered user: ${userCredential.user}');
const snackBar =
SnackBar(content: Text('User has been successfully registered!'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
} on FirebaseAuthException catch (e) {
print('Error: $e');
}
}
}
This error is due to chances of userCredential being null, i.e Firebase not being able to create a user with given credentials. So it'd be better to await FirebaseAuth as
UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(email: _email, password: _password)
and then check if user returned is null by using an if statement, then continue with the above Firestore part.
Easier way, add nullcheck here:
...
.then((userCredential!) {
...
This happened because you use ! on userCredential which may be null, You can change your code to this:
try {
UserCredential? userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: _email, password: _password);
if (userCredential != null) {
FirebaseFirestore.instance
.collection('users')
.doc(userCredential.user!.uid)
.set({
"uid": userCredential.user!.uid,
'Name': _name,
'userName': _userName,
'email': _email,
});
Navigator.pushNamed(context, '/home');
print('Registered user: ${userCredential.user}');
const snackBar =
SnackBar(content: Text('User has been successfully registered!'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
} on FirebaseAuthException catch (e) {
print('Error: $e');
}

How can I get a specific field into Firestore in Flutter

I have this function which is called when I push an Upload Button. It should create a collection in Firestore called userPosts with postId, ownerId, and mediaUrl. Everything is working except username because I have to take it from another collection in Firestore called users. So I have this error: Unhandled Exception: Invalid argument: Instance of 'Future <String>' How can I fix this? Thanks!
final userRef = FirebaseFirestore.instance.collection('users');
final postsRef = FirebaseFirestore.instance.collection('posts');
createPostInFirestore({required String mediaUrl}) {
postsRef.doc(user!.uid).collection("userPosts").doc(postId).set({
"postId": postId,
"ownerId": user!.uid,
"username": userRef.doc(user!.uid).get().then((snapshot) {
return snapshot.data()!['username'].toString();
}),
"mediaUrl": mediaUrl,
"timestamp": timestamp,
"likes": {},
});
}
the get() and set() methods are asynchronous ( needs time to resolve ), so we need to make the function asynchronous with the async keyword, then wait to get the username, after that, wait to update the data with set().
try this:
final userRef = FirebaseFirestore.instance.collection('users');
final postsRef = FirebaseFirestore.instance.collection('posts');
Future<void> createPostInFirestore({required String mediaUrl}) async {
final username = await userRef.doc(user!.uid).get().then((snapshot) {
return (snapshot.data() as Map<String, dynamic>)!['username'].toString();
});
await postsRef.doc(user!.uid).collection("userPosts").doc(postId).set({
"postId": postId,
"ownerId": user!.uid,
"username": username,
"mediaUrl": mediaUrl,
"timestamp": timestamp,
"likes": {},
});
}
then on the onPressed or the method which will execute this function, you need to wait for it also like this:
onPressed: () async {
await createPostInFirestore("your string URL here");
}
now it will work fine

How to get the current UserId from Firestore?

I have a collection users where every user has his own document. Now I want to create a subcollection to store more data related to a specific user.
This is the code so far:
class DatabaseService {
Future isUserRegistered(String uid) async{
return await FirebaseFirestore.instance.collection('users')
.where('uid', isEqualTo: uid)
.get();
}
Future registerNewUser(email, password, uid) async{
return await FirebaseFirestore.instance.collection('users')
.doc(uid).set(
{
"email": email,
"password": password,
"uid": uid,
"token": -1,
"userGoal": false,
"userGender": false,
},
);
}
I created a save function but instead of storing data in a subcollection within the document with the current uid, firestore creates a new document named 'uid'. How to fix that?
Future saveInSubcollectionToRemote() async{
Map<String, dynamic> data = UserManager.userWeights;
return await FirebaseFirestore.instance.collection('users')
.doc('uid')
.collection('weights')
.doc(data['userWeight'])
.set(data);
}
class UserManager {
static Map<String, dynamic> userWeights = {'weights': []};
}
EDIT
This is my google authentication, here i get an id but instead of this id i want the uid
///Authentication
void signInGoogle(context) {
DatabaseService handler = new DatabaseService();
_googleSignIn
.signIn()
.then((userdata) => {
print(userdata.toString()),
handler
.isUserRegistered(userdata.id.toString())
.then((value) => {
if (value.docs.length == 0)
{
print("Not registered"),
registerUserToApp(
context, userdata.email.toString(), "password", userdata.id.toString())
}
else
{
print(value.docs[0].data().toString()),
UserManager.userdata = value.docs[0].data(),
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return NavBar();
},
),
(route) => false,
),
}
})
.catchError((e) => {
showAlertDialog(
context, "Error", ""),
})
})
.catchError(
(e) => {showAlertDialog(context, "Error", "")});
}
void registerUserToApp(context, email, password, uid) {
DatabaseService handler = new DatabaseService();
try {
handler.registerNewUser(email, password, uid).then((value) => {
showAlertDialog(context, "Congratulations!",
"You registered to the app"),
});
} catch (error) {
print(error.toString());
showAlertDialog(context, "Error", "");
}
}
}
The uid in your code is typically the unique identified of the user. Firestore itself has no knowledge of such a uid. Instead, the uid comes from the identity provider that you use.
You could use the user ID from Google Sign-in to identify the user in Firestore, but it's more common to sign in with Firebase (too).
Once you've signed in to Google, you can use those credentials to sign in to Firebase Authentication by calling signInWithCredential as shown in the documentation on social authentication.
Once you're signed in to Firebase Authentication you'll get a UID from Firebase Authentication, which you can then use to identify the user's documents in Firestore (and later also secure access to those documents).
Once you've done that, you can get the current user (and from there their UID) through FirebaseAuth.instance.currentUser (once) or FirebaseAuth.instance.currentUser() (continuous) and then again use that in your Firestore calls.
Using doc('uid') is setting your document id as 'uid'. This is whats causing your issue.
Try this:
Future saveInSubcollectionToRemote(String uid) async{
Map<String, dynamic> data = UserManager.userWeights;
return await FirebaseFirestore.instance.collection('users')
.doc(uid)
.collection('weights')
.doc(data['userWeight'])
.set(data);
}
pass in uid like you did in registerNewUser()

Flutter - Firebase Realtime Database Problem

I have recently approached the world of flutter and now I have a problem, in practice I need to write during the first recording of data in a Realtime Database.
I created the void function (I've done the association final databaseReference = FirebaseDatabase.instance.reference(); before.
This is the function
void writeDB() async{
User user = await _firebaseAuth.currentUser;
FirebaseDatabase.instance.reference().child('user').equalTo(user.uid);
databaseReference.child('user').set({
'email': FirebaseAuth.instance.currentUser.email,
'name': "",
'nick': "",
"score": "0"
});
}
And this is the signIn function :
Future<String> signIn(String email, String password) async {
UserCredential result = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
writeDB();
User user = result.user;
return user.uid;
}
The registration and login system with firebase works fine, but the database is not written
Any help?
It seems you are using the new version of firebase auth. The currentUser property doesnt return a Future, try the following:
void writeDB() async{
User user = _firebaseAuth.currentUser;
await databaseReference.child('user').set({
'email': FirebaseAuth.instance.currentUser.email,
'name': "",
'nick': "",
"score": "0"
});
}