In my application, I happen to have two types of users, hospital, and patients, both are configured to use the same authentication by firebase. What I would like to know is, how do I load the page for the respective user depending on how they were signed in previously? For example, if a hospital had signed in and not logged out, when they run the app, it should display the hospitals' dashboard and not the patients'. How do I configure this?
shared_prefs supports Flutter web. Save a value stating the account type.
See this answer:
https://stackoverflow.com/a/59579821/13714686
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isHospital = (prefs.getBool('isHospitalAccount');
if(isHospital == true){
//hospital navigation
}
else{
//patient navigation
}
First, you need to check whether the user is logged in or not. For this, you can check through the below code.
class MyApp extends StatelessWidget{
#override
Widget build(BuildContext context){
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot){
if (snapshot.hasData){
FirebaseUser user = snapshot.data; // this is your user
/// is because there is a user already logged, So route them to a Screen of Dashboard directly.
return MainScreen();
}
/// other way there is no user logged.
return LoginScreen();
}
);
}
}
Now, you need to maintain a list of users in FireStore where the user's metadata like the last login, User Type information will be stored. Using this information you can Route the user accordingly.
Related
onAuthStateChanged no longer listens to changes, so basically, when I create a new account or sign in to an existing one, it's stuck in the loading spinner but the user did create it in the firebase users.
I'm using StreamBuilder:
home:StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (ctx, userSnapshot) {
if (userSnapshot.hasData) {
return SellerScreen(docsRef);
}
return AuthScreen();
},
),
what I get in the console:
D/FirebaseAuth( 9477): Notifying id token listeners about user ( VQghDgOucFdCcWLdPlCJNTd5eO72 ).
D/FirebaseAuth( 9477): Notifying auth state listeners about user ( VQghDgOucFdCcWLdPlCJNTd5eO72 ).
The code in the console stipulates that the user has either been created or signed in.
Your problem might be with where your spinner widget is located in the code...
Can i have a snippet on that to see if I can help?
...in any case, what i usually do is:
bool loading = false;
#override
Widget build(BuildContext context) {
return loading ? Loading() : HomeScreen();
}
With this, I've told flutter to show the loading screen while the user is being created or signed in.
The bool type loading is just to toggle between the true and false state of the loading widget
I am new to Flutter/Firebase and I want to program an app where a user can login/register and then he needs to create a profile with his information like his name, age... and only if he has created his profile, he should be able to continue and see the "main part" of the app.
I already implemented the Firebase Auth with a working Login / Register Page, but my question is now, how to create the Profile thing the most efficent.
At the moment I created this method here at my own:
Future checkUserProfile() async{
// get snapshot from document
final snapShot = await Firestore.instance.collection('profiles').document(uid).get();
if(snapShot == null || !snapShot.exists){
User.gotProfile = false;
} else {
User.gotProfile = true;
}
This method is checking if an user-profile with the Firebase Auth User UID already exists and if not, the user will be send to the "ProfilePage" with a FutureBuilder executing the method above and if it already exists, he will see the main part of the app.
As I already said, I tried it by myself and I wanted to ask if this is already an good implementation or is there even an easier & better way to do it?
Yes this is an good implementation. In my app I have the check User method like yours. The following method is an example. When the user is not registered he forwarded to the RegisterPage else he forwarded to the MainPage.
checkUserAlreadyExists(FirebaseUser user) async {
final userData = await Firestore.instance.collection('users').document(user.uid).get();
if (userData == null || !userData.exists) {
setState(() {
Navigator.pushAndRemoveUntil(context,
MaterialPageRoute(builder: (BuildContext context) => RegisterPage()), ModalRoute.withName('/'));
});
} else {
setState(() {
Navigator.pushAndRemoveUntil(context,
MaterialPageRoute(builder: (BuildContext context) => MainPage()), ModalRoute.withName('/'));
});
}
}
I am pretty new to flutter and are designing an app that requires user to login. Once users have registered an account they will be required to fill out some user information before being taken to the home screen. If the user registers an account however doesnt fill out their info the next time they log in they should be returned to this screen. Currently, there is a stream that watches the value of the user. If this value is null then it shows the login page, otherwise it will show the home page.
I am having trouble implementing the user information screen. Would setting up a stream that watches a firestore document and, if the document exists return the home page, otherwise show the user infromation screen be the best method and if so how would I go about doing so?
Here is my code that checks whether or not the user is signed in:
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
home: SignedIn(),
)
);
}
And the code for the SignedIn() widget:
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
if (user == null) {
return Authenticate();
} else {
return Home();
}
}
I would probably try something like this.
StreamSubscription _subscription;
_subscription = yourStream.listen((data) {
// navigate to whatever screen depending on the data
if(data.signedIn){
Navigator.pushNamed(context, "whatever_route");
}
});
I am using firebase in my flutter app and accessing the logged in user would be done something like this -
Future<FirebaseUser> getLoggedInUser() async {
return await FirebaseAuth.instance.currentUser();
}
I use BLOC and was thinking of adding this to my AuthenticationBloc class. Since this BLOC is injected early, I should be able to access this from anywhere in the app -
AuthenticationBloc authBloc = BlocProvider.of<AuthenticationBloc>(context);
FirebaseUser user = await authBloc.getLoggedInUser()
But this leads to a few problems like accessing this in a StreamBuilder becomes an issue because of the need of using await which means I would need to make the StreamBuilder async (not sure how).
What would be the best/cleanest way of accessing the user object FirebaseUser user from anywhere in the app ?
Thanks !
Edit 1 :
So one way to do this would be to use a stateful widget every time I want the current user
class _MyWidgetState extends State<MyWidget> {
FirebaseUser user;
#override
void initState() {
super.initState();
_updateCurrentUser();
}
void _updateCurrentUser() async {
FirebaseUser currUser = await Firebase.instance.currentUser();
setState(() {
user = currUser;
});
}
But using a stateful widget every time I want the currUser seems weird. Is there a better way out ?
You can access the user by using stream such as
StreamBuilder(
stream:FirebaseAuth.instance.onAuthStateChanged,
builder:(context,snapshot){
if (snapshot.connectionState == ConnectionState.active) {
final user = snapshot.data;
return Text("User Id:${user.uid}");
}else{
return Center(
child:CircularProgressIndicator(),
);
}
}
);
There is a slight bug in my app made with Flutter, that when the user has signed in, it fetches the user information from my database but not fast enough and causes a visual error on my front end of the app. The app has layouts that use the user information (name, location, and image) and it is not being loaded quick enough. I was wondering if there is a way to wait for my future to complete and once it is done, it can navigate the user to the front end with no problem.
You Should fetch your date from the database in the initState() function, then you have to modify your widget builder to use FutureBuilder, here's an example:
Widget build(BuildContext context) {
return FutureBuilder(
future: getProfile(),
builder: (BuildContext context, AsyncSnapshot<SharedPreferences> snapshot) {
if(snapshot.connectionState == ConnectionState.done){
return new MaterialApp();
}
}
)
}
note that you can replace AsyncSnapshot<SharedPreferences> with the type your Future function returns.