improved file op report overlay
This commit is contained in:
parent
79aefc3aa5
commit
797f8a8d07
1 changed files with 83 additions and 28 deletions
|
@ -35,11 +35,60 @@ mixin FeedbackMixin {
|
||||||
@required Stream<T> opStream,
|
@required Stream<T> opStream,
|
||||||
@required void Function(Set<T> processed) onDone,
|
@required void Function(Set<T> processed) onDone,
|
||||||
}) {
|
}) {
|
||||||
final processed = <T>{};
|
_opReportOverlayEntry = OverlayEntry(
|
||||||
|
builder: (context) => ReportOverlay<T>(
|
||||||
|
opStream: opStream,
|
||||||
|
itemCount: selection.length,
|
||||||
|
onDone: (processed) {
|
||||||
|
_opReportOverlayEntry?.remove();
|
||||||
|
_opReportOverlayEntry = null;
|
||||||
|
onDone(processed);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
Overlay.of(context).insert(_opReportOverlayEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReportOverlay<T> extends StatefulWidget {
|
||||||
|
final Stream<T> opStream;
|
||||||
|
final int itemCount;
|
||||||
|
final void Function(Set<T> processed) onDone;
|
||||||
|
|
||||||
|
const ReportOverlay({
|
||||||
|
@required this.opStream,
|
||||||
|
@required this.itemCount,
|
||||||
|
@required this.onDone,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ReportOverlayState createState() => _ReportOverlayState<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReportOverlayState<T> extends State<ReportOverlay<T>> with SingleTickerProviderStateMixin {
|
||||||
|
final processed = <T>{};
|
||||||
|
AnimationController _animationController;
|
||||||
|
Animation<double> _animation;
|
||||||
|
|
||||||
|
Stream<T> get opStream => widget.opStream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_animationController = AnimationController(
|
||||||
|
duration: Durations.collectionOpOverlayAnimation,
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
_animation = CurvedAnimation(
|
||||||
|
parent: _animationController,
|
||||||
|
curve: Curves.easeOutQuad,
|
||||||
|
);
|
||||||
|
_animationController.forward();
|
||||||
|
|
||||||
// do not handle completion inside `StreamBuilder`
|
// do not handle completion inside `StreamBuilder`
|
||||||
// as it could be called multiple times
|
// as it could be called multiple times
|
||||||
Future<void> onComplete() => _hideOpReportOverlay().then((_) => onDone(processed));
|
Future<void> onComplete() => _animationController.reverse().then((_) => widget.onDone(processed));
|
||||||
opStream.listen(
|
opStream.listen(
|
||||||
processed.add,
|
processed.add,
|
||||||
onError: (error) {
|
onError: (error) {
|
||||||
|
@ -48,17 +97,34 @@ mixin FeedbackMixin {
|
||||||
},
|
},
|
||||||
onDone: onComplete,
|
onDone: onComplete,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_opReportOverlayEntry = OverlayEntry(
|
@override
|
||||||
builder: (context) {
|
void dispose() {
|
||||||
return AbsorbPointer(
|
_animationController.dispose();
|
||||||
child: StreamBuilder<T>(
|
super.dispose();
|
||||||
stream: opStream,
|
}
|
||||||
builder: (context, snapshot) {
|
|
||||||
Widget child = SizedBox.shrink();
|
@override
|
||||||
if (!snapshot.hasError) {
|
Widget build(BuildContext context) {
|
||||||
final percent = processed.length.toDouble() / selection.length;
|
return AbsorbPointer(
|
||||||
child = CircularPercentIndicator(
|
child: StreamBuilder<T>(
|
||||||
|
stream: opStream,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final percent = processed.length.toDouble() / widget.itemCount;
|
||||||
|
return FadeTransition(
|
||||||
|
opacity: _animation,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: RadialGradient(
|
||||||
|
colors: [
|
||||||
|
Colors.black,
|
||||||
|
Colors.black54,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: CircularPercentIndicator(
|
||||||
percent: percent,
|
percent: percent,
|
||||||
lineWidth: 16,
|
lineWidth: 16,
|
||||||
radius: 160,
|
radius: 160,
|
||||||
|
@ -67,22 +133,11 @@ mixin FeedbackMixin {
|
||||||
animation: true,
|
animation: true,
|
||||||
center: Text(NumberFormat.percentPattern().format(percent)),
|
center: Text(NumberFormat.percentPattern().format(percent)),
|
||||||
animateFromLastPercent: true,
|
animateFromLastPercent: true,
|
||||||
);
|
),
|
||||||
}
|
),
|
||||||
return AnimatedSwitcher(
|
),
|
||||||
duration: Durations.collectionOpOverlayAnimation,
|
);
|
||||||
child: child,
|
}),
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
Overlay.of(context).insert(_opReportOverlayEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _hideOpReportOverlay() async {
|
|
||||||
await Future.delayed(Durations.collectionOpOverlayAnimation * timeDilation);
|
|
||||||
_opReportOverlayEntry?.remove();
|
|
||||||
_opReportOverlayEntry = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue