diff --git a/lib/src/circular_progress_builder.dart b/lib/src/circular_progress_builder.dart index ad6ae7d..a3dd4a5 100644 --- a/lib/src/circular_progress_builder.dart +++ b/lib/src/circular_progress_builder.dart @@ -4,11 +4,9 @@ import 'action_controller.dart'; import 'progress_builder.dart'; class CircularProgressBuilder extends ProgressBuilder { - static Widget _progressBuilder(context, [double? value]) => - CircularProgressIndicator(value: value); + static Widget _progressBuilder(context, [double? value]) => CircularProgressIndicator(value: value); - static Widget _adaptiveProgressBuilder(context, [double? value]) => - CircularProgressIndicator.adaptive(value: value); + static Widget _adaptiveProgressBuilder(context, [double? value]) => CircularProgressIndicator.adaptive(value: value); const CircularProgressBuilder({ required ProgressChildWidgetBuilder builder, @@ -18,6 +16,7 @@ class CircularProgressBuilder extends ProgressBuilder { VoidCallback? onStart, VoidCallback? onSuccess, ActionController? controller, + int? animationDuration, Key? key, }) : super( action: action, @@ -28,6 +27,7 @@ class CircularProgressBuilder extends ProgressBuilder { onSuccess: onSuccess, progressBuilder: _progressBuilder, controller: controller, + animationDuration: animationDuration, key: key, ); @@ -39,6 +39,7 @@ class CircularProgressBuilder extends ProgressBuilder { VoidCallback? onStart, VoidCallback? onSuccess, ActionController? controller, + int? animationDuration, Key? key, }) : super( action: action, @@ -49,6 +50,7 @@ class CircularProgressBuilder extends ProgressBuilder { onSuccess: onSuccess, progressBuilder: _adaptiveProgressBuilder, controller: controller, + animationDuration: animationDuration, key: key, ); } diff --git a/lib/src/linear_progress_builder.dart b/lib/src/linear_progress_builder.dart index 15f5887..71cee76 100644 --- a/lib/src/linear_progress_builder.dart +++ b/lib/src/linear_progress_builder.dart @@ -4,8 +4,7 @@ import 'action_controller.dart'; import 'progress_builder.dart'; class LinearProgressBuilder extends ProgressBuilder { - static Widget _progressBuilder([context, double? value]) => - LinearProgressIndicator(value: value); + static Widget _progressBuilder([context, double? value]) => LinearProgressIndicator(value: value); const LinearProgressBuilder({ required ProgressChildWidgetBuilder builder, @@ -15,6 +14,7 @@ class LinearProgressBuilder extends ProgressBuilder { VoidCallback? onStart, VoidCallback? onSuccess, ActionController? controller, + int? animationDuration, Key? key, }) : super( action: action, @@ -25,6 +25,7 @@ class LinearProgressBuilder extends ProgressBuilder { onSuccess: onSuccess, progressBuilder: _progressBuilder, controller: controller, + animationDuration: animationDuration, key: key, ); } diff --git a/lib/src/progress_builder.dart b/lib/src/progress_builder.dart index 3df44b5..e3be8bf 100644 --- a/lib/src/progress_builder.dart +++ b/lib/src/progress_builder.dart @@ -2,17 +2,14 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:progress_builder/progress_builder.dart'; -import 'action_controller.dart'; /// /// Builds a widget in the non-progress/loading state /// -typedef ProgressChildWidgetBuilder = Widget Function( - BuildContext context, void Function()? action, Object? error); +typedef ProgressChildWidgetBuilder = Widget Function(BuildContext context, void Function()? action, Object? error); /// Builds a progress indicator with [double progress] -typedef ProgressIndicatorWidgetBuilder = Widget Function(BuildContext context, - [double? progress]); +typedef ProgressIndicatorWidgetBuilder = Widget Function(BuildContext context, [double? progress]); /// The call back from action to notify about the progress typedef ProgressCallback = void Function(double? progress); @@ -55,6 +52,9 @@ class ProgressBuilder extends StatefulWidget { /// The stream to listen for triggering action externally final ActionController? controller; + /// The animation duration in milliseconds, defaults to 500 + final int? animationDuration; + /// Creates a ProgressBuilder. /// /// The [builder] builds the child, either in initial, done or error state (error != null). @@ -70,6 +70,7 @@ class ProgressBuilder extends StatefulWidget { this.onSuccess, this.onDone, this.onStart, + this.animationDuration, Key? key, }) : super(key: key); @@ -77,47 +78,58 @@ class ProgressBuilder extends StatefulWidget { _ProgressBuilderState createState() => _ProgressBuilderState(); } -class _ProgressBuilderState extends State { - double? _progress; +class _ProgressBuilderState extends State with SingleTickerProviderStateMixin { dynamic _error; - + bool _isInProgress = false; + late final AnimationController _progressAnimationController; StreamSubscription? _subscription; + late final Duration _animationDuration; @override void initState() { - _subscription = (widget.controller ?? DefaultActionController.of(context)) - ?.stream - .listen((event) { - if (event == ActionType.start && mounted && _progress == null) { + super.initState(); + _animationDuration = Duration(milliseconds: widget.animationDuration ?? 500); + _progressAnimationController = AnimationController( + vsync: this, + duration: _animationDuration, + ); + + _subscription = (widget.controller ?? DefaultActionController.of(context))?.stream.listen((event) { + if (event == ActionType.start && mounted && !_isInProgress) { _action(); } }); - super.initState(); } @override void dispose() { + _progressAnimationController.dispose(); _subscription?.cancel(); super.dispose(); } - void _progressCallback(double? progress) { - setState(() { - _progress = progress ?? -1; - }); - } - Future _action() async { setState(() { - _progress = -1; + _isInProgress = true; + _progressAnimationController.value = 0.0; _error = null; }); + widget.onStart?.call(); + try { - await widget.action?.call(_progressCallback); + await widget.action?.call((progress) { + _progressAnimationController.animateTo( + progress ?? 0, + duration: _animationDuration, + curve: Curves.ease, + ); + }); + widget.onSuccess?.call(); } catch (e) { _error = e; + if (widget.onError != null) { widget.onError!(e); } else { @@ -125,22 +137,34 @@ class _ProgressBuilderState extends State { } } finally { if (mounted) { - setState(() { - _progress = null; + await _progressAnimationController + .animateTo( + 1.0, + duration: _animationDuration, + curve: Curves.ease, + ) + .then((_) { + if (mounted) { + setState(() { + _isInProgress = false; + }); + } }); + + widget.onDone?.call(); } - widget.onDone?.call(); } } @override - Widget build(BuildContext context) { - if (_progress != null) { - final progress = _progress! < 0 ? null : _progress; - return widget.progressBuilder.call(context, progress); - } else { - return widget.builder( - context, widget.action != null ? _action : null, _error); - } - } + Widget build(BuildContext context) => AnimatedBuilder( + animation: _progressAnimationController, + builder: (context, child) { + if (_isInProgress) { + return widget.progressBuilder.call(context, _progressAnimationController.value); + } else { + return widget.builder(context, widget.action != null ? _action : null, _error); + } + }, + ); }