Is setState() ignored by try & catch? - flutter

I use Firebase Auth to allow users to sign up.
If the user registers the correct email address and a sufficiently secure password, they will be registered with Firebase Auth.
I can register, but when I fail to sign up, I don't get an error.
String _state = ""; //global
Future signUp(String email, String password) async {
try {
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
setState(() {
_state = ('The password provided is too weak.');
});
} else if (e.code == 'email-already-in-use') {
setState(() {
_state = ('The account already exists for that email.');
});
}
} catch (e) {
setState(() {
_state = e.toString();
});
}
}
Referred here.
This code executes createUserWithEmailAndPassword() by passing the email address and password as arguments.
I'm trying to display on the screen the cause of a sign-in failure with try & catch statement.
But for some reason setState() doesn't change the Text() that has global _state.
#immutable
class signUp extends StatefulWidget {
static String route = '/signup';
const signUp({Key? key}) : super(key: key);
#override
_signUp createState() => _signUp();
}
class _signUp extends State<signUp> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: myAppBar(context), //custom appBar. ignore this.
body: const Center(
child: Text(
_state
),
));
}
}
I declared Text() in StatefulWidget so that it can be updated with setState().
But for some reason setState() is ignored and Text(_state) is not executed.
I feel that the cause of this problem is in the try & catch statement, but I don't know what to do.
What should I do to display the sign-up results as text?
Thank you.

I changed code like this; this solved my issue.
String stateCode = "";
try {
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
stateCode = ('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
stateCode = ('The account already exists for that email.');
} else {
stateCode = "error: " + e.code;
}
} catch (e) {
stateCode = "error: " + e.toString();
}
setState(() {
_state = (stateCode);
});
All I had to do was display the e.code when an exception occurred.

I can register, but when I fail to sign up, I don't get an error.
Could you check if your sign-in really fails? Checking your code, signUp is a Future<void>. How are you handling the UserCredential being returned by FirebaseAuth.instance.createUserWithEmailAndPassword?
This block catches an Exception, not a successful login.
catch (e) {
setState(() {
_state = "Succeeded!";
});
}
You can also check for UserCredential after the login request to debug.
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
debugPrint(uid: ${userCredential?.user?.uid}

Related

I want dynamic error message instead of this static error message

I want a dynamic error message instead of this static error message.
Please review my code and help me out with the code to show an error message in Flutter while logging in with Firebase.
I am making a login page for my app and I am using the Firebase authentication service for that. Now I am trying to show an error dialog message when a user attempts with the wrong credentials or any other case. And so for I have done this... I have coded this and it executes successfully but the error message is static "An unexpected error occurred", instead of this I want a dynamic error message which particularly shows what's wrong with the login credentials, for example, whether the email is badly formatted or password is wrong etc.
My code:
class LoginPage extends StatefulWidget {
final VoidCallback showRegisterPage;
const LoginPage({Key? key, required this.showRegisterPage}) : super(key: key);
#override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final formKey = GlobalKey<FormState>(); //key for form
String name = "";
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
void showErrorMessage(Object error) {
String errorMessage;
if (error is String) {
errorMessage = error;
} else if (error is PlatformException) {
errorMessage = error.message ?? 'An unknown error occurred';
} else {
errorMessage = 'An unexpected error occurred';
}
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Error'),
content: Text(errorMessage),
actions: <Widget>[
ElevatedButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Future LoginPage() async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
);
} catch (error) {
showErrorMessage(error);
}
}
void showErrorMessage(Object error){
check this snippet for ref.
This is a generic Authentication Method but you can modify as needed. For a list of codes, see this
Future<String> loginUser({
required String email,
required String password,
}) async {
String res = 'Some error occurred';
try {
if (email.isNotEmpty || password.isNotEmpty) {
//Login user
await _auth.signInWithEmailAndPassword(
email: email, password: password);
res = 'success';
} else if (email.isEmpty && password.isEmpty) {
res = 'Please enter email and password';
} else if (email.isEmpty || password.isEmpty) {
res = 'Please enter email and password';
}
} on FirebaseAuthException catch (err) {
print(err);
if (err.code == 'user-not-found') {
res = 'No account associated with email address';
} else if (err.code == 'wrong-password') {
res = 'Password is incorrect';
} else if (err.code == 'invalid-email') {
res = 'Please enter valid email address';
} else {
res = 'Please enter valid email and password';
}
} catch (err) {
res = err.toString();
}
return res;
}
You need to catch the error codes given by firebase and then do checks to see what error was thrown and then display to the user.
Sign-up can be done with a similar approach. An example of error handling below:
on FirebaseAuthException catch (err) {
print(err);
if (err.code == 'invalid-email') {
res = 'The email address is badly formatted';
} else if(err.code == 'unknown') {
res = 'Please enter password';
} else if (err.code == 'weak-password') {
res = 'The password must be longer than 6 characters';
} else if (err.code == 'email-already-in-use') {
res = 'The email address already exists';
} else {
res = err.code.toString();
}
} catch (err) {
res = err.toString();
print(res);
}

How to get user credential while moving to welcome screen in flutter

I have created simple home screen for login and register,
Here I have taken readymade code from a channel, and now I need to change little bit..
code is simple, so no more details to explain
just I want to pass Usercredential to my welcome screen...
here is my code
class MainPage extends StatelessWidget {
const MainPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context,snapshot){
if(snapshot.hasData)
{
print(snapshot.data);
return WelcomePage(usercredential:
//how to get usercredential,
);
}
else
{
return AuthPage();
}
},
),
);
}
}
here is my login page's login code
Future signin() async {
UserCredential? usercredential;
try {
usercredential=await FirebaseAuth.instance.signInWithEmailAndPassword(
email: txtemailcontroller.text, password: txtpasswordcontroller.text);
} on FirebaseAuthException catch (e) {
print("Error is =" + e.toString());
}
}
and register page's register code
Future signup() async {
UserCredential? usercredential;
try {
if (txtconfirmpasswordcontroller.text.trim() ==
txtpasswordcontroller.text.trim()) {
usercredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: txtemailcontroller.text,
password: txtpasswordcontroller.text);
} else {
print("passwrod does not match");
}
} on FirebaseAuthException catch (e) {
print('Error while register' + e.toString());
}
if (usercredential != null) {
String userid = usercredential.user!.uid;
UserModel newuser = UserModel(
email: txtemailcontroller.text,
userid: userid,
fullname:
txtfirstnamecontroller.text + ' ' + txtlastnamecontroller.text,
profilepicture: '');
}
}
so far I know, user credential generated while createuserwithemailandpassword and signinwithemailandpassword method, but how to get it here....where I need...
Add this In your Welcome page:
User? currentUser=FirebaseAuth.instance.currentUser;
Then you can call it any where and get user details like email & id & display name.
for example:
currentUser.email
or
currentUser.uid

Flutter Connection State Management

Hello I am doing my fist App in Flutter and i am just setting up the authentication with FireBase, and a mistake its happenning. Im trying to manage the state and navigate between Home and Login with the streambuilder, and its working fine but only if i do a hot restart on Android Studio after registering a new user. After the hot reload it works fine, i am able to login with any of the existing users and it navigates to the home screen, and when i log out goes back to login screen, but if i create new user than just stops working, the screens do not alterate anymore when i log in with any of the old users...
here its my main
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(primaryColor: cPrimary),
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.active){
if(snapshot.hasData){
return Home_Screen();
} else if (snapshot.hasError){
return Center(child: Text('${snapshot.error}'),);
}
} else if (snapshot.connectionState == ConnectionState.waiting){
return Center(child: CircularProgressIndicator(color: cPrimary,));
}
return LoginScreen();
}
)
);
}
}
Here is my login and register functions
//Sign Up
Future <void> signUp({
required String email,
required String password,
required String username,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty && username.isNotEmpty){
UserCredential userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//add user to database
await _firestore.collection('users').doc(userCredential.user!.uid).set({
'username' : username,
'email' : email,
'uid' : userCredential.user!.uid,
});
}
} 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);
}
}
//Log In
Future <void> logIn({
required String email,
required String password,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty ){
UserCredential userCredential = await _auth.signInWithEmailAndPassword(
email: email,
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.');
}
}
}
and here its how i am calling the functions on my screens
ElevatedButton(
onPressed: () async {
setState(() {
_isLoading = true;
});
await AuthService().logIn(
email: _emailController.text,
password: _passwordController.text,);
setState(() {
setState(() {
_isLoading = false;
});
});
},
ElevatedButton(
onPressed: () async {
setState(() {
_isLoading = true;
});
await AuthService().signUp(
email: _emailController.text,
password: _passwordController.text,
username: _usernameController.text,
);
setState(() {
_isLoading = false;
});
After creating the user account, ensure you log in as well.
//Sign Up
Future <void> signUp({
required String email,
required String password,
required String username,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty && username.isNotEmpty){
UserCredential userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//add user to database
await _firestore.collection('users').doc(userCredential.user!.uid).set({
'username' : username,
'email' : email,
'uid' : userCredential.user!.uid,
});
}
// add this
await logIn(email: email, password: password);
} 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);
}
}

Firebase authentication! I'm able to move to home page even if i enter a non registered user

I've successfully added firebase to my flutter2.0 project. I've enables authentication also.I'm able to register a new user also. But the logic to move to home page after authentication is not working. I'm able to login even if I enter a wrong user. I want if I enter proper user then I should navigate to home page, but if the user is not registered it one should not be able to navigate to next page. ie..the basic use of authentication.
But it's not happening here. I'm able to navigate to next place even if I enter wrong user.
Future signInWithEmailAndPassword(String email, String password) async {
try {
UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email:email,
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.');
}
}
}
Future newAccount(String email, String password) async {
try {
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
} 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.toString());
}
}
}
//this is how I can this function and try to navigate to next page.
void logMeIn() {
if (formKey.currentState!.validate()) {
authMethods
.signInWithEmailAndPassword(usernameTextEditingContoller.text,
passwordTextEditingContoller.text)
.then((value) {
print('value is: ');
print(value);
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) {
return Home();
}));
});
}
}**strong text**
signInWithEmailAndPassword returns a UserCredential object.
In your logic, you are using .then((value) {...etc})
This value is the result of signInWithEmailAndPassword.
Try changing your logic to this:
authMethods
.signInWithEmailAndPassword(usernameTextEditingContoller.text,
passwordTextEditingContoller.text)
.then((value) {
print('value is: ');
print(value);
if(value.user ==null) return "Error in authentication"; // this will prevent your function form going further down the navigation if the usercredential doesn't have a valid user.
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) {
return Home();

Flutter onAuthStateChanged stream not updating child when registering or signing in

I wrapped my app inside a StreamProvider.value, where the value is an onAuthStateChanged stream, and the child is the main MaterialApp. My main wrapper listens to this value using Provider.of. This works fine for signing out; once I sign out, the StreamProvider notifies my main wrapper, and the app is redirected to the welcome screen.
But when I try to create an account or sign in, it seems the StreamProvider is not being notified of the onAuthStateChanged stream. This is why it's so weird, if the stream wasn't working, then signing out should also not work. Also, when I hot restart, I do get redirected to the home screen. I've scattered the internet: no luck. Here's the appropriate code:
In main.dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<FirebaseUser>.value(
value: AuthService().userStream,
child: MaterialApp(
home: Wrapper(),
theme: ThemeData.light().copyWith(
appBarTheme: AppBarTheme(color: Colors.lightBlue),
scaffoldBackgroundColor: Colors.white,
),
),
);
}
}
In wrapper.dart
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
print('Rebuilding');
final user = Provider.of<FirebaseUser>(context);
if (user == null) {
return Welcome();
} else {
return Home();
}
}
}
In auth_service.dart
class AuthService {
FirebaseAuth _auth = FirebaseAuth.instance;
Stream<FirebaseUser> get userStream {
return _auth.onAuthStateChanged;
}
Future registerWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString());
return null;
}
}
Future signInWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString());
return null;
}
}
void signOut() {
try {
_auth.signOut();
} catch (e) {
print(e);
}
}
}
Also, inside my welcome.dart, I have this set up as a test:
onPressed: () {
FirebaseAuth.instance.onAuthStateChanged
.listen((event) {
print('$event from .listen');
});
}
And this does notify my everytime I sign in, out or register, this tells me that there is nothing wrong with onAuthStateChanged, or the way I set it up.
If you need any more information, let me know. I don't want to make the question any longer. Thank you for your help!