I built a login page using firebase. When the user clicks the login button, a CircularProgressIndicator is started and if the user gave the correct credentials everything works perfectly but if there is an error (e.g user not found OR wrong password) the user will be not forwarded to the next page but the CircularProgressIndicator will not stop showing.
The aim is, that if there is an error, I want to stop the CircularProgressIndicator and want to show an error message but I don't know how to stop the CircularProgressIndicator.
My code looks the following:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
final navigatorKey = GlobalKey<NavigatorState>();
class LoginUser {
Future loginUser(userEmail, userPassword, context) async {
navigatorKey: navigatorKey;
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => Center(child: CircularProgressIndicator())
);
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: userEmail,
password: userPassword
);
// Close Dialog when route changes
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
return "ec-unf";
} else if (e.code == 'wrong-password') {
return "ec-wp";
}
navigatorKey.currentState!.popUntil((route) => route.isFirst);
}
}
}
Does anybody know how to do this?
Thanks!
Chris
maybe you can add isLoading and finaly condition after try catch
isLoading = true
try {
//your code
print("done !");
isLoading
} catch (err) {
print("error");
isLoading = false
} finally {
print("Finish "); //error and success
isLoading = false
}
Just for completeness, here is how i solved it.
I created a separate function in the login file and when i clicked the Sign in buttton, the following function was executed:
Future login() async{
isSignInLoading = true; // START LOADING CYCLE
// --- LOADING CYCLE - START ---
if (isSignInLoading == true) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => Center(child: CircularProgressIndicator())
);
}
// --- LOADING CYCLE - END ---
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _controllerEmail.text,
password: _controllerPassword.text
);
} catch (e) {
isSignInLoading = false; // START LOADING CYCLE
isErrorLogin = true; // START LOADING CYCLE
}
Navigator.of(context).pop();
// --- ERROR MESSAGE - START ---
if (isErrorLogin == true) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => Center(child:
AlertDialog(
title: const Text('Something went wrong!'),
content: const Text('Please check your entries, either the user does not exist or the password is incorrect.'),
actions: [
TextButton(
child: const Text(
'Close',
style: TextStyle(
color: Color(0xff004494),
fontWeight: FontWeight.w500
),
),
onPressed: () {
Navigator.of(context).pop();
},
),
],
)
)
);
}
// --- ERROR MESSAGE - END ---
//var loginInfo = await LoginUser().loginUser(_controllerEmail.text,_controllerPassword.text, context);
if (FirebaseAuth.instance.currentUser != null) {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("userLoginStatus", true);
Navigator.popAndPushNamed(context, '/overview');
}
}
Pretty sure there is a way better way to do it but this worked for me.
Related
I'm trying to login in users using a third party api. But the problem is whenever an error occurs and the catch error is executed the "then" function that holds the navigation to the HomeScreen also is executed. Please is there a way to login user only when there is no error.
void signIn() {
setState(() {
_isLoading = true;
});
final isValid = _formKey.currentState!.validate();
if (isValid == false) {
setState(() {
_isLoading = false;
});
return;
} else {
setState(() {
_isLoading = true;
});
Provider.of<Authorization>(context, listen: false)
.loginUser(
_emailController.text.trim(),
_passwordController.text.trim(),
)
.catchError((error) {
const snackBar = SnackBar(
backgroundColor: Colors.red,
content: Text("An error occured please try again."),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}).then((_) {
setState(() {
_isLoading = false;
});
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => const HomeScreen()),
),
);
});
}
}
Thanks in advance.
You can use another way to run this function and make it easier to you to understand and also more easy to code
void signIn() async{
setState(() {
_isLoading = true;
});
final isValid = _formKey.currentState!.validate();
if (isValid == false) {
setState(() {
_isLoading = false;
});
return;
} else {
setState(() {
_isLoading = true;
});
// here you need to make the login user function back a bool value either true or false true for success false for failed
final result = await Provider.of<Authorization>(context, listen: false)
.loginUser(
_emailController.text.trim(),
_passwordController.text.trim(),
)
// hide the loading
setState(() {
_isLoading = false;
});
// check if the result back from the function is true we success
if(result == true){
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => const HomeScreen()),
),
);
}
// else we failed
else{
const snackBar = SnackBar(
backgroundColor: Colors.red,
content: Text("An error occured please try again."),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
}
this answer i think will work perfectly with you you just need to make the login user function return a Future and if success return true or if it failed return false and every thing will work successfully
thanks and i hope this answer helps you
I have a loading spinner that I would like to turn off if the user cancels the purchase using RevenueCat inside of flutter.
I have a try catch block that I use to make the purchase but the error block is never initiated because the try block is always successful.
Here is the code:
purchase(BuildContext ctx, PaymentPlanType selectedPlanType) async {
final offerings = await PurchaseApi.fetchOffers();
try {
if (selectedPlanType == PaymentPlanType.weekly) {
await PurchaseApi.purchasePackage(offerings[0].availablePackages[0]);
} else if (selectedPlanType == PaymentPlanType.monthly) {
await PurchaseApi.purchasePackage(offerings[0].availablePackages[1]);
} else if (selectedPlanType == PaymentPlanType.yearly) {
await PurchaseApi.purchasePackage(offerings[0].availablePackages[2]);
}
} on PlatformException catch (e) {
var errorCode = PurchasesErrorHelper.getErrorCode(e);
if (errorCode == PurchasesErrorCode.purchaseCancelledError) {
showDialog(
context: ctx,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(e.toString()),
actions: [
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'))
],
);
});
}
}
}
How do I just catch that error so I can change an isLoading bool to false?
I am trying to put an if statement inside another if inside an insitstate in flutter app as I did it but It did't do what it is supposed to do like if the initstate focused on being a function instead of being an initstate here is my code :
#override
void initState() {
super.initState();
FirebaseAuth.instance.currentUser().then((res) {
print(res);
if (res != null) {
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('Error In Validating Your Account.'),
actions: [
FlatButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
});
}
It is supposed to get the firebase user which it did but It doesn't do auto login when I do restart which it happens by deleting the second if and only doing one Navigation without controlling it, So any Ideas what is the proplem, because I reached a dead end XD.
Where I assign a val to userType 'Which is working as I printed Its val':
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'];
});
print('$userType');
});
} catch (e) {
print(e.toString);
}
}
I am trying to implement a CircularProgressIndicator when waiting user to finish their authentication process, here's the code, I am using Firebase as the auth backend
Future<void> signIn() async {
if (_formKey.currentState.validate()) {
new Loading();
_formKey.currentState.save();
try {
final user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
if (user != null) {
final FirebaseUser user = await auth.currentUser();
print('success login');
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(user: user),
));
}
} catch (e) {
print(e);
}
}
}
how to implement the circularprogressindicator into the code?
CircularProgressIndicator can be implemented in UI with a condition.If you want to implement it in some area of your page you can use boolean to make it work like this:
bool showCircular = false;
Future<void> signIn() async {
if (_formKey.currentState.validate()) {
new Loading();
_formKey.currentState.save();
setState(() {
showCircular=true;
});
try {
final user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
if (user != null) {
final FirebaseUser user = await auth.currentUser();
setState(() {
showCircular=false;
});
print('success login');
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(user: user),
));
}
} catch (e) {
print(e);
}
}
}
Now anywhere in your UI add this widget:
showCircular ? CircularProgressIndicator() : SizedBox(),
Recommended way is using an AlertDialog to show progress indicator. Here is an example with AlertDialog.To open Dialogs you need context so take BuildContext as a parameter and call signIn(context); from sign in button.We will call dialog using openLoadingDialog function and when sign in is completed we will pop it using Navigator.of(context).pop();
Future<void> signIn(BuildContext context) async {
if (_formKey.currentState.validate()) {
new Loading();
_formKey.currentState.save();
openLoadingDialog(context, 'Signing In...');
try {
final user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
if (user != null) {
final FirebaseUser user = await auth.currentUser();
Navigator.of(context).pop();
print('success login');
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(user: user),
));
}
} catch (e) {
print(e);
}
}
}
Paste this dialog anywhere in your app.You can call it by passing context and message you want to show.
openLoadingDialog(BuildContext context, String text) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
content: Row(children: <Widget>[
SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(
strokeWidth: 1,
valueColor: AlwaysStoppedAnimation(Colors.black)
)
),
SizedBox(width: 10),
Text(text)
]),
)
);
}
I mean when I log in, but the network to the database there is a problem, an information dialog will appear that the network has a problem. I'm confused about using else if here..
_login() async {
if (formKey.currentState.validate()) {
formKey.currentState.save();
try {
final response = await UserController.login({
"username": username,
"password": password,
});
if (response != null && response["success"]) {
Http.setAccessToken(response["token"]);
return Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => MainActivity(),
));
} else {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Information"),
content: Text("Your account is not registered!"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
} catch (e) {
print(e.message);
}
}
}
how do I put conditions if the network has a problem then return showDialog ??
Check out the connectivity package from the Flutter Team. https://pub.dev/packages/connectivity
You can listen for any issues in changes to your network then show a snackbar or dialogbox if disconnected.
I hope this helps.
JC