Home > Software design >  Show loading indicator only if there's no exceptions in Flutter
Show loading indicator only if there's no exceptions in Flutter

Time:02-24

I've created a login screen and once the email and password got verified user will be pushed to the dashboard. So what I need to do is, show a loading indicator only if there are no exceptions that get thrown otherwise it should show the alert which I've implemented with in a try-catch.

log-in button -

SizedBox(
                    width: MediaQuery.of(context).size.width,
                    child: TextButton(
                      onPressed: signIn,
                      style: ButtonStyle(
                        padding: MaterialStateProperty.all<EdgeInsets>(
                          const EdgeInsets.fromLTRB(0, 20, 0, 20),
                        ),
                        shape:
                            MaterialStateProperty.all<RoundedRectangleBorder>(
                                RoundedRectangleBorder(
                                    borderRadius: BorderRadius.circular(30.0))),
                        backgroundColor:
                            MaterialStateProperty.all(primaryColor),
                      ),
                      child: const Text(
                        'Login',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 15,
                          fontFamily: 'InterBold',
                        ),
                      ),
                    ),
                  ),

Validation class -

Future signIn() async {
    if (_key.currentState!.validate()) {
      try {
        await FirebaseAuth.instance.signInWithEmailAndPassword(
            email: emailController.text.trim(),
            password: passwordCrontroller.text.trim());

        errorMessage = '';
      } on FirebaseAuthException catch (e) {
        showDialog(
            context: context,
            builder: (context) => AlertDialog(
                  title: const Text(
                    'Error',
                    style: TextStyle(color: mainText),
                  ),
                  content: Text(
                    e.message!,
                    style: const TextStyle(color: secondaryText),
                  ),
                  contentPadding:
                      const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0.0),
                  backgroundColor: Colors.white,
                  actions: [
                    TextButton(
                        onPressed: () {
                          navigatorKey.currentState!.pop();
                        },
                        child: const Text(
                          'Close',
                          style: TextStyle(color: primaryColor),
                        ))
                  ],
                ));
      }
    }
  }

  String? validateEmail(String? formEmail) {
    String pattern = r'\w @\w \.\w ';
    RegExp regex = RegExp(pattern);

    if (formEmail == null || formEmail.isEmpty || !regex.hasMatch(formEmail)) {
      return '';
    }

    return null;
  }

  String? validatePassword(String? formPassword) {
    String pattern =
        r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{6,}$';
    RegExp regex = RegExp(pattern);
    if (formPassword == null ||
        formPassword.isEmpty ||
        !regex.hasMatch(formPassword)) {
      return '';
    }
    return null;
  }
}

Loading indicator -

showLoadingIndicatorDialog(BuildContext context) {
  return showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => const Center(
            child: CircularProgressIndicator(
              color: primaryColor,
            ),
          ));
}

CodePudding user response:

So what you can do is the following :

declare the bool value _isLoading =false;

you can use the setstate to change the state.

So what does the below code do:

  1. Initially _isLoading will be false so it will show you the text widget.
  2. when you hit the signin button it will make it true so the circular progress indicator will be appearing.
  3. then when the api call is complete then resetting it back to false and that we can see the text widget.
  4. And if there comes any error en the exception making the _isLoading to false so that it will be the text widget and there will be dialog shown with error message.

I have taken your code and just made the changes check the use of bool value and use it as per you state management needs, I have elaborated with a simple setState.

class App extends StatelessWidget {

  bool _isLoading =false;

 @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      child: TextButton(
        onPressed: signIn,
        style: ButtonStyle(
          padding: MaterialStateProperty.all<EdgeInsets>(
            const EdgeInsets.fromLTRB(0, 20, 0, 20),
          ),
          shape:
          MaterialStateProperty.all<RoundedRectangleBorder>(
              RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(30.0))),
          // backgroundColor:
          // MaterialStateProperty.all(primaryColor),
        ),
        child:

        _isLoading ?
        const CircularProgressIndicator():
        const Text(
          'Login',
          style: TextStyle(
            color: Colors.white,
            fontSize: 15,
            fontFamily: 'InterBold',
          ),
        ),
      ),
    );
  }
  Future signIn() async {

    if (_key.currentState!.validate()) {
      try {

        setState({
          _isLoading =true;
        });
        await FirebaseAuth.instance.signInWithEmailAndPassword(
            email: emailController.text.trim(),
            password: passwordCrontroller.text.trim());

        errorMessage = '';
        setState({
        _isLoading =false;
        });

      } on FirebaseAuthException catch (e) {
        setState({
        _isLoading =false;
        });
        showDialog(
            context: context,
            builder: (context) => AlertDialog(
              title: const Text(
                'Error',
                style: TextStyle(color: mainText),
              ),
              content: Text(
                e.message!,
                style: const TextStyle(color: secondaryText),
              ),
              contentPadding:
              const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0.0),
              backgroundColor: Colors.white,
              actions: [
                TextButton(
                    onPressed: () {
                      navigatorKey.currentState!.pop();
                    },
                    child: const Text(
                      'Close',
                      style: TextStyle(color: primaryColor),
                    ))
              ],
            ));
      }
    }
  }

}

Let me know if it works

  • Related