Null-safety support
This commit is contained in:
parent
d99551203d
commit
36db28ce11
|
@ -34,24 +34,24 @@ class Miniplayer extends StatefulWidget {
|
||||||
|
|
||||||
///Allows you to use a global ValueNotifier with the current progress.
|
///Allows you to use a global ValueNotifier with the current progress.
|
||||||
///This can be used to hide the BottomNavigationBar.
|
///This can be used to hide the BottomNavigationBar.
|
||||||
final ValueNotifier<double> valueNotifier;
|
final ValueNotifier<double>? valueNotifier;
|
||||||
|
|
||||||
///Deprecated
|
///Deprecated
|
||||||
@Deprecated(
|
@Deprecated(
|
||||||
"Migrate onDismiss to onDismissed as onDismiss will be used differently in a future version.")
|
"Migrate onDismiss to onDismissed as onDismiss will be used differently in a future version.")
|
||||||
final Function onDismiss;
|
final Function? onDismiss;
|
||||||
|
|
||||||
///If onDismissed is set, the miniplayer can be dismissed
|
///If onDismissed is set, the miniplayer can be dismissed
|
||||||
final Function onDismissed;
|
final Function? onDismissed;
|
||||||
|
|
||||||
//Allows you to manually control the miniplayer in code
|
//Allows you to manually control the miniplayer in code
|
||||||
final MiniplayerController controller;
|
final MiniplayerController? controller;
|
||||||
|
|
||||||
const Miniplayer({
|
const Miniplayer({
|
||||||
Key key,
|
Key? key,
|
||||||
@required this.minHeight,
|
required this.minHeight,
|
||||||
@required this.maxHeight,
|
required this.maxHeight,
|
||||||
@required this.builder,
|
required this.builder,
|
||||||
this.curve = Curves.easeOut,
|
this.curve = Curves.easeOut,
|
||||||
this.elevation = 0,
|
this.elevation = 0,
|
||||||
this.backgroundColor = const Color(0x70000000),
|
this.backgroundColor = const Color(0x70000000),
|
||||||
|
@ -67,17 +67,17 @@ class Miniplayer extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
ValueNotifier<double> heightNotifier;
|
late ValueNotifier<double> heightNotifier;
|
||||||
ValueNotifier<double> dragDownPercentage = ValueNotifier(0);
|
ValueNotifier<double> dragDownPercentage = ValueNotifier(0);
|
||||||
|
|
||||||
///Temporary variable as long as onDismiss is deprecated. Will be removed in a future version.
|
///Temporary variable as long as onDismiss is deprecated. Will be removed in a future version.
|
||||||
Function onDismissed;
|
Function? onDismissed;
|
||||||
|
|
||||||
///Current y position of drag gesture
|
///Current y position of drag gesture
|
||||||
double _dragHeight;
|
late double _dragHeight;
|
||||||
|
|
||||||
///Used to determine SnapPosition
|
///Used to determine SnapPosition
|
||||||
double _startHeight;
|
double? _startHeight;
|
||||||
|
|
||||||
bool dismissed = false;
|
bool dismissed = false;
|
||||||
|
|
||||||
|
@ -88,19 +88,19 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
|
|
||||||
StreamController<double> _heightController =
|
StreamController<double> _heightController =
|
||||||
StreamController<double>.broadcast();
|
StreamController<double>.broadcast();
|
||||||
AnimationController _animationController;
|
AnimationController? _animationController;
|
||||||
|
|
||||||
void _statusListener(AnimationStatus status) {
|
void _statusListener(AnimationStatus status) {
|
||||||
if (status == AnimationStatus.completed) _resetAnimationController();
|
if (status == AnimationStatus.completed) _resetAnimationController();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _resetAnimationController({Duration duration}) {
|
void _resetAnimationController({Duration? duration}) {
|
||||||
if (_animationController != null) _animationController.dispose();
|
if (_animationController != null) _animationController!.dispose();
|
||||||
_animationController = AnimationController(
|
_animationController = AnimationController(
|
||||||
vsync: this,
|
vsync: this,
|
||||||
duration: duration == null ? widget.duration : duration,
|
duration: duration == null ? widget.duration : duration,
|
||||||
);
|
);
|
||||||
_animationController.addStatusListener(_statusListener);
|
_animationController!.addStatusListener(_statusListener);
|
||||||
animating = false;
|
animating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,14 +109,14 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
if (widget.valueNotifier == null)
|
if (widget.valueNotifier == null)
|
||||||
heightNotifier = ValueNotifier(widget.minHeight);
|
heightNotifier = ValueNotifier(widget.minHeight);
|
||||||
else
|
else
|
||||||
heightNotifier = widget.valueNotifier;
|
heightNotifier = widget.valueNotifier!;
|
||||||
|
|
||||||
_resetAnimationController();
|
_resetAnimationController();
|
||||||
|
|
||||||
_dragHeight = heightNotifier.value;
|
_dragHeight = heightNotifier.value;
|
||||||
|
|
||||||
if (widget.controller != null)
|
if (widget.controller != null)
|
||||||
widget.controller.addListener(controllerListener);
|
widget.controller!.addListener(controllerListener);
|
||||||
|
|
||||||
if (widget.onDismissed != null)
|
if (widget.onDismissed != null)
|
||||||
onDismissed = widget.onDismissed;
|
onDismissed = widget.onDismissed;
|
||||||
|
@ -130,10 +130,10 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_heightController.close();
|
_heightController.close();
|
||||||
_animationController.dispose();
|
_animationController!.dispose();
|
||||||
|
|
||||||
if (widget.controller != null)
|
if (widget.controller != null)
|
||||||
widget.controller.removeListener(controllerListener);
|
widget.controller!.removeListener(controllerListener);
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -143,9 +143,9 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
if (dismissed) return Container();
|
if (dismissed) return Container();
|
||||||
|
|
||||||
return ValueListenableBuilder(
|
return ValueListenableBuilder(
|
||||||
builder: (BuildContext context, double value, Widget child) {
|
builder: (BuildContext context, double? value, Widget? child) {
|
||||||
var _percentage = ((value - widget.minHeight)) /
|
var _percentage =
|
||||||
(widget.maxHeight - widget.minHeight);
|
(value! - widget.minHeight) / (widget.maxHeight - widget.minHeight);
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
|
@ -166,12 +166,14 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
child: ValueListenableBuilder(
|
child: ValueListenableBuilder(
|
||||||
valueListenable: dragDownPercentage,
|
valueListenable: dragDownPercentage,
|
||||||
builder: (context, value, child) {
|
builder: (context, dynamic value, child) {
|
||||||
if (value == 0) return child;
|
if (value == 0) return child!;
|
||||||
|
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: borderDouble(
|
opacity: borderDouble(
|
||||||
minRange: 0, maxRange: 1, value: 1 - value * 0.8),
|
minRange: 0,
|
||||||
|
maxRange: 1,
|
||||||
|
value: 1 - value * 0.8 as double),
|
||||||
child: Transform.translate(
|
child: Transform.translate(
|
||||||
offset: Offset(0.0, widget.minHeight * value * 0.5),
|
offset: Offset(0.0, widget.minHeight * value * 0.5),
|
||||||
child: child,
|
child: child,
|
||||||
|
@ -206,12 +208,12 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
},
|
},
|
||||||
onPanEnd: (details) async {
|
onPanEnd: (details) async {
|
||||||
///Calculates drag speed
|
///Calculates drag speed
|
||||||
double speed =
|
double speed = (_dragHeight - _startHeight! * _dragHeight <
|
||||||
(_dragHeight - _startHeight * _dragHeight < _startHeight
|
_startHeight!
|
||||||
? 1
|
? 1
|
||||||
: -1) /
|
: -1) /
|
||||||
updateCount *
|
updateCount *
|
||||||
100;
|
100;
|
||||||
|
|
||||||
///Define the percentage distance depending on the speed with which the widget should snap
|
///Define the percentage distance depending on the speed with which the widget should snap
|
||||||
double snapPercentage = 0.005;
|
double snapPercentage = 0.005;
|
||||||
|
@ -230,7 +232,7 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
value: _dragHeight);
|
value: _dragHeight);
|
||||||
|
|
||||||
///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 = PanelState.MAX;
|
snap = PanelState.MAX;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +296,7 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
dragDownPercentage.value = percentageDown;
|
dragDownPercentage.value = percentageDown;
|
||||||
|
|
||||||
if (percentageDown >= 1 && animation && !dismissed) {
|
if (percentageDown >= 1 && animation && !dismissed) {
|
||||||
if (onDismissed != null) onDismissed();
|
if (onDismissed != null) onDismissed!();
|
||||||
setState(() {
|
setState(() {
|
||||||
dismissed = true;
|
dismissed = true;
|
||||||
});
|
});
|
||||||
|
@ -318,7 +320,7 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
}
|
}
|
||||||
|
|
||||||
///Animates the panel height to a specific value
|
///Animates the panel height to a specific value
|
||||||
void _animateToHeight(final double h, {Duration duration}) {
|
void _animateToHeight(final double h, {Duration? duration}) {
|
||||||
final startHeight = _dragHeight;
|
final startHeight = _dragHeight;
|
||||||
|
|
||||||
if (duration != null) _resetAnimationController(duration: duration);
|
if (duration != null) _resetAnimationController(duration: duration);
|
||||||
|
@ -327,7 +329,7 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
begin: startHeight,
|
begin: startHeight,
|
||||||
end: h,
|
end: h,
|
||||||
).animate(
|
).animate(
|
||||||
CurvedAnimation(parent: _animationController, curve: widget.curve));
|
CurvedAnimation(parent: _animationController!, curve: widget.curve));
|
||||||
|
|
||||||
_sizeAnimation.addListener(() {
|
_sizeAnimation.addListener(() {
|
||||||
if (_sizeAnimation.value == startHeight) return;
|
if (_sizeAnimation.value == startHeight) return;
|
||||||
|
@ -338,34 +340,35 @@ class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
||||||
});
|
});
|
||||||
|
|
||||||
animating = true;
|
animating = true;
|
||||||
_animationController.forward(from: 0);
|
_animationController!.forward(from: 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Listener function for the controller
|
///Listener function for the controller
|
||||||
|
///Controller is always non-null as listener is only added after a null check
|
||||||
void controllerListener() {
|
void controllerListener() {
|
||||||
switch (widget.controller.value.height) {
|
switch (widget.controller!.value!.height) {
|
||||||
case -1:
|
case -1:
|
||||||
_animateToHeight(
|
_animateToHeight(
|
||||||
widget.minHeight,
|
widget.minHeight,
|
||||||
duration: widget.controller.value.duration,
|
duration: widget.controller!.value!.duration,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case -2:
|
case -2:
|
||||||
_animateToHeight(
|
_animateToHeight(
|
||||||
widget.maxHeight,
|
widget.maxHeight,
|
||||||
duration: widget.controller.value.duration,
|
duration: widget.controller!.value!.duration,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case -3:
|
case -3:
|
||||||
_animateToHeight(
|
_animateToHeight(
|
||||||
0,
|
0,
|
||||||
duration: widget.controller.value.duration,
|
duration: widget.controller!.value!.duration,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_animateToHeight(
|
_animateToHeight(
|
||||||
widget.controller.value.height.toDouble(),
|
widget.controller!.value!.height.toDouble(),
|
||||||
duration: widget.controller.value.duration,
|
duration: widget.controller!.value!.duration,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -378,29 +381,30 @@ enum PanelState { MAX, MIN, DISMISS }
|
||||||
//ControllerData class. Used for the controller
|
//ControllerData class. Used for the controller
|
||||||
class ControllerData {
|
class ControllerData {
|
||||||
final int height;
|
final int height;
|
||||||
final Duration duration;
|
final Duration? duration;
|
||||||
|
|
||||||
const ControllerData(this.height, this.duration);
|
const ControllerData(this.height, this.duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
//MiniplayerController class
|
//MiniplayerController class
|
||||||
class MiniplayerController extends ValueNotifier<ControllerData> {
|
class MiniplayerController extends ValueNotifier<ControllerData?> {
|
||||||
MiniplayerController() : super(null);
|
MiniplayerController() : super(null);
|
||||||
|
|
||||||
//Animates to a given height or state(expanded, dismissed, ...)
|
//Animates to a given height or state(expanded, dismissed, ...)
|
||||||
void animateToHeight({double height, PanelState state, Duration duration}) {
|
void animateToHeight(
|
||||||
|
{double? height, PanelState? state, Duration? duration}) {
|
||||||
if (height == null && state == null)
|
if (height == null && state == null)
|
||||||
throw ("Miniplayer: One of the two parameters, height or status, is required.");
|
throw ("Miniplayer: One of the two parameters, height or status, is required.");
|
||||||
|
|
||||||
if (height != null && state != null)
|
if (height != null && state != null)
|
||||||
throw ("Miniplayer: Only one of the two parameters, height or status, can be specified.");
|
throw ("Miniplayer: Only one of the two parameters, height or status, can be specified.");
|
||||||
|
|
||||||
ControllerData valBefore = value;
|
ControllerData? valBefore = value;
|
||||||
|
|
||||||
if (state != null)
|
if (state != null)
|
||||||
value = ControllerData(state.heightCode, duration);
|
value = ControllerData(state.heightCode, duration);
|
||||||
else {
|
else {
|
||||||
if (height < 0) return;
|
if (height! < 0) return;
|
||||||
|
|
||||||
value = ControllerData(height.round(), duration);
|
value = ControllerData(height.round(), duration);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,16 @@ extension SelectedColorExtension on PanelState {
|
||||||
}
|
}
|
||||||
|
|
||||||
///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(
|
||||||
|
{required double min, required max, required value}) {
|
||||||
return (value - min) / (max - min);
|
return (value - min) / (max - min);
|
||||||
}
|
}
|
||||||
|
|
||||||
double borderDouble({double minRange, double maxRange, double value}) {
|
double borderDouble({
|
||||||
|
required double minRange,
|
||||||
|
required double maxRange,
|
||||||
|
required double value,
|
||||||
|
}) {
|
||||||
if (value > maxRange) return maxRange;
|
if (value > maxRange) return maxRange;
|
||||||
if (value < minRange) return minRange;
|
if (value < minRange) return minRange;
|
||||||
return value;
|
return 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.6.0 <3.0.0"
|
sdk: '>=2.12.0-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