Paula Ysabelle Medina
Paula Ysabelle Medina

Reputation: 562

Dart: How to properly dispatch bloc event in another bloc

I need to access AuthenticationBloc in my LoginBloc so I can fire the AuthenticationLogin() event if the login is successful. What I did so far is not working.

What I've done:

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final AuthenticationBloc authenticationBloc;
  final AuthenticateCredentialsUsecase authenticateCredentialsUsecase;

//code

  Stream<LoginState> mapEventToState(
    LoginEvent event,
  ) async* {
        //code
        authenticationBloc.add(AuthenticationLogin());
        yield LoginLoadSuccess();
        //code
  }
}

What I'm trying to accomplish:

class _AppViewState extends State<AppView> {

  final _navigatorKey = GlobalKey<NavigatorState>();
  NavigatorState get _navigator => _navigatorKey.currentState;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: _navigatorKey,
      builder: (context, child) {
        return BlocListener<AuthenticationBloc, AuthenticationState>(
          listener: (context, state) {
             if (state is AuthenticationAuthenticated) {
                _navigator.pushAndRemoveUntil<void>(
                  HomePage.route(),
                  (route) => false,
                );
             }
             else if (state is AuthenticationUnauthenticated){
                _navigator.pushAndRemoveUntil<void>(
                  LoginScreen.route(),
                  (route) => false,
                );
             }
          },
          child: child,
        );
      },
      onGenerateRoute: (_) => SplashPage.route(),
    );
  }
}

As you can see, the user is currently in the LoginScreen, once the login is successful, I need to yield the AuthenticationAuthenticated() state in my AuthenticationBloc() so my users will be directed to the HomePage()

How can I yield the AuthenticationAuthenticated() state of the AuthenticationBloc() inside my LoginBloc() - since my login logic happens inside the LoginBloc.

Upvotes: 1

Views: 4762

Answers (2)

Paula Ysabelle Medina
Paula Ysabelle Medina

Reputation: 562

  1. I subscribed the AuthenticationBloc to the status stream of my AuthenticateCredentialsUsecase class.
  2. When the AuthenticateCredentialsUsecase is called in my LoginBloc and the credentials are authenticated...
  3. I then update the status stream - _controller.add(AuthenticationStatus.authenticated);
  4. Which inturn will trigger the AuthenticationLogin event inside the AuthenticationBloc

AuthenticationBloc

 AuthenticationBloc({
    @required CheckAuthenticationStatusUsecase checkAuthenticationStatus,
    @required LogoutAuthenticatedUserUsecase logoutAuthenticatedUser,
    @required AuthenticateCredentialsUsecase authenticateCredentials,
  })  : assert(checkAuthenticationStatus != null),
        assert(logoutAuthenticatedUser != null),
        assert(authenticateCredentials != null),
        checkAuthenticationStatusUsecase = checkAuthenticationStatus,
        logoutAuthenticatedUserUsecase = logoutAuthenticatedUser,
        authenticateCredentialsUsecase = authenticateCredentials,
        super(AuthenticationInitial()) {
    add(AuthenticationStatusRequested());
    _loginStatusSubscription =
        authenticateCredentialsUsecase.status.listen((event) {
      if (event == AuthenticationStatus.authenticated) {
        add(AuthenticationLogin());
      }
    });
  }

AuthenticateCredentialsUsecase

  final _controller = StreamController<AuthenticationStatus>();

  Stream<AuthenticationStatus> get status async* {
    yield AuthenticationStatus.unknown;
    yield* _controller.stream;
  }

  void dispose() => _controller.close();

  @override
  Future<Either<Failure, AuthenticatedUser>> call(AuthenticationParams params) async {

    final result = await repository.authenticateCredentials(params.userName, params.password);

    if(result is Right){
      _controller.add(AuthenticationStatus.authenticated);
    }

    return result;
  }

Upvotes: 2

Lapa Ny Aina Tanjona
Lapa Ny Aina Tanjona

Reputation: 1268

Here is one way to do it. You must call BlocBuilder to handles building the widget in response to new states.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      debugShowCheckedModeBanner: false,
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (context, state) {
          //If the login is successful, show homepage
          if (state is AuthenticationAuthenticated) {
            return HomePage();
          }
          //If the login failed, show login screen
          if (state is AuthenticationUnauthenticated) {
            return LoginScreen();
          }
          //If the login is in process, show loading indicator
          if (state is AuthenticationInProgress) {
            return LoadingIndicator();
          }
          return SplashScreen();
        },
      ),
    );
  }
}

At first, the state is AuthenticationUnauthenticated and displays the login screen. If the login is successful then we display homepage, otherwise if it failed we will display LoginScreen.

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final AuthenticationBloc authenticationBloc;
  final AuthenticateCredentialsUsecase authenticateCredentialsUsecase;

//code

  Stream<LoginState> mapEventToState(
    LoginEvent event,
  ) async* {

    if(event is LoginButtonPressed) {
        // some logic code
        // eg. : final response = UserRepository.login(username: event.username, password: event.password);
            authenticationBloc.add(AuthenticationLogin());
            //code

    }
        
  }
}

And here is the AuthenticationBloc () code which will handle the authentication.

 class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState>{
    
    //code
    
      Stream<AuthenticationState> mapEventToState(
        AuthenticationEvent event,
      ) async* {
          if(event is AuthenticationLogin) {
             yield AuthenticationInProgress();
             //code
             yield AuthenticationAuthenticated();
          }
    }
}
    

Upvotes: 0

Related Questions