import 'package:flutter/material.dart'; enum ProgressDialogType { normal, download } String _dialogMessage = "Loading..."; double _progress = 0.0, _maxProgress = 100.0; Widget? _customBody; TextAlign _textAlign = TextAlign.left; Alignment _progressWidgetAlignment = Alignment.centerLeft; TextDirection _direction = TextDirection.ltr; bool _isShowing = false; BuildContext? _context, _dismissingContext; ProgressDialogType? _progressDialogType; bool _barrierDismissible = true, _showLogs = false; Color? _barrierColor; TextStyle _progressTextStyle = const TextStyle( color: Colors.black, fontSize: 12.0, fontWeight: FontWeight.w400, ), _messageStyle = const TextStyle( color: Colors.black, fontSize: 18.0, fontWeight: FontWeight.w600, ); double _dialogElevation = 8.0, _borderRadius = 8.0; Color _backgroundColor = Colors.white; Curve _insetAnimCurve = Curves.easeInOut; EdgeInsets _dialogPadding = const EdgeInsets.all(8.0); Widget _progressWidget = Image.asset( 'assets/double_ring_loading_io.gif', package: 'progress_dialog', ); class ProgressDialog { _Body? _dialog; ProgressDialog( BuildContext context, { ProgressDialogType? type, bool? isDismissible, bool? showLogs, TextDirection? textDirection, Widget? customBody, Color? barrierColor, }) { _context = context; _progressDialogType = type ?? ProgressDialogType.normal; _barrierDismissible = isDismissible ?? true; _showLogs = showLogs ?? false; _customBody = customBody; _direction = textDirection ?? TextDirection.ltr; _barrierColor = barrierColor ?? barrierColor; } void style({ Widget? child, double? progress, double? maxProgress, String? message, Widget? progressWidget, Color? backgroundColor, TextStyle? progressTextStyle, TextStyle? messageTextStyle, double? elevation, TextAlign? textAlign, double? borderRadius, Curve? insetAnimCurve, EdgeInsets? padding, Alignment? progressWidgetAlignment, }) { if (_isShowing) return; if (_progressDialogType == ProgressDialogType.download) { _progress = progress ?? _progress; } _dialogMessage = message ?? _dialogMessage; _maxProgress = maxProgress ?? _maxProgress; _progressWidget = progressWidget ?? _progressWidget; _backgroundColor = backgroundColor ?? _backgroundColor; _messageStyle = messageTextStyle ?? _messageStyle; _progressTextStyle = progressTextStyle ?? _progressTextStyle; _dialogElevation = elevation ?? _dialogElevation; _borderRadius = borderRadius ?? _borderRadius; _insetAnimCurve = insetAnimCurve ?? _insetAnimCurve; _textAlign = textAlign ?? _textAlign; _progressWidget = child ?? _progressWidget; _dialogPadding = padding ?? _dialogPadding; _progressWidgetAlignment = progressWidgetAlignment ?? _progressWidgetAlignment; } void update({ double? progress, double? maxProgress, String? message, Widget? progressWidget, TextStyle? progressTextStyle, TextStyle? messageTextStyle, }) { if (_progressDialogType == ProgressDialogType.download) { _progress = progress ?? _progress; } _dialogMessage = message ?? _dialogMessage; _maxProgress = maxProgress ?? _maxProgress; _progressWidget = progressWidget ?? _progressWidget; _messageStyle = messageTextStyle ?? _messageStyle; _progressTextStyle = progressTextStyle ?? _progressTextStyle; if (_isShowing) _dialog!.update(); } bool isShowing() { return _isShowing; } Future hide() async { try { if (_isShowing) { _isShowing = false; if (_dismissingContext != null) { Navigator.of(_dismissingContext!).pop(); } if (_showLogs) debugPrint('ProgressDialog dismissed'); return Future.value(true); } else { if (_showLogs) debugPrint('ProgressDialog already dismissed'); return Future.value(false); } } catch (err) { debugPrint('Seems there is an issue hiding dialog'); debugPrint(err.toString()); return Future.value(false); } } Future show() async { try { if (!_isShowing) { _dialog = _Body(); showDialog( context: _context!, barrierDismissible: _barrierDismissible, barrierColor: _barrierColor, builder: (BuildContext context) { _dismissingContext = context; return WillPopScope( onWillPop: () async => _barrierDismissible, child: Dialog( backgroundColor: _backgroundColor, insetAnimationCurve: _insetAnimCurve, insetAnimationDuration: const Duration(milliseconds: 100), elevation: _dialogElevation, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(_borderRadius)), ), child: _dialog, ), ); }, ); // Delaying the function for 200 milliseconds // [Default transitionDuration of DialogRoute] await Future.delayed(const Duration(milliseconds: 200)); if (_showLogs) debugPrint('ProgressDialog shown'); _isShowing = true; return true; } else { if (_showLogs) debugPrint("ProgressDialog already shown/showing"); return false; } } catch (err) { _isShowing = false; debugPrint('Exception while showing the dialog'); debugPrint(err.toString()); return false; } } } // ignore: must_be_immutable class _Body extends StatefulWidget { final _BodyState _dialog = _BodyState(); update() { _dialog.update(); } @override State createState() { return _dialog; } } class _BodyState extends State<_Body> { update() { setState(() {}); } @override void dispose() { _isShowing = false; if (_showLogs) debugPrint('ProgressDialog dismissed by back button'); super.dispose(); } @override Widget build(BuildContext context) { final loader = Align( alignment: _progressWidgetAlignment, child: SizedBox( width: 60.0, height: 60.0, child: _progressWidget, ), ); final text = Expanded( child: _progressDialogType == ProgressDialogType.normal ? Text( _dialogMessage, textAlign: _textAlign, style: _messageStyle, textDirection: _direction, ) : Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ const SizedBox(height: 8.0), Row( children: [ Expanded( child: Text( _dialogMessage, style: _messageStyle, textDirection: _direction, ), ), ], ), const SizedBox(height: 4.0), Align( alignment: Alignment.bottomRight, child: Text( "$_progress/$_maxProgress", style: _progressTextStyle, textDirection: _direction, ), ), ], ), ), ); return _customBody ?? Container( padding: _dialogPadding, child: Column( mainAxisSize: MainAxisSize.min, children: [ // row body Row( mainAxisSize: MainAxisSize.min, children: [ const SizedBox(width: 8.0), _direction == TextDirection.ltr ? loader : text, const SizedBox(width: 8.0), _direction == TextDirection.rtl ? loader : text, const SizedBox(width: 8.0), ], ), ], ), ); } }