I created bool parameter and I am passing it from auth.dart to wrapper.dart. Parameter changes its value after loging/registering and signing out - false should return in wrapper.dart Loging widget and true should return HomePage widget. But wrapper.dart only reads authorised's value at the start, and even if it changes, Wrapper does nothing. Any idea how to solve it?
auth.dart:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
bool authorised = true;
//Registering with email and password
void register(String email, String password) async {
final FirebaseUser user = (
await _auth.createUserWithEmailAndPassword(email: email, password: password)
).user;
authorised = true;
print(authorised);
}
//Logging with email and password
void login(String email, String password) async {
final FirebaseUser user = (
await _auth.signInWithEmailAndPassword(email: email, password: password)
).user;
authorised = true;
print(authorised);
}
//Signing out
void signOut() async {
await _auth.signOut();
authorised = false;
print(authorised);
}
}
wrapper.dart:
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
final FirebaseAuth _auth = FirebaseAuth.instance;
AuthService authService = AuthService();
#override
Widget build(BuildContext context) {
return authService.authorised ? HomePage() : Registering();
}
}
I have also tried doing if(user != null){...} in auth.dart and if(authService.authorised = true){return HomePage();} in wrapper.dart, but it also doesn't work :/
Related
I'm new in Flutter, I'm working on a simple authentication app when I registered i should navigate to the chat screen and i want to grab current user but when i call FireBaseAuth.instance.currentUser() I got an exception "the expression doesn't evaluate to a function, so it can't be invoked." Why I'm seeing this? Please Help
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
class ChatScreen extends StatefulWidget {
static const String id = "chatScreen";
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final FirebaseAuth _auth = FirebaseAuth.instance;
// ignore: deprecated_member_use
FirebaseUser loginUser;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
// HERE I got an Exception "The expression doesn't evaluate to a function, so it can't be invoked."
final user = await _auth.currentUser();
if (user != null) {
loginUser = user;
print(loginUser.email);
}
}
Why do you invoke currentUser as a function ? It is a field, not a method.
final user = await _auth.currentUser;
Update:
Since currentUser does not return a future, the use of await is useless, even if it doesn't cause errors (await on a non-future object causes, under the cover, the object to be wrapped in a new future).
Doc reference: https://pub.dev/documentation/firebase_auth/latest/firebase_auth/FirebaseAuth/currentUser.html
final currentUser = await _firebaseAuth.currentUser();
Simply replace the above code with
final currentUser = _firebaseAuth.currentUser;
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,);
}
}
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;
I am trying to fill my CurrentUser object with the same information as the uid of the logged in user when my users login to the application
My databaseService :
final CollectionReference userCollection =
Firestore.instance.collection('users');
Future<User> getCurrentUserData(String uid) async{
var doc = userCollection.document(uid);
And My Home Page :
class HomeScreen extends StatefulWidget {
final FirebaseUser currentUser;
HomeScreen({#required this.currentUser});
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
And My CurrentUser Model :
class CurrentUser {
static String name;
static String lastName;
static String uid;
static String phone;
static String addresses;
static String photoString;
static int cityId;
static int districtId;
static List<Loss> userLosses;
}
But i cant figure out connect them
If you are using the firebase authentication then you can use FiresbaseAuth.instance.currentUser, it will return a FirebaseUser object that will contain the info of the current user.
I figure it like this:
Future<User> getCurrentUserData(String uid)async {
var docRef = await userCollection.document(uid).get();
User currentUser = User.fromJson(docRef.data);
currentUser.uid=docRef.documentID;
return currentUser;
}
docRef.data is <String,dynamic> map and just i change my user class like this:
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['Name'].toString(),
lastName: json['LastName'].toString(),
phone: json['Phone'].toString(),
photoString: json['PhotoString'].toString(),
districtId: int.parse(json['DistrictId'].toString()),
cityId: int.parse(json['CityId'].toString()),
addresses: json['Addresess'].toString());
}
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.