Null-safety support

This commit is contained in:
David 2020-11-21 11:52:52 +01:00
parent d99551203d
commit 36db28ce11
3 changed files with 61 additions and 52 deletions

View File

@ -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);
} }

View File

@ -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;

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.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: