skip to Main Content

I am trying to integrate flutter_login widget with bloc. Here is the sample code I am using

BlocProvider(
      create: (ctx) => UserAuthenticationPageBloc(ctx),
      child: BlocListener<UserAuthenticationPageBloc, UserAuthenticationPageState>(
        listener: (context, state) {
          // not used at the moment
        },
        child: BlocBuilder<UserAuthenticationPageBloc, UserAuthenticationPageState>(
          builder: (context, state) {
            final bloc = context.read<UserAuthenticationPageBloc>();

            return FlutterLogin(onLogin: (loginData) async {
              bloc.add(SignIn(loginData: loginData));
              return state.loginMessage;
            }, onRecoverPassword: (email) async {
              bloc.add(RecoverPassword(email: email));
              return state.recoverPasswordMessage;
            });
          },
        ),
      ),
    )

Here is the bloc file

class UserAuthenticationPageBloc extends Bloc<UserAuthenticationPageEvent, UserAuthenticationPageState> {
  UserAuthenticationPageBloc(BuildContext context) : super(const UserAuthenticationPageState()) {
    on<SignIn>((event, emit) {
      try {
        emit(state.copyWith(signInStatus: SignInStatus.loading));

        User user = User(); // need to be replaced by async http call

        final GlobalBloc globalBloc = BlocProvider.of<GlobalBloc>(context);

        globalBloc.add(GlobalSignIn(user: user));
        emit(state.copyWith(loginMessage: 'some error', signInStatus: SignInStatus.failure));
      } catch (_) {
        //emit(CovidError("Failed to fetch data. is your device online?"));
      }
    });
    on<RecoverPassword>((event, emit) {
    });
  }
}

What I would like to do is to add an event to bloc and then return a message. The flutter_login widget will show snack bar based on the message returned.

How can I wait for bloc event to finish before retrieving the loginMessage from the state? Or maybe I should not put the loginMessage in state?

Thank you

2

Answers


  1. You could try to pass onLogin function and onRecoverPassword function and state in separate parameters, and inside FlutterLogin check onloginMessage and recoverPasswordMessage not being null.

    I also think you should you make yourself familiar with bloc by looking at different examples, I suggest the examples folder in the package itself https://github.com/felangel/bloc/tree/master/examples

    Login or Signup to reply.
  2. In most scenarios, these types of things can all be handled pretty easily with the BlocListener widget. Usually, in the UI you don’t have to manually await anything coming from a bloc stream. This is one exception, where you’re trying to utilize the built in UI elements of flutter_widget.

    Since the onLogin callback requires a return of null on success or error message string on failure, you want to await the stream directly.

    The syntax for that looks like this

     final authBloc = context.read<GlobalBloc>();
    // fire the sign in event
    
    // You know the first emitted state will be loading, so the next state is either success or failure
    
     await authBloc.stream.firstWhere(
                  (state) => state.status != AuthStatus.loading,
                );
    
    

    The whole widget would look something like this.

    FlutterLogin(
              onLogin: (loginData) async {
                final authBloc = context.read<GlobalBloc>()
                  ..add(
                    SignIn(
                      email: loginData.name,
                      password: loginData.password,
                    ),
                  );
    
                await authBloc.stream.firstWhere(
                  (state) => state.status != AuthStatus.loading,
                );
    
                return authBloc.state.status == AuthStatus.authenticated
                    ? null
                    : 'Login failed';
              },
              onRecoverPassword: (_) async {
                return null;
              },
            );
    

    A couple things with what you shared.

    1. BlocBuilder widgets should not be placed directly below the BlocProvider. So in this case, to avoid that you could just create a new widget with the BlocBuilder wrapping a FlutterLogin. Although as you can see, in this case to use the built in snackbar, you don’t need the BlocBuilder here.
    2. You’re calling an event from the build method that makes network requests. This is pretty much always a bad idea, because we don’t always have full control over how many times the build method is called and you run the risk of making way to many unintended network calls.
    3. Your UserAuthenticationPageBloc depends directly on GlobalBloc, which according to the docs should be avoided at all times. This is easily avoided with the BlocListener widget. I’m also not seeing why there are 2 separate blocs here at all just for login. So my example was simplified to just one Bloc class that handles login.

    The gif below shows a 2 second wait and the bloc emitting an error state.

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search