Отобразить индикатор загрузки, используя состояния из blo c и показать диалог, если произошла ошибка - PullRequest
0 голосов
/ 27 февраля 2020

Я новичок в разработке Flutter и создаю приложение, в котором я использую библиотеку Blo c с состояниями и событиями. У меня есть страница, где пользователь может ввести свой адрес электронной почты в TextFormField. После этого ему нужно нажать кнопку отправки, где приложение отправит вызов API через Blo c. Моя проблема заключается в том, чтобы показать диалоговое окно прогресса выполнения круга во время выполнения вызова API и затем скрыть индикатор загрузки круга и отобразить диалоговое окно успеха или сообщение об ошибке.

Я использую чистый architecutre, поэтому приложение представляет собой структуры, подобные пользовательскому интерфейсу - Blo c - Usecas - Репозиторий - RemoteDataSource. Ниже приведен код для пользовательского интерфейса и Blo c, который я использовал, и в настоящее время приложение отображает диалоговое окно, но я не уверен, является ли это правильным способом обновления интерфейса на основе состояния, которое я получаю от Blo * 1009. *. Кроме того, я не уверен, как отобразить диалоговое окно, когда состояние Loaded или Error, так как в текущей реализации мне нужно вернуть виджет. Любая помощь будет принята с благодарностью.

class ResetPasswordPage extends StatefulWidget {
  @override
 _ResetPasswordPageState createState() => _ResetPasswordPageState();
}

class _ResetPasswordPageState extends State<ResetPasswordPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: WebitAppBar(
      leading:  GestureDetector(
      child: Image(
        image: new AssetImage('assets/images/toolbar_logo.png'),
        height: 10,
        width: 10,
      ),
    ),
    title: Text(
        AppLocalizations.of(context)
            .translate('reset_password_toolbar_text'),
        style: AppTheme.toolbarTitle),
   ),
    body: SingleChildScrollView(
        child: buildBody(context),
     ),
   );
 }

  buildBody(BuildContext context) {
    return BlocProvider(
      create: (_) => injectionContainer<ResetPasswordBloc>(),
      child: Padding(
          padding: EdgeInsets.only(
          left: 60,
          right: 60,
          bottom: 0,
       ),
       child: Stack(
         children: <Widget>[
           Column(
             mainAxisAlignment: MainAxisAlignment.spaceBetween,
             crossAxisAlignment: CrossAxisAlignment.stretch,
             children: <Widget>[
               ResetPasswordInitialViewState(
                 isLoading: true,
               ),
             ],
           ),
           _buildBlocState(),
         ],
       ),
     ),
   );
 }

 Widget _buildBlocState() {
   return BlocBuilder<ResetPasswordBloc, ResetPasswordState>(
     builder: (context, state) {
       if (state is Empty) {
         return Container(
           height: 0,
           width: 0,
         );
       } else if (state is Loading) {
         return LoadingWidget();
       } else if (state is Loaded) {
         return Container(
           height: 0,
           width: 0,
         );
       } else if (state is Error) {
         return Container(
           height: 0,
           width: 0,
         );
       }
     },
   );
 }
}

  ///Error message when text is not supplied
 const String INVALID_INPUT_FAILURE_MESSAGE = 'Invalid Input - The text should not be empty';

 /// Error message when network call fails
 const String SERVER_FAILURE_MESSAGE = 'Server Failure';

 class ResetPasswordBloc extends Bloc<ResetPasswordEvent, ResetPasswordState> {
     ///Property to store the use-case for resetting  user password
     final ResetPasswordUseCase resetPasswordUseCase;

     /// Property to store InputConverter used for validating user input
     final InputConverter inputConverter;

     ResetPasswordBloc({
        @required ResetPasswordUseCase resetPasswordUseCase,
        @required InputConverter inputConverter,
     })  : assert(resetPasswordUseCase != null),
        assert(inputConverter != null),
        resetPasswordUseCase = resetPasswordUseCase,
        inputConverter = inputConverter;

     ///Method to supply the initial state of the screen.
     @override
     ResetPasswordState get initialState => Empty();

     ///Method called when passing event from the view
     @override
     Stream<ResetPasswordState> mapEventToState(ResetPasswordEvent event) async* {
       if (event is ResetPassword) {
          final inputEither = inputConverter.checkIfInputIsEmptry(event.email);

          yield* inputEither.fold(
           (failure) async* {
             yield Error(message: INVALID_INPUT_FAILURE_MESSAGE);
         },
           (integer) async* {
            yield Loading();
            final failureOrTrivia =
               await resetPasswordUseCase(Params(email: integer));
           yield* _eitherLoadedOrErrorState(failureOrTrivia);
         },
      );
    }
   }

   Stream<ResetPasswordState> _eitherLoadedOrErrorState(
     Either<Failure, ResetPasswordEntity> failureOrTrivia,
   ) async* {
     yield failureOrTrivia.fold(
      (failure) => Error(message: _mapFailureToMessage(failure)),
      (resetPasswordResponse) => Loaded(response: resetPasswordResponse),
    );
 }

  String _mapFailureToMessage(Failure failure) {
    switch (failure.runtimeType) {
      case ServerFailure:
        return SERVER_FAILURE_MESSAGE;
      default:
       return 'Unexpected error';
    }
  }
}


  @immutable
  abstract class ResetPasswordState extends Equatable {
    @override
    List<Object> get props => [];
  }

  class Empty extends ResetPasswordState {}

  class Loading extends ResetPasswordState {}

  class Loaded extends ResetPasswordState {
     final ResetPasswordEntity response;

     Loaded({@required this.response});

     @override
    List<Object> get props => [response];
   }

  class Error extends ResetPasswordState {
     final String message;

     Error({@required this.message});

     @override
     List<Object> get props => [message];
  }
...