diff --git a/example/lib/main.dart b/example/lib/main.dart index 7a16d43..bcccc22 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,7 +3,7 @@ import 'screens/audio_screen.dart'; import 'widgets/player.dart'; import 'utils.dart'; -ValueNotifier currentlyPlaying = ValueNotifier(null); +ValueNotifier currentlyPlaying = ValueNotifier(null); const double playerMinHeight = 70; const double playerMaxHeight = 370; @@ -48,30 +48,20 @@ class _MyHomePageState extends State { ), ValueListenableBuilder( valueListenable: currentlyPlaying, - builder: - (BuildContext context, AudioObject audioObject, Widget child) => - audioObject != null - ? DetailedPlayer(audioObject: audioObject) - : Container(), + builder: (BuildContext context, AudioObject? audioObject, + Widget? child) => + audioObject != null + ? DetailedPlayer(audioObject: audioObject) + : Container(), ), ], ), bottomNavigationBar: ValueListenableBuilder( valueListenable: playerExpandProgress, - child: BottomNavigationBar( - currentIndex: 0, - selectedItemColor: Colors.blue, - items: [ - BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Feed'), - BottomNavigationBarItem( - icon: Icon(Icons.library_books), label: 'Library'), - ], - ), - builder: (BuildContext context, double height, Widget child) { + builder: (BuildContext context, double height, Widget? child) { final value = percentageFromValueInRange( min: playerMinHeight, max: playerMaxHeight, value: height); - if (value == null) return child; var opacity = 1 - value; if (opacity < 0) opacity = 0; if (opacity > 1) opacity = 1; @@ -85,6 +75,15 @@ class _MyHomePageState extends State { ), ); }, + child: BottomNavigationBar( + currentIndex: 0, + selectedItemColor: Colors.blue, + items: [ + BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Feed'), + BottomNavigationBarItem( + icon: Icon(Icons.library_books), label: 'Library'), + ], + ), ), ); } diff --git a/example/lib/screens/audio_screen.dart b/example/lib/screens/audio_screen.dart index 787ae58..1067d5d 100644 --- a/example/lib/screens/audio_screen.dart +++ b/example/lib/screens/audio_screen.dart @@ -27,7 +27,7 @@ const Set audioExamples = { class AudioUi extends StatelessWidget { final OnTap onTap; - const AudioUi({Key key, @required this.onTap}) : super(key: key); + const AudioUi({Key? key, required this.onTap}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/example/lib/utils.dart b/example/lib/utils.dart index bcc1219..400a92d 100644 --- a/example/lib/utils.dart +++ b/example/lib/utils.dart @@ -1,5 +1,3 @@ -import 'package:flutter/foundation.dart'; - class AudioObject { final String title, subtitle, img; @@ -7,10 +5,10 @@ class AudioObject { } double valueFromPercentageInRange( - {@required final double min, max, percentage}) { + {required final double min, max, percentage}) { return percentage * (max - min) + min; } -double percentageFromValueInRange({@required final double min, max, value}) { +double percentageFromValueInRange({required final double min, max, value}) { return (value - min) / (max - min); } diff --git a/example/lib/widgets/audio_list_tile.dart b/example/lib/widgets/audio_list_tile.dart index 649db37..8ee49b5 100644 --- a/example/lib/widgets/audio_list_tile.dart +++ b/example/lib/widgets/audio_list_tile.dart @@ -9,7 +9,7 @@ class AudioListTile extends StatelessWidget { final Function onTap; const AudioListTile( - {Key key, @required this.audioObject, @required this.onTap}) + {Key? key, required this.audioObject, required this.onTap}) : super(key: key); @override @@ -32,7 +32,7 @@ class AudioListTile extends StatelessWidget { ), trailing: IconButton( icon: Icon(Icons.play_arrow_outlined), - onPressed: onTap, + onPressed: () => onTap(), ), ); } diff --git a/example/lib/widgets/player.dart b/example/lib/widgets/player.dart index 6bf7951..c630d75 100644 --- a/example/lib/widgets/player.dart +++ b/example/lib/widgets/player.dart @@ -12,7 +12,7 @@ final MiniplayerController controller = MiniplayerController(); class DetailedPlayer extends StatelessWidget { final AudioObject audioObject; - const DetailedPlayer({Key key, @required this.audioObject}) : super(key: key); + const DetailedPlayer({Key? key, required this.audioObject}) : super(key: key); @override Widget build(BuildContext context) { @@ -150,13 +150,13 @@ class DetailedPlayer extends StatelessWidget { Text(audioObject.title, style: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .copyWith(fontSize: 16)), Text( audioObject.subtitle, style: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .copyWith( color: Colors.black.withOpacity(0.55)), ), diff --git a/lib/miniplayer.dart b/lib/miniplayer.dart index ada35bd..78b5d7d 100644 --- a/lib/miniplayer.dart +++ b/lib/miniplayer.dart @@ -37,24 +37,24 @@ class Miniplayer extends StatefulWidget { ///Allows you to use a global ValueNotifier with the current progress. ///This can be used to hide the BottomNavigationBar. - final ValueNotifier valueNotifier; + final ValueNotifier? valueNotifier; ///Deprecated @Deprecated( "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 - final Function onDismissed; + final Function? onDismissed; //Allows you to manually control the miniplayer in code - final MiniplayerController controller; + final MiniplayerController? controller; const Miniplayer({ - Key key, - @required this.minHeight, - @required this.maxHeight, - @required this.builder, + Key? key, + required this.minHeight, + required this.maxHeight, + required this.builder, this.curve = Curves.easeOut, this.elevation = 0, this.backgroundColor = const Color(0x70000000), @@ -70,17 +70,17 @@ class Miniplayer extends StatefulWidget { } class _MiniplayerState extends State with TickerProviderStateMixin { - ValueNotifier heightNotifier; + late ValueNotifier heightNotifier; ValueNotifier dragDownPercentage = ValueNotifier(0); ///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 - double _dragHeight; + late double _dragHeight; ///Used to determine SnapPosition - double _startHeight; + late double _startHeight; bool dismissed = false; @@ -91,19 +91,19 @@ class _MiniplayerState extends State with TickerProviderStateMixin { StreamController _heightController = StreamController.broadcast(); - AnimationController _animationController; + AnimationController? _animationController; void _statusListener(AnimationStatus status) { if (status == AnimationStatus.completed) _resetAnimationController(); } - void _resetAnimationController({Duration duration}) { - if (_animationController != null) _animationController.dispose(); + void _resetAnimationController({Duration? duration}) { + if (_animationController != null) _animationController!.dispose(); _animationController = AnimationController( vsync: this, - duration: duration == null ? widget.duration : duration, + duration: duration ?? widget.duration, ); - _animationController.addStatusListener(_statusListener); + _animationController!.addStatusListener(_statusListener); animating = false; } @@ -112,14 +112,14 @@ class _MiniplayerState extends State with TickerProviderStateMixin { if (widget.valueNotifier == null) heightNotifier = ValueNotifier(widget.minHeight); else - heightNotifier = widget.valueNotifier; + heightNotifier = widget.valueNotifier!; _resetAnimationController(); _dragHeight = heightNotifier.value; if (widget.controller != null) - widget.controller.addListener(controllerListener); + widget.controller!.addListener(controllerListener); if (widget.onDismissed != null) onDismissed = widget.onDismissed; @@ -133,10 +133,10 @@ class _MiniplayerState extends State with TickerProviderStateMixin { @override void dispose() { _heightController.close(); - _animationController.dispose(); + if (_animationController != null) _animationController!.dispose(); if (widget.controller != null) - widget.controller.removeListener(controllerListener); + widget.controller!.removeListener(controllerListener); super.dispose(); } @@ -154,8 +154,9 @@ class _MiniplayerState extends State with TickerProviderStateMixin { return true; }, child: ValueListenableBuilder( - builder: (BuildContext context, double value, Widget child) { - var _percentage = ((value - widget.minHeight)) / + valueListenable: heightNotifier, + builder: (BuildContext context, double height, Widget? _) { + var _percentage = ((height - widget.minHeight)) / (widget.maxHeight - widget.minHeight); return Stack( @@ -173,12 +174,13 @@ class _MiniplayerState extends State with TickerProviderStateMixin { Align( alignment: Alignment.bottomCenter, child: SizedBox( - height: value, + height: height, child: GestureDetector( child: ValueListenableBuilder( valueListenable: dragDownPercentage, - builder: (context, value, child) { - if (value == 0) return child; + builder: + (BuildContext context, double value, Widget? child) { + if (value == 0) return child!; return Opacity( opacity: borderDouble( @@ -193,7 +195,7 @@ class _MiniplayerState extends State with TickerProviderStateMixin { color: Theme.of(context).canvasColor, child: Container( constraints: BoxConstraints.expand(), - child: widget.builder(value, _percentage), + child: widget.builder(height, _percentage), decoration: BoxDecoration( boxShadow: [ BoxShadow( @@ -278,7 +280,6 @@ class _MiniplayerState extends State with TickerProviderStateMixin { ], ); }, - valueListenable: heightNotifier, ), ); } @@ -306,7 +307,7 @@ class _MiniplayerState extends State with TickerProviderStateMixin { dragDownPercentage.value = percentageDown; if (percentageDown >= 1 && animation && !dismissed) { - if (onDismissed != null) onDismissed(); + if (onDismissed != null) onDismissed!(); setState(() { dismissed = true; }); @@ -330,7 +331,8 @@ class _MiniplayerState extends State with TickerProviderStateMixin { } ///Animates the panel height to a specific value - void _animateToHeight(final double h, {Duration duration}) { + void _animateToHeight(final double h, {Duration? duration}) { + if (_animationController == null) return; final startHeight = _dragHeight; if (duration != null) _resetAnimationController(duration: duration); @@ -339,7 +341,7 @@ class _MiniplayerState extends State with TickerProviderStateMixin { begin: startHeight, end: h, ).animate( - CurvedAnimation(parent: _animationController, curve: widget.curve)); + CurvedAnimation(parent: _animationController!, curve: widget.curve)); _sizeAnimation.addListener(() { if (_sizeAnimation.value == startHeight) return; @@ -350,34 +352,37 @@ class _MiniplayerState extends State with TickerProviderStateMixin { }); animating = true; - _animationController.forward(from: 0); + _animationController!.forward(from: 0); } //Listener function for the controller void controllerListener() { - switch (widget.controller.value.height) { + if (widget.controller == null) return; + if (widget.controller!.value == null) return; + + switch (widget.controller!.value!.height) { case -1: _animateToHeight( widget.minHeight, - duration: widget.controller.value.duration, + duration: widget.controller!.value!.duration, ); break; case -2: _animateToHeight( widget.maxHeight, - duration: widget.controller.value.duration, + duration: widget.controller!.value!.duration, ); break; case -3: _animateToHeight( 0, - duration: widget.controller.value.duration, + duration: widget.controller!.value!.duration, ); break; default: _animateToHeight( - widget.controller.value.height.toDouble(), - duration: widget.controller.value.duration, + widget.controller!.value!.height.toDouble(), + duration: widget.controller!.value!.duration, ); break; } @@ -390,29 +395,30 @@ enum PanelState { MAX, MIN, DISMISS } //ControllerData class. Used for the controller class ControllerData { final int height; - final Duration duration; + final Duration? duration; const ControllerData(this.height, this.duration); } //MiniplayerController class -class MiniplayerController extends ValueNotifier { +class MiniplayerController extends ValueNotifier { MiniplayerController() : super(null); //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) throw ("Miniplayer: One of the two parameters, height or status, is required."); if (height != null && state != null) throw ("Miniplayer: Only one of the two parameters, height or status, can be specified."); - ControllerData valBefore = value; + ControllerData? valBefore = value; if (state != null) value = ControllerData(state.heightCode, duration); else { - if (height < 0) return; + if (height! < 0) return; value = ControllerData(height.round(), duration); } diff --git a/lib/src/miniplayer_will_pop_scope.dart b/lib/src/miniplayer_will_pop_scope.dart index 5a1cb08..799b5bf 100644 --- a/lib/src/miniplayer_will_pop_scope.dart +++ b/lib/src/miniplayer_will_pop_scope.dart @@ -2,11 +2,10 @@ import 'package:flutter/material.dart'; class MiniplayerWillPopScope extends StatefulWidget { const MiniplayerWillPopScope({ - Key key, - @required this.child, - @required this.onWillPop, - }) : assert(child != null), - super(key: key); + Key? key, + required this.child, + required this.onWillPop, + }) : super(key: key); final Widget child; final WillPopCallback onWillPop; @@ -14,15 +13,15 @@ class MiniplayerWillPopScope extends StatefulWidget { @override _MiniplayerWillPopScopeState createState() => _MiniplayerWillPopScopeState(); - static _MiniplayerWillPopScopeState of(BuildContext context) { + static _MiniplayerWillPopScopeState? of(BuildContext context) { return context.findAncestorStateOfType<_MiniplayerWillPopScopeState>(); } } class _MiniplayerWillPopScopeState extends State { - ModalRoute _route; + ModalRoute? _route; - _MiniplayerWillPopScopeState _descendant; + _MiniplayerWillPopScopeState? _descendant; set descendant(state) { _descendant = state; @@ -30,11 +29,11 @@ class _MiniplayerWillPopScopeState extends State { } Future onWillPop() async { - bool willPop; + bool? willPop; if (_descendant != null) { - willPop = await _descendant.onWillPop(); + willPop = await _descendant!.onWillPop(); } - if (willPop == null || willPop) { + if (willPop == null) { willPop = await widget.onWillPop(); } return willPop; diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 28134a2..d324afd 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -16,11 +16,11 @@ extension SelectedColorExtension on PanelState { } ///Calculates the percentage of a value within a given range of values -double percentageFromValueInRange({final double min, max, value}) { +double percentageFromValueInRange({required double min, max, value}) { return (value - min) / (max - min); } -double borderDouble({double minRange, double maxRange, double value}) { +double borderDouble({required double minRange, maxRange, value}) { if (value > maxRange) return maxRange; if (value < minRange) return minRange; return value; diff --git a/pubspec.yaml b/pubspec.yaml index f6f0ec3..283edee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,8 +5,8 @@ homepage: https://www.peterscode.dev repository: https://github.com/peterscodee/miniplayer environment: - sdk: ">=2.6.0 <3.0.0" - flutter: ">=1.0.0 <2.0.0" + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.0.1 <3.0.0" dependencies: flutter: