我是 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];
}