'Login Page with REST API done using Retrofit & sharedPreferences to store required credentials

I wanted to implement login page with functionality and login should be validated by a rest Api with post method and integration should be done with Retrofit and After login user should land on home page also SharedPrefrences to store the required credencials. so that when user is login login screen should not showing Again and again. how to start implementing all this?

I tried this but not understanding what next:

Login Page:

import 'package:flutter/material.dart';
import 'package:task1/HomePage.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // This widget is the root of your application.
 
  bool _isLoading = false;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Trails',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: MainPage()
    );
  }
}

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {

 final _formKey = GlobalKey<FormState>();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Trails"),
    
      ),
      body: SingleChildScrollView(
        child: Form(
        key: _formKey,
          child: Column(
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.only(top: 60.0),
                child: Center(
                  child: Container(               
                      child: Image.asset('assets/logo.png')),
                ),
              ),
              Padding(
                //padding: const EdgeInsets.only(left:15.0,right: 
           15.0,top:0,bottom: 0),
                padding: EdgeInsets.symmetric(horizontal: 15),
                child: TextFormField(
                  maxLines: 1,
                  decoration: InputDecoration(                     
                      labelText: 'Username',
                      hintText: 'Enter your username'),
                       validator: (value) {
                      if (value == null || value.isEmpty) {
                      return 'Please enter your username';
                  }
                   return null;
                 },
                ),
              ),
              Padding(
                padding: const EdgeInsets.only(
                    left: 15.0, right: 15.0, top: 15, bottom: 0),
                //padding: EdgeInsets.symmetric(horizontal: 15),
                child: TextFormField(
                  obscureText: true,
                  maxLines: 1,
                  decoration: InputDecoration(
                      labelText: 'Password', hintText: 'Enter secure password'),
                       validator: (value) {
                          if (value!.trim().isEmpty) {
                            return 'Enter the password';
                          } else
                            return null;
                        },                  
                ),
              ),
              Align(
                alignment: Alignment.bottomRight,
                child: FlatButton(
                  onPressed: () {
                  },
                  child: Text(
                    'Forgot Password',
                    style: TextStyle(fontSize: 12),
                  ),
                ),
              ),
              Container(
                height: 40,
                width: 125,
                decoration: BoxDecoration(
                    color: Color.fromRGBO(76, 175, 80, 1), borderRadius: BorderRadius.circular(20)),
                child:ElevatedButton(
                 onPressed: () {
                   
                // Validate returns true if the form is valid, or false otherwise.
                if (_formKey.currentState!.validate()) {
                  Navigator.push( context, MaterialPageRoute(builder: (context) =>  HomePage()),
                     );
                }
              },
              child: const Text('Login'),
            ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

APIClient.dart :

import 'package:retrofit/http.dart';
import 'package:dio/dio.dart';
import 'APIClient.dart';
 
@RestApi(baseUrl: "https://api.*****.****/authentication")

abstract class APIClient {

  factory APIClient(Dio dio) = _APIClient;
 
  @POST("/login")
  @FormUrlEncoded()
  Future<LoginResponse> loginPage(@Field("username")username,@Field("password")password);
}

Repo Class:

import 'APIClient.dart';
import 'package:dio/dio.dart';

**class RepoClass{

 late APIClient mClient;
  RepoClass(){
    mClient= APIClient(Dio());
  }
 
  loginPage() async {
    var username = "black_coder";
    var password = "123456";
    var loginModel = await mClient.loginPage(username,password);
    //You can use your login model data as per your requirements.
  }**

but getting error at APIClient.dar saying

The name '_APIClient' isn't a type and can't be used in a redirected constructor.
Try redirecting to a different constructor.


Solution 1:[1]

create SharedPreferences instance and save token as your preferable key

void signIn() async {

  var data = {'mobile': mobile, 'password': password};
  var res = await Network().signIn(data, '/login');
  var body = json.decode(res.body);
      
  if (res.statusCode == 200) {
      SharedPreferences localStorage = await  SharedPreferences.getInstance();
     localStorage.setString('token', json.encode(body['data']  ['token']));

 localStorage.setString('data', json.encode(body['data']));
 Navigator.pushReplacement(context, new MaterialPageRoute(builder: (context) => HomePage()),
         );
 } else if (res.statusCode != 200) {
 // mobileError = "These credentials do not match our records.";
}
}

Solution 2:[2]

You can read more about retrofit(network handler) & shared_preference(for save login state) at Readme & Example part

Retrofit: https://pub.dev/packages/retrofit

shared_preference: https://pub.dev/packages/shared_preferences

Example of Retrofit: demo Github link: https://github.com/HienNguyen102/flutter_retrofit

APIClient.dart

import 'package:retrofit/retrofit.dart';
import 'package:dio/dio.dart';
part 'APIClient.g.dart';

@RestApi(baseUrl: "https://example.com")
abstract class APIClient {
  factory APIClient(Dio dio) = _APIClient;
 
  @POST("/login")
  @FormUrlEncoded()
  Future<String> loginPage(@Field("email")emailId,@Field("password")password);
 
}

Don't forget to add these

dependencies:
  retrofit: ^3.0.1
  dio: ^4.0.4
  json_annotation: ^4.4.0
  json_serializable: ^6.1.4

dev_dependencies:
  retrofit_generator: ^4.0.1
  build_runner: ^2.1.7

and run

flutter pub run build_runner build

so you can get this

part 'APIClient.g.dart';

Next class

RepoClass.dart

class RepoClass{
  APIClient mClient;
  RepoClass(){
    mClient= APIClient(Dio());
  }
 
  loginPage() async {
    var email = "[email protected]";
    var password = "123456";
    var loginModel = await mClient.loginPage(email,password);
    //You can use your login model data as per your requirements.
  }
 
}

Example of Share preference

//Save string data
prefs.setString('email', "[email protected]");
prefs.setString('password', "123456");
//Get string data
string email = prefs.getString('email');
string password = prefs.getString('password');

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Samu Chakraborty
Solution 2