Flutter BLoC - Display a Dialog During Asynchronous Processing

Created At: 2023-09-15 07:56:08 Updated At: 2023-09-15 18:23:19

The goal is to display a dialog before starting, during, and completing an asynchronous process in Flutter.

Before starting → Dialog asking whether to execute the process (Yes or No dialog).
Processing      → Dialog informing the user that the process is in progress using CircularProgressIndicator or LinearProgressIndicator, etc.
Upon completion → Dialog informing the user that the process is completed.

The following are respectively referred to as the pre-start dialog, processing dialog, and completion dialog.

It can be used in applications that download large files.

Add the package/plugin to your pubspec.yaml and press the pub get button.

dependencies:
  rxdart: ^0.27.5

Process flow
Uses the BLoC design pattern. This time, we will prepare the two streams shown below.

Widget        → BLoC class (tells the dialog operation to the BLoC class) _triggerController

BLoC class → Widget (tells the widget the type of dialog to be displayed) _dialogController

Initializes the BLoC class on the widget side and immediately starts listening to _dialogController

Flow the data (Status.inPreparation) that signals the display of the pre-start dialog to _dialogController

Display the pre-start dialog When the "OK" button is pressed in the pre-start dialog, flow the data to _triggerController

Start asynchronous processing with BLoC

Processing at the same time send the data (Status.inProgress) that signals the dialog display to _dialogController

Dialog display during processing when the asynchronous process ends.

Send the data (Status.completed) that signals the dialog display to _dialogController dialog display at completion.

The source code for the complete implementation version can be viewed on GitHub.
Click here for the repository bloc asynchronomous
The code shown below is an excerpt of the important parts.

import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:bloc/dialog.dart';
import 'package:bloc/status.dart';


class _MyHomePageState extends State<MyHomePage> {
  late BLoC _BLoC;

  @override
  void initState(){
    super.initState();
    _BLoC = BLoC();
    _BLoC.onDialogChange.listen((Status status) async {
      if(Navigator.of(context).canPop() == true){
        Navigator.pop(context);
      }
      if(status == Status.inPreparation){
       //Show the dialog box before you start.
        bool result = await DialogManager.showNormalDialog(
          context: context,
          title:' Confirm download',
          content:' Do you want to download data?'
        );
        if(result == true){
          _BLoC.triggerAction.add(null);
        }
      }else if(status == Status.inProgress){
       //Displays the dialog box being processed.
        await DialogManager.showProgressDialog(
            context: context,
            text: 'Downloading'
        );
      }else if(status == Status.completed){
        //Show dialog box when finished
        await DialogManager.showNoticeDialog(
          context: context,
         title:' Download complete',
         content:' Download complete.'
        );
      }
    });
  }

  @override
  void dispose(){
    _BLoC.close();
    super.dispose();
  }

}
A class that collects methods for displaying dialogs
import 'package:flutter/material.dart';

class DialogManager{
  static Future<bool> showProgressDialog({
    required BuildContext context,
    required String text,
  }) async {
      //(abbreviated)
      //Dialog box display processing
  }

  static Future<bool> showNormalDialog({
    required BuildContext context,
    required String title,
    required String content
  }) async {
       //(abbreviated)
       //Dialog box display processing
  }

  static Future<bool> showNoticeDialog({
    required BuildContext context,
    required String title,
    required String content
  }) async {
     //(abbreviated)
     //Dialog box display processing
  }
}

BLoC class

A class that collects methods for displaying dialogs

import 'dart:async';
import 'package:rxdart/rxdart.dart';
import 'package:bloc/status.dart';

class BLoC {
  //stream
  final _triggerController = BehaviorSubject<void>();
  Sink<void> get triggerAction => _triggerController.sink;
  
  final _dialogController = BehaviorSubject<Status>();
  Stream<Status> get onDialogChange => _dialogController.stream;

  BLoC(){
    _dialogController.sink.add(Status.inPreparation);

    _triggerController.stream.listen((_) {
      _dialogController.sink.add(Status.inProgress)
      //Actually performs the download process
      Future.delayed(Duration(seconds: 3)).then((_) {
        _dialogController.sink.add(Status.completed);
      });
    });
  }

  void close() {
    _triggerController.close();
    _dialogController.close();
  }
}

Status (enum type)

enum Status{
  inPreparation,
  inProgress,
  completed
}

Navigator.pop(context) is used when switching between assignment dialogs. Therefore, if another screen transition interrupts the process, unexpected behavior may occur. It may be better to include processing to prevent another screen transition from interrupting the asynchronous processing. If you have any other problems, please feel free to let me know.

Comment

Add Reviews