Cannot set user display name in my flutter app - firebase

I have been trying to set my user display name upon signup. All of the solution I have found in stackoverflow suggest to use updateProfile(). But it is deprecated, and flutter docs say to use updateDisplayName instead.
I have tried to implement it in this way,
void donorSignUp() async {
try {
showLoading();
await auth
.createUserWithEmailAndPassword(
email: email.text.trim(), password: password.text.trim())
.then((result) {
String _userId = result.user!.uid;
_addDonorToFirestore(_userId);
_clearSignUpControllers();
result.user?.updateDisplayName(donorModel.value.name);
});
} catch (e) {
debugPrint(e.toString());
Get.snackbar('Sign Up Failed', 'Try again');
}
}
However, when I try to show it in my Drawer, calling user?.displayName it doesn't show anything. I have also checked that donorModel.value.name consists a string value, I know its not null. What should I do?
the function donorSignUp() is called inside an elevatedbutton,
child: ElevatedButton(
child: Text(
'Register',
style: buttonFontSansita,
),
onPressed: () {
if (authController
.signupFormKey.currentState!
.validate()) {
authController.donorSignUp();
}
},

The recommended way to always have the real-time auth state is to use the authStateChanges listener:
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
You can read more about it here. Ideally you can use a Provider to make the data available through the whole app.

Related

Display error message outside build widget

I am using a Model class to authenticate user before registering or logging.the problem is that i don't know a way to print error message to the user in snackbar,because no widget is defined in this class.
How can i display error message to user from Model Class?
Model class:
class FireAuth {
static Future<User> registerUsingEmailPassword({
String name,
String email,
String password,
}) async {
FirebaseAuth auth = FirebaseAuth.instance;
User user;
try {
UserCredential userCredential = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
user = userCredential.user;
await user.updateDisplayName(name);
await user.reload();
user = auth.currentUser;
//check if email is registered before
//add user data to firestore
CollectionReference users = FirebaseFirestore.instance.collection('users');
users.doc(user.uid).set({
'uid':user.uid,
'img_url':'0',
'name': name,
'phone': '',
'email': email,
'job_title':'',
'university':'',
'procedures':'',
'expert_in':'',
})
.then((value) => print("User Added"))
.catchError(
(error) => print("Failed to add user: $error"));
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
return user;
}
}
I need 'The account already exists for that email.' error message to display to user,not only printing it in log.
Excellent question, and I'll try to answer in the general so as to benefit your overall pattern in handling this very important case.
Depending on BuildContext is a common inconvenience in flutter. And it often comes up, but for good reason. You can think of it like this: You need the context because you need to specify where in the tree that UI is going to show. Knowing how to handle these cases makes the difference between beginner and more advanced flutter developers.
So one way is to pass the BuildContext around, but I wouldn't recommended it.
Lets say I have a function foo that returns some Future Rather than change the signature of the function to accept context, you can simply await the function and use the context in the callback already in your UI. For example,
instead of
Future foo(BuildContext context) {
try {
// await some async process
// Use context to show success.
} catch (e) {
// Use context to show failure.
}
}
You can do this
GestureDetector(
onTap: () async {
try {
await foo();
// Use context to show success.
} catch (e) {
// Use context to show failure.
}
},
child: // some child
),
The point is in the second example the context is already there in the widget. The signuture of foo is simpler. It requires some restructuring. Here I'm assuming that the series of events is traced back to a GestureDetector but it could be anything else.

Firebase Authentication with Flutter not working

I am trying to create a signup page which should give an error message if user with particular email id already exist. But it's not working.
signUp() {
if (formkey.currentState!.validate()) {
Map<String, String> userDataMap = {
"name": usernameC.text,
"email": emailC.text
};
setState(() {
isLoading = true;
});
authMethods.signUp(emailC.text, passwordC.text).then((value) {
databaseMethods.uploadUserData(userDataMap);
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => ChatRoom()));
});
}
}
It calls the signUp() function from auth.dart given below
UserData? _userFromFirebase(User? user) {
return user != null ? UserData(userid: user.uid) : null;
}
Future signUp(String email, String pass) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: pass);
User? user = result.user;
return _userFromFirebase(user);
} catch (e) {
print(e}
}
Every time I signup with same email it doesn't give any error.
If you sign up with the same email you should get this message:
[firebase_auth/email-already-in-use] The email address is already in use by another account.
I use print(e.hashCode) and then use this hash code to show an error message.
Ok I tried this method and it worked out. Just added null check for the "value" attribute in.
authMethods.signUp(emailC.text, passwordC.text).then((value)
It was returning null without any other message. That's why I was unable to see the error.

How to handle the exception "The method 'onLogin' was called on null"

Good day, I am receiving the following error when running code for my application:
The method 'onLogin' was called on null
( 6100): Receiver: null
( 6100): Tried calling: onLogin("Succeed")
I was trying to neaten my code by putting my analytics stuff within a different file, but doing so has brought up this error and it now no longer sends a "login" event to Firebase. I'm very curious to know why I can not use this method to achieve the same goal. Code:
login-page.dart
Widget _signInButton() {
return OutlineButton(
splashColor: Colors.grey,
onPressed: () async {
FireBaseAnalyticsData user;
String result = await signInWithGoogle();
if (result == "Succeed") {
Navigator.pushNamed(context, '/specials-page'); //'specials' = tab-creation page
user.onLogin(result); //track login
}
else
print("error logging in");
},
... //other code
firebase-analytics.dart
final FirebaseAnalytics analytics = FirebaseAnalytics();
class FireBaseAnalyticsData {
void onLogin(var x) {
if(x == "Succeed")
{
analytics.logLogin();
print("Log in successful");
}
else
print("Error delivering login stats");
}
}
I am not getting any syntax errors with my implementation, but I seem to be missing something with regards to the logic of this. Any and all help would be appreciated. Thank you.
You only declared user variable. you have to initialize it before using it inuser.onLogin(result)
Widget _signInButton() {
return OutlineButton(
splashColor: Colors.grey,
onPressed: () async {
final user = FireBaseAnalyticsData(); //TODO: Initialize user here
String result = await signInWithGoogle();
if (result == "Succeed") {
Navigator.pushNamed(context, '/specials-page'); //'specials' = tab-creation page
user.onLogin(result); //track login
}
else
print("error logging in");
},
You have just created a user variable of type FireBaseAnalyticsData, but have not initialized it. You need to initialize the user variable for user.onLogin(result) to function properly. Just initialize it as shown below and everything should work fine. 👍🏼
FireBaseAnalyticsData user = FireBaseAnalyticsData();

How to increase the speed of Firebase authentication in flutter app

I have build an app which has login and register features. I also added signout feature and also when the user close and reopens the app firebase checks whether the user is logout or not, but the problem is when i open the app firebase taking lot of time atleast 8-10 second to check whether the user is already logged in or not, so how to increase the speed from firebase so that the user need not wait for 8-10 seconds for more.
void initState() {
super.initState();
pageController = PageController();
// Detects when user signed in
googleSignIn.onCurrentUserChanged.listen((account) {
handleSignIn(account);
}, onError: (err) {
print('Error signing in: $err');
});
// Reauthenticate user when app is opened
googleSignIn.signInSilently(suppressErrors: false).then((account) {
handleSignIn(account);
}).catchError((err) {
print('Error signing in: $err');
});
}
handleSignIn(GoogleSignInAccount account) async {
if (account != null) {
await createUserInFirestore();
setState(() {
isAuth = true;
});
configurePushNotifications();
} else {
setState(() {
isAuth = false;
});
}
}
I am using this way to check wheater the user is login or not the app
Auth auth = Auth();
await auth.getCurrentUser().then((user) async {
runApp(MaterialApp(
theme: _themeData(),
home: user != null
? Home(
userId: user.uid
)
: Login(),
debugShowCheckedModeBanner: false,
routes: routes,
));
}).catchError((error) {
print("Here is ERROR $error");
});
}
It hardly takes one or two seconds to tell the user uid. I hope it will resolve your issue.

Firebase not validating email

I'm currently creating an app using Flutter.
The goal is to check to see if an account's email is verified before logging them in.
As it is now, a user signs in to their account using Auth.signInWithEmailAndPassword
At this point, Auth.isEmailVerified returns false
Afterwards, a verification email is sent, the user then clicks on the link to verify their account and a window popup appears stating that their account is now verified.
The user tries to login again, but Auth.isEmailVerified still returns false.
Any ideas?
This is the auth.dart class file I'm using.
https://github.com/AndriousSolutions/auth/blob/master/lib/auth.dart
And this is my code.
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: () async {
if (_formKey.currentState.validate()) {
Auth.signInWithEmailAndPassword(
email: emailAddressController.text,
password: passwordController.text)
.then((onSuccess) {
Auth.reload();
if ((onSuccess)) {
if (Auth.isEmailVerified) {
db.createUser(
emailAddress: Auth.email,
firstName: Tools.getFirstName(Auth.displayName),
googleAccount: false);
Navigator.of(context).pushReplacementNamed(HomePage.tag);
} else {
emailVerificationDialog(context);
Auth.sendEmailVerification();
}
}
}).catchError((e) {
print(" LSAHJDSAKHDSA " + e);
});
}
},
color: ThemeSettings.RaisedButtonColor,
child: Text('Log In', style: TextStyle(color: Colors.white)),
),
Thank you so so much!!
Looking at the library that you are using the Auth.reload call needs to be awaited. It should be
static Future<bool> reload() async {
await _user?.reload();
return _setUserFromFireBase(_user);
}
Since it is not awaiting on reload, the your code simply keeps on going and it checks isEmailVerified before it has a chance to complete the reload.
This issue is reporting it which I have shared this info.

Resources