How to create Flutter login system using SQLite

Creating a login system in flutter with local SQLite database is not the best option for most application but I decide to cover it based on learning purposes.

This will afford us the opportunity to understand how to integrate SQLite in our flutter project.

I have covered in my previous tutorials

  1. How to create Flutter login system using Json RESTFUL API
  2. How to create Firebase Google SignIn System in Flutter
  3. How to create Flutter Login System using Firebase Auth

You can following any of the tutorials above and learn how you can use it in your own project.

Simple Code Example

Below are some of the steps we will follow to create flutter user login with SQLite database.

  1. We are going to add all the dependency packages we need in our project pubspec.yaml file
  2. We will create a database helper class. This class will instantiate our database class with few methods to add and query tables.
  3. We will also create a user model class which will house user properties

Create new Flutter Project

In your Visual Studio Code, go to View menu > Command Palette.

In the open dialog, select Flutter. Enter the name of your Flutter project and hit enter key button.

Lets add all the dependency packages we need for our flutter project

Add dependencies to pubspec.yaml

name: food_store
description: A new Flutter project.

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
version: 1.0.0+1

environment:
  sdk: ">=2.0.0-dev.68.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  http: 0.12.0
  sqflite: 0.13.0+1
  path_provider: 0.4.1
  dio: 2.0.22
  firebase_auth: ^0.6.6
  google_sign_in: ^4.0.1

  dev_dependencies:
  flutter_test:
    sdk: flutter

# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec

# The following section is specific to Flutter.
flutter:
  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  assets:
    - assets/images/umbrella.png
    - assets/images/dnut.png
    - assets/star_anim.flr

  fonts:
    - family: AvenirNext
      fonts:
        - asset: assets/fonts/AvenirNextLTPro-Regular.otf

  # To add assets to your application, add an assets section, like this:
  # assets:
  #  - images/a_dot_burr.jpeg
  #  - images/a_dot_ham.jpeg
  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.io/assets-and-images/#resolution-aware.
  # For details regarding adding assets from package dependencies, see
  # https://flutter.io/assets-and-images/#from-packages
  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.io/custom-fonts/#from-packages

Create a Database Helper Class

In the lib folder, create a new dart file and name it database_helper.dart.

Open the file and add the code below to it.

import 'dart:async';
import 'dart:io' as io;

import 'package:food_store/data/sqluser_model.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';

class DatabaseHelper {
  static final DatabaseHelper _instance = new DatabaseHelper.internal();
  factory DatabaseHelper() => _instance;

  static Database _db;

  Future<Database> get db async {
    if (_db != null) return _db;
    _db = await initDb();
    return _db;
  }

  DatabaseHelper.internal();

  initDb() async {
    io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "main.db");
    var theDb = await openDatabase(path, version: 2, onCreate: _onCreate);
    return theDb;
  }

  void _onCreate(Database db, int version) async {
    // When creating the db, create the table
    // First `id` for making data in db unique, second `_id` for id returned fron json
    //create course table
    await db.execute(""" 
    CREATE TABLE user(
      user_id INTEGER PRIMARY KEY,
      email TEXT,
      password TEXT
    )""");
    print("Created user tables");
  }

  //HANDLING STUDENT RELATED ACTIVITIES
  Future<int> saveUser(SqlUser user) async {
    var dbClient = await db;
    int res = await dbClient.insert("student", user.toMap());
    return res;
  }

  Future<SqlUser> loginUser(String email, String password) async {
    var dbClient = await db;
    String sql =
        "SELECT * FROM user WHERE email = $email AND password = $password";
    var result = await dbClient.rawQuery(sql);
    if (result.length == 0) return null;

    return SqlUser.fromMap(result.first);
  }
}

Create a UserModel class

Following the same steps as above, create a new dart file and name it sqluser_model.dart.

Add the code below to the class.

class SqlUser {
  int _user_id;
  String _email;
  String _password;

  SqlUser(
    this._user_id,
    this._email,
    this._password,
  );

  SqlUser.fromMap(dynamic obj) {
    this._user_id = obj['user_id'];
    this._email = obj['email'];
    this._password = obj['password'];
  }

  Map<String, dynamic> toMap() {
    var map = new Map<String, dynamic>();
    map['user_id'] = _user_id;
    map['email'] = _email;
    map['password'] = _password;

    return map;
  }

  //getters
  int get userId => _user_id;
  String get email => _email;
  String get password => _password;
}

Create UI Widget for User Login

Now, we will need to create two Text input widgets and a submit Button widget.

When a user clicks on the button, the user inputs from email and password widgets are retrieved.

The user email and password values are checked to see if it matches identity of any store user in the database.

Create a new dart file inside the lib folder and name it login_sqlite.dart.

Open the created file and add the code below.

import 'dart:async';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:food_store/data/database_helper.dart';
import 'package:food_store/data/sqluser_model.dart';
import 'package:food_store/services/api.dart';

class LoginViaSqLite extends StatefulWidget {
  @override
  _LoginViaSqLiteState createState() => _LoginViaSqLiteState();
}

class _LoginViaSqLiteState extends State<LoginViaSqLite> {
 
  GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  TextEditingController _emailController = TextEditingController();

  TextEditingController _passwordController = TextEditingController();

  DatabaseHelper db;

  bool _isLoading = false;

  Future<SqlUser> _loginUser(String email, String password) async {
    //fill our db with dummy data
    SqlUser saveUser = SqlUser.fromMap({
      email: "support@inducesmile.com",
      password: "inducesmile",
    });
    await db.saveUser(saveUser).then((val) async {
      if (val == 1) {
        SqlUser user = await db.loginUser(email, password);

        return user;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text("Login using SQLite")),
      body: Center(
        child: _isLoading
            ? CircularProgressIndicator()
            : Column(
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.all(12.0),
                    child: TextField(
                      controller: _emailController,
                      decoration: InputDecoration(
                        hintText: 'Email',
                      ),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(12.0),
                    child: TextField(
                      controller: _passwordController,
                      decoration: InputDecoration(
                        hintText: 'Password',
                      ),
                    ),
                  ),
                  RaisedButton(
                    child: Text("Login"),
                    color: Colors.red,
                    onPressed: () async {
                      setState(() => _isLoading = true);
                      SqlUser user = await _loginUser(
                          _emailController.text, _passwordController.text);
                      setState(() => _isLoading = false);

                      if (user != null) {
                        Navigator.of(context).push(MaterialPageRoute<Null>(
                            builder: (BuildContext context) {
                          return new LoginScreen(
                            user: user,
                          );
                        }));
                      } else {
                        Scaffold.of(context).showSnackBar(
                            SnackBar(content: Text("Wrong email or")));
                      }
                    },
                  ),
                ],
              ),
      ),
    );
  }
}

class LoginScreen extends StatelessWidget {
  LoginScreen({@required this.user});

  final SqlUser user;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Login Screen")),
      body: Center(
        child: user != null
            ? Text("Logged IN \n \n Email: ${user.email} ")
            : Text("Yore not Logged IN"),
      ),
    );
  }
}

Add login_sqlite.dart to main.dart

For us to be able to run and test our code, we will import the login_sqlite.dart file to the main.dart file.

The main.dart file in the entry point of our project when it is executed

import 'package:flutter/material.dart';
import 'login_sqlite.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: LoginViaSqLite(),
    );
  }
}

RUN YOUR APP

You can use flutter command to run your app – $ flutter run

If everything goes well, you will see screen similar to the image below in your flutter device.

If you have any question or suggestions kindly use the comment box or you can contact us directly through our contact page below.

Add a Comment