2020-07-29 22:13:39 +02:00
|
|
|
library miniplayer;
|
|
|
|
|
2020-07-29 22:32:28 +02:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
2021-01-16 09:34:09 +01:00
|
|
|
import 'package:miniplayer/src/miniplayer_will_pop_scope.dart';
|
2020-09-26 15:12:50 +02:00
|
|
|
import 'package:miniplayer/src/utils.dart';
|
2020-07-29 22:32:28 +02:00
|
|
|
|
2021-01-16 09:34:09 +01:00
|
|
|
export 'package:miniplayer/src/miniplayer_will_pop_scope.dart';
|
|
|
|
|
2020-09-26 15:13:06 +02:00
|
|
|
///Type definition for the builder function
|
2020-07-29 22:32:28 +02:00
|
|
|
typedef Widget MiniplayerBuilder(double height, double percentage);
|
|
|
|
|
2020-11-21 11:32:25 +01:00
|
|
|
///Type definition for onDismiss. Will be used in a future version.
|
|
|
|
typedef void DismissCallback(double percentage);
|
|
|
|
|
2020-11-11 10:57:47 +01:00
|
|
|
///Miniplayer class
|
2020-07-29 22:32:28 +02:00
|
|
|
class Miniplayer extends StatefulWidget {
|
2020-09-26 15:13:06 +02:00
|
|
|
///Required option to set the minimum and maximum height
|
|
|
|
final double minHeight, maxHeight;
|
|
|
|
|
|
|
|
///Option to enable and set elevation for the miniplayer
|
|
|
|
final double elevation;
|
|
|
|
|
|
|
|
///Central API-Element
|
|
|
|
///Provides a builder with useful information
|
2020-07-29 22:32:28 +02:00
|
|
|
final MiniplayerBuilder builder;
|
2020-09-26 15:13:06 +02:00
|
|
|
|
|
|
|
///Option to set the animation curve
|
2020-07-29 22:32:28 +02:00
|
|
|
final Curve curve;
|
2020-09-26 15:13:06 +02:00
|
|
|
|
|
|
|
///Sets the background-color of the miniplayer
|
2020-07-31 10:02:40 +02:00
|
|
|
final Color backgroundColor;
|
2020-09-26 15:13:06 +02:00
|
|
|
|
|
|
|
///Option to set the animation duration
|
2020-08-26 16:40:39 +02:00
|
|
|
final Duration duration;
|
2020-09-26 15:13:06 +02:00
|
|
|
|
|
|
|
///Allows you to use a global ValueNotifier with the current progress.
|
|
|
|
///This can be used to hide the BottomNavigationBar.
|
2020-11-21 11:52:52 +01:00
|
|
|
final ValueNotifier<double>? valueNotifier;
|
2020-09-26 15:13:06 +02:00
|
|
|
|
2020-11-21 11:32:25 +01:00
|
|
|
///Deprecated
|
|
|
|
@Deprecated(
|
|
|
|
"Migrate onDismiss to onDismissed as onDismiss will be used differently in a future version.")
|
2020-11-21 11:52:52 +01:00
|
|
|
final Function? onDismiss;
|
2020-07-29 22:32:28 +02:00
|
|
|
|
2020-11-21 11:32:25 +01:00
|
|
|
///If onDismissed is set, the miniplayer can be dismissed
|
2020-11-21 11:52:52 +01:00
|
|
|
final Function? onDismissed;
|
2020-11-21 11:32:25 +01:00
|
|
|
|
2020-11-11 10:57:47 +01:00
|
|
|
//Allows you to manually control the miniplayer in code
|
2020-11-21 11:52:52 +01:00
|
|
|
final MiniplayerController? controller;
|
2020-10-06 20:57:24 +02:00
|
|
|
|
2020-07-30 17:01:37 +02:00
|
|
|
const Miniplayer({
|
2020-11-21 11:52:52 +01:00
|
|
|
Key? key,
|
|
|
|
required this.minHeight,
|
|
|
|
required this.maxHeight,
|
|
|
|
required this.builder,
|
2020-09-21 13:30:22 +02:00
|
|
|
this.curve = Curves.easeOut,
|
2020-07-30 17:01:37 +02:00
|
|
|
this.elevation = 0,
|
2020-07-31 10:02:40 +02:00
|
|
|
this.backgroundColor = const Color(0x70000000),
|
2020-08-03 10:43:54 +02:00
|
|
|
this.valueNotifier,
|
2020-08-26 16:40:39 +02:00
|
|
|
this.duration = const Duration(milliseconds: 300),
|
2020-09-20 18:42:43 +02:00
|
|
|
this.onDismiss,
|
2020-11-21 11:32:25 +01:00
|
|
|
this.onDismissed,
|
2020-10-06 20:57:24 +02:00
|
|
|
this.controller,
|
2020-07-30 17:01:37 +02:00
|
|
|
}) : super(key: key);
|
2020-07-29 22:32:28 +02:00
|
|
|
|
|
|
|
@override
|
|
|
|
_MiniplayerState createState() => _MiniplayerState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _MiniplayerState extends State<Miniplayer> with TickerProviderStateMixin {
|
2020-11-21 11:52:52 +01:00
|
|
|
late ValueNotifier<double> heightNotifier;
|
2020-09-20 18:42:43 +02:00
|
|
|
ValueNotifier<double> dragDownPercentage = ValueNotifier(0);
|
|
|
|
|
2020-11-21 11:32:25 +01:00
|
|
|
///Temporary variable as long as onDismiss is deprecated. Will be removed in a future version.
|
2020-11-21 11:52:52 +01:00
|
|
|
Function? onDismissed;
|
2020-09-20 18:42:43 +02:00
|
|
|
|
|
|
|
///Current y position of drag gesture
|
2020-11-21 11:52:52 +01:00
|
|
|
late double _dragHeight;
|
2020-08-03 10:43:54 +02:00
|
|
|
|
2020-09-20 18:42:43 +02:00
|
|
|
///Used to determine SnapPosition
|
2021-03-06 15:26:00 +01:00
|
|
|
late double _startHeight;
|
2020-07-29 22:32:28 +02:00
|
|
|
|
2020-09-20 18:42:43 +02:00
|
|
|
bool dismissed = false;
|
|
|
|
|
|
|
|
bool animating = false;
|
2020-07-29 22:32:28 +02:00
|
|
|
|
2020-09-21 00:12:58 +02:00
|
|
|
///Counts how many updates were required for a distance (onPanUpdate) -> necessary to calculate the drag speed
|
|
|
|
int updateCount = 0;
|
|
|
|
|
2020-07-29 22:32:28 +02:00
|
|
|
StreamController<double> _heightController =
|
|
|
|
StreamController<double>.broadcast();
|
2020-11-21 11:52:52 +01:00
|
|
|
AnimationController? _animationController;
|
2020-09-20 18:42:43 +02:00
|
|
|
|
2020-09-23 08:06:05 +02:00
|
|
|
void _statusListener(AnimationStatus status) {
|
2020-09-23 08:19:07 +02:00
|
|
|
if (status == AnimationStatus.completed) _resetAnimationController();
|
|
|
|
}
|
|
|
|
|
2020-11-21 11:52:52 +01:00
|
|
|
void _resetAnimationController({Duration? duration}) {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (_animationController != null) {
|
|
|
|
_animationController!.dispose();
|
|
|
|
}
|
2020-09-23 08:19:07 +02:00
|
|
|
_animationController = AnimationController(
|
|
|
|
vsync: this,
|
2021-03-06 15:26:00 +01:00
|
|
|
duration: duration ?? widget.duration,
|
2020-09-23 08:19:07 +02:00
|
|
|
);
|
2020-11-21 11:52:52 +01:00
|
|
|
_animationController!.addStatusListener(_statusListener);
|
2020-09-23 08:19:07 +02:00
|
|
|
animating = false;
|
2020-09-20 18:42:43 +02:00
|
|
|
}
|
2020-07-29 22:32:28 +02:00
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (widget.valueNotifier == null) {
|
2020-08-03 10:43:54 +02:00
|
|
|
heightNotifier = ValueNotifier(widget.minHeight);
|
2021-11-10 23:01:47 +01:00
|
|
|
} else {
|
2020-11-21 11:52:52 +01:00
|
|
|
heightNotifier = widget.valueNotifier!;
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-08-03 10:43:54 +02:00
|
|
|
|
2020-09-23 08:19:07 +02:00
|
|
|
_resetAnimationController();
|
2020-09-20 18:42:43 +02:00
|
|
|
|
2020-10-09 20:40:09 +02:00
|
|
|
_dragHeight = heightNotifier.value;
|
2020-07-29 22:32:28 +02:00
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (widget.controller != null) {
|
2020-11-21 11:52:52 +01:00
|
|
|
widget.controller!.addListener(controllerListener);
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-10-06 20:57:24 +02:00
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (widget.onDismissed != null) {
|
2020-11-21 11:32:25 +01:00
|
|
|
onDismissed = widget.onDismissed;
|
2021-11-10 23:01:47 +01:00
|
|
|
} else {
|
2020-11-21 11:32:25 +01:00
|
|
|
// ignore: deprecated_member_use_from_same_package
|
|
|
|
onDismissed = widget.onDismiss;
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-11-21 11:32:25 +01:00
|
|
|
|
2020-07-29 22:32:28 +02:00
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
_heightController.close();
|
2020-10-09 20:52:45 +02:00
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (_animationController != null) {
|
|
|
|
_animationController!.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (widget.controller != null) {
|
2020-11-21 11:52:52 +01:00
|
|
|
widget.controller!.removeListener(controllerListener);
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-10-09 20:52:45 +02:00
|
|
|
|
2020-07-29 22:32:28 +02:00
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (dismissed) {
|
|
|
|
return Container();
|
|
|
|
}
|
2020-09-20 18:42:43 +02:00
|
|
|
|
2021-01-16 09:34:09 +01:00
|
|
|
return MiniplayerWillPopScope(
|
2020-12-15 13:14:16 +01:00
|
|
|
onWillPop: () async {
|
|
|
|
if (heightNotifier.value > widget.minHeight) {
|
|
|
|
_snapToPosition(PanelState.MIN);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
child: ValueListenableBuilder(
|
2021-03-06 15:26:00 +01:00
|
|
|
valueListenable: heightNotifier,
|
|
|
|
builder: (BuildContext context, double height, Widget? _) {
|
|
|
|
var _percentage = ((height - widget.minHeight)) /
|
2020-12-15 13:14:16 +01:00
|
|
|
(widget.maxHeight - widget.minHeight);
|
|
|
|
|
|
|
|
return Stack(
|
|
|
|
alignment: Alignment.bottomCenter,
|
|
|
|
children: [
|
|
|
|
if (_percentage > 0)
|
|
|
|
GestureDetector(
|
|
|
|
onTap: () => _animateToHeight(widget.minHeight),
|
|
|
|
child: Opacity(
|
|
|
|
opacity: borderDouble(
|
2021-06-23 22:17:18 +02:00
|
|
|
minRange: 0.0, maxRange: 1.0, value: _percentage),
|
2020-12-15 13:14:16 +01:00
|
|
|
child: Container(color: widget.backgroundColor),
|
|
|
|
),
|
2020-07-29 22:32:28 +02:00
|
|
|
),
|
2020-12-15 13:14:16 +01:00
|
|
|
Align(
|
|
|
|
alignment: Alignment.bottomCenter,
|
|
|
|
child: SizedBox(
|
2021-03-06 15:26:00 +01:00
|
|
|
height: height,
|
2020-12-15 13:14:16 +01:00
|
|
|
child: GestureDetector(
|
|
|
|
child: ValueListenableBuilder(
|
|
|
|
valueListenable: dragDownPercentage,
|
2021-03-06 15:26:00 +01:00
|
|
|
builder:
|
|
|
|
(BuildContext context, double value, Widget? child) {
|
2020-12-15 13:14:16 +01:00
|
|
|
return Opacity(
|
|
|
|
opacity: borderDouble(
|
2021-06-23 22:17:18 +02:00
|
|
|
minRange: 0.0,
|
|
|
|
maxRange: 1.0,
|
|
|
|
value: 1 - value * 0.8),
|
2020-12-15 13:14:16 +01:00
|
|
|
child: Transform.translate(
|
|
|
|
offset: Offset(0.0, widget.minHeight * value * 0.5),
|
|
|
|
child: child,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
child: Material(
|
|
|
|
child: Container(
|
|
|
|
constraints: BoxConstraints.expand(),
|
2021-03-06 15:26:00 +01:00
|
|
|
child: widget.builder(height, _percentage),
|
2020-12-15 13:14:16 +01:00
|
|
|
decoration: BoxDecoration(
|
|
|
|
boxShadow: <BoxShadow>[
|
|
|
|
BoxShadow(
|
|
|
|
color: Colors.black45,
|
|
|
|
blurRadius: widget.elevation,
|
|
|
|
offset: Offset(0.0, 4))
|
|
|
|
],
|
2022-04-29 13:06:31 +02:00
|
|
|
color: widget.backgroundColor, //kopa
|
2020-12-15 13:14:16 +01:00
|
|
|
),
|
2020-09-20 18:42:43 +02:00
|
|
|
),
|
2020-08-27 11:41:09 +02:00
|
|
|
),
|
2020-07-30 17:01:37 +02:00
|
|
|
),
|
2020-12-15 13:14:16 +01:00
|
|
|
onTap: () => _snapToPosition(_dragHeight != widget.maxHeight
|
|
|
|
? PanelState.MAX
|
|
|
|
: PanelState.MIN),
|
|
|
|
onPanStart: (details) {
|
|
|
|
_startHeight = _dragHeight;
|
|
|
|
updateCount = 0;
|
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (animating) {
|
|
|
|
_resetAnimationController();
|
|
|
|
}
|
2020-12-15 13:14:16 +01:00
|
|
|
},
|
|
|
|
onPanEnd: (details) async {
|
|
|
|
///Calculates drag speed
|
|
|
|
double speed = (_dragHeight - _startHeight * _dragHeight <
|
|
|
|
_startHeight
|
|
|
|
? 1
|
|
|
|
: -1) /
|
|
|
|
updateCount *
|
|
|
|
100;
|
|
|
|
|
|
|
|
///Define the percentage distance depending on the speed with which the widget should snap
|
|
|
|
double snapPercentage = 0.005;
|
2021-11-10 23:01:47 +01:00
|
|
|
if (speed <= 4) {
|
2020-12-15 13:14:16 +01:00
|
|
|
snapPercentage = 0.2;
|
2021-11-10 23:01:47 +01:00
|
|
|
} else if (speed <= 9) {
|
2020-12-15 13:14:16 +01:00
|
|
|
snapPercentage = 0.08;
|
2021-11-10 23:01:47 +01:00
|
|
|
} else if (speed <= 50) {
|
|
|
|
snapPercentage = 0.01;
|
|
|
|
}
|
2020-12-15 13:14:16 +01:00
|
|
|
|
|
|
|
///Determine to which SnapPosition the widget should snap
|
|
|
|
PanelState snap = PanelState.MIN;
|
|
|
|
|
|
|
|
final _percentageMax = percentageFromValueInRange(
|
|
|
|
min: widget.minHeight,
|
|
|
|
max: widget.maxHeight,
|
|
|
|
value: _dragHeight);
|
|
|
|
|
|
|
|
///Started from expanded state
|
|
|
|
if (_startHeight > widget.minHeight) {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (_percentageMax > 1 - snapPercentage) {
|
2020-12-15 13:14:16 +01:00
|
|
|
snap = PanelState.MAX;
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-12-15 13:14:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
///Started from minified state
|
|
|
|
else {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (_percentageMax > snapPercentage) {
|
2020-12-15 13:14:16 +01:00
|
|
|
snap = PanelState.MAX;
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-12-15 13:14:16 +01:00
|
|
|
|
|
|
|
///DismissedPercentage > 0.2 -> dismiss
|
2021-11-10 23:01:47 +01:00
|
|
|
else if (onDismissed != null &&
|
2020-12-15 13:14:16 +01:00
|
|
|
percentageFromValueInRange(
|
2021-11-10 23:01:47 +01:00
|
|
|
min: widget.minHeight,
|
|
|
|
max: 0,
|
|
|
|
value: _dragHeight,
|
|
|
|
) >
|
|
|
|
snapPercentage) {
|
|
|
|
snap = PanelState.DISMISS;
|
|
|
|
}
|
2020-12-15 13:14:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
///Snap to position
|
|
|
|
_snapToPosition(snap);
|
|
|
|
},
|
|
|
|
onPanUpdate: (details) {
|
|
|
|
if (dismissed) return;
|
|
|
|
|
|
|
|
_dragHeight -= details.delta.dy;
|
|
|
|
updateCount++;
|
|
|
|
|
|
|
|
_handleHeightChange();
|
|
|
|
},
|
2020-07-30 17:01:37 +02:00
|
|
|
),
|
2020-07-29 22:32:28 +02:00
|
|
|
),
|
|
|
|
),
|
2020-12-15 13:14:16 +01:00
|
|
|
],
|
|
|
|
);
|
|
|
|
},
|
|
|
|
),
|
2020-07-29 22:32:28 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-09-20 18:42:43 +02:00
|
|
|
///Determines whether the panel should be updated in height or discarded
|
2020-09-23 08:06:05 +02:00
|
|
|
void _handleHeightChange({bool animation = false}) {
|
2020-09-21 13:29:11 +02:00
|
|
|
///Drag above minHeight
|
2020-09-20 18:42:43 +02:00
|
|
|
if (_dragHeight >= widget.minHeight) {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (dragDownPercentage.value != 0) {
|
|
|
|
dragDownPercentage.value = 0;
|
|
|
|
}
|
2020-09-21 14:10:15 +02:00
|
|
|
|
2020-09-23 08:19:07 +02:00
|
|
|
if (_dragHeight > widget.maxHeight) return;
|
2020-09-21 14:10:15 +02:00
|
|
|
|
|
|
|
heightNotifier.value = _dragHeight;
|
2020-09-21 13:29:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
///Drag below minHeight
|
2020-11-21 11:32:25 +01:00
|
|
|
else if (onDismissed != null) {
|
2021-11-10 23:01:47 +01:00
|
|
|
final percentageDown = borderDouble(
|
2021-06-23 22:17:18 +02:00
|
|
|
minRange: 0.0,
|
|
|
|
maxRange: 1.0,
|
2020-09-26 15:12:50 +02:00
|
|
|
value: percentageFromValueInRange(
|
2020-09-20 18:42:43 +02:00
|
|
|
min: widget.minHeight, max: 0, value: _dragHeight));
|
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (dragDownPercentage.value != percentageDown) {
|
2020-09-20 18:42:43 +02:00
|
|
|
dragDownPercentage.value = percentageDown;
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-09-20 18:42:43 +02:00
|
|
|
|
2020-09-21 13:58:35 +02:00
|
|
|
if (percentageDown >= 1 && animation && !dismissed) {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (onDismissed != null) {
|
|
|
|
onDismissed!();
|
|
|
|
}
|
|
|
|
setState(() => dismissed = true);
|
2020-09-20 18:42:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///Animates the panel height according to a SnapPoint
|
2020-10-06 20:57:24 +02:00
|
|
|
void _snapToPosition(PanelState snapPosition) {
|
2020-09-20 18:42:43 +02:00
|
|
|
switch (snapPosition) {
|
2020-10-06 20:57:24 +02:00
|
|
|
case PanelState.MAX:
|
2020-09-20 18:42:43 +02:00
|
|
|
_animateToHeight(widget.maxHeight);
|
|
|
|
return;
|
2020-10-06 20:57:24 +02:00
|
|
|
case PanelState.MIN:
|
2020-09-20 18:42:43 +02:00
|
|
|
_animateToHeight(widget.minHeight);
|
|
|
|
return;
|
2020-10-06 20:57:24 +02:00
|
|
|
case PanelState.DISMISS:
|
2020-09-20 18:42:43 +02:00
|
|
|
_animateToHeight(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///Animates the panel height to a specific value
|
2020-11-21 11:52:52 +01:00
|
|
|
void _animateToHeight(final double h, {Duration? duration}) {
|
2021-03-06 15:26:00 +01:00
|
|
|
if (_animationController == null) return;
|
2020-09-20 18:42:43 +02:00
|
|
|
final startHeight = _dragHeight;
|
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (duration != null) {
|
|
|
|
_resetAnimationController(duration: duration);
|
|
|
|
}
|
2020-10-06 20:57:24 +02:00
|
|
|
|
2020-09-20 18:42:43 +02:00
|
|
|
Animation<double> _sizeAnimation = Tween(
|
|
|
|
begin: startHeight,
|
2020-07-29 22:32:28 +02:00
|
|
|
end: h,
|
|
|
|
).animate(
|
2020-11-21 11:52:52 +01:00
|
|
|
CurvedAnimation(parent: _animationController!, curve: widget.curve));
|
2020-07-29 22:32:28 +02:00
|
|
|
|
|
|
|
_sizeAnimation.addListener(() {
|
2020-09-20 18:42:43 +02:00
|
|
|
if (_sizeAnimation.value == startHeight) return;
|
|
|
|
|
|
|
|
_dragHeight = _sizeAnimation.value;
|
|
|
|
|
2020-09-23 08:06:05 +02:00
|
|
|
_handleHeightChange(animation: true);
|
2020-07-29 22:32:28 +02:00
|
|
|
});
|
2020-09-20 18:42:43 +02:00
|
|
|
|
|
|
|
animating = true;
|
2020-11-21 11:52:52 +01:00
|
|
|
_animationController!.forward(from: 0);
|
2020-07-29 22:32:28 +02:00
|
|
|
}
|
2020-10-09 20:52:45 +02:00
|
|
|
|
2020-11-11 10:57:47 +01:00
|
|
|
//Listener function for the controller
|
2020-10-09 20:52:45 +02:00
|
|
|
void controllerListener() {
|
2021-03-06 15:26:00 +01:00
|
|
|
if (widget.controller == null) return;
|
|
|
|
if (widget.controller!.value == null) return;
|
|
|
|
|
2020-11-21 11:52:52 +01:00
|
|
|
switch (widget.controller!.value!.height) {
|
2020-10-09 20:52:45 +02:00
|
|
|
case -1:
|
|
|
|
_animateToHeight(
|
|
|
|
widget.minHeight,
|
2020-11-21 11:52:52 +01:00
|
|
|
duration: widget.controller!.value!.duration,
|
2020-10-09 20:52:45 +02:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
case -2:
|
|
|
|
_animateToHeight(
|
|
|
|
widget.maxHeight,
|
2020-11-21 11:52:52 +01:00
|
|
|
duration: widget.controller!.value!.duration,
|
2020-10-09 20:52:45 +02:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
case -3:
|
|
|
|
_animateToHeight(
|
|
|
|
0,
|
2020-11-21 11:52:52 +01:00
|
|
|
duration: widget.controller!.value!.duration,
|
2020-10-09 20:52:45 +02:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
_animateToHeight(
|
2020-11-21 11:52:52 +01:00
|
|
|
widget.controller!.value!.height.toDouble(),
|
|
|
|
duration: widget.controller!.value!.duration,
|
2020-10-09 20:52:45 +02:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-07-29 22:13:39 +02:00
|
|
|
}
|
2020-10-06 20:57:24 +02:00
|
|
|
|
|
|
|
///-1 Min, -2 Max, -3 Dismiss
|
|
|
|
enum PanelState { MAX, MIN, DISMISS }
|
|
|
|
|
2020-11-11 10:57:47 +01:00
|
|
|
//ControllerData class. Used for the controller
|
2020-10-06 20:57:24 +02:00
|
|
|
class ControllerData {
|
|
|
|
final int height;
|
2020-11-21 11:52:52 +01:00
|
|
|
final Duration? duration;
|
2020-10-06 20:57:24 +02:00
|
|
|
|
|
|
|
const ControllerData(this.height, this.duration);
|
|
|
|
}
|
|
|
|
|
2020-11-11 10:57:47 +01:00
|
|
|
//MiniplayerController class
|
2020-11-21 11:52:52 +01:00
|
|
|
class MiniplayerController extends ValueNotifier<ControllerData?> {
|
2020-10-06 20:57:24 +02:00
|
|
|
MiniplayerController() : super(null);
|
|
|
|
|
2020-11-11 10:57:47 +01:00
|
|
|
//Animates to a given height or state(expanded, dismissed, ...)
|
2020-11-21 11:52:52 +01:00
|
|
|
void animateToHeight(
|
|
|
|
{double? height, PanelState? state, Duration? duration}) {
|
2021-11-10 23:01:47 +01:00
|
|
|
if (height == null && state == null) {
|
2020-10-07 16:48:23 +02:00
|
|
|
throw ("Miniplayer: One of the two parameters, height or status, is required.");
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-10-07 16:48:23 +02:00
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (height != null && state != null) {
|
2020-10-07 16:48:23 +02:00
|
|
|
throw ("Miniplayer: Only one of the two parameters, height or status, can be specified.");
|
2021-11-10 23:01:47 +01:00
|
|
|
}
|
2020-10-06 20:57:24 +02:00
|
|
|
|
2020-11-21 11:52:52 +01:00
|
|
|
ControllerData? valBefore = value;
|
2020-10-06 20:57:24 +02:00
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (state != null) {
|
2020-10-06 20:57:24 +02:00
|
|
|
value = ControllerData(state.heightCode, duration);
|
2021-11-10 23:01:47 +01:00
|
|
|
} else {
|
2020-11-21 11:52:52 +01:00
|
|
|
if (height! < 0) return;
|
2020-10-06 20:57:24 +02:00
|
|
|
|
|
|
|
value = ControllerData(height.round(), duration);
|
|
|
|
}
|
|
|
|
|
2021-11-10 23:01:47 +01:00
|
|
|
if (valBefore == value) {
|
|
|
|
notifyListeners();
|
|
|
|
}
|
2020-10-06 20:57:24 +02:00
|
|
|
}
|
|
|
|
}
|