Check if Firebase User is null in Flutter - flutter

I'm making a Flutter App and I want to check if the user is registered in the database when he logs in the app.
So basically if he's registered and he logs in with no errors, there will be a loading indicator and he will be redirected to the Homepage.
If he made an error (wrong email/password for example) he will get snackbar displaying the error.
The problem is that I couldn't find the right 'if statement' to check if the user is registered or not.
Here's my Login button :
`
TextButton(
onPressed: () async {
if (_key.currentState!.validate()) {
var email = _emailController.text;
var password = _passwordController.text;
User? user =
(await _auth.login(email, password, context));
user != null
? setState(() => loading = true)
: setState(() => loading = false);
print(loading);
}
},
child: loading
? const CircularProgressIndicator()
: Text('Connect'),
),
`
And the login function :
Future login(String email, password, BuildContext context) async {
try {
User user = (await _auth.signInWithEmailAndPassword(
email: email, password: password))
.user!;
Navigator.pushNamed(context, DiscoverPage.id);
} on FirebaseAuthException catch (error) {
var message = '';
switch (error.code) {
case 'user-not-found':
message = 'User not found';
}
print(error.code);
ScaffoldMessenger.of(context).showSnackBar(
CustomSnackBar(message, context),
);
}
}
'loading' is initiated to false and when I print(loading) it always returns false, no matter if there's an error or not. The setState dont seem to work.
What am I missing here ?
Thanks.

try this:
try {
User user = (await _auth.signInWithEmailAndPassword(
email: email, password: password))
.user!;
if(FirebaseAuth.instance.currentUser != null) {
Navigator.pushNamed(context, DiscoverPage.id);
}
} on ...

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

Flutter, How to use multiple shared preferences

My goal was to avoid users getting logged out once they close and reopened the app. So, I used shared_preferences to store the user's email and password locally so, that whenever the user reopens the app I could use firebase's signInWithEmailAndPassword and provide locally stored email and password to it. I used setString() to store email password but I was able to store only email and not the password, I get the error "Password is null" How do I solve this. Did I do the code right?
Storing email and password when user registers in app
onPressed: () async {
try {
final user =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (user != null) {
final SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
sharedPreferences.setString(
'email',
email,
);
sharedPreferences.setString('password', password);
Get.to(() => const BorrowerList());
}
} catch (e) {
Get.snackbar('Error', e.toString(),
backgroundColor: (Colors.red));
}
},
fetching email password and login after reopening.
#override
void initState() {
super.initState();
validateUserAuth();
}
final _firestore = FirebaseFirestore.instance;
void validateUserAuth() async {
final SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
var obtainedEmail = sharedPreferences.getString('email');
var obtainedPassword = sharedPreferences.getString('password');
if (obtainedEmail != null || obtainedPassword != null) {
setState(() {
loggedinUserEmail = obtainedEmail!;
loggedinUserPassword = obtainedPassword!;
});
if (loggedinUserEmail != null || loggedinUserPassword != null) {
final loggedinuser = await auth.signInWithEmailAndPassword(
email: loggedinUserEmail, password: obtainedPassword!);
if (loggedinuser != null) {
Get.to(() => const BorrowerList());
}
}
} else {
Get.to(() => AuthScreen());
}
}
The error is apparent.
You can't save a null value in shared_preferences.
Your code is not complete. somehow your password variable is null.
You can paste complete code so we can help you better
Can you provide more information about the project? So far, it's obvious that you're trying to store a null value in shared_preferences. You can't do that. I'm pretty sure the problem is that when the user enters a password, it's not stored in the password variable here:
try {
final user =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (user != null) {
final SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
sharedPreferences.setString(
'email',
email,
);
// NULLABLE VARIABLE!
sharedPreferences.setString('password', password);
Get.to(() => const BorrowerList());
}
} catch (e) {
Get.snackbar('Error', e.toString(),
backgroundColor: (Colors.red));
}
},
Additionally, it is not recommended to use shared_preferences for storing sensitive data. Flutter Secure Storage is much better suited for this.

How to send a verification email on registerUsingEmailPassword() in flutter

I wan't when a user clicks sign up button an email verification is sent. So far with my code on signup an email verification is sent but user can't navigate to the next page (CircularProgressIndicator keeps on loading)
Here is my code
onPressed: () async {
if (_regFormKey.currentState!.validate()) {
setState(() {
_isProcessing = true;
});
User? user = await FireAuth.registerUsingEmailPassword(
name: nameController,
email: _emailController.text,
password: _passwordController.text,
);
if (user != null) {
bool EmailSent = user.sendEmailVerification() as bool;
//I think something is wrong here
if (EmailSent) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => ProfilePage(user: user),
),
ModalRoute.withName('/'),
); }
} else{
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(' Account exists or Network problems'),
backgroundColor: Colors.red,
));}
setState(() {
_isProcessing = false;
});
}}
sendEmailVerification() returns a Future<void> so EmailSent is not going to get set. You should await the verification call in a try...catch to handle the response.
More like this:
if (user != null) {
try {
await user.sendEmailVerification();
/// sent successfully
// TODO: put your navigation here
} catch (e) {
/// error sending verification
// TODO: show snackbar
// TODO: set _isProcessing to false
}
}

Flutter unable to login after create new account

After building the app, if I try to login it's working fine, but if I create a new account then try to login again, login is not working. I have seen after debugging that I'm getting token in _authenticate method. I think notifyListeners not working here but I don't know why?
I'm using the provider package in my flutter app. I have an Auth provider class where I'm saving data in firebase and also login by firebase. Below it's my provider class.
class Auth with ChangeNotifier {
String? _token;
late DateTime _expiryDate = DateTime.now();
late String _userId;
bool get isAuth {
return token != null;
}
String? get token {
if ((_expiryDate).isAfter(DateTime.now())) {
return _token;
}
return null;
}
Future _authenticate(String email, String password, String urlSegment) async {
var urlParse = Uri.parse(urlSegment);
try {
final response = await http.post(urlParse,
body: jsonEncode({
'email': email,
'password': password,
'returnSecureToken': true
})
);
final responseData = jsonDecode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
// set token and user id from firebase response
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now()
.add(Duration(seconds: int.parse(responseData['expiresIn'])));
notifyListeners();
return responseData['idToken'];
} catch (error) {
rethrow;
}
}
Future login(String email, String password) async {
print(email);
String url = Constants.firebaseLoginUrl;
return _authenticate(email, password, url);
}
Future signup(String email, String password) async {
String url = Constants.firebaseSignupUrl;
return _authenticate(email, password, url);
}
}
In signUp page I have tried below code to create a new user
Future<void> signUpSubmit() async {
if (_formKey.currentState!.validate()) {
await Provider.of<Auth>(context, listen: false).signup(_email.text, _pass.text);
}
I have checked new data is saving perfectly.
In signUp page there has a login button, after click on login button I have redirect in login page,
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const LoginPage()
),
);
},
child: const Text('Log in to access'),
)
After click on login I have redirect in login page, then tried login again but it's not working. In debug I'm getting token if I print(token) in _authenticate method.
In main.dart my consumer is looks like
child: Consumer<Auth>(
builder: (ctx,auth, _) => MaterialApp(
home: auth.isAuth ? const HomePage():const LoginPage(),
)
After create account if I rebuild app again then login is working? How I will solve this problem?
See you are redirecting directly in loginPage rather than via the main page ! Just redirect the login button to main page, in your main page there has condition
home: auth.isAuth ? const HomePage(): const LoginPage()
So, if it is auth false it will always redirect to the login page.
Change
MaterialPageRoute( builder: (context) => const LoginPage() ),
To
MaterialPageRoute( builder: (context) => const MainPage() ),

How to do autologin with three diffrent userTypes in flutter and firebase?

I have this app that do login with firebase auth and firestore to get the userType, This code is written obviously in the login page, What I want to add is autologin ASA the app runs which firebase offers with the correct userType So the first proplem how to transfer the email value to the main.dart page as I search in the firestore with the email to get the userType, Second proplem is that When I tried to do auto login in the login page with three different userTypes It does login but not auto login
CODE :
#override
void initState() {
super.initState();
FirebaseAuth.instance.currentUser().then(
(result) {
if (result != null) {
if (userType == 'userType1') {
Navigator.pushReplacementNamed(context, '/userType1page');
}
if (userType == 'userType2') {
Navigator.pushReplacementNamed(context, '/userType2page');
}
if (userType == 'userType3') {
Navigator.pushReplacementNamed(context, '/userType3page');
}
}
So Here It gets the user But no auto login, what I observed that When U remove the other IFs inside the big if and do 1 Navigation It works So don't know what to do, Please Help me I asked three questions before and didn't get an answer.
PS : NEW TO FLUTTER :)
#FLUTTER_FOREVER
Getting user Data from firestore:
void getUserData() async {
try {
firestoreInstance
.collection('Users')
.document(usernameController.text)
.get()
.then((value) {
setState(() {
email = (value.data)['email'];
password = (value.data)['password'];
gender = (value.data)['gender'];
username = (value.data)['username'];
userType = (value.data)['userType'];
});
});
} catch (e) {
print(e.toString);
}
}
Logining in :
void login() async {
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
firebaseAuth
.signInWithEmailAndPassword(
email: emailController.text, password: passwordController.text)
.then((result) {
{
if (userType == 'Student') {
Navigator.pushReplacementNamed(context, '/StudentsPage');
} else if (userType == 'Teacher') {
Navigator.pushReplacementNamed(context, '/TeacherPage');
} else if (userType == 'Admin') {
Navigator.pushReplacementNamed(context, '/AdminPage');
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Error'),
content: Text(
'Please make sure that you have an internet connection '),
actions: [
FlatButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
},
);
}
}
I found the answer I must identify the var userType inside the initState and It worked by using the getUserData() function but I had a problem I can't use usernameController because It's a var and I didn't defined it so any idea how to get the userType with the document reference usernameController Which I can't identify X-( 'R.I.P #omardeveloper'