Add MiniplayerController

This commit is contained in:
David 2020-10-06 20:57:24 +02:00
parent e1bef9b40f
commit de7e89f8cf
3 changed files with 101 additions and 16 deletions

View File

@ -38,6 +38,8 @@ class Miniplayer extends StatefulWidget {
///If onDismiss is set, the miniplayer can be dismissed ///If onDismiss is set, the miniplayer can be dismissed
final Function onDismiss; final Function onDismiss;
final MiniplayerController controller;
const Miniplayer({ const Miniplayer({
Key key, Key key,
@required this.minHeight, @required this.minHeight,
@ -49,6 +51,7 @@ class Miniplayer extends StatefulWidget {
this.valueNotifier, this.valueNotifier,
this.duration = const Duration(milliseconds: 300), this.duration = const Duration(milliseconds: 300),
this.onDismiss, this.onDismiss,
this.controller,
}) : super(key: key); }) : super(key: key);
@override @override
@ -59,7 +62,7 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
ValueNotifier<double> heightNotifier; ValueNotifier<double> heightNotifier;
ValueNotifier<double> dragDownPercentage = ValueNotifier(0); ValueNotifier<double> dragDownPercentage = ValueNotifier(0);
SnapPosition snap; PanelState snap;
///Current y position of drag gesture ///Current y position of drag gesture
double _dragHeight; double _dragHeight;
@ -82,11 +85,11 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
if (status == AnimationStatus.completed) _resetAnimationController(); if (status == AnimationStatus.completed) _resetAnimationController();
} }
void _resetAnimationController() { void _resetAnimationController({Duration duration}) {
if (_animationController != null) _animationController.dispose(); if (_animationController != null) _animationController.dispose();
_animationController = AnimationController( _animationController = AnimationController(
vsync: this, vsync: this,
duration: widget.duration, duration: duration == null ? widget.duration : duration,
); );
_animationController.addStatusListener(_statusListener); _animationController.addStatusListener(_statusListener);
animating = false; animating = false;
@ -103,6 +106,37 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
_dragHeight = widget.minHeight; _dragHeight = widget.minHeight;
if (widget.controller != null) {
widget.controller.addListener(() {
switch (widget.controller.value.height) {
case -1:
_animateToHeight(
widget.minHeight,
duration: widget.controller.value.duration,
);
break;
case -2:
_animateToHeight(
widget.maxHeight,
duration: widget.controller.value.duration,
);
break;
case -3:
_animateToHeight(
-1,
duration: widget.controller.value.duration,
);
break;
default:
_animateToHeight(
widget.controller.value.height.toDouble(),
duration: widget.controller.value.duration,
);
break;
}
});
}
super.initState(); super.initState();
} }
@ -171,8 +205,8 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
), ),
), ),
onTap: () => _snapToPosition(_dragHeight != widget.maxHeight onTap: () => _snapToPosition(_dragHeight != widget.maxHeight
? SnapPosition.MAX ? PanelState.MAX
: SnapPosition.MIN), : PanelState.MIN),
onPanStart: (details) { onPanStart: (details) {
_startHeight = _dragHeight; _startHeight = _dragHeight;
updateCount = 0; updateCount = 0;
@ -197,7 +231,7 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
else if (speed <= 50) snapPercentage = 0.01; else if (speed <= 50) snapPercentage = 0.01;
///Determine to which SnapPosition the widget should snap ///Determine to which SnapPosition the widget should snap
SnapPosition snap = SnapPosition.MIN; PanelState snap = PanelState.MIN;
final _percentageMax = percentageFromValueInRange( final _percentageMax = percentageFromValueInRange(
min: widget.minHeight, min: widget.minHeight,
@ -207,13 +241,13 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
///Started from expanded state ///Started from expanded state
if (_startHeight > widget.minHeight) { if (_startHeight > widget.minHeight) {
if (_percentageMax > 1 - snapPercentage) if (_percentageMax > 1 - snapPercentage)
snap = SnapPosition.MAX; snap = PanelState.MAX;
} }
///Started from minified state ///Started from minified state
else { else {
if (_percentageMax > snapPercentage) if (_percentageMax > snapPercentage)
snap = SnapPosition.MAX; snap = PanelState.MAX;
else else
///DismissedPercentage > 0.2 -> dismiss ///DismissedPercentage > 0.2 -> dismiss
@ -222,7 +256,7 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
min: widget.minHeight, min: widget.minHeight,
max: 0, max: 0,
value: _dragHeight) > value: _dragHeight) >
snapPercentage) snap = SnapPosition.DISMISS; snapPercentage) snap = PanelState.DISMISS;
} }
///Snap to position ///Snap to position
@ -278,24 +312,26 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
} }
///Animates the panel height according to a SnapPoint ///Animates the panel height according to a SnapPoint
void _snapToPosition(SnapPosition snapPosition) { void _snapToPosition(PanelState snapPosition) {
switch (snapPosition) { switch (snapPosition) {
case SnapPosition.MAX: case PanelState.MAX:
_animateToHeight(widget.maxHeight); _animateToHeight(widget.maxHeight);
return; return;
case SnapPosition.MIN: case PanelState.MIN:
_animateToHeight(widget.minHeight); _animateToHeight(widget.minHeight);
return; return;
case SnapPosition.DISMISS: case PanelState.DISMISS:
_animateToHeight(0); _animateToHeight(0);
return; return;
} }
} }
///Animates the panel height to a specific value ///Animates the panel height to a specific value
void _animateToHeight(final double h) { void _animateToHeight(final double h, {Duration duration}) {
final startHeight = _dragHeight; final startHeight = _dragHeight;
if (duration != null) _resetAnimationController(duration: duration);
Animation<double> _sizeAnimation = Tween( Animation<double> _sizeAnimation = Tween(
begin: startHeight, begin: startHeight,
end: h, end: h,
@ -314,3 +350,37 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
_animationController.forward(from: 0); _animationController.forward(from: 0);
} }
} }
///-1 Min, -2 Max, -3 Dismiss
enum PanelState { MAX, MIN, DISMISS }
class ControllerData {
final int height;
final Duration duration;
const ControllerData(this.height, this.duration);
}
class MiniplayerController extends ValueNotifier<ControllerData> {
MiniplayerController() : super(null);
void animateToHeight(
{double height, PanelState state, Duration duration}) {
if (height == null && state == null) return;
if (height != null && state != null) return;
ControllerData valBefore = value;
if (state != null)
value = ControllerData(state.heightCode, duration);
else {
if (height < 0) return;
value = ControllerData(height.round(), duration);
}
if (valBefore == value) notifyListeners();
}
void dismiss() {}
}

View File

@ -1,4 +1,19 @@
enum SnapPosition { MAX, MIN, DISMISS } import 'package:miniplayer/miniplayer.dart';
extension SelectedColorExtension on PanelState {
int get heightCode {
switch (this) {
case PanelState.MIN:
return -1;
case PanelState.MAX:
return -2;
case PanelState.DISMISS:
return -3;
default:
return -1;
}
}
}
///Calculates the percentage of a value within a given range of values ///Calculates the percentage of a value within a given range of values
double percentageFromValueInRange({final double min, max, value}) { double percentageFromValueInRange({final double min, max, value}) {

View File

@ -5,7 +5,7 @@ homepage: https://www.peterscode.dev
repository: https://github.com/peterscodee/miniplayer repository: https://github.com/peterscodee/miniplayer
environment: environment:
sdk: ">=2.3.0 <3.0.0" sdk: ">=2.6.0 <3.0.0"
flutter: ">=1.0.0 <2.0.0" flutter: ">=1.0.0 <2.0.0"
dependencies: dependencies: