Add MiniplayerController
This commit is contained in:
parent
e1bef9b40f
commit
de7e89f8cf
|
@ -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() {}
|
||||||
|
}
|
||||||
|
|
|
@ -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}) {
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue