Flutter starter - GetX Flutter Firebase Auth Example

Overview

GetX Flutter Firebase Auth Example

UPDATE: Version 2.0.0 Changed to new language options and added null safety.

GetX is a relatively new package for Flutter that provides the missing link in making Flutter development simpler. I recently converted a firebase auth project I had created which used provider for state management. Switching to GetX simplified many of the pain points I have had with Flutter development. I no longer was having to pass context into functions. I could also better separate my logic from the UI. GetX also greatly simplifies routing, displaying snackbars and dialogs.

There are some really good projects and tutorials that I made use of in making this project. See these links for more help with GetX. GetX Documentation, Todo GetX example, Amateur Coder GetX Videos and Loading Overlay.

So why would you want to use GetX? Let me give you an example of how it simplified my own code. When I used Provider there was a lot more boilerplate code. It felt much more esoteric to use. GetX made my code easier to understand. Here is my code for main.dart original vs. GetX.

Once you understand the GetX way it becomes much easier to organize your code and separate your concerns between your UI and functions. For instance when calling a function in the UI I was having to handle the results from the function and display snackbars with the results. With GetX I was able to move the snackbars into the actual function which makes more sense since I no longer have to send success and fail messages in and out of functions. Below I show a button which signs in the user with the old way vs GetX way. I prefer the GetX way even though it isn’t a lot shorter, but I like having my logic all separated from the UI.

GetX also has a storage package called get_storage. It can take the place of shared preferences. It simplifies the way to store data on the device. Here is another example of before and after code.

There are many other features of GetX to make things simpler, such as working with themes, getting various device settings, etc. This package simplifies a lot of the problems developers face daily when building an app.

When building an auth project there are a lot of the features you need for a production flutter project. I wanted light and dark mode theming but also the ability to detect and switch themes automatically. I needed the ability to switch between languages easily and automatically detect the user’s language. I wanted a simple way to handle translating from english (the only language I know unfortunately). This is accomplished by running a commandline app to generate the GetX Localization class which pulls from a google sheet and easily translate into other languages. Also I needed a way to do simple user roles and it needed to be secure. I see a lot of auth packages including roles in the user’s collection in firestore which is usually editable by that same user. This would make it trivial for the user to assign himself admin privileges. I also wanted to show how to put some basic rules in firestore to secure it. Finally I wanted to have a way the user could alter their profile and change their email or password.

To handle the language translation you need to create a translation for your app in google sheets. Then open /helpers/update_localizations.dart and replace the docID and sheetId with your own documentId and sheetId. After doing that your will need to drop to the command line and go into the helpers directory. Then type: dart update_localizations.dart. This will create or overwrite the localization.g.dart file with your custom translation. There should not be a need to edit this file directly. Every time you make changes to your translation you will need to re-run this generator.

You can copy my sheet as a starting point for your own app. The cool thing about using a google sheet is you can have google translate a field with a simple google formula: =GOOGLETRANSLATE(B4,en,fr) This says translate the phrase in field B4 from english to french.

To handle user roles I created a separate admin collection and added a document with the same document id as the uid of my user. The reason to do this is to make it secure as explained in this medium article. I went with the second method explained in that article. If we had just put the roles as a field in the users collection any user could have upgraded themselves to an admin user. So by moving the admin role to a separate collection we can create some rules in firestore that allow the user to update fields about themselves without giving them access to change the role they were assigned. You can also generate other roles for the user by simply adding additional collections for the other roles..

The rules I have setup in firestore for this project are fairly simple. Here are the rules I have created.

The first rule matches any user in the admin collection and allows you to read that document only. No one is allowed to write to this collection. I manually add my admin users through the firebase console. The second rule allows the user to read and write only if the user matches the currently logged in user. So a user can only change information about themselves. Here is how my collections are setup in firestore.

Finally I wanted to explain a little bit about my ui. I try to control as much as possible with the theme. You can change a lot about the look with the user interface by changing the theme. I am still learning about what all can be changed with just the theme. I also break out small ui components into a separate components folder. Then I make a custom widget instead of using the standard widget directly. This allows me to make changes in one spot if I decide to make ui changes to say a form field in my form_input_field.dart instead of changing a bunch of TextFormField widgets spread through a dozen files.

Overview of project

main.dart — contains info for maintaining the state of the app for the theme, language and user. It initializes language and theme settings. Sets up routing.

/constants/

app_themes.dart — contains info related to our light and dark themes.

globals.dart — contains some global app settings

app_routes.dart — contains the app routes.

/controllers/

auth_controller.dart — our user and authentication functions for creating, logging in and out our user and saving our user data.

language_controller.dart — saves and loads our selected language.

theme_controller.dart — saves and loads our selected theme.

/helpers/

validator.dart — contains some validation functions for our form fields.

update_localizations.dart — command line dart app that generates the localization.g.dart file.

localizations.g.dart — this file is generated from our google sheet (do not manually edit this file).

/models/

user_model.dart — contains the model for our user saved in firestore.

menu_option_model.dart — contains our model for our language options and theme options in settings.

/ui/

home_ui.dart — contains the ui for the home which shows info about the user.

settings_ui.dart — contains the settings screen for setting the theme and language and some user settings.

splash_ui.dart — contains the initial loading screen, currently just a circular progress indicator.

/ui/auth/

reset_password_ui.dart — sends a password reset email to the user.

sign_in_ui.dart — allows user to login with email and password.

sign_up_ui.dart — allows user to create a new account.

update_profile_ui.dart — allows user to change his email or name.

/ui/components/

avatar.dart — displays a user avatar on the home_ui.

dropdown_picker.dart — shows a dropdown list.

dropdown_picker_with_icon.dart — shows a dropdown list with icons.

form_input_field.dart — handles our form field elements.

form_input_field_with_icon.dart — handles our form field elements but has an icon too.

form_vertical_spacing.dart — just a space in the ui.

label_button.dart — one type of button in ui.

loading.dart — circular loading indicator overlay.

logo_graphic_header.dart — a graphic displayed in our ui.

primary_button.dart — another button in the ui.

segmented_selector.dart — a control used to select the theme.

Provider is also a great package and what I was using for Flutter development until I found GetX. Flutter is still new and evolving fast. It is fun to watch it progress so rapidly with the help of the Flutter community!

Anyway hopefully this project will help someone. Feel free to use any of it, I didn’t create all of this code as parts of it came from watching the tutorials and reviewing the projects mentioned above. Make sure you setup firebase with your project.

Comments
  • When signed in it shows the data of previous user which was signed in before

    When signed in it shows the data of previous user which was signed in before

    import 'package:flutter/services.dart';
    import 'dart:async';
    import 'package:firebase_auth/firebase_auth.dart';
    import 'package:get/get.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:simple_gravatar/simple_gravatar.dart';
    import 'package:flutter_starter/localizations.dart';
    import 'package:flutter_starter/models/models.dart';
    import 'package:flutter_starter/ui/auth/auth.dart';
    import 'package:flutter_starter/ui/ui.dart';
    import 'package:flutter_starter/ui/components/components.dart';
    
    class AuthController extends GetxController {
      static AuthController to = Get.find();
      AppLocalizations_Labels labels;
      TextEditingController nameController = TextEditingController();
      TextEditingController emailController = TextEditingController();
      TextEditingController passwordController = TextEditingController();
      final FirebaseAuth _auth = FirebaseAuth.instance;
      final FirebaseFirestore _db = FirebaseFirestore.instance;
      Rx<User> firebaseUser = Rx<User>();
      Rx<UserModel> firestoreUser = Rx<UserModel>();
      final RxBool admin = false.obs;
      final RxBool teacher =false.obs;
      @override
      void onReady() async {
        //run every time auth state changes
        ever(firebaseUser, handleAuthChanged);
        firebaseUser.value = await getUser;
        firebaseUser.bindStream(user);
        super.onInit();
      }
    
      @override
      void onClose() {
        nameController?.dispose();
        emailController?.dispose();
        passwordController?.dispose();
        super.onClose();
      }
    
      handleAuthChanged(_firebaseUser) async {
        //get user data from firestore
        if (_firebaseUser?.uid != null) {
          firestoreUser.bindStream(streamFirestoreUser());
          await isAdmin();
        }
    
        if (_firebaseUser == null) {
          Get.offAll(SignInUI());
        } else {
          Get.offAll(HomeUI());
        }
      }
    
      // Firebase user one-time fetch
      Future<User> get getUser async => _auth.currentUser;
    
      // Firebase user a realtime stream
      Stream<User> get user => _auth.authStateChanges();
    
      //Streams the firestore user from the firestore collection
      Stream<UserModel> streamFirestoreUser() {
        print('streamFirestoreUser()');
        if (firebaseUser?.value?.uid != null) {
          isAdmin();
          if(admin.value){
    
            return _db
                .doc('/admin/${firebaseUser.value.uid}')
                .snapshots()
                .map((snapshot) => UserModel.fromMap(snapshot.data()));
          }
          return _db
              .doc('/users/${firebaseUser.value.uid}')
              .snapshots()
              .map((snapshot) => UserModel.fromMap(snapshot.data()));
        }
    
        return null;
      }
    
      //get the firestore user from the firestore collection
      Future<UserModel> getFirestoreUser() {
    
        if (firebaseUser?.value?.uid != null) {
          isAdmin();
          if(admin.value){
    
            return _db.doc('admin/${firebaseUser.value.uid}').get().then(
                (documentSnapshot) =>UserModel.fromMap(documentSnapshot.data())
            );
          }
          else{
          return _db.doc('/users/${firebaseUser.value.uid}').get().then(
              (documentSnapshot) => UserModel.fromMap(documentSnapshot.data()));
          }
        }
        return null;
      }
    
      //Method to handle user sign in using email and password
      signInWithEmailAndPassword(BuildContext context) async {
        final labels = AppLocalizations.of(context);
        showLoadingIndicator();
        try {
          await _auth.signInWithEmailAndPassword(
              email: emailController.text.trim(),
              password: passwordController.text.trim());
          emailController.clear();
          passwordController.clear();
          hideLoadingIndicator();
        } catch (error) {
          hideLoadingIndicator();
          Get.snackbar(labels.auth.signInErrorTitle, labels.auth.signInError,
              snackPosition: SnackPosition.BOTTOM,
              duration: Duration(seconds: 7),
              backgroundColor: Get.theme.snackBarTheme.backgroundColor,
              colorText: Get.theme.snackBarTheme.actionTextColor);
        }
      }
    
      // User registration using email and password
      registerWithEmailAndPassword(BuildContext context) async {
        final labels = AppLocalizations.of(context);
        showLoadingIndicator();
        try {
          await _auth
              .createUserWithEmailAndPassword(
                  email: emailController.text, password: passwordController.text)
              .then((result) async {
            print('uID: ' + result.user.uid);
            print('email: ' + result.user.email);
            //get photo url from gravatar if user has one
            Gravatar gravatar = Gravatar(emailController.text);
            String gravatarUrl = gravatar.imageUrl(
              size: 200,
              defaultImage: GravatarImage.retro,
              rating: GravatarRating.pg,
              fileExtension: true,
            );
            //create the new user object
            UserModel _newUser = UserModel(
                uid: result.user.uid,
                email: result.user.email,
                name: nameController.text,
                photoUrl: gravatarUrl);
            //create the user in firestore
            _createUserFirestore(_newUser, result.user);
            emailController.clear();
            passwordController.clear();
            hideLoadingIndicator();
          });
        } catch (error) {
          hideLoadingIndicator();
          Get.snackbar(labels.auth.signUpErrorTitle, error.message,
              snackPosition: SnackPosition.BOTTOM,
              duration: Duration(seconds: 10),
              backgroundColor: Get.theme.snackBarTheme.backgroundColor,
              colorText: Get.theme.snackBarTheme.actionTextColor);
        }
      }
    
      //handles updating the user when updating profile
      Future<void> updateUser(BuildContext context, UserModel user, String oldEmail,
          String password) async {
        final labels = AppLocalizations.of(context);
        try {
          showLoadingIndicator();
          await _auth
              .signInWithEmailAndPassword(email: oldEmail, password: password)
              .then((_firebaseUser) {
            _firebaseUser.user
                .updateEmail(user.email)
                .then((value) => _updateUserFirestore(user, _firebaseUser.user));
          });
          hideLoadingIndicator();
          Get.snackbar(labels.auth.updateUserSuccessNoticeTitle,
              labels.auth.updateUserSuccessNotice,
              snackPosition: SnackPosition.BOTTOM,
              duration: Duration(seconds: 5),
              backgroundColor: Get.theme.snackBarTheme.backgroundColor,
              colorText: Get.theme.snackBarTheme.actionTextColor);
        } on PlatformException catch (error) {
          //List<String> errors = error.toString().split(',');
          // print("Error: " + errors[1]);
          hideLoadingIndicator();
          print(error.code);
          String authError;
          switch (error.code) {
            case 'ERROR_WRONG_PASSWORD':
              authError = labels.auth.wrongPasswordNotice;
              break;
            default:
              authError = labels.auth.unknownError;
              break;
          }
          Get.snackbar(labels.auth.wrongPasswordNoticeTitle, authError,
              snackPosition: SnackPosition.BOTTOM,
              duration: Duration(seconds: 10),
              backgroundColor: Get.theme.snackBarTheme.backgroundColor,
              colorText: Get.theme.snackBarTheme.actionTextColor);
        }
      }
    
      //updates the firestore user in users collection
      void _updateUserFirestore(UserModel user, User _firebaseUser) {
        _db.doc('/users/${_firebaseUser.uid}').update(user.toJson());
        update();
      }
    
      //create the firestore user in users collection
      void _createUserFirestore(UserModel user, User _firebaseUser) {
        _db.doc('/users/${_firebaseUser.uid}').set(user.toJson());
        update();
      }
    
      //password reset email
      Future<void> sendPasswordResetEmail(BuildContext context) async {
        final labels = AppLocalizations.of(context);
        showLoadingIndicator();
        try {
          await _auth.sendPasswordResetEmail(email: emailController.text);
          hideLoadingIndicator();
          Get.snackbar(
              labels.auth.resetPasswordNoticeTitle, labels.auth.resetPasswordNotice,
              snackPosition: SnackPosition.BOTTOM,
              duration: Duration(seconds: 5),
              backgroundColor: Get.theme.snackBarTheme.backgroundColor,
              colorText: Get.theme.snackBarTheme.actionTextColor);
        } catch (error) {
          hideLoadingIndicator();
          Get.snackbar(labels.auth.resetPasswordFailed, error.message,
              snackPosition: SnackPosition.BOTTOM,
              duration: Duration(seconds: 10),
              backgroundColor: Get.theme.snackBarTheme.backgroundColor,
              colorText: Get.theme.snackBarTheme.actionTextColor);
        }
      }
    
      //check if user is an admin user
      isAdmin() async {
        await getUser.then((user) async {
          DocumentSnapshot adminRef =
              await _db.collection('admin').doc(user?.uid).get();
          if (adminRef.exists) {
            admin.value = true;
          } else {
            admin.value = false;
          }
          update();
        });
      }
    
      isTeacher() async{
        await getUser.then((user) async{
          DocumentSnapshot teachRef =
              await _db.collection('teacher').doc(user?.uid).get();
          if(teachRef.exists){
            teacher.value=true;
          }
          else{
            teacher.value=false;
          }
          update();
        });
      }
    
      // Sign out
      Future<void> signOut() {
        nameController.clear();
        emailController.clear();
        passwordController.clear();
        _auth.signOut();
        update();
      }
    }
    

    This is the AuthController file

    import 'package:flutter/material.dart';
    import 'package:flutter_starter/localizations.dart';
    import 'package:flutter_starter/controllers/controllers.dart';
    import 'package:flutter_starter/ui/components/components.dart';
    import 'package:flutter_starter/ui/ui.dart';
    import 'package:get/get.dart';
    
    class HomeUI extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final labels = AppLocalizations.of(context);
    
        return GetBuilder<AuthController>(
          init: AuthController(),
          builder: (controller) => controller?.firestoreUser?.value?.uid == null
              ? Center(
                  child: CircularProgressIndicator(),
                )
              : Scaffold(
                  appBar: AppBar(
                    title: Text(labels?.home?.title),
                    actions: [
                      IconButton(
                          icon: Icon(Icons.settings),
                          onPressed: () {
                            Get.to(SettingsUI());
                          }),
                    ],
                  ),
                  body: Center(
                    child: Column(
                      children: <Widget>[
                        SizedBox(height: 120),
                        Avatar(controller.firestoreUser.value),
                        Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            FormVerticalSpace(),
                            Text(
                                labels.home.uidLabel +
                                    ': ' +
                                    controller.firestoreUser.value.uid,
                                style: TextStyle(fontSize: 16)),
                            FormVerticalSpace(),
                            Text(
                                labels.home.nameLabel +
                                    ': ' +
                                    controller.firestoreUser.value.name,
                                style: TextStyle(fontSize: 16)),
                            FormVerticalSpace(),
                            Text(
                                labels.home.emailLabel +
                                    ': ' +
                                    controller.firestoreUser.value.email,
                                style: TextStyle(fontSize: 16)),
                            FormVerticalSpace(),
                            Text(
                                labels.home.adminUserLabel +
                                    ': ' +
                                    controller.admin.value.toString(),
                                style: TextStyle(fontSize: 16)),
                          ],
                        ),
                      ],
                    ),
                  ),
                ),
        );
      }
    }
    

    This is the home ui file

    opened by KaivalyaNaik 15
  • Breaking changes with latest Firebase Auth update

    Breaking changes with latest Firebase Auth update

    Hey Jeff, Thanks for sharing your work and all was working well until Tuesday! There are breaking changes with the newest version of Firebase Auth released a few days ago. I've managed to solve the other problems and just this one remains.

    in the auth_controller.dart file you declare final FirebaseAuth _auth = FirebaseAuth.instance;
    and the getter Future<User> get getUser => _auth.currentUser(); <===== this changed from <FirebaseUser> to just <User> and Stream<User> get user => _auth.authStateChanges(); <===== this changed from _auth.onAuthStateChanged()

    the currentUser method has changed and this now fails due to 'the expression doesn't evaluate to a function, so it can't be invoked.'

    BREAKING: Accessing the current user via currentUser() is now synchronous via the currentUser getter is the problem

    I've updated the main.dart file to look like this: Future main() async { WidgetsFlutterBinding.ensureInitialized(); Get.put(AuthController()); Get.put(ThemeController()); Get.put(LanguageController()); await Firebase.initializeApp(); <===== added to ensure that Firebase is initialized prior to runApp await GetStorage.init();
    runApp(MyApp()); }

    Any thoughts on how to fix this synchronous issue ? Thanks C

    opened by CHR15TOV 12
  • Some deprecate warnings are produced during build

    Some deprecate warnings are produced during build

    While building following warnings are generated.

    Note: C:\git\flutter\.pub-cache\hosted\pub.dartlang.org\firebase_core-1.3.0\android\src\main\java\io\flutter\plugins\firebase\core\FlutterFirebaseCorePlugin.java uses or overrides a deprecated API.
    Note: Recompile with -Xlint:deprecation for details.
    Note: C:\git\flutter\.pub-cache\hosted\pub.dartlang.org\firebase_auth-1.4.1\android\src\main\java\io\flutter\plugins\firebase\auth\FlutterFirebaseAuthPlugin.java uses or overrides a deprecated API.
    Note: Recompile with -Xlint:deprecation for details.
    Note: C:\git\flutter\.pub-cache\hosted\pub.dartlang.org\cloud_firestore-2.2.2\android\src\main\java\io\flutter\plugins\firebase\firestore\FlutterFirebaseFirestorePlugin.java uses or overrides a deprecated API.
    Note: Recompile with -Xlint:deprecation for details.
    Note: C:\git\flutter\.pub-cache\hosted\pub.dartlang.org\cloud_firestore-2.2.2\android\src\main\java\io\flutter\plugins\firebase\firestore\streamhandler\TransactionStreamHandler.java uses unchecked or unsafe operations.
    Note: Recompile with -Xlint:unchecked for details.
    
    opened by rajeshtaneja 6
  • Issue with snackBarTheme

    Issue with snackBarTheme

    Hi, Changing the snackBarTheme in the themes as no effect... for example it is impossible for me to change color from text or background. Seems you got the same issue since you have hard coded SnackBar color in your controller code. Do you know why it doesn't work ? Thanks

    opened by sloosh 6
  • Sample List & Details Pages

    Sample List & Details Pages

    Hello, wondering if you can provide a sample that includes a real world scenario to see how you structure and list things.

    One example would be a list of restaurants. When you click on the name of the restaurant you get a details page with: Name, Address, Phone Number, Photos, Lat/Lon, Rating etc.

    Just curious how you would do things with your starter and feel it would help people learn by example.

    Thanks

    opened by jtkeyva 5
  • Update User Success Notice Bug

    Update User Success Notice Bug

    When you update your email with an email that already exists in the database, you get an update user success notice even though the update should fail and the snack bar notice should be "Email is already in use" or something like that.

    opened by HussainON 4
  • Possible to access translation labels without context?

    Possible to access translation labels without context?

    Great tutorial on Medium!! Thanks a lot!

    Is there a way to eliminate the necessity of passing BuildContext in

    final labels = AppLocalizations.of(context);

    using GetX? I sometimes have to reference the translation labels also in some of my controller/services classes where I usually try to avoid using BuildContext as much as possible (trying to separate UI and Business Logic).

    opened by JonathanRhein 4
  • Error with dependencies when running the project

    Error with dependencies when running the project

    When running your sample project i receive the following error.

    Because firebase_auth >=0.18.4 <=0.18.4 depends on firebase_auth_web ^0.3.2+2 and firebase_auth ^0.18.4+1 depends on firebase_auth_web ^0.3.2+3, firebase_auth ^0.18.4 requires firebase_auth_web ^0.3.2+2. (1) So, because firebase_auth >=0.18.3+1 <0.18.4 depends on firebase_auth_web ^0.3.2+1, firebase_auth ^0.18.3+1 requires firebase_auth_web ^0.3.2+1.

    Because firebase_auth >=0.18.3 <=0.18.3 depends on firebase_auth_web ^0.3.2 and firebase_auth >=0.18.2 <0.18.3 depends on firebase_auth_web ^0.3.1+2, firebase_auth >=0.18.2 <=0.18.3 requires firebase_auth_web ^0.3.1+2.        
    And because firebase_auth >=0.18.1+2 <0.18.2 depends on firebase_auth_web ^0.3.1+1, firebase_auth >=0.18.1+2 <=0.18.3 requires firebase_auth_web ^0.3.1+1.
    And because firebase_auth >=0.18.1 <=0.18.1+1 depends on firebase_auth_web ^0.3.1 and no versions of firebase_auth match >0.18.0+1 <0.18.1, firebase_auth >0.18.0+1 <=0.18.3 requires firebase_auth_web ^0.3.1.
    And because firebase_auth ^0.18.3+1 requires firebase_auth_web ^0.3.2+1 (1), firebase_auth >0.18.0+1 <0.19.0 requires firebase_auth_web ^0.3.1.
    And because firebase_auth 0.18.0+1 depends on firebase_auth_web ^0.3.0+1, firebase_auth ^0.18.0+1 requires firebase_auth_web ^0.3.0+1.
    And because firebase_auth_web >=0.3.0-dev.1 <0.4.0-1.0.nullsafety.0 depends on intl ^0.16.1 and every version of flutter_localizations from sdk depends on intl 0.17.0-nullsafety.2, firebase_auth ^0.18.0+1 is incompatible with 
    

    flutter_localizations from sdk. So, because flutter_starter depends on both flutter_localizations any from sdk and firebase_auth ^0.18.0+1, version solving failed. Running "flutter pub get" in flutter_starter-master...
    pub get failed (1; So, because flutter_starter depends on both flutter_localizations any from sdk and firebase_auth ^0.18.0+1, version solving failed.)

    opened by razfazz 3
  • Update Profile Password Dialog

    Update Profile Password Dialog

    Hi Jeff,

    When you enter a wrong or empty password when trying to update profile info, the progress indicator keeps showing up and you no longer can press anything. I have to kill and rerun the code to work again.

    opened by HussainON 2
  • Updating to Flutter 1.22.3 causes looping calls to handleAuthChanged

    Updating to Flutter 1.22.3 causes looping calls to handleAuthChanged

    Thanks for creating the starter project, it was working brilliantly for me and far more elegant than I could of hoped to build myself. I have found an issue however since upgrading to flutter version 1.22.3 where the ever() method in the onReady function is repeadly called on a loop, the behaviour causes the get.offAll(HomeUI()) to be constantly hit maxing out the CPU and the app becomes unresponsive. Pubspec.yaml: ` name: trofng_core description: Next Generation Project.

    publish_to: 'none' # Remove this line if you wish to publish to pub.dev

    version: 1.0.0+1

    environment: sdk: ">=2.7.0 <3.0.0"

    dependencies: get: ^3.17.1 flutter: sdk: flutter flutter_localizations: sdk: flutter cupertino_icons: ^1.0.0 json_annotation: ^3.1.0 firebase_core: '^0.5.0' firebase_analytics: '^6.0.0' firebase_auth: '^0.18.0+1' cloud_firestore: '^0.14.0+2' get_storage: ^1.3.2 uuid: ^2.2.2 simple_gravatar: ^1.0.5 flutter_sheet_localization: ^1.0.0

    dev_dependencies: flutter_test: sdk: flutter json_serializable: ^3.5.0 build_runner: ^1.0.0

    flutter_sheet_localization_generator: ^1.0.0

    flutter: uses-material-design: true

    assets: - assets/images/default.png - assets/images/defaultDark.png Flutter Doctor: Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 1.22.3, on Mac OS X 10.15.7 19H2, locale en-GB)

    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2) [✓] Xcode - develop for iOS and macOS (Xcode 12.2) [!] Android Studio (version 4.1) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [✓] VS Code (version 1.51.1) [✓] Connected device (2 available)`

    The code in my auth_controller: `

    class AuthController extends GetxController { static AuthController to = Get.find(); TextEditingController nameController = TextEditingController(); TextEditingController emailController = TextEditingController(); TextEditingController passwordController = TextEditingController(); final FirebaseAuth _auth = FirebaseAuth.instance; final FirebaseFirestore _db = FirebaseFirestore.instance; Rx firebaseUser = Rx(); Rx firestoreUser = Rx(); final RxBool admin = false.obs;

    @override void onReady() async { //run every time auth state changes ever(firebaseUser, handleAuthChanged); firebaseUser.value = await getUser; firebaseUser.bindStream(_auth.authStateChanges()); super.onReady(); }

    @override void onClose() { nameController?.dispose(); emailController?.dispose(); passwordController?.dispose(); super.onClose(); }

    handleAuthChanged(_firebaseUser) async { //get user data from firestore if (_firebaseUser?.uid != null) { firestoreUser.bindStream(streamFirestoreUser()); //await isAdmin(); }

    if (_firebaseUser == null) {
      Get.offAll(SignInUI());
    } else {
      Get.offAll(HomeUI());
    }
    

    }

    // Firebase user one-time fetch Future get getUser async => _auth.currentUser;

    // Firebase user a realtime stream Stream get user => _auth.authStateChanges();

    //Streams the firestore user from the firestore collection Stream streamFirestoreUser() { if (firebaseUser?.value?.uid != null) { return _db .doc('/users/${firebaseUser.value.uid}') .snapshots() .map((snapshot) => TrofUser.fromJson(snapshot.data())); } return null; }

    //get the firestore user from the firestore collection Future getFirestoreUser() { if (firebaseUser?.value?.uid != null) { return _db.doc('/users/${firebaseUser.value.uid}').get().then( (documentSnapshot) => TrofUser.fromJson(documentSnapshot.data())); } return null; }

    //Method to handle user sign in using email and password signInWithEmailAndPassword(BuildContext context) async { showLoadingIndicator(); try { await _auth.signInWithEmailAndPassword( email: emailController.text.trim(), password: passwordController.text.trim()); emailController.clear(); passwordController.clear(); hideLoadingIndicator(); } catch (error) { hideLoadingIndicator(); Get.snackbar('Sign in Error', 'Error in Sign on', snackPosition: SnackPosition.BOTTOM, duration: Duration(seconds: 7), backgroundColor: Get.theme.snackBarTheme.backgroundColor, colorText: Get.theme.snackBarTheme.actionTextColor); } }

    // User registration using email and password registerWithEmailAndPassword(BuildContext context) async { showLoadingIndicator(); try { await _auth .createUserWithEmailAndPassword( email: emailController.text, password: passwordController.text) .then((result) async { print('uID: ' + result.user.uid); print('email: ' + result.user.email); //get photo url from gravatar if user has one Gravatar gravatar = Gravatar(emailController.text); String gravatarUrl = gravatar.imageUrl( size: 200, defaultImage: GravatarImage.retro, rating: GravatarRating.pg, fileExtension: true, ); //create the new user object TrofUser _newUser = TrofUser( uid: result.user.uid, userEmail: result.user.email, firstName: nameController.text, photoUrl: gravatarUrl); //create the user in firestore _createUserFirestore(_newUser, result.user); emailController.clear(); passwordController.clear(); hideLoadingIndicator(); }); } catch (error) { hideLoadingIndicator(); Get.snackbar('Sign Up Error', error.message, snackPosition: SnackPosition.BOTTOM, duration: Duration(seconds: 10), backgroundColor: Get.theme.snackBarTheme.backgroundColor, colorText: Get.theme.snackBarTheme.actionTextColor); } }

    //handles updating the user when updating profile Future updateUser(BuildContext context, TrofUser user, String oldEmail, String password) async { try { showLoadingIndicator(); await _auth .signInWithEmailAndPassword(email: oldEmail, password: password) .then((_firebaseUser) { _firebaseUser.user .updateEmail(user.userEmail) .then((value) => _updateUserFirestore(user, _firebaseUser.user)); }); hideLoadingIndicator(); Get.snackbar( 'Update Profile Success', 'Profile update has been successful', snackPosition: SnackPosition.BOTTOM, duration: Duration(seconds: 5), backgroundColor: Get.theme.snackBarTheme.backgroundColor, colorText: Get.theme.snackBarTheme.actionTextColor); } on PlatformException catch (error) { //List errors = error.toString().split(','); // print("Error: " + errors[1]); hideLoadingIndicator(); print(error.code); String authError; switch (error.code) { case 'ERROR_WRONG_PASSWORD': authError = 'Wrong Password'; break; default: authError = 'Auth Error'; break; } Get.snackbar('Wrong Password', authError, snackPosition: SnackPosition.BOTTOM, duration: Duration(seconds: 10), backgroundColor: Get.theme.snackBarTheme.backgroundColor, colorText: Get.theme.snackBarTheme.actionTextColor); } }

    //updates the firestore user in users collection void _updateUserFirestore(TrofUser user, User _firebaseUser) { _db.doc('/users/${_firebaseUser.uid}').update(user.toJson()); update(); }

    //create the firestore user in users collection void _createUserFirestore(TrofUser user, User _firebaseUser) { _db.doc('/users/${_firebaseUser.uid}').set(user.toJson()); update(); }

    //password reset email Future sendPasswordResetEmail(BuildContext context) async { showLoadingIndicator(); try { await _auth.sendPasswordResetEmail(email: emailController.text); hideLoadingIndicator(); Get.snackbar('Password Reset Sent', 'Check your email for the reset link', snackPosition: SnackPosition.BOTTOM, duration: Duration(seconds: 5), backgroundColor: Get.theme.snackBarTheme.backgroundColor, colorText: Get.theme.snackBarTheme.actionTextColor); } catch (error) { hideLoadingIndicator(); Get.snackbar('Reset Password Error', error.message, snackPosition: SnackPosition.BOTTOM, duration: Duration(seconds: 10), backgroundColor: Get.theme.snackBarTheme.backgroundColor, colorText: Get.theme.snackBarTheme.actionTextColor); } }

    //check if user is an admin user isAdmin() async { await getUser.then((user) async { DocumentSnapshot adminRef = await _db.collection('admin').doc(user?.uid).get(); if (adminRef.exists) { admin.value = true; } else { admin.value = false; } update(); }); }

    // Sign out Future signOut() { nameController.clear(); emailController.clear(); passwordController.clear(); return _auth.signOut(); } } `

    opened by trof-app 2
  • ever(firebaseUser, handleAuthChanged) fires non-stop

    ever(firebaseUser, handleAuthChanged) fires non-stop

    Authentication was working perfectly fine until I decided to update Android Studio, Flutter, and dependencies.

    All of a sudden, the ever(firebaseUser, handleAuthChanged) in auth_controller now fires non-stop when a user logs in. Eventually Firebase will not allow any additional queries due to hitting the quota limit and the app crashes. I tried rolling back the dependencies to when this was working, but it didn't help, which leads me to believe it's something that has changed in Flutter or Dart.

    [✓] Flutter (Channel master, 1.24.0-8.0.pre.236, on Mac OS X 10.15.7 19H2 darwin-x64, locale en-US) [✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2) [✓] Xcode - develop for iOS and macOS (Xcode 12.2) [✓] Android Studio (version 4.1) [✓] VS Code (version 1.50.1) [✓] Connected device (1 available)

    firebase_auth: 0.18.3 firebase_core: 0.5.2

    Would you by chance have any idea why this is happening? I can't seem to figure it out. Thanks!

    opened by psenechal 2
  • Home page not showing latest name

    Home page not showing latest name

    Steps to reproduce:

    1. Create a new account
    2. (or login to an existing account)
    3. Go to setting
    4. Go to update your profile
    5. Change name
    6. UPDATE PROFILE + input password
    7. Go to homepage
    8. Updated name is showing correctly
    9. Go to setting (without signing out)
    10. Go to update your profile
    11. Change name
    12. UPDATE PROFILE + input password
    13. Go to homepage
    14. Name is not updated <- bug
    15. Go to setting (without signing out)
    16. Go to update your profile
    17. Change name
    18. UPDATE PROFILE + input password
    19. Go to homepage
    20. Previous name change is showing <- bug
    opened by countryst 1
Owner
Jeff McMorris
Jeff McMorris
A starter kit for beginner learns with Bloc pattern, RxDart, sqflite, Fluro and Dio to architect a flutter project. This starter kit build an App Store app as a example

Flutter Starter Kit - App Store Example A starter kit for beginner learns with Bloc pattern, RxDart, sqflite, Fluro and Dio to architect a flutter pro

kw101 678 Jan 8, 2023
Flutter plugin for Firebase Auth UI. Supports popular auth providers by using native SDK for Android and iOS.

firebase_auth_ui Flutter plugin of Firebase UI which allows to add login/sign-up quickly. NOTE: This plugin is under development. Please provide Feedb

Sandip Fichadiya 50 Mar 23, 2022
Starter-Flutter - Starter flutter project for best architecture and seperation of code

Modular-Architecture Codebase CodeBase , Infrastructure and the common Layers (c

Ahmed Tawfiq 13 Feb 16, 2022
A simple flutter starter with firebase & getX

Flutter starter GetX simplify & optimise a lot how to use Flutter! You should read a bit about GetX and Firebase. Package used Firebase (firebase_core

Guillaume Huard Hughes 4 Jun 9, 2022
FlutterfirebaseAuth - Flutter firebase auth with GetX

loginsignup A new Flutter project for login and sign up Using firebase/firestore

null 35 Oct 25, 2022
User auth form - Signup and signin user auth form with ability to stay signed in and have an option to signout.

user_auth_form SIgnup and signin user authentification form Getting Started This project is a starting point for a Flutter application. A few resource

null 0 Jan 6, 2022
This repo provides a starter kit thats include Getx package.

Getx_Starter This repo provides a starter kit thats include Getx package. It includes key-value databases, sample pages, and components which they are

Okan 2 Apr 27, 2022
Flutter firebase auth - Simple implementation of Firebase Authentication using Flutter

FlutterFire Authentication Sample A simple implementation of Firebase Authentica

Souvik Biswas 4 Apr 2, 2022
A starter example of a Flutter + Mobx + Notifications

flutter-example A starter example of a Flutter + Mobx + Firebase Nofitications Before Debug $ flutter packages pub run build_runner watch --delete-con

Jonatas Walker 10 Feb 3, 2021
Flutter-GetX-Toturials - Getx full tutorials for flutter

getx_full_tutorials A new Flutter getx tutorial. This Project Contains: Snackbar

Inzimam Bhatti 2 Dec 1, 2022
Flutter getx template - A Flutter Template using GetX package for State management, routing and Dependency Injection

Flutter GetX Template (GetX, Dio, MVVM) This Flutter Template using GetX package

Tareq Islam 6 Aug 27, 2022
constructing... Flutter, Ganache, Truffle, Remix, Getx Pattern, Infura, GetX, Blockchain

constructing... Flutter, Ganache, Truffle, Remix, Getx Pattern, Infura, GetX, Blockchain

Kauê Murakami 20 Dec 20, 2022
A basic boilerplate template for starting a Flutter GetX project. GetX, Dio, MVVM, get CLI, Localization, Pagination etc are implemented.

Flutter GetX Template (GetX, Dio, MVVM) This Flutter Template using GetX package for State management, routing and Dependency Injection (bindings). We

Hasan Abdullah 214 Jan 9, 2023
Flutter GetX Template (GetX, Dio, MVVM)

Flutter GetX Template (GetX, Dio, MVVM) This Flutter Template using GetX package for State management, routing and Dependency Injection (bindings). We

null 7 Dec 18, 2022
Flutter firebase starter project

Flutter Firebase Starter project Made with ?? from Nepal A project you can clone to build your next project with Flutter with Firebase services. What

Damodar Lohani 262 Dec 29, 2022
Flutter Login Screen with Firebase Auth and Facebook Login

Flutter Login Screen with Firebase Auth and Facebook Login Jumpstart your Flutter app development with this pre-built Flutter starter kit. Don't reinv

null 296 Dec 29, 2022
Ifoodcare - Food Donation App in Flutter using Firebase Auth, Firestore

Food Donation App in Flutter using Firebase Auth, Firestore

Raunak Chatterjee 3 Nov 17, 2022
A working Twitter clone written in Flutter using Firebase auth,realtime,firestore database and storage

A working Twitter clone written in Flutter using Firebase auth,realtime,firestore database and storage

The Github Mafia 17 Dec 24, 2022
Cross Platform app in Flutter with Firebase Auth and Firestore. Available for Mobile,Web,Desktop

NavokiNotes Navoki Notes, a note app app, will sync data to cloud and on all devices. We have application for Android, iOS, Web App, PWA, Windows, mac

shivam srivastava 93 Dec 27, 2022