Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions lib/src/circular_progress_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -18,6 +16,7 @@ class CircularProgressBuilder extends ProgressBuilder {
VoidCallback? onStart,
VoidCallback? onSuccess,
ActionController? controller,
int? animationDuration,
Key? key,
}) : super(
action: action,
Expand All @@ -28,6 +27,7 @@ class CircularProgressBuilder extends ProgressBuilder {
onSuccess: onSuccess,
progressBuilder: _progressBuilder,
controller: controller,
animationDuration: animationDuration,
key: key,
);

Expand All @@ -39,6 +39,7 @@ class CircularProgressBuilder extends ProgressBuilder {
VoidCallback? onStart,
VoidCallback? onSuccess,
ActionController? controller,
int? animationDuration,
Key? key,
}) : super(
action: action,
Expand All @@ -49,6 +50,7 @@ class CircularProgressBuilder extends ProgressBuilder {
onSuccess: onSuccess,
progressBuilder: _adaptiveProgressBuilder,
controller: controller,
animationDuration: animationDuration,
key: key,
);
}
5 changes: 3 additions & 2 deletions lib/src/linear_progress_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -15,6 +14,7 @@ class LinearProgressBuilder extends ProgressBuilder {
VoidCallback? onStart,
VoidCallback? onSuccess,
ActionController? controller,
int? animationDuration,
Key? key,
}) : super(
action: action,
Expand All @@ -25,6 +25,7 @@ class LinearProgressBuilder extends ProgressBuilder {
onSuccess: onSuccess,
progressBuilder: _progressBuilder,
controller: controller,
animationDuration: animationDuration,
key: key,
);
}
90 changes: 57 additions & 33 deletions lib/src/progress_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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).
Expand All @@ -70,77 +70,101 @@ class ProgressBuilder extends StatefulWidget {
this.onSuccess,
this.onDone,
this.onStart,
this.animationDuration,
Key? key,
}) : super(key: key);

@override
_ProgressBuilderState createState() => _ProgressBuilderState();
}

class _ProgressBuilderState extends State<ProgressBuilder> {
double? _progress;
class _ProgressBuilderState extends State<ProgressBuilder> with SingleTickerProviderStateMixin {
dynamic _error;

bool _isInProgress = false;
late final AnimationController _progressAnimationController;
StreamSubscription<ActionType>? _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<void> _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,
);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the progress should be completed when the action is done.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the code. Now the _progressAnimationController is told to animate to 1.0 (or 100%) when the action completes, regardless of whether the action was successful or not. This should ensure that the progress bar completes before switching back to the non-progress state.


widget.onSuccess?.call();
} catch (e) {
_error = e;

if (widget.onError != null) {
widget.onError!(e);
} else {
rethrow;
}
} 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);
}
},
);
}