How to fix login issue? Flutter - Firebase - firebase

Here is what I'm doing in my code.
ReusableButton(
title: "Login",
color: Colors.white,
onPress: () async {
try {
final user = await _auth.signInWithEmailAndPassword(
email: myEmailController.text,
password: myPasswordController.text,
);
if (user != null) {
await Navigator.pushNamed(context, AllTasks.id);
}
} catch (e) {
String newString = e.toString().split("]").removeLast();
setState(() {
showDialog(
context: context,
builder: (value) => AlertDialog(
title: Text(
"Wrong Information",
style: kNormalTextStyle,
),
content: Text(
newString,
),
actions: [
FlatButton(
onPressed: () {
Navigator.of(value).pop();
},
child: Text(
"Close",
style: kNormalTextStyle,
))
],
));
});
}
},
),
I'm trying to login and after that pushin the page to another page. However this login part is a little bit slow so I get an error like this:
I'm assuming this is about the connection speed with firebase but is there a solution to solve this? Btw, when I reload the code, it starts working.
Here is my AllTasks code block:
https://github.com/sonelektrikci/task_manager_app_flutter/blob/main/task_management_app_flutter/lib/screens/all_tasks.dart
I'm pushing the page to here when user logs in.

This is most likely causing your issue:
.where('email', isEqualTo: loggedInUser!.email)
How are you asserting that the user is indeed logged in and promising your compiler that an email is retrievable? This is the explanation of your error.
Refactor your code, in a way to not make it into this block, unless loggedInUser is not null.

Related

How to find Firebase document field and delete document

I have a button that lets a user delete their account. When users signup their email and name is saved to a Firestore collection called users, I want to search in the collection's documents where the uid field is equal to the current user uid then delete that document. Deleting the account works but not the document and I'm not getting any errors, I'm not sure what I'm doing wrong...
CollectionReference users = FirebaseFirestore.instance.collection('users');
TextButton(
onPressed: () async {
try {
await users
.where('uid', isEqualTo: _auth.currentUser!.uid).firestore.doc(users.doc().path).delete();
await _auth.currentUser!.delete().then((value) =>
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => const WelcomeScreen())));
} on FirebaseAuthException catch (error) {
Fluttertoast.showToast( msg: error.message.toString(),
gravity: ToastGravity.TOP,
backgroundColor: Colors.red,
textColor: Colors.white);
} on FirebaseException catch (error) { Fluttertoast.showToast(
msg: error.message.toString(),
gravity: ToastGravity.TOP,
backgroundColor: Colors.red,
textColor: Colors.white);
}
},
child: const Text( 'Delete', style: TextStyle(color: Colors.red),
))
I got the problem I was just working on my app and found a similar code so here is the solution. Just declare user id as variable for ease not necessary (optional) like this
final uid = _auth.currentUser!.uid; //optional
& then use this in your code:-
await users.doc(uid).delete();
instead of
await users
.where('uid', isEqualTo: _auth.currentUser!.uid).firestore.doc(users.doc().path).delete();
and Boom now it works like an charm!!
Hope this works!!

Writing to Firebase Realtime Database with Flutter

I've perused the forums, google, and youtube for info on writing data to a real-time database with flutter and haven't found a proper guide for even the most basic write.
That being said, in my app, I am currently trying to save the user's email to the database as a child of the user's new id. I am attempting to do this immediately after calling .createUserWithEmailAndPassword. This all should occur on click of a Material Button. I previously had the write inside of the then statement, but that was giving me an error.
Code:
FirebaseAuth userAuth = FirebaseAuth.instance;
void saveEmailInDb(String userId, String email) {
final userRef = FirebaseDatabase.instance.reference();
userRef.child(userId).child("Email").push().set(email);
}
//inside of the build widget
MaterialButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
color: colorPalette.chooseColor('yellow'),
child: Container(
padding: EdgeInsets.all(13),
child: Text(
'Register',
style: GoogleFonts.ubuntu(
color: colorPalette.chooseColor('darkGrey'),
fontSize: 17),
),
),
onPressed: () async {
try {
UserCredential userCredential = await userAuth
.createUserWithEmailAndPassword(
email: tecEmail.text,
password: tecPassword.text)
.then(
(value) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoadingPage(),
),
),
);
saveEmailInDb(
userCredential.user.uid, tecEmail.text);
} 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);
}
},
),
I have instantiated firebase in the main widget:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
GetMaterialApp(
home: LoadingPage(),
),
);
}
Now, I know that flutter is hooked up properly to my app because an account is created in the firebase console under authentication. However, nothing is written to the database and as there are no proper guides or official documentation, I am unsure how to proceed.
Database Rules:
{
"rules": {
".read": true,
".write": true
}
}
Answer: Moving the navigation code outside of the then statement, and below the database write, was sufficient to solve this problem. Basically, the navigation was poping the widget before the database code was called. Revised code below:
MaterialButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
color: colorPalette.chooseColor('yellow'),
child: Container(
padding: EdgeInsets.all(13),
child: Text(
'Register',
style: GoogleFonts.ubuntu(
color: colorPalette.chooseColor('darkGrey'),
fontSize: 17),
),
),
onPressed: () async {
try {
UserCredential userCredential =
await userAuth.createUserWithEmailAndPassword(
email: tecEmail.text,
password: tecPassword.text);
saveEmailInDb(userCredential.user.uid, tecEmail.text);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoadingPage(),
),
);
} 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);
}
},
),

How to platform exception error flutter 2020

I am trying to get to get a dialog pop to indicate to the user that the email already exists, but I keep getting this error an the dialog pop doesn't show, have gone through similar solution but none seem to work any help will be appreciated
Exception has occurred.
FirebaseAuthException ([firebase_auth/email-already-in-use] The email address is already in use by another account.)
Below is my authentication code
void registerToFb() {
firebaseAuth
.createUserWithEmailAndPassword(
email: emailController.text, password: passwordController.text)
.then((result) {
dbRef.child(result.user.uid).set({
"email": emailController.text,
"age": ageController.text,
"name": nameController.text
}).then((res) {
isLoading = false;
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => Home(uid: result.user.uid)),
);
});
}).catchError((err) {
print(err);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Error"),
content: Text(err.message),
actions: [
FlatButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
});
}
I've not checked the latest docs but I think the error codes have changed. First check by printing what's inside err.message. I read somewhere this changed to err.code!

Flutter Firebase updated display name successfully but still can't access. It is null

display name of firebase user is updated but still the getter was called on 'null'.
I registered with email and password.
The function used for registering is....
void _registerAccount() async {
final User user = (await _auth.createUserWithEmailAndPassword(
email: emailC.text,
password: passwordC.text,
))
.user;
if (user != null) {
if (!user.emailVerified) {
await user.sendEmailVerification();
}
await user.updateProfile(displayName: usernameC.text);
final user1 = _auth.currentUser;
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => Home(
user: user1,
username: usernameC.text,
)));
} else {
bool _isSuccess = false;
}
}
passwordC,usernameC and emailC are the controllers.
After, signing up I wanted to show 'Display name' on the screen. but I tried to print it and see first, it showed null.
This is my build method of homepage...
#override
Widget build(BuildContext context) {
initialize();
print('Reached here');
print(widget.user.displayName);
return Scaffold(
body: Center(
child: Container(
child: Column(
children: [
Text(''),
Center(
child: RaisedButton(
child: Text("Logout"),
onPressed: () {
FirebaseAuth.instance.signOut();
}),
),
],
)),
),
bottomNavigationBar: BottomNavigationBar(
onTap: (index) {
setState(() {
currentindex = index;
});
},
currentIndex: currentindex,
items: [
BottomNavigationBarItem(
title: Text("Home"), icon: Icon(Icons.account_balance_wallet)),
BottomNavigationBarItem(
title: Text("Home"), icon: Icon(Icons.search)),
BottomNavigationBarItem(
title: Text("Home"), icon: Icon(Icons.account_circle)),
]),
);
initialize method here is to call these two methods
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
initialize method cannot be problem anyway.
Thank you.
FirebaseAuth.currentUser() will only detect changes made locally to the user, but if any server-side changes occur, it won't detect them, unless FirebaseUser.reload() is called first so you have to call
await user.reload();
after the update() is called.

Flutter - Always getting wrong POST 400 response before getting the expected 200

I'm having some trouble trying to get the correct response to a POST request in Flutter. This is the method I have written:
Future<void> processUnload(String code) async {
Map info = {
'code': "$code",
};
try {
var response = await http.post(
url + "/unload/code",
body: json.encode(info), headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $token"
}
);
if (response.statusCode == 200) {
showUnloadOKMessage();
} else {
showUnloadNotOKMessage(response.body);
}
}catch (error) {
if (error.toString().contains("Failed host lookup")) {
notDelivered.add(OfflineCart(code, DateTime.now().toString()));
showOfflineUnloadMessage();
}
}
}
showUnloadOKMessage() {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title:
Text('Unload OK.', style: TextStyle(color: Colors.green)),
actions: <Widget>[
FlatButton(
child: Text('OK', style: botonGrandeRojo),
onPressed: () {
Navigator.of(context).pop();
FocusScope.of(contextobuild).requestFocus(focusNode);
},
),
],
);
},
);
}
showUnloadNotOKMessage(String msg) {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(msg, style: TextStyle(color: Colors.red)),
actions: <Widget>[
FlatButton(
child: Text('OK', style: botonGrandeRojo),
onPressed: () {
Navigator.of(context).pop();
FocusScope.of(contextobuild).requestFocus(focusNode);
},
),
],
);
},
);
}
The problem is that, when the POST request is made, I ALWAYS get 4 or 5 response.statusCode == 400 before getting the actual and expected response.statusCode == 200. Thus, the app always displays 4 or 5 "Not OK messages" before displaying the expected "Unload OK" one.
I've read quite a few async/await/then articles (Threading in Flutter, Using Futures Guide for Beginners, Flutter Async Loader), and I'm pretty sure the problem is the way I've written the code, but I can't get it to work properly, since I don't have any experience working with asynchronous calls.
Thank you.
I found the bug. The problem was that the processUnload method was being called multiple times within a setState(). So, I just had to add a flag to prevent it to be called more than once at the same time and remove the setState():
Widget createCodeText() {
bool processing = false;
return Expanded(
child: TextField(
autofocus: true,
decoration: InputDecoration(hintText: 'Esperando lectura...'),
showCursor: false,
controller: controllerCode,
focusNode: focusNode,
onChanged: (code) async {
if (!processing){
processing = true;
await processUnload (code);
processing = false;
controllerCode.clear();
}
},
),
);
}

Resources