Dart: как правильно отправить событие блока в другой блок

Мне нужно получить доступ к AuthenticationBloc в моем LoginBloc, чтобы я мог запустить событие AuthenticationLogin () в случае успешного входа в систему. То, что я сделал до сих пор, не работает.

Что я сделал:

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
  }
}

Чего я пытаюсь достичь:

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(),
    );
  }
}

Как вы можете видеть, пользователь в настоящее время находится на экране входа в систему, после успешного входа в систему мне нужно передать состояние AuthenticationAuthenticated () в моем AuthenticationBloc (), чтобы мои пользователи были направлены на HomePage ()

Как я могу получить состояние AuthenticationAuthenticated () для AuthenticationBloc () внутри моего LoginBloc () - поскольку моя логика входа происходит внутри LoginBloc.


person Paula Ysabelle Medina    schedule 17.08.2020    source источник
comment
Привет! Это не совсем понятно. Что вы хотите сделать в событии Authenticationlogin (), если вход в систему прошел успешно. Перейти на другую страницу?   -  person Lapa Ny Aina Tanjona    schedule 18.08.2020
comment
Мне нужно вызвать событие AuthenticationLogin (), чтобы оно могло дать новое состояние - AuthenticationAuthenticated () и перейти к HomePage (). Я отредактирую свой вопрос, чтобы было понятнее, спасибо, что указали на это   -  person Paula Ysabelle Medina    schedule 18.08.2020


Ответы (2)


Вот один из способов сделать это. Вы должны вызвать BlocBuilder, чтобы обработать построение виджета в ответ на новые состояния.

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();
        },
      ),
    );
  }
}

Сначала состояние AuthenticationUnauthenticated и отображает экран входа в систему. Если вход в систему прошел успешно, мы отображаем домашнюю страницу, в противном случае мы отображаем 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

    }
        
  }
}

А вот код AuthenticationBloc (), который будет обрабатывать аутентификацию.

 class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState>{
    
    //code
    
      Stream<AuthenticationState> mapEventToState(
        AuthenticationEvent event,
      ) async* {
          if(event is AuthenticationLogin) {
             yield AuthenticationInProgress();
             //code
             yield AuthenticationAuthenticated();
          }
    }
}
    
person Lapa Ny Aina Tanjona    schedule 18.08.2020
comment
У меня есть BlocBuilder в моем родительском виджете. И я уже реализую код, который вы дали, но мой вопрос - как я могу получить состояние AuthenticationAuthenticated () для AuthenticationBloc () внутри моего LoginBloc () - поскольку моя логика входа происходит внутри LoginBloc - person Paula Ysabelle Medina; 19.08.2020
comment
Нет, вы не можете передать состояние AuthenticationAuthenticated () для AuthenticationBloc () внутри вашего LoginBloc (). Это просто AuthenticationBloc (), который будет управлять отображением виджетов (экрана) из того состояния, которое у вас есть! Из LoginBloc () вы можете отправить событие в AuthenticationBloc (), и последний вызовет состояние AuthenticationAuthenticated () и вернет соответствующий виджет (здесь это HomePage ()). Я только что обновил свой код - person Lapa Ny Aina Tanjona; 19.08.2020
comment
хорошо, но если вы проверите мой код выше, я уже сделал то, что вы только что сказали, но он все еще не работает (виджет не обновляется) - person Paula Ysabelle Medina; 19.08.2020
comment
Можете ли вы поделиться еще кодом, чтобы я мог правильно решить вашу проблему? - person Lapa Ny Aina Tanjona; 19.08.2020
comment
привет спасибо за помощь. Я отказался от своей старой реализации. Вместо этого я подписал свой AuthenticationBloc на поток состояния моего класса AuthenticateCredentialsUsecase, и когда учетные данные аутентифицированы, я затем обновляю поток состояния, который inturn вызовет событие AuthenticationLogin внутри AuthenticationBloc - person Paula Ysabelle Medina; 27.08.2020
comment
@paulaysabellemedina отлично :) - person Lapa Ny Aina Tanjona; 28.08.2020

  1. Я подписал AuthenticationBloc на поток статуса моего класса AuthenticateCredentialsUsecase.
  2. Когда AuthenticateCredentialsUsecase вызывается в моем LoginBloc и учетные данные аутентифицируются ...
  3. Затем я обновляю поток статуса - _controller.add(AuthenticationStatus.authenticated);
  4. Какой inturn вызовет событие AuthenticationLogin внутри 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;
  }
person Paula Ysabelle Medina    schedule 27.08.2020