Retrieving user email from Firebase in Flutter - firebase

In my AuthProvider class where I handle my sign in, sign, out authentications, I created 2 functions that returns a Future String like so
Future<String> currentUser() async {
FirebaseUser user = await _auth.currentUser();
return user.uid;
}
Future<String> getCurrentUserEmail() async {
FirebaseUser user = await _auth.currentUser();
final String email = user.email.toString();
// print(email);
return email;
}
In my menu screen, I want to display my current signed in user email in a text field and I am calling it as below.
UserAccountsDrawerHeader(
accountName: Text('Brad Pitt'),
accountEmail: Text(
'${AuthProvider.of(context).auth.getCurrentUserEmail()}'),
I have tried using both the currenUser() and getCurrentUserEmail() to try to display the loggedIn user's email but I keep getting a "Instance of Future" displayed.
Is there something I'm overlooking here? I've tried every possible hack I can think of.
Thanks.

Since your getCurrentUserEmail returns a Future, you'll need to use a FutureBuilder to use it in your build method.
accountEmail: FutureBuilder<String>(
future: AuthProvider.of(context).auth.getCurrentUserEmail(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data)
}
else {
return Text("Loading user data...")
}
}
)

The best thing to do is to upgrade to firebase_auth:0.18.0, after upgrade you can get the currentUser synchronously!
dependencies:
flutter:
sdk: flutter
firebase_core : ^0.5.0
firebase_auth : ^0.18.0
initialize Firebase:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
Then in UsersAccountDrawerHeader:
UserAccountsDrawerHeader(
accountName: Text('Brad Pitt'),
accountEmail: Text('${auth.instance.currentUser.email}'),
Also check:
Undefined class 'FirebaseUser'
No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() in Flutter and Firebase

Retrieving user email, null safety supported.
var currentUser = FirebaseAuth.instance.currentUser;
Text('admin email: ${FirebaseAuth.instance.currentUser!.email}'),

You need to add ~await~ in front of the function as it's a function that returns a ~Future~
await AuthProvider.of(context).auth.getCurrentUserEmail()

After initilizing your Firebase in your main
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
Now in the Text widget to display the current user's email use
Text('${FirebaseAuth.instance.currentUser!.email}',),

Related

I can't display name while I'm trying to do a profile why?

I followed some tutos and I add user on firestore successly but I can't print this user on the profile page when the current user is logging because I'm having a error too in my front end.
This is my entire frontend with this error:
The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!')."
I tried ? and ! but with not success.
hope you help me !
FutureBuilder(
future: FirebaseFirestore.instance
.collection('users')
.doc('uid')
.get(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(snapshot.data['displayName'],
);
} else {
return Text("Loading...");
and my backend if needed
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
Future userSetup(String displayName) async {
CollectionReference users = FirebaseFirestore.instance.collection('Users');
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser!.uid.toString();
await users.doc(uid).set({'displayName': displayName, 'uid': uid });
final result = await users.doc(uid).get();
final data = result.data() as Map<String, dynamic>;
return data['displayName'];
}

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
});

how to login once and stay logged in until you log out?

I couldn't figure it out. as i restart the app (if i am signed in or not) it goes to the login page, can you guys help me out on this. i am new to flutter so detailed instructions will be appreciated. Thanks
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: (googleSignIn.isSignedIn() != null) ? MainPage() : LoginPage(),
routes: {
'upload': (context) => ItemInput(),
'toyota': (context) => Toyota(),
},
));
}
Auth.dart
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<User> signInWithGoogle() async {
final GoogleSignInAccount googleSignInAcount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAcount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
idToken: googleSignInAuthentication.idToken,
accessToken: googleSignInAuthentication.accessToken);
final UserCredential authResult =
await _auth.signInWithCredential(credential);
final User user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = _auth.currentUser;
assert(currentUser.uid == user.uid);
return user;
}
void signOutGoogle() async {
await googleSignIn.signOut();
}
Login.dart
void click() {
signInWithGoogle().then((user) => {
this.user = user,
Navigator.push(
context, MaterialPageRoute(builder: (context) => MainPage()))
});
}
RaisedButton.icon(
onPressed: () async {
click();
},
label: Text(
'Sign-up with Google ',
)),
Firebase automatically restores the user's authentication state when the app is restarted. So you'd typically detect whether the user is already signed in, and then navigate to the post-login screen when they are.
According to the documentation on authentication state you can get the authentication state with:
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
// ... navigate to post-login screen
}
});
One way to do it is by using shared preference, see, https://pub.dev/packages/shared_preferences
When the signin is successful do,
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("isLoggedIn", true);
This will store a boolean value that you use to check if the user is signed in or not. It will be saved even after the app is closed unless you uninstall or clear app data.
and in the main.dart use that stored prefs value to check if the user is already signed in or not by doing -
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isLoggedIn = prefs.getBool("isLoggedIn");
Use the isLoggedIn value, navigate the user to either Login Screen or Home Screen, and use it to perform other logic.

How can you manually trigger onAuthStateChanged for Firebase Authentication in Flutter?

I have a an app built around a StreamBuilder listening for FirebaseAuth.instance.onAuthStateChanged
return new StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) { ...
I'm trying to reload the user and use onAuthStateChanged to pick up when an email is verified. User.reload() is insufficient with the StreamBuilder. It's a similar issue to this onAuthStateChanged doesn't get called when email is verified in flutter
I thought a solution would be to force a logout and login but I'm at a loss on how to do that - e.g. step 2, login again to trigger onAuthStateChanged.
_auth.signOut(); //sign out and immediate sign in
final FirebaseUser user = await _auth.signIn----( //which signin function?
Have you tried refreshing auth token?
https://firebase.google.com/docs/auth/admin/manage-sessions
Use _auth.userChanges() stream instead of _auth.onAuthStateChanges()
return StreamBuilder(
stream: _auth.userChanges(),
builder: (ctx, userSnapshot) {
User? user = _auth.currentUser;
if (userSnapshot.hasData && user != null && user.emailVerified) {
// load screen on successful login
}
// fallback to auth screen
},
);
and on successful verification call refreshToken in your verification method
Future<void> verifyEmail() async {
user = _auth.currentUser;
await user!.reload();
if (user!.emailVerified) {
setState(() {
_isEmailBeingVerified = false;
});
user!.refreshToken;
}
}

How to retrieve specific user details from firestore with flutter

I'm new to flutter and firebase so bear with me. I'm using email sign up with firestore and flutter on my app, on registration some additional fields are saved to firestore. I want to retrieve those fields to display on the user profile.
The key identifier for the fields saved to the users collection is the auto generated user id upon sign up.
I have in my widget build context
child: new FutureBuilder<FirebaseUser>(
future: _firebaseAuth.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
String userID = snapshot.data.uid;
_userDetails(userID);
return new Text(firstName);
}
else {
return new Text('Loading...');
}
},
),
And my get associated data method is:
Future<void> getData(userID) async {
// return await Firestore.instance.collection('users').document(userID).get();
DocumentSnapshot result = await Firestore.instance.collection('users').document(userID).get();
return result;
}
To retrieve the user details
void _userDetails(userID) async {
final userDetails = getData(userID);
setState(() {
firstName = userDetails.toString();
new Text(firstName);
});
}
I have tried adding a .then() to the set state in _userdetails but its saying userDetails is a type of void and cannot be assigned to string.
The current code block here returns instance of 'Future' instead of the user Details.
Your method is marked as async so you have to await for the result :
Future<void> _userDetails(userID) async {
final userDetails = await getData(userID);
setState(() {
firstName = userDetails.toString();
new Text(firstName);
});
}

Resources