The Problem

Most Flutter apps need to run tasks that take a few seconds — fetching data from an API, uploading a file, or processing a payment. During that wait the user stares at a frozen screen with no indication that anything is happening. They tap the button again, trigger duplicate requests, or assume the app has crashed.

The standard solution is to manually manage a loading state: flip a boolean, show a spinner, await the future, hide the spinner, then handle the result or error. That logic ends up duplicated across dozens of screens with subtle differences each time.

Common pain points include:

  • Boilerplate loading-state management repeated in every screen
  • Users tapping buttons multiple times because there is no visual feedback
  • Dismissed dialogs that leave orphaned futures still running in the background
  • Inconsistent error handling — some screens catch exceptions, others crash silently

How flutter_future_progress_dialog Solves It

flutter_future_progress_dialog replaces all of that boilerplate with a single function call. Pass your async task in, and the package shows a non-dismissible progress dialog, waits for the result, closes the dialog, and hands you back a type-safe result — either Success with the value or Failure with the error.

Error handling is built into the result type, so you never forget to catch an exception.

What It Supports

  • Material dialogshowProgressDialog displays a standard Material circular progress indicator
  • Cupertino dialogshowCupertinoProgressDialog shows an iOS-styled activity indicator
  • Adaptive dialogshowAdaptiveProgressDialog picks the right style for the current platform automatically
  • Custom dialog UI — pass a builder to replace the default indicator with any widget you need
  • Type-safe resultsProgressDialogResult<T> is a sealed class with Success and Failure variants, supporting pattern matching and convenience methods like unwrap() and map()
  • Error captureFailure includes both the error object and the stack trace

Real-World Use Cases

Payment processing

A checkout screen calls a payment gateway API. Without a progress dialog, users tap "Pay" again when nothing seems to happen — causing duplicate charges. With showProgressDialog, the dialog stays on screen and blocks interaction until the gateway responds, then pattern-match the result to navigate to a confirmation or error screen.

File uploads

A document scanner uploads images to a server. The upload can take several seconds on slow connections. Wrapping the upload in showAdaptiveProgressDialog gives users immediate visual feedback and ensures the dialog matches the platform — Material on Android, Cupertino on iOS.

Form submissions

A multi-step form sends data to a backend on the final step. Using the progress dialog prevents double-submission and gives you a clean Success/Failure result to decide whether to show a success screen or an inline error message.

Background data sync

A CRM app syncs local changes with a remote server. A custom builder can show a branded loading animation instead of the default spinner, keeping the user experience consistent with the rest of the app.

Getting Started

Install the package:

flutter pub add flutter_future_progress_dialog

Then call showProgressDialog with your async task:

final result = await showProgressDialog(
  context: context,
  future: () => fetchData(),
);

switch (result) {
  case Success(:final value):
    // Use the value
  case Failure(:final error):
    // Handle the error
}

Three dialog functions are available: showProgressDialog (Material), showCupertinoProgressDialog (Cupertino), and showAdaptiveProgressDialog (platform-automatic). All accept an optional builder parameter for custom UI.

A complete working example is available in the example directory.

No. The dialog is non-dismissible by default, which prevents orphaned futures and duplicate submissions. The dialog closes automatically when the async task completes.
The dialog closes and the result is returned as a Failure containing the error and stack trace. Your code can pattern-match on the result to handle errors without try-catch blocks.
Yes. Use showProgressDialog for Material style, showCupertinoProgressDialog for iOS style, or showAdaptiveProgressDialog to automatically match the host platform.
Yes. Pass a builder parameter to any of the three dialog functions to replace the default progress indicator with your own widget — a branded animation, a message, or any other Flutter widget.
ProgressDialogResult<T> is a sealed class with two variants: Success<T> containing the returned value, and Failure<T> containing the error and stack trace. You can use Dart pattern matching, or convenience methods like isSuccess, isError, unwrap(), and map().