I am new to Flutter development and i am build an application where i am usign the Bloc library with states and events. I have a page where the user can entre his email address in TextFormField. After that he needs to press the send button where the applicaiton will send an api call throught the Bloc. My issue is with showing a circle progress dialog while the api call is runnign and later hiding the circle loading indicator and showing a success dialog or error message.

I am using clean architecutre so the applicaiton is structures like UI - Bloc - Usecas - Repository - RemoteDataSource. Below is the code for the UI and Bloc which i have used and currenty the app displays a dialog howerve i am not sure if this is the correct way of updating the UI based on the state which i receive from the Bloc. Furthermore i am not sure how display a dialog when the state is Loaded or Error as with the current implementation i need to return a widget. Any help will be greatly appreciated.

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


Solution 1: Omatt

One way of updating the screen when using bloc is with the use of BlocBuilder. When the Stream in the bloc is updated, the BlocBuilder automatically rebuilds to handle the response in the new state. Once the BlocBuilder rebuilds, you can check the state for its current data and update the child Widgets. In this case, you can trigger the displaying of ProgressIndicator along with the request, and dismiss the ProgressIndicator when the BlocBuilder rebuilds.