diff --git a/lib/miniplayer.dart b/lib/miniplayer.dart index 78086ea..ada35bd 100644 --- a/lib/miniplayer.dart +++ b/lib/miniplayer.dart @@ -3,8 +3,11 @@ library miniplayer; import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:miniplayer/src/miniplayer_will_pop_scope.dart'; import 'package:miniplayer/src/utils.dart'; +export 'package:miniplayer/src/miniplayer_will_pop_scope.dart'; + ///Type definition for the builder function typedef Widget MiniplayerBuilder(double height, double percentage); @@ -142,7 +145,7 @@ class _MiniplayerState extends State with TickerProviderStateMixin { Widget build(BuildContext context) { if (dismissed) return Container(); - return WillPopScope( + return MiniplayerWillPopScope( onWillPop: () async { if (heightNotifier.value > widget.minHeight) { _snapToPosition(PanelState.MIN); diff --git a/lib/src/miniplayer_will_pop_scope.dart b/lib/src/miniplayer_will_pop_scope.dart new file mode 100644 index 0000000..5a1cb08 --- /dev/null +++ b/lib/src/miniplayer_will_pop_scope.dart @@ -0,0 +1,67 @@ +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); + + final Widget child; + final WillPopCallback onWillPop; + + @override + _MiniplayerWillPopScopeState createState() => _MiniplayerWillPopScopeState(); + + static _MiniplayerWillPopScopeState of(BuildContext context) { + return context.findAncestorStateOfType<_MiniplayerWillPopScopeState>(); + } +} + +class _MiniplayerWillPopScopeState extends State { + ModalRoute _route; + + _MiniplayerWillPopScopeState _descendant; + + set descendant(state) { + _descendant = state; + updateRouteCallback(); + } + + Future onWillPop() async { + bool willPop; + if (_descendant != null) { + willPop = await _descendant.onWillPop(); + } + if (willPop == null || willPop) { + willPop = await widget.onWillPop(); + } + return willPop; + } + + void updateRouteCallback() { + _route?.removeScopedWillPopCallback(onWillPop); + _route = ModalRoute.of(context); + _route?.addScopedWillPopCallback(onWillPop); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + var parentGuard = MiniplayerWillPopScope.of(context); + if (parentGuard != null) { + parentGuard.descendant = this; + } + updateRouteCallback(); + } + + @override + void dispose() { + _route?.removeScopedWillPopCallback(onWillPop); + super.dispose(); + } + + @override + Widget build(BuildContext context) => widget.child; +}