Flutter + Firebase Authentication - update user after updateProfile - firebase

I am trying to update user profile and then reloading it and getting back updated user.
FirebaseAuth auth = FirebaseAuth.instance;
updateDisplayName(user, displayname) async {
await user.updateProfile(displayName: displayname);
await user.reload().then((user) {
return auth.currentUser;
});
}
And then I am calling the above 'updateDisplayName' in an InkWell
InkWell(
onTap: () {
user = updateDisplayName(widget.username, displayName);
print(user);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
MobileNumberScreen(widget.username),
));
},
child: ....
)
The print in onTap returns
flutter: Instance of 'Future'
Basically what I want is I want to update the display name and return updated user so going forward from here I have the user with updated details.

Related

Flutter Authentication signOut - uid waas called null error

I'm logging out of the application with authentication, but I still get uid null error
This is my signOut method
Future<bool> signOut() async {
try {
await _auth.signOut();
_user = null;
return true;
} catch (e) {
return false;
}
}
This is my widget.I can log out successfully, but when switching to the next page it gives uid error and switches
actions: <Widget>[
PopupMenuButton<String>(
onSelected: (value) async {
switch (value) {
case 'Çıkış Yap':
//problem here
var provider = Provider.of<AuthServices>(context, listen: false);
await provider.signOut();
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => GirisEkrani()));
break;
case 'Profil Ayarları':
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilGuncellemeEkrani()));
break;
}
},
itemBuilder: (BuildContext context) {
return {'Profil Ayarları', 'Çıkış Yap'}.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
Error
The getter 'uid' was called on null.
Receiver: null
Tried calling: uid
It looks like you're using the user's uid in the GirisEkrani widget.
You should remove any reference to the uid in there since the user is already signed out and you've set the _user variable in your provider to null.

When I sign-in I get the username of the previous user until I reload app Flutter

I have been trying to make an app with Firebase and Flutter for a while but I noticed that when I reload or sing-up I get the username of the previous user in the Profile page.
Code to get the username:
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<String> getUsername() async {
// Getting current user
final FirebaseUser currentUser = await _auth.currentUser();
// Getting the username
final value = await userCol.document(currentUser.uid).get();
final username = await value.data["username"];
return username;
}
Code of profile page:
String _username;
var dbUsername = DatabaseService().getUsername();
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
// getting current username
dbUsername.then((value) {
print(value);
_username = value;
return _username;
});
return FutureBuilder<String>(
future: dbUsername,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Stack(
children: <Widget>[
Scaffold(
appBar: appbar.ProfileAppBar(name: _username),
body: ...
Version of dependencies
firebase_auth: ^0.14.0+5
cloud_firestore: ^0.12.9+4
provider: ^5.0.0
Until you signout or clear app data the auth session exist. Try signout.
If still not working then try:
// Getting current user
final FirebaseUser currentUser = await _auth.currentUser();
await currentUser.reload();
Use authStateChanges(), this will return stream of current user Stream<User>
FirebaseAuth.instance.authStateChanges().listen((currentUser) {
print(currentUser); // this is give current user instantly when auth state are changed
});

Some Problems In Flutter Firebase Login

I tried coding a login and registration form in an app with firebase auth. There are some problems in my login from.
Please look at this loginForm function which will execute when login button is pressed.
Future loginForm() async {
FormState formSate = _formKey.currentState;
if (formSate.validate()) {
final User firebaseUser = (await firebaseAuth
.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text)
.catchError((errMsg) {
displayToast("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
setState(() {
loading = true;
});
usersRef.child(firebaseUser.uid).once().then((DataSnapshot snap) async {
if (snap.value != null) {
SharedPreferences preferences =
await SharedPreferences.getInstance();
preferences.setString("email", _emailcontroller.text);
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return LocationHome();
}));
displayToast("Succesfully LoggedIn!", context);
} else {
firebaseAuth.signOut();
displayToast("No user found! Please try SignUp", context);
}
});
} else {
displayToast("Error Occured! Cannot log you in", context);
}
}
}
}
You can see here that after login I have programmed it to navigate to Location Page.
But to make user stay logged in I have used a StreamBuilder and checking if snapshot.hasdata in the main file
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
title: 'TaakStore',
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (snapshot.hasData) {
print(snapshot);
return Home();
} else {
return Login();
}
},
),
));
}
In this, you can see that if snapshot.hasdata it should navigate to home screen and if not data then nav to the login screen. The first time when a user opens the app the snapshot has no data so it will open a login screen which is perfect. But the problem is when the user clicks on login button instead of going to location screen it is directly going to home screen because the snapshot has data which is ridiculous.
If someone understand my problem please help me
I think the problem is occuring by using the streamBuilder as streamBuilder continously keeps looking for stream or data and as soon it found the appropriate data it performs the assigned function which is navigating the user to the homeScreen() instead of LocationScreen()
Repleace StreamBuilder on the Main() with the bellow code:
if (FirebaseAuth.instance.currentUser != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(),
),
);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Location(
),
),
);
}
This will not keep on looking for the stream and only execute the function once when the app is restarted. The same method have been suggested by FirebaseFlutter .

Flutter firebase authentication login success no matter if the user is in the database

If I try to fill TextFormFields responsible for email and password and submit, the login procedure gonna be success always.. no matter if user is in firebase authentication field. I've done login and register pages before with firebase working perfectly. Only diffrence was using pushNamed instead pushReplace. Should it do difference?
That's form inkwell onTap :
onTap: () {
final formState = _formkey.currentState;
if (formState.validate()) {
formState.save();
signIn(_email, _password).whenComplete(
() => Navigator.of(context)
.pushReplacement(
MaterialPageRoute(
builder: (context) =>
HomePage(),
)));
}
}
and authentication:
FirebaseAuth _auth = FirebaseAuth.instance;
Future<void> signIn(String _email, String _password) async {
try {
UserCredential user = await _auth.signInWithEmailAndPassword(
email: _email, password: _password);
} on FirebaseAuthException catch (e) {
print('error');
}
}
Email/password sign-in method is turn on.
How to fix this problem and allow to log in only users that exist in firebase?

How to Signout a user in Flutter with Firebase authentication

I have a problem signing out the current user from my app
the method I am using is as follows:
....
onPressed:_signOut
//jump to function
void _signOut() {
FirebaseAuth.instance.signOut();
FirebaseUser user = FirebaseAuth.instance.currentUser;
//print('$user');
runApp(
new MaterialApp(
home: new LoginPage(),
)
);
}
So now when I press the button it should sign the user out and redirect them to the home page which they will have to login again, however, the redirecting happens but the user data would still be saved so when I press the button again it automatically sign in again with the last account. How can I remove user data so the app asks about their credentials each time they try to login after a logout ?
I feel I am missing something in the linkage between pages and how their behavior change accordingly, but what is it ?
Update: I use google sign in function with firebase authentication
Future<String> _testSignInWithGoogle() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final FirebaseUser user = await _auth.signInWithGoogle(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
assert(user.email != null);
assert(user.displayName != null);
assert(!user.isAnonymous);
assert(await user.getToken() != null);
return 'signInWithGoogle succeeded: $user';
}
My login page looks like this:
class LoginPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Login"), backgroundColor: Colors.blue,),
body: new Container(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new IconButton(
icon: new Icon(Icons.account_box, color: Colors.red),
onPressed: _signIn,
iconSize: 80.0,),
new Text("Google Signin")
],
)
)
)
);
}
}
Update: Changed _signOut() method to be async as follows:
Future <LoginPage> _signOut() async{
await FirebaseAuth.instance.signOut();
return new LoginPage();
}
Now when I press on signout, it does not redirect me to the LoginPagae nor does it sign the user out.
Firebase auth's signOut method is asynchronous. You should make your _signOut method async.
Future<void> _signOut() async {
await FirebaseAuth.instance.signOut();
}
so that the call to runApp occurs after the user is signed out.
You should also call _googleSignIn.signOut() when logging out if you want signIn to present the user with an authentication dialog instead of silently and automatically re-using the current Google user.
You need to have an Instances of FirebaseAuth
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
And Then
_signOut() async {
await _firebaseAuth.signOut();
}
Most demos I've looked at only logout of Firebase using a command like _auth.signOut();
This doesn't appear to exist anymore (see Collin's reply above):
_googleSignIn.signOut()
So, I had to use this one method to signout/logout of Google.
_googleSignIn.disconnect();
First create an instance of FirebaseAuth like so
FirebaseAuth auth = FirebaseAuth.instance;
Then add this to either your logout button or any means you wish to use for the logout.
signOut() async {
await auth.signOut();
}
You can also create a function and then call the signOut within your button like so
import 'package:flutter/material.dart';
class SignOut extends StatefulWidget {
#override
_ SignOut State createState() => _ SignOut State();
}
class _ SignOut State extends State< SignOut > {
FirebaseAuth auth = FirebaseAuth.instance;
signOut() async {
await _firebaseAuth.signOut();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Container(
child: RaisedButton(
onPressed: () {
signOut();
},
)
),
),
);
}
}
You decide.
If every answer above is not working, maybe a Page is laying above everything else, then use Navigator.of(context).pop(); to pop the page.
I've searched hours looking for a mistake that wasn't even there just for this small mistake.
you should make your signout function asynchronous
Future<void> _signOut() async {
await FirebaseAuth.instance.signOut();
}
Declare a Future method to call logout function and redirect your page when logout is finished:
Future logout() async {
await _firebaseAuth.signOut().then((value) => Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) => LoginPage()),(route) => false)));
}

Resources