Flutter access firebase user email from different class - firebase

I am stuck for hours now on this problem.
I have no problem to access the final currentUser = loggedInUser.email;when the getCurrentUser function is defined and called in the same class (SlateScreen).
My SlateScreen Class ad MessageStream Class are both in the same .dart file. So this here works:
final firestore = Firestore.instance;
/// loggedInUser variable for fetching the user email later
FirebaseUser loggedInUser;
DatabaseMethods databaseMethods = DatabaseMethods();
class TheSlateScreen extends StatefulWidget {
static String id = 'theslate_screen';
#override
_TheSlateScreenState createState() => _TheSlateScreenState();
}
class _TheSlateScreenState extends State<TheSlateScreen> {
final _auth = FirebaseAuth.instance;
// call getCurrentUser in initState
#override
void initState() {
super.initState();
getCurrenUser();
}
getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
print(loggedInUser);
}
} catch (e) {
print(e);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
// fetch the email from my getCurrentUser function
final currentUser = loggedInUser.email;
But I get "The getter email was called on null" error if I define my getCurrentUser() function in the DatabaseMethods Class, and then call it in the SlateScreen class' via
#override
void initState() {
super.initState();
databaseMethods.getCurrentUser(_auth);
}
My DatabaseMethods Class:
class DatabaseMethods {
FirebaseUser loggedInUser;
getCurrentUser(FirebaseAuth _auth) async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}
I tried all kind of adjustments, but didn t get anywhere...
UPDATE / SOLUTION:
Thanks to the the anwsers provided, I found a way:
in my DatabaseMethods class I simply return the user:
Class DatabaseMethods {
getCurrentUser(FirebaseAuth _auth) async {
try {
final user = await _auth.currentUser();
if (user != null) {
return user;
}
} catch (e) {
print(e);
}
}
}
and in the SlateScreen Class, I am using a helper function that I can call in initState():
#override
void initState() {
super.initState();
logInUser(_auth);
}
logInUser(_auth) async {
loggedInUser = await DatabaseMethods().getCurrentUser(_auth);
}

In this snippet:
// fetch the email from my getCurrentUser function
final currentUser = loggedInUser.email;
The loggedInUser variable is only set once the getCurrentUser method has completed. So you can't just do loggedInUser.email anywhere in your code, but can only do that after you've made sure getCurrentUser has completed.
So this would work fine:
await databaseMethods.getCurrentUser(_auth);
final currentUser = loggedInUser.email;
Given what you shared, it may be able to add that await in your initState:
#override
void initState() {
super.initState();
await databaseMethods.getCurrentUser(_auth);
}

You need to initialize loggedInUser, just do the following:
loggedInUser = await FirebaseAuth.instance.currentUser();
final currentUser = loggedInUser.email;

Related

The argument type 'Object? Function()' can't be assigned to the parameter type 'Map<String, dynamic>'

I created a class called 'tasks' and implement it. I edit gradle files for connecting with firebase. I gain some errors in my code. So please help me to solve this error.
class _MyHomePageState extends State<MyHomePage> {
late List<Task> items;
FirestoreService fireServ = new FirestoreService();
late StreamSubscription<QuerySnapshot> todoTasks;
#override
void initState() {
super.initState();
items= [];
todoTasks.cancel();
todoTasks=fireServ.getTaskList().listen((QuerySnapshot snapshot){
final List<Task> tasks=snapshot.docs
.map((documentSnapshot) => Task. fromMap(documentSnapshot.data))
.toList();
setState(() {
this.items = tasks;
});
});
}
This is my firestore class service
class FirestoreService {
Future<Task> createTODOTask(String taskname, String taskdetails,String taskdate,String tasktime,String tasktype) async {
final TransactionHandler createTransaction = (Transaction tx) async {
final DocumentSnapshot ds = await tx.get(myCollection.doc());
final Task task = new Task(taskname, taskdetails,taskdate,tasktime,tasktype);
final Map<String, dynamic> data = task.toMap();
await tx.set(ds.reference, data);
return data;
};
return FirebaseFirestore.instance.runTransaction(createTransaction).then((mapData) {
return Task.fromMap(mapData);
}).catchError((error) {
print('error: $error');
return null;
});
}
Stream<QuerySnapshot> getTaskList({int offset=0, int limit=0}) {
Stream<QuerySnapshot> snapshots = myCollection.snapshots();
if (offset != null) {
snapshots = snapshots.skip(offset);
}
if (limit != null) {
snapshots = snapshots.take(limit);
}
return snapshots;
}
}
You need to change:
documentSnapshot.data
to this:
documentSnapshot.data()
.data() is a method and not a property of the DocumentSnapshot object.

Different screen based on user role not working

Hi I'am new to Flutter making an app for booking appointments which require to screens for two types of users i.e. patient and doctor.
class DashboardPage extends StatefulWidget {
#override
_DashboardPageState createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
UserProvider userProvider;
final AuthMethods _authMethods = AuthMethods();
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) async {
userProvider = Provider.of<UserProvider>(context, listen: false);
await userProvider.refreshUser();
_authMethods. getUserDetails();
});
}
User user = User();
#override
Widget build(BuildContext context) {
if (user.role == 'patient') {
return PatientHomePage();
}
else if (user.role == 'doctor') {
return DoctorHomePage();}
return Container(color: Colors.red,);
}
}
role variable is defined in another dart file:
class User { String uid; String name; String email; String role = "patient"; String profilePhoto; User({ this.uid, this.name, this.email, this.role, this.profilePhoto, }); ........... }
the default value "patient" is assigned to it when a user logs in. Future<void> addDataToDb(FirebaseUser currentUser) async { User user = User( uid: currentUser.uid, email: currentUser.email, name: currentUser.displayName, profilePhoto: currentUser.photoUrl, role: "patient"); firestore .collection(USERS_COLLECTION) .document(currentUser.uid) .setData(user.toMap(user)); } all this is happening in another dart file
But this logic is not working as expected as it's showing only the red screen on phone which implies that
there is some issue in getting user.role from firebase.
Please help me...
class DashboardPage extends StatefulWidget {
#override
_DashboardPageState createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
UserProvider userProvider;
final AuthMethods _authMethods = AuthMethods();
User user = User();
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) async {
userProvider = Provider.of<UserProvider>(context, listen: false);
/// This method is future method so it might happen that after widget render you are getting response.
await userProvider.refreshUser();
/// seState will rebuild your widget with new user details
setState(() {
user = _authMethods. getUserDetails();
});
});
}
#override
Widget build(BuildContext context) {
if (user.role == 'patient') {
return PatientHomePage();
}
else if (user.role == 'doctor') {
return DoctorHomePage();}
return Container(color: Colors.red,);
}
}

How to work around 'Future<dynamic>' is not a subtype of type 'FirebaseUser' error

I have a FirebaseActions class which is doing signup and signin works for me. I added a getCurrentUser method in it. I'm calling that function from my HomeScreen widget. I need to put the returned value(type= FirebaseUser) into a variable in my HomeScreen to reach loggedInUser.email. But I get this error. My question; is there any way to get a FirebaseUser type data into a Future type variable? When I write this function in HomeScreen instead of FirebasAction class, it works but is it the best practice?
FirebaseActions class
static getCurrentUser(context) async {
final user = await _auth.currentUser().catchError((error) {
Scaffold.of(context).showSnackBar(AppSnackBar.appSnackBar(error.message));
});
if (user != null) {
return user;
}
}
HomeScreen widget
class _HomeScreenState extends State<HomeScreen> {
FirebaseUser loggedInUser;
#override
void initState() {
super.initState();
loggedInUser = FirebaseActions.getCurrentUser(context);
print(loggedInUser.toString());
}
You are getting this error because you didn't specify a return type in your getCurrentUser() function.
Replace your code with the one below and everything will work fine.
To solve this issue:
Check the code below: It works perfectly fine:
Firebase Action Class
// give your function a return type
static Future<FirebaseUser> getCurrentUser(context) async {
final user = await _auth.currentUser().catchError((error) {
Scaffold.of(context).showSnackBar(AppSnackBar.appSnackBar(error.message));
});
if (user != null) {
return user;
}
}
Home Screen Widget
class _HomeScreenState extends State<HomeScreen> {
FirebaseUser loggedInUser;
#override
void initState() {
super.initState();
call the function here
logInUser();
print(loggedInUser.toString());
}
I hope this helps
UPDATE
// create a new function to log in user
void logInUser() async {
// await the result because you are invoking a future method
loggedInUser = await FirebaseActions.getCurrentUser(context);
}
You are not specified return type of method and also method is async, so you have to put await where you are calling.
static Future<FirebaseUser> getCurrentUser(context) async {
also, add await where you are calling.
loggedInUser = await FirebaseActions.getCurrentUser(context);
update:
create new function and call in that function.
callme() async{
loggedInUser = FirebaseActions.getCurrentUser(context);
print(loggedInUser.toString());
}
initstate:
#override
void initState() {
super.initState();
callme();
}
Here's how I handle async functions in my initstate:
FirebaseActions.getCurrentUser(context).then((val){loggedInUser = val});
Also make sure you specify the return type in your asynchronous function.
Future<FirebaseUser> getCurrentUser(context) async {...

How can I get a value from firebase and and put it in a text in Flutter

I'm having a simple problem which is how to get specific values from database Firebase.
For example, I want to get the value of "name" and put it in text. How can I do that? Can you write a detailed code?
class _HomePageState extends State<HomePage> {
String myuid;
FirebaseUser currentUser;
// To get id
void _loadCurrentUser() {
FirebaseAuth.instance.currentUser().then((FirebaseUser user) {
setState(() { // call setState to rebuild the view
this.currentUser = user;
});
});
}
#override
void initState() {
super.initState();
_loadCurrentUser();
}
#override
Widget build(BuildContext context) {
myuid = currentUser.uid;
var getname;
Future<void> getName() async {
DocumentSnapshot ds =
await Firestore.instance.collection('users').document(myuid).get();
getname = ds.data['name'];
}
Try
String name;
Future<null> getName() async {
DocumentSnapshot document = await Firestore.instance.collection('users').document(FirebaseUser().uid).get();
name = document.data['name']
}
This is how you can get data from the Firestore Database Document once
val docRef = db.collection("users").document("mhPtwy..........")
docRef.get()
.addOnSuccessListener { document ->
if (document != null) {
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
} else {
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
This is a kind of cheeky way to get the data and store it in a variable
var name;
Future<void> getName(){
DocumentSnapshot ds = await
Firestore.instance.collection('users').document(uid).get();
name = ds.data['name']
}
then just throw that in your text field
Text(name);

FirebaseAuth logout() in Flutter doesn't work

I'm trying to log out from FirebaseAuth, but even though the user is null after I logged out, it seems like the instance is somehow still cached.
When I log out and in again, the user.metadata.lastSignInTime and the FirebaseAuth.instance.hashCode are still the same as before I logged out.
That causes, that my onboarding is displayed even after the second login as I'm checking if user.creationTime == user.lastSignInTime.
My _logOut Method:
void _logOut(BuildContext context) async {
await GoogleSignIn().signOut();
await FirebaseAuth.instance.signOut();
}
The initial SignUp Page whitch is beeing called when user == null :
class SignUpPage extends StatefulWidget {
final String title;
SignUpPage({Key key, this.title}) : super(key: key);
#override
SignUpPageState createState() => SignUpPageState();
}
class SignUpPageState extends State<SignUpPage> {
final FirebaseAuth _auth = FirebaseAuth.instance;
bool isloaded = false;
#override
void initState() {
super.initState();
//detects when user logs out:
_auth.onAuthStateChanged.listen((user) => {
if (user == null)
{
//This page is the first one in the route
Navigator.of(context).popUntil((route) => route.isFirst),
setState(() {
isloaded = true;
}),
}
});
// Enabled persistent log-ins by checking the Firebase Auth instance for previously logged in users
_auth.currentUser().then((user) {
setState(() {
isloaded = true;
});
if (user != null) {
_pushPage(context, HomePage());
}
});
}
#override
Widget build(BuildContext context) {
//Building Page here
}
}
I'm just starting with Flutter, but I tried everything I could think of to actually fully dispose the FirebaseAuth.instance in _logOut() without success.

Resources