How to handle errors with ValueNotifier

Viewed 243

I have a ValueNotifier class that performs some logic, then alerts all listeners when done. The problem I have is how to alert the listeners when there is an error in the processing so that an appropriate message can be displayed in the UI.

Here is the ValueNotifier class:

class LoginStateNotifier extends ValueNotifier<LoggedInStates> {
  LoginStateNotifier(LoggedInStates value) : super(value);

  Future<void> login({required String email, required String password}) async {
    try {
      final userCredential = await FirebaseAuth.instance
          .signInWithEmailAndPassword(email: email, password: password);

      print(userCredential);
    } on FirebaseAuthException catch (e) {
      switch (e.code) {
        case "invalid-email":
          throw (Constants.invalidEmail);
        case "user-disabled":
          throw (Constants.userDisabled);
        case "user-not-found":
          throw (Constants.userNotFound);
        case "wrong-password":
          throw (Constants.wrongPassword);
        default:
          throw ("${e.code} is an invalid FirebaseAuth exception");
      }
    } catch (e) {
      throw ("DEBUG: ${e.toString()} - occurred in login()");
    }
  }

  Future<void> logOut() async {
    await FirebaseAuth.instance.signOut();
  }
} 

Here is the widget in the UI that is listening for changes:

        ValueListenableBuilder<LoggedInStates>(
          valueListenable: _loginScreenController.loginStateNotifier,
          builder: (context, loggedInStates, child) {
            return loggedInStates == LoggedInStates.loggedIn
                ? Text(
                    'Logged In',
                    style: Theme.of(context).textTheme.headline2,
                  )
                : Text(
                    'Logged Out',
                    style: Theme.of(context).textTheme.headline2,
                  );
          },
        ),

I just need a way for the listener to know when errors occur as well, not just when the value changes.

1 Answers

Well, probably not the most optimal, but the solution I gave to this problem was to create a second valueNotifier to propagate custom exceptions as:

abstract class CustomException implements Exception {
  final String message; // Note that this message is for logging not displaying to the user

  CustomException(this.message);
}

class ExampleAuthException extends CustomException {
  final int remainingAttempts;

  ExampleAuthException({required this.remainingAttempts, required String message}) : super(message);
}
class ErrorNotifier extends ValueNotifier<CustomException?> {
  ErrorNotifier(CustomException? value) : super(value);
}
class ViewState{
final ErrorNotifier errorNotifier;
final LoginStateNotifier loginState;
...
}

I make it nullable as to now when there are no errors, and I use this as a second communication channel.

Related