show progress indicator only if there are no errors

177 views Asked by At

I have a login screen with firebase authentication and error validation. When a user inserts their credentials, firebase does validation and returns error code. I am translating the error then displaying it on a snack bar. My issue is on clicking of the login button, I want the progress indicator to come up and if there are any errors caught, it must stop and only the snack bar must show. My code is as follows

myButtonOnPressed: () async {
    try {
        final newUser = await _auth.signInWithEmailAndPassword(
            email: email,
            password: password,
        );

        if (newUser != null) {
            Navigator.pushNamed(context, HomeScreen.id);
        }
    } on FirebaseAuthException catch (e) {
        ///look for error conde in switch statement and return
        ///english error code

        String fireBaseAuthErrorCode = funcFireBaseAuthErrors(e.code);
        ScaffoldMessenger.of(context).showSnackBar(
            ///add SnackBar function
            funcSnackBar(
                errorMessage: fireBaseAuthErrorCode,
                snackBarColor: Color(snackBarColor),
                snackBarTextColor: Color(snackBarTextColor),
                snackBarTextFont: snackBarTextFont,
                snackBarTextSize: snackBarTextSize,
                showErrorDuration: kLoginScreenSnackBarDisplayDuration,
            ),
        );
    }
},

How on earth do I do this?

1

There are 1 answers

1
dkpk On

I am assuming that you are using a StatefulWidget - using which this can be achieved with a boolean variable and conditional rendering in the button.

class YourWidget extends StatefulWidget {
  const YourWidget({Key? key}) : super(key: key);

  @override
  State<YourWidget> createState() => _YourWidgetState();
}

class _YourWidgetState extends State<YourWidget> {
  bool authInProgress = false;

  Future<void> login() async {
    try {
      // Initiate login by setting authInProgress to true.
      setState(() {
        authInProgress = true;
      });

      final newUser = await _auth.signInWithEmailAndPassword(
        email: email,
        password: password,
      );

      if (newUser != null) {
        Navigator.pushNamed(context, HomeScreen.id);
      }
    } on FirebaseAuthException catch (e) {
      ///look for error conde in switch statement and return
      ///english error code

      String fireBaseAuthErrorCode = funcFireBaseAuthErrors(e.code);
      ScaffoldMessenger.of(context).showSnackBar(
        ///add SnackBar function
        funcSnackBar(
          errorMessage: fireBaseAuthErrorCode,
          snackBarColor: Color(snackBarColor),
          snackBarTextColor: Color(snackBarTextColor),
          snackBarTextFont: snackBarTextFont,
          snackBarTextSize: snackBarTextSize,
          showErrorDuration: kLoginScreenSnackBarDisplayDuration,
        ),
      );
    } finally {
      // Regardless of the outcome, after the process is done,
      // set authInProgress to false.
      setState(() {
        authInProgress = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: login,
      child: authInProgress
          ? const CircularProgressIndicator()
          : const Text("Login"),
    );
  }
}

Explanation

  1. Create a variable authInProgress with initial value of false, indicating that process has not yet begun.
  2. In the login function, using the setState method set the authInProgress to true in the try block, and add a finally block, set it back to false. The finally block will execute regardless of the outcome in the try block. So, in this case - whether login fails or succeeds, finally block is always executed.
  3. I have used the ElevatedButton for this case, in which, if authInProgress is true, we will render CircularProgressIndicator(), else the Text(), that you want to display.

P.S.

  • I have written the login() outside of build() for the sake of brevity.