Pages

Firebase Authentication using Provider in Flutter

Implementation of firebase auth along with provider in Flutter, a state management helper that provides varieties of widgets to make attractive widgets. Provider package allows you to use various widgets and even rebuilt the widget when you need to do some changes. 


The most frequent classes used in the Firebase provider package are Consumer, ChangeNotifier, ChangeNotifierProvider. The model class which is important for the app widget tree extended for ChangeNotifier. This class includes all the application state-managing variables, methods, and objects. 


In case you want to update the application state you are required to call notifiyListeners(). This method is to notify all the available widgets that need to listen to the change in order to update and rebuilt the UI. There are two methods that are used to consume the data. Use Provider.of and Consumer widget.


Before starting with the code, you first need to install the following packages inside your pubspec.yalm file.


provider|Flutter Package

get_it|Dart Package

firebase_auth| Flutter Package

firebase_core|Flutter Package  


Usage of routes for navigation

You need to use onGenerateRoute, initialRoute functionality that MaterialApp provides. RouteSetting is a parameter when used onGenerateRoute and return Route. 


Here we are going to use the switch method and initialize the navigation cases in a separate class. static Route<dynamic> is a method that takes RouteSettings parameters. 


routers.dart file


import 'package:flutter/material.dart';

import 'package:flutter_chat_app/ui/homePage.dart';

import 'package:flutter_chat_app/ui/landingPage.dart';


class Routers {

 static Route<dynamic> generateRoute(RouteSettings settings) {

   switch (settings.name) {

     case 'home':

       return MaterialPageRoute(builder: (_) => HomePage());

     case 'landing':

       return MaterialPageRoute(builder: (_) => LandingPage());

     default:

       return MaterialPageRoute(builder: (_) {

         return Scaffold(

           body: Center(

             child: Text('No route defined for ${settings.name}'),

           ),

         );

       });

   }

 }

}


After that, you need to provide onGenerateRoute which also initializes the initialRoute. 


class MyApp extends StatelessWidget {

 // This widget is the root of your application.

 @override

 Widget build(BuildContext context) {

   return MaterialApp(

     initialRoute: 'landing',

     onGenerateRoute: Routers.generateRoute,

   );

 }

}


In order to use navigation, you can use pushNamed method which allows you to navigate to another screen by using the route name which is defined in the router.dart. 

onPressed: () async {

     Navigator.pushNamed(context, 'route_name');

 }


Start with code

Use enums ViewState, AuthState, to manage the state of the application. 


enum ViewState { Ideal, Busy }

enum AuthState { SignIn, SignUp }


Now, use BaseModel class which extends ChangeNotifier. This class includes all the methods that are required to update the UI. 


import 'package:flutter/material.dart';

import 'package:flutter_chat_app/enum/appState.dart';


class BaseModel extends ChangeNotifier {

 ViewState _viewState;


 ViewState get viewState => _viewState;


 setViewState(ViewState viewState) {

   _viewState = viewState;

   notifyListeners();

 }


 AuthState _authState;


 AuthState get authState => _authState;


 setAuthState(AuthState authState) {

   _authState = authState;

   notifyListeners();

 }

}


In the above code, we have used two methods for the state change. The use of setViewState is to switch the ViewState from Busy to Idel and vice versa. 


The use of setAuthState method will help you to switch the AuthState from SignOut to SignIn and vice-versa.  This Flutter provider login example will help you to generate a sign widget. 


The sign-in and sign out widget can be developed by using provider in Flutter Firebase


authModel.dart file


import 'package:firebase_auth/firebase_auth.dart';

import 'package:flutter_chat_app/enum/appState.dart';


import 'baseModel.dart';


class AuthModel extends BaseModel {

 FirebaseAuth firebaseAuth = FirebaseAuth.instance;


 void createNewUser(String email, String password) async {

   setViewState(ViewState.Busy);

   await firebaseAuth.createUserWithEmailAndPassword(

       email: email, password: password);

   setViewState(ViewState.Ideal);

 }


 void signIn(String email, String password) async {

   setViewState(ViewState.Busy);

   await firebaseAuth.signInWithEmailAndPassword(

       email: email, password: password);

   setViewState(ViewState.Ideal);

 }


 void logOut() async {

   setViewState(ViewState.Busy);

   await firebaseAuth.signOut();

   setViewState(ViewState.Ideal);

 }

}


The aforementioned class will enable you to use various methods that handle the authentication of an application. After this, create all the methods that will handle all the changes in UI when a user will switch between the options ‘ sign in and sign out.’


authStateModel.dart file


import 'package:flutter/cupertino.dart';

import 'package:flutter_chat_app/enum/appState.dart';

import 'package:flutter_chat_app/model/authModel.dart';

import 'package:flutter_chat_app/model/baseModel.dart';


class AuthStateModel extends BaseModel {

 switchAuthenticationState(AuthModel authModel) {

   authModel.authState == AuthState.SignIn

       ? authModel.setAuthState(AuthState.SignUp)

       : authModel.setAuthState(AuthState.SignIn);

 }


 switchAuthenticationMethod(

   AuthModel authModel,

   TextEditingController emailController,

   TextEditingController passwordController,

 ) {

   authModel.authState == AuthState.SignIn

       ? authModel.signIn(

           emailController.text,

           passwordController.text,

         )

       : authModel.createNewUser(

           emailController.text,

           passwordController.text,

         );

 }


 switchAuthenticationText(AuthModel authModel) {

   return authModel.authState == AuthState.SignIn ? "Sign In" : "Sign Up";

 }


 switchAuthenticationOption(AuthModel authModel) {

   return authModel.authState == AuthState.SignIn

       ? "Create account ??"

       : "Already registered ??";

 }

}

Now, you need to create a BaseView class which you can use to update the UI and pass the model data that was created earlier. A custom widget in Firebase auth provider is perfect to design a widget according to your choice. 


Builder function is used in BaseView method that requires BuildContext, Widget, and a Model as a parameter. 


baseView.dart file


import 'package:flutter/material.dart';

import 'package:flutter_chat_app/locator.dart';

import 'package:flutter_chat_app/model/baseModel.dart';

import 'package:provider/provider.dart';


class BaseView<T extends BaseModel> extends StatefulWidget {

 final Widget Function(BuildContext context, T model, Widget child) builder;


 BaseView({

   @required this.builder,

 });


 @override

 _BaseViewState<T> createState() => _BaseViewState<T>();

}


class _BaseViewState<T extends BaseModel> extends State<BaseView<T>> {

 T model = locator<T>();


 @override

 Widget build(BuildContext context) {

   return ChangeNotifierProvider<T>.value(

     //builder: (context) => model,

     child: Consumer<T>(builder: widget.builder),

     //notifier: model,

     value: model,

   );

 }

}


App UI Page



Landing Page

landingPage.dart


import 'package:firebase_auth/firebase_auth.dart';

import 'package:flutter/material.dart';

import 'package:flutter_chat_app/model/authModel.dart';

import 'package:flutter_chat_app/ui/authPage.dart';


import 'package:flutter_chat_app/ui/baseView.dart';

import 'package:flutter_chat_app/ui/homePage.dart';


// ignore: must_be_immutable

class LandingPage extends StatelessWidget {

 TextEditingController emailController = TextEditingController();

 TextEditingController passwordController = TextEditingController();


 @override

 Widget build(BuildContext context) {

   return BaseView<AuthModel>(

     builder: (context, authModel, child) => StreamBuilder(

         stream: FirebaseAuth.instance.authStateChanges(),

         builder: (context, snapshot) {

           return snapshot.hasData

               ? HomePage()

               : AuthPage(

                   emailController: emailController,

                   passwordController: passwordController,

                   authModel: authModel,

                 );

         }),

   );

 }

}


authPage.dart file


import 'package:flutter/material.dart';

import 'package:flutter_chat_app/enum/appState.dart';

import 'package:flutter_chat_app/model/authModel.dart';

import 'package:flutter_chat_app/model/authStateModel.dart';

import 'package:flutter_chat_app/ui/baseView.dart';


class AuthPage extends StatelessWidget {

 final TextEditingController emailController;

 final TextEditingController passwordController;

 final AuthModel authModel;


 AuthPage({

   @required this.emailController,

   @required this.passwordController,

   @required this.authModel,

 });


 @override

 Widget build(BuildContext context) {

   return BaseView<AuthStateModel>(builder: (context, authStateModel, __) {

     return Scaffold(

       body: Padding(

         padding: const EdgeInsets.all(20),

         child: Center(

           child: Column(

             children: [

               SizedBox(

                 height: 200,

               ),

               TextFormField(

                 decoration: InputDecoration(hintText: "Email"),

                 controller: emailController,

               ),

               TextFormField(

                 controller: passwordController,

                 decoration: InputDecoration(hintText: "Password"),

               ),

               authModel.viewState == ViewState.Busy

                   ? CircularProgressIndicator()

                   : RaisedButton(

                       child: Text(

                           authStateModel.switchAuthenticationText(authModel)),

                       color: Colors.cyanAccent,

                       onPressed: () {

                         authStateModel.switchAuthenticationMethod(

                             authModel, emailController, passwordController);

                       }),

               InkWell(

                 onTap: () {

                   authStateModel.switchAuthenticationState(authModel);

                 },

                 child:

                     Text(authStateModel.switchAuthenticationOption(authModel)),

               ),

             ],

           ),

         ),

       ),

     );

   });

 }

}


homePage.dart file


import 'package:flutter/material.dart';

import 'package:flutter_chat_app/model/authModel.dart';

import 'package:flutter_chat_app/ui/baseView.dart';


class HomePage extends StatelessWidget {

 @override

 Widget build(BuildContext context) {

   return BaseView<AuthModel>(

     builder: (context, model, __) => Scaffold(

       body: Center(

         child: RaisedButton(

           color: Colors.cyanAccent,

           child: Text("Log Out"),

           onPressed: () {

             model.logOut();

           },

         ),

       ),

     ),

   );

 }

}


Register every service with the locator. 

locator.dart file


import 'package:flutter_chat_app/model/authModel.dart';

import 'package:flutter_chat_app/model/authStateModel.dart';

import 'package:flutter_chat_app/model/baseModel.dart';

import 'package:get_it/get_it.dart';



final locator = GetIt.instance;


void setupLocator(){

 locator.registerLazySingleton(() => BaseModel());

 locator.registerLazySingleton(() => AuthModel());

 locator.registerLazySingleton(() => AuthStateModel());

}


Initialize method setupLocator() inside the main function.

void main() async {

 WidgetsFlutterBinding.ensureInitialized();

 await Firebase.initializeApp();

 setupLocator();

 runApp(MyApp());

}

 

No comments:

Post a Comment

Make new Model/Controller/Migration in Laravel

  In this article, we have included steps to create a model and controller or resource controller with the help of command line(CLI). Here w...