Problem with the initialRoute of my flutter app - flutter

initialRoute: FirebaseAuth.instance.currentUser == null
? "FirstPage"
: FirebaseAuth.instance.currentUser!.emailVerified
? "Home"
: "FirstPage/SignIn/VerificaEmail",
Thanks to this script I know if the user is already logged in, if he has completed the registration or if he has to do everything from the beginning. This way I can send it to the necessary page.
My problem is that before bringing it to the home, if the registration is complete, I want to check if its document exists on the firestore db; otherwise I want to take the user to the appropriate page to enter the data and create the document.
I was able to do this in my login and signin page thanks to the following code:
void verifica(context) async {
var doc = await FirebaseFirestore.instance
.collection("Users")
.doc(FirebaseAuth.instance.currentUser!.uid)
.get();
if (doc.exists) {
Navigator.pushNamedAndRemoveUntil(context, "Home", (route) => false);
} else {
Navigator.pushNamedAndRemoveUntil(context, "ModificaProfilo", (route) => false);
}
}
But I am not able to implement this function in main.

Related

How to navigate to home screen after successfully login in flutter?

I'm using the following code for login. But the problem is after successfully login it's not able to navigate to home page. If I navigate inside on pressed button then it automatically navigate to home and it will not check either user exists or not.
try {
final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: emailAddress,
password: password
);
} 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.');
}
}
I have called isUserLoggedIn function after pressing login button.
Change like this,
try {
final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: emailAddress,
password: password
);
//---------------------- add this part --------------
if (user != null) {
Navigator.of(context).pushNamedAndRemoveUntil(
'/home', (Route<dynamic> route) => false);
// route set to use this.
}
} 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.');
}
}
You can also use this method,
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(),
),
);
But If you use this, the user can back to login screen without signout. So, use pushNamedAndRemoveUntil method to navigate. It will remove all past routes. can't go back.
Read about pushNamedAndRemoveUntil
If you just want to check for the user and navigate based on that, HoRiz has answered.
But I would suggest that you implement a state management solution first like BLoC, Riverpod, etc. It will help you to manage all your data like user info or any other data.
Also if you are not using named routes, then you can use this instead to navigate:
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => NewScreen(),
),
);
Also, if want to learn all the things about routing then you can check Flutter's Oficial Website: Link
Navigator.pushReplacement(context,MaterialPageRoute(builder: (context)=>HomePage()));

Log out button for different type of accounts in flutter firebase Auth

I have a flutter app with multiple sign in options (Email and password, Google account, phone number). Once the user sign in to the application, he will then have a drawer.
There is a Sign out button inside this drawer which should sign the user out when he press it and send him back to the signup page. So I have been using the sign out instance from firebase auth
await FirebaseAuth.instance.signOut();
But since I added the google sign in options I started facing a problem which is that for google sign out, I nee dto disconnect the user first await googleSignIn.disconnect();
So I added this line to the sign out function to be like this:
Future<void> SignOut() async {
await googleSignIn.disconnect();
await FirebaseAuth.instance.signOut();
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => AuthPage(),
),
(route) => false,
);}
This button works fine when the user sign in with google but if he signs in with different method then an error will be thrown:
Unhandled Exception: PlatformException(status, Failed to disconnect., null, null)
How can I handle different type of users signout with one button?
Future<void> SignOut() async {
if (googleSignIn.currentUser != null){
await googleSignIn.disconnect();
await FirebaseAuth.instance.signOut();}
else{
await FirebaseAuth.instance.signOut();}

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 Session stores data but can't make decisions based off it

I'm using FlutterSession to store phone number/email (based on user's choice) as a method of logging into the app. The session works fine in case of email but when I store and retrieve phone number, it shows me the snapshot has no data.
This is the method where I'm setting the session value for the phone number:
void phoneSignIn() async {
if (phoneNumber == null || phoneNumber.length < 10) {
print('Please enter a valid phone number!');
}
else {
await fillers.session.set("phoneNum", phoneNumber);
print('Phone number is: '+ phoneNumber);
setState(() {
phoneSignedIn = true;
});
var sessionCheck = await fillers.session.get("phoneNum");
print("Session value: $sessionCheck");
print(phoneSignedIn);
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => OnboardOne()));
}
}
In the above code, I've made sure using print statements that the session is storing phone number value and also that the phoneSignedIn bool is set to true.
This is the method where I'm setting session value for email:
void signIn() async {
response = await Dio().post(url,
data: {
"email": emailVal,
"password": passwordVal
}
);
if (response.statusCode == 200) {
await fillers.session.set('email', emailVal);
await fillers.session.set('password', passwordVal);
print('Sign In successful!');
print('Email: $emailVal');
print('Password: $passwordVal');
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => OnboardOne()));
}
else
{
print('Exited with statuscode ${response.statusCode}');
print('Email: $emailVal');
print('Password: $passwordVal');
}
}
This is my firstpage where I decide on which page to go based on whether the user has logged in or not:
class _FirstPageState extends State<FirstPage> {
#override
Widget build(BuildContext context) {
return Material(
child: FutureBuilder(
future: phoneSignedIn ? session.get("phoneNum") : session.get('email'),
builder: (context, snapshot) {
return snapshot.hasData ? Dashboard() : SignUpIn();
}
),
);
}
}
As you can see, I've done nothing different in the email sign in (except using a backend api to auth the email). Ultimately, I'm using the same technique to store both the email and phone number. But when I've signed in using phone number and then reopen the app, the app goes to the SignUpIn() page, when it should actually go to the Dashboard() page.
Also, on the dashboard, there's a button "Sign Out", on pressing which, the session values are cleared.
What am I doing wrong?

Provider keeps data after logout

In my first screen, I consume data from Firebase and store it in provider.
This data will be used in another screen.
#override
void initState() {
super.initState();
FirestorePreviousPage.documentsListDescending().then((query) {
final totalHisabProvider = Provider.of<TotalHisab>(context, listen: false);
totalHisabProvider.addItemsFromSnapshot(query);
final unpaidHisabProvider = Provider.of<UnpaidHisab>(context, listen: false);
unpaidHisabProvider.addItems(query);
final paidHisabProvider = Provider.of<PaidHisab>(context, listen: false);
paidHisabProvider.addItems(query);
});
}
The documentsListAscending method:
static Future<QuerySnapshot> documentsListDescending() async {
final user = await CurrentUser.getCurrentUser();
return await Firestore.instance
.collection(user.uid)
.orderBy('serverTimestamp', descending: true)
.getDocuments();
}
My logout method:
static Future<void> logout(BuildContext context) async {
await FirebaseAuth.instance.signOut();
Navigator.of(context).pushNamedAndRemoveUntil(
WelcomeScreen.routeName,
(Route<dynamic> route) => false,
);
}
Now when I do logout and login with a different user, this new user still has access to the data of the previous user. Now I think I understand this part. As long as the app is working, it will keep the data in the state management.
But why doesn't the retrieve the new data from Firebase?
Shouldn't this line update data with the new user ID: .collection(user.uid)
I have an idea of how to solve this. Just clear the data in all the providers in the logout method. But that doesn't feel right. I need to understand why it isn't working first.
I ended up clearing the providers manually:
static Future<void> logout(BuildContext context) async {
await FirebaseAuth.instance.signOut();
// Clear all providers
Provider.of<Cart>(context, listen: false).clear();
Provider.of<UnpaidHisab>(context, listen: false).clear();
Provider.of<PaidHisab>(context, listen: false).clear();
Provider.of<TotalHisab>(context, listen: false).clear();
Navigator.of(context).pushNamedAndRemoveUntil(
WelcomeScreen.routeName,
(Route<dynamic> route) => false,
);
}
It works just fine as far I can tell.