`I’m creating a role based flutter app where the roles are patient, telenurse, consultant and an admin. I’ve created the login page and everyone is able to log in correctly but when you close the app and come back, it does not keep the user signed in but sends you back to the login screen, how can i fix this problem?
This is what i tried;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:telenursingapp/admin_portal.dart';
import 'package:telenursingapp/consultant_portal.dart';
import 'package:telenursingapp/patients_portal.dart';
import 'package:telenursingapp/telenurse_portal.dart';
class SignIn extends StatefulWidget {
const SignIn({super.key});
@override
State<SignIn> createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
// text controllers
bool _isObscure3 = true;
bool visible = false;
final _formkey = GlobalKey<FormState>();
final TextEditingController emailController = new TextEditingController();
final TextEditingController passwordController = new TextEditingController();
final _auth = FirebaseAuth.instance;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.blueGrey, Color(0xFF3EB489)]),
),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 1.0,
child: Center(
child: Container(
margin: EdgeInsets.all(12),
child: Form(
key: _formkey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 30,
),
Image.asset('assets/YourDoc-black.png', width: 70),
Icon(
FontAwesomeIcons.solidHandshake,
size: 20,
color: Colors.black,
),
SizedBox(height: 80,),
Text('Login to your account!',
style: TextStyle(
color: Colors.white,
fontSize: 44,
fontWeight: FontWeight.bold
)),
const SizedBox(height: 10,),
const Text('Welcome back to YourDoc',
style: TextStyle(
color: Color.fromARGB(255, 88, 85, 85),
fontSize: 24,)),
SizedBox(
height: 20,
),
TextFormField(
controller: emailController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: 'Email',
enabled: true,
contentPadding: const EdgeInsets.only(
left: 14.0, bottom: 8.0, top: 8.0),
focusedBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.white),
borderRadius: new BorderRadius.circular(10),
),
enabledBorder: UnderlineInputBorder(
borderSide: new BorderSide(color: Colors.white),
borderRadius: new BorderRadius.circular(10),
),
),
validator: (value) {
if (value!.length == 0) {
return "Email cannot be empty";
}
if (!RegExp(
"^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+.[a-z]")
.hasMatch(value)) {
return ("Please enter a valid email");
} else {
return null;
}
},
onSaved: (value) {
emailController.text = value!;
},
keyboardType: TextInputType.emailAddress,
),
SizedBox(
height: 20,
),
TextFormField(
controller: passwordController,
obscureText: _isObscure3,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(_isObscure3
? Icons.visibility
: Icons.visibility_off),
onPressed: () {
setState(() {
_isObscure3 = !_isObscure3;
});
}),
filled: true,
fillColor: Colors.white,
hintText: 'Password',
enabled: true,
contentPadding: const EdgeInsets.only(
left: 14.0, bottom: 8.0, top: 15.0),
focusedBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.white),
borderRadius: new BorderRadius.circular(10),
),
enabledBorder: UnderlineInputBorder(
borderSide: new BorderSide(color: Colors.white),
borderRadius: new BorderRadius.circular(10),
),
),
validator: (value) {
RegExp regex = new RegExp(r'^.{6,}$');
if (value!.isEmpty) {
return "Password cannot be empty";
}
if (!regex.hasMatch(value)) {
return ("please enter valid password min. 6 character");
} else {
return null;
}
},
onSaved: (value) {
passwordController.text = value!;
},
keyboardType: TextInputType.emailAddress,
),
SizedBox(
height: 20,
),
MaterialButton(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(20.0))),
elevation: 5.0,
height: 40,
minWidth: 500,
onPressed: () {
setState(() {
visible = true;
});
signIn(
emailController.text, passwordController.text);
},
color: Color.fromARGB(255, 20, 85, 206),
child: Text(
"Login",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
SizedBox(
height: 10,
),
Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: visible,
child: Container(
child: CircularProgressIndicator(
color: Colors.white,
))),
],
),
),
),
),
),
],
),
),
);
}
void route() {
User? user = FirebaseAuth.instance.currentUser;
var kk = FirebaseFirestore.instance
.collection('users')
.doc(user!.uid)
.get()
.then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
if (documentSnapshot.get('role') == "Patient") {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => PatientsPortal(),
),
);
}
else if(documentSnapshot.get('role') == "Consultant"){
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => ConsultantPortal()));
}
else if(documentSnapshot.get('role') == "New Admin"){
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => AdminPortal()));
}
else if(documentSnapshot.get('role') == "Telenurse"){
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => TelenursePortal()));
}
else{
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => SignIn(),
),
);
}
} else {
print('Document does not exist on the database');
}
});
}
void signIn(String email, String password) async {
if (_formkey.currentState!.validate()) {
try {
UserCredential userCredential =
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password,
);
route();
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
}
}
}
2
Answers
You should use Hive local DB or Shared Preferences to store one boolean variable locally named isLoggedInUser and once the user logs in you can make this variable as true and default value for this will be false.
So what happens is that you can check in Splash screen if that flag is true then you will redirect user to Dashboard or else you can redirect user to the Login screen.
You can also store other variables like user type and their id for further use in the application. This way user will not need to login every-time they open the app.
Here’s a class which you can use to store and get variables locally.
import ‘package:shared_preferences/shared_preferences.dart’;
Use it like this :
Set :
MyPrefs().setValue("isLoggedInUser", true/false);
. <– Here you need to pass true or false as valueGet :
await MyPrefs().getValue("isLoggedInUser", false);
. <– Here false is a default valueThe Firebase Authentication SDK automatically stores the credentials of the user in local storage and restores them from there when the app restarts.
Doing this however requires it to make a call to the server, to check if the credentials are still valid and to ensure that the user hasn’t been disabled, and this takes time.
Instead of making the app wait to render for the first time during this check, the app starts up normally while this is happening. And that runs your
build
androute
for the first time, which (I guess, as I don’t see this code in what you shared) then checkFirebaseAuth.instance.currentUser
and notes that it isnull
, so nobody is signed in (yet).There is no way to prevent this behavior. So instead you should react to when Firebase has completed its restore flow by listening to the
authStateChanges()
stream as shown in the first example of the documentation on getting the current user:Since you’re likely going to be doing this in the UI, you’ll want to use a
StreamBuilder
in there to wrapFirebaseAuth.instance.authStateChanges()
.