4

我是 Flutter 开发的新手,我正在构建一个应用程序,我在其中使用 Bloc 库与状态和事件。我有一个页面,用户可以在 TextFormField 中输入他的电子邮件地址。之后,他需要按下发送按钮,应用程序将通过 Bloc 发送 api 调用。我的问题是在 api 调用运行时显示圆形进度对话框,然后隐藏圆形加载指示器并显示成功对话框或错误消息。

我正在使用干净的架构,所以应用程序是 UI - Bloc - Usecas - Repository - RemoteDataSource 之类的结构。下面是我使用的 UI 和 Bloc 的代码,当前应用程序显示一个对话框,但是我不确定这是否是根据我从 Bloc 收到的状态更新 UI 的正确方法。此外,我不确定当状态为 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];
  }
4

0 回答 0