1

I posted yesterday this question but i didn't get any valid answer. My current situation is i can successfully log the user in but when i restart the app i have to login again so i need to save the details of the user in a shared preference so that the user can stay logged for the entire session until logout.But i am unable to do that so please help me with it. Thanks in advance

login.dart :

Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromRGBO(3, 9, 23, 1),
      body: Container(
          padding: EdgeInsets.only(
            top: 100,
            right: 30,
            left: 30,
          ),
          child: SingleChildScrollView(
            child: Form(
              key: _formKey,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  FadeAnimation(
                      1.2,
                      Container(
                        padding: EdgeInsets.all(70.0),
                        margin: EdgeInsets.only(bottom: 50.0),
                        decoration: BoxDecoration(
                            image: DecorationImage(
                                image: AssetImage(
                                    'assets/images/trakinglogo.png'))),
                      )),
                  SizedBox(
                    height: 30,
                  ),
                  FadeAnimation(
                      1.5,
                      Container(
                        padding: EdgeInsets.all(10),
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(10),
                            color: Colors.white),
                        child: Column(
                          children: <Widget>[
                            Container(
                              decoration: BoxDecoration(
                                  border: Border(
                                      bottom:
                                          BorderSide(color: Colors.grey[300]))),
                              child: TextFormField(
                                controller: _emailController,
                                onFieldSubmitted: (_) =>
                                    FocusScope.of(context).nextFocus(),
                                textInputAction: TextInputAction.done,
                                validator: (value) {
                                  if (value.isEmpty) {
                                    return 'Email is required';
                                  }
                                  return null;
                                },
                                decoration: InputDecoration(
                                    border: InputBorder.none,
                                    hintStyle: TextStyle(
                                        color: Colors.grey.withOpacity(.8)),
                                    hintText: "Votre adresse mail"),
                              ),
                            ),
                            Container(
                              decoration: BoxDecoration(),
                              child: TextFormField(
                                controller: _passwordController,
                                validator: (value) {
                                  if (value.isEmpty) {
                                    return 'Password is required';
                                  }
                                  return null;
                                },
                                obscureText: _isHidden,
                                decoration: InputDecoration(
                                  border: InputBorder.none,
                                  hintStyle: TextStyle(
                                      color: Colors.grey.withOpacity(.8)),
                                  hintText: "Mot de passe",
                                  suffix: InkWell(
                                      onTap: _togglePasswordView,
                                      child: Icon(
                                        _isHidden
                                            ? (CommunityMaterialIcons
                                                .eye_outline)
                                            : (CommunityMaterialIcons.eye_off),
                                        color: Color(0xFF939394),
                      
                  SizedBox(
                    height: 40,
                  ),
                  FadeAnimation(
                      1.8,
                      Center(
                          child: Column(
                        children: [
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.center,
                            children: [
                              Container(
                                child: RaisedButton(
                                  textColor: Colors.white,
                                  color: kPrimaryColor,
                                  child: Text("Se connecter"),
                                  onPressed: () async {
                                    if (_formKey.currentState.validate()) {
                                      showDialog(
                                          context: context,
                                          builder: (BuildContext context) {
                                            return Center(
                                              child:
                                                  CircularProgressIndicator(),
                                            );
                                          });
                                      await loginUser();
                                    }
                                    /*  Navigator.push(
                                      context,
                                      MaterialPageRoute(
                                          builder: (context) => MyWidget()),
                                    );*/
                                    // Navigator.pushNamed(context, 'Mywidget');
                                  },
                                  shape: new RoundedRectangleBorder(
                                    borderRadius:
                                        new BorderRadius.circular(30.0),
                                  ),
                                ),
                                width: 250,
                                padding: EdgeInsets.all(15),
                              )
                            ],
                          ),
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              AlreadyHaveAnAccountCheck(
                                press: () {
                                  Navigator.push(
                                    context,
                                    MaterialPageRoute(
                                      builder: (context) {
                                        return SignUp();

 void loginUser() async {
    // if (_formKey.currentState.validate()) {
    setState(() {
      _isLoading = true;
    });
    String email = _emailController.text;
    String password = _passwordController.text;

    authentication.login(email, password).then((user) {
      if (user != null)
        Navigator.push(
            context, MaterialPageRoute(builder: (context) => MyWidget()));
    }).catchError((error) {
      ScaffoldMessenger.of(context)
          .showSnackBar(SnackBar(content: Text(error.toString())));
    });

    setState(() {
      _isLoading = false;
    });
  }

and this is login function :

Future<User> login(String email, String password) async {
  await checkInternet();

  Map<String, String> headers = {
    'Content-type': 'application/json',
    'Accept': 'application/json',
  };
  Map<String, String> body = {'email': email, 'password': password};

  var response = await http.post(Uri.parse(ApiUtil.AUTH_LOGIN),
      headers: headers, body: jsonEncode(body));
  switch (response.statusCode) {
    case 200:
      var body = jsonDecode(response.body);
      var data = body['user'];
      User user = User.fromJson(data);
      Track track = Track.fromJson(body);

      if (body['code'] == 0) {
        SharedPreferences localStorage =
        await SharedPreferences.getInstance();
        localStorage.setInt('id', body['user']['id']);
        localStorage.setString('adress', body['user']['adress']);
        localStorage.setString('phone', body['user']['phone']);
        localStorage.setString('access_token', body['access_token']);
        localStorage.setString('user', json.encode(body['user']));
        String user = localStorage.getString('user');

      }
      return user;
    case 500:
      throw ('Erreur serveur');
      break;

    case 400:
      throw LoginFailed();
    default:
      throw ('connection timeout');
      break;
  }
}
lucky
  • 185
  • 5
  • 18
  • I recommend you to use [Flutter secure storage](https://pub.dev/packages/flutter_secure_storage) instead of SharedPreferences if you want to store personal information – quoci May 31 '21 at 08:55
  • i have some problem with secure storage plugin and sdk version . Now my goal is how to keep user logged . – lucky May 31 '21 at 08:58

2 Answers2

1

When i do the first login i'm saving the data on the shared preferences

 ApiRepository.get().login(LoginRequest(username: _emailController.text, password: _passwordController.text)).then((response) async {
  if (response != null) {
    //save on the shared preferences that the user is logged in
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool(SHARED_LOGGED, true);
    await prefs.setString(SHARED_USER, _emailController.text);
    await prefs.setString(SHARED_PASSWORD, _passwordController.text);
  }
}).catchError((error) { 
});

Everytime i'm opening the app i have a splashscreen, here i do an implicit login and than i make skip the login page and bring the user on the home page

void checkUserIsLogged() async {
    final prefs = await SharedPreferences.getInstance();
    if ((prefs.getBool(SHARED_LOGGED) != null) && prefs.getBool(SHARED_LOGGED)) {
      ApiRepository.get().login(LoginRequest(username: prefs.getString(SHARED_USER), password: prefs.getString(SHARED_PASSWORD))).then((response) {
        if (response != null) {
          //"do something"
        }
      }).catchError((error) {
        
      });
    } else {

    }
  }

FULL code SplashPageLoading.dart

class SplashPageLoading extends StatefulWidget {
  @override
  _SplashPageLoadingState createState() => _SplashPageLoadingState();
}

class _SplashPageLoadingState extends State<SplashPageLoading> {
  bool _doLogin = false;

  @override
  void initState() {
    super.initState();

    new Future.delayed(const Duration(seconds: 3), () => checkUserIsLogged());
  }

  void checkUserIsLogged() async {
    final prefs = await SharedPreferences.getInstance();
    if ((prefs.getBool(SHARED_LOGGED) != null) && prefs.getBool(SHARED_LOGGED)) {
      setState(() {
        _doLogin = true;
      });
      ApiRepository.get().login(LoginRequest(username: prefs.getString(SHARED_USER), password: prefs.getString(SHARED_PASSWORD))).then((response) {
        if (response != null) {
          Navigator.of(context).pushReplacementNamed(HomePage.routeName);
        }
      }).catchError((error) {
        Navigator.of(context).pushReplacementNamed(LoginPage.routeName);
      });
    } else {
      new Future.delayed(const Duration(seconds: 1), () => Navigator.of(context).pushReplacementNamed(LoginPage.routeName));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text(
          _doLogin ? "Login.." : "No data for login",
          style: TextStyle(color: Colors.black),
        ),
      ),
    );
  }
}

Strings.dart

const String SHARED_LOGGED = "USER_IS_LOGGED";
const String SHARED_USER = "USER";
const String SHARED_PASSWORD = "PASSWORD";

shared preferences library

  • where i can put checkUserIsLogged() in my code ? How i can use it ccorrectly ? @Alessandro Cignolini – lucky May 31 '21 at 10:25
  • 1
    it depends on how your app is structured. For example in my app i have a splashscreen, everytime i'm opening the app the first page that start is the splash. inside it on the initState i make the call new Future.delayed(const Duration(seconds: 3), () => checkUserIsLogged()); – Alessandro Cignolini May 31 '21 at 10:49
  • I use an intermediary page to understand if the user is logged in or not. if he is logged in I send him to the HomePage if he is not logged in I send him to the LoginPage. All this process I do in the splash – Alessandro Cignolini May 31 '21 at 10:56
  • It's not such a good practice to store sensitive data (like passwords) in Shared Preference. My recommendation would be using [Secure Storage](https://pub.dev/packages/flutter_secure_storage). Furthermore, it would even be better if you could get an auth token from the backend and store that token instead of the user credentials. You can google JWT for example – Gpack May 31 '21 at 11:03
  • can you show me a complete example ?? @Alessandro Cignolini – lucky May 31 '21 at 11:05
  • I know that . i have problem with secure storage plugin and my sdk version @ Gpack – lucky May 31 '21 at 11:06
  • I have SplashScreen code bit i can't implement it correctly .@Alessandro Cignolini – lucky May 31 '21 at 11:08
  • i update with the full code of my splashpage. if you still have problem pls post me the problem and i will try to help you. – Alessandro Cignolini May 31 '21 at 11:37
  • authentication.login ( email: prefs.getString(SHARED_USER), password: prefs.getString(SHARED_PASSWORD))) .then((user) : error : 2 positional argument(s) expected, but 0 found. @Alessandro Cignolini – lucky May 31 '21 at 11:52
  • 1
    remove the label name and email authentication.login (prefs.getString(SHARED_USER), prefs.getString(SHARED_PASSWORD))).then((user) @lucky – Alessandro Cignolini May 31 '21 at 12:13
  • .pushReplacementNamed(LoginPage().routeName); error :The getter 'routeName' isn't defined for the type 'LoginPage'. @Alessandro Cignolini – lucky May 31 '21 at 12:26
  • 1
    If you use named references for push a page you need to create a constant in your loginpage static const routeName = '/loginPage'; Use the following code if you don't know how to use pushNamed Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage()),); – Alessandro Cignolini May 31 '21 at 12:36
  • ok i correct it . SplashPageLoading.dart is ok . then where i should call it ? how i use it in my code ? @Alessandro Cignolini – lucky May 31 '21 at 12:51
  • 1
    set your SplashPageLoading as the first page when you run your app. Than call the method checkUserIsLogged inside the init of SplashPageLoading. Now it suppose to work. How it will work. your SplashPageLoading will start and init will call checkUserIsLogged() method. if you have data in sharedpreferences the implicit login will start and you will be brought in HomePage, if you don't have nothing in shared preferences you will be brought in the LoginPage. – Alessandro Cignolini May 31 '21 at 12:57
  • How i can set SplashPageLoading as the first page in my app ? @Alessandro Cignolini – lucky May 31 '21 at 13:05
  • initialRoute: '/', routes: { '/': (context) => Welcome(), '/splash': (context) => Splash( title: 'Accueil', ), '/traking': (context) => Traking( title: 'Traking', ), '/fuel': (context) => Fuel( title: 'Carburant', ), '/caisse': (context) => Caisse( title: 'Caisse', ), '/notifications': (context) => Notifications( title: 'Notifications', ) }, – lucky May 31 '21 at 13:06
  • there are many ways to do this. I suggest you to check the flutter documentation. The easy way is in your main.dart you suppose to have a MaterialApp, set the home: SplashPageLoading() – Alessandro Cignolini May 31 '21 at 13:10
  • i changed it ... it show a black screen . myabe i have problem in SplashPageLoading.dart .@Alessandro Cignolini – lucky May 31 '21 at 13:15
  • ok as i can see you already have a Welcome() as first page just switch with my or just push the code on your second page called Splash. i mean you know need to understand how to use the code properly – Alessandro Cignolini May 31 '21 at 13:15
  • yes .. it's in the end of SplashPageLoading.dart .@Alessandro Cignolini – lucky May 31 '21 at 13:18
  • let me explain or you call SplashPageLoading() inside another page with a scaffold ecc ecc or you add a scaffold inside SplashPageLoading as stand alone page. in my example the page will be called in another place so i didn0t need a scaffold – Alessandro Cignolini May 31 '21 at 13:21
  • i add the final code of SplashPageLoading.dart . check it please and correct if has error @Alessandro Cignolini – lucky May 31 '21 at 13:31
  • ok i update the @override Widget build in my answer, i put the scaffold just copy it – Alessandro Cignolini May 31 '21 at 13:41
  • the screen worked fine and show me "No data for login" . @Alessandro Cignolini – lucky May 31 '21 at 13:45
  • 1
    perfect the first time it will give you that message and it's correct you need to do atleast 1 login manually for have the data stored in shared preferences. When i write manually i mean the login from LoginPage – Alessandro Cignolini May 31 '21 at 13:48
  • that's mean i have problem in () => Navigator.of(context).pushReplacementNamed('/')); . it should redirect me to LoginPage() .@Alessandro Cignolini – lucky May 31 '21 at 13:58
  • 1
    yep :/ but I don't know which one it is. you can try instead of doing pushReplacementNamed doing pushReplacement Navigator.pushReplacement( context, MaterialPageRoute( builder: (BuildContext context) => LoginPage())) – Alessandro Cignolini May 31 '21 at 14:01
  • i correct it . but when i run the app it show me the loginscreen. after success login i closed the app. and i reopen it ==> it show me no data for login and redirect me to loginPage() . what is the problem ? @Alessandro Cignolini – lucky May 31 '21 at 14:07
  • when you do the login do you save the data in shared preferences like i show you in the first snippet code on my answer? – Alessandro Cignolini May 31 '21 at 14:16
  • My friend it's works fine now but i have two issues . the first is when i closed the app and reopen it ==> it show me no data for login for 2 secondes the switch to login ... and the app logged succefully . how i can show directly the message : login ... instead of No data for login @Alessandro Cignolini – lucky May 31 '21 at 14:25
  • 1
    ok the text that change is because _doLogin is false at the start and than became true. I mean that text is just for debugging you can delete and put just a progress bar with a text "Login" remove the variable _doLogin add a progress bar and add a text with the text "Login" and should be fine. – Alessandro Cignolini May 31 '21 at 14:28
  • the second issue is when i press logout and close the app . after that if i reopen the app it show me the dashboard directly . i think after that it should show me the loginpage not the dashboard . how i can correct it ?@Alessandro Cignolini – lucky May 31 '21 at 14:34
  • 1
    call this method on your logout button void clearSharedPreferences() async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setBool(SHARED_LOGGED, false); await prefs.remove(SHARED_USER); await prefs.remove(SHARED_PASSWORD); await prefs.remove(STOVE_SHARED_PREF_ID); } – Alessandro Cignolini May 31 '21 at 14:40
  • i add my actual logout() as answer ... check it please @Alessandro Cignolini – lucky May 31 '21 at 14:44
  • 1
    localStorage.remove('id'); localStorage.remove('access_token'); localStorage.remove('email'); in your logout this key are wrong You save the data under this key static const String SHARED_LOGGED = "USER_IS_LOGGED"; static const String SHARED_USER = "USER"; static const String SHARED_PASSWORD = "PASSWORD"; so you must delete the data using the same key not a different one – Alessandro Cignolini Jun 01 '21 at 05:55
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/233164/discussion-between-lucky-and-alessandro-cignolini). – lucky Jun 01 '21 at 08:34
0

SplashPageLoading.dart :

class SplashPageLoading extends StatefulWidget {
      @override
      _SplashPageLoadingState createState() => _SplashPageLoadingState();
    }
    
    class _SplashPageLoadingState extends State<SplashPageLoading> {
      bool _doLogin = false;
      Authentication authentication = Authentication();
    
      static const String SHARED_LOGGED = "USER_IS_LOGGED";
      static const String SHARED_USER = "USER";
      static const String SHARED_PASSWORD = "PASSWORD";
    
      @override
      void initState() {
        super.initState();
    
        new Future.delayed(const Duration(seconds: 3), () => checkUserIsLogged());
      }
    
      void checkUserIsLogged() async {
        final prefs = await SharedPreferences.getInstance();
        if ((prefs.getBool(SHARED_LOGGED) != null) &&
            prefs.getBool(SHARED_LOGGED)) {
          setState(() {
            _doLogin = true;
          });
          authentication
              .login(prefs.getString(SHARED_USER), prefs.getString(SHARED_PASSWORD))
              .then((user) {
            if (user != null) {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => MyWidget()),
              );
    
              // Navigator.of(context).pushReplacementNamed('/splash');
            }
          }).catchError((error) {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => MyWidget()),
            );
    
            //  Navigator.of(context).pushReplacementNamed('/splash');
          });
        } else {
          new Future.delayed(const Duration(seconds: 1),
              () => Navigator.of(context).pushReplacementNamed('/'));
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Text(
          _doLogin ? "Login.." : "",
          style: TextStyle(color: Colors.white),
        );
      }
    }
lucky
  • 185
  • 5
  • 18