#603 fixed switching to PiP when going home with gesture navigation
This commit is contained in:
parent
192cae3c1b
commit
e7985c5ea5
3 changed files with 40 additions and 30 deletions
|
@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Video: switching to PiP when going home with gesture navigation
|
||||||
- Viewer: multi-page context update when removing burst entries
|
- Viewer: multi-page context update when removing burst entries
|
||||||
- prevent editing item when Exif editing changes mime type
|
- prevent editing item when Exif editing changes mime type
|
||||||
- parsing videos with skippable boxes in `meta` box
|
- parsing videos with skippable boxes in `meta` box
|
||||||
|
|
|
@ -61,6 +61,11 @@ class AvesApp extends StatefulWidget {
|
||||||
static final List<Locale> supportedLocales = AppLocalizations.supportedLocales.where((v) => !_unsupportedLocales.contains(v)).toList();
|
static final List<Locale> supportedLocales = AppLocalizations.supportedLocales.where((v) => !_unsupportedLocales.contains(v)).toList();
|
||||||
static final ValueNotifier<EdgeInsets> cutoutInsetsNotifier = ValueNotifier(EdgeInsets.zero);
|
static final ValueNotifier<EdgeInsets> cutoutInsetsNotifier = ValueNotifier(EdgeInsets.zero);
|
||||||
|
|
||||||
|
// children widgets registering as `WidgetsBinding` observers and implementing `didChangeAppLifecycleState`
|
||||||
|
// do not receive events fast enough for time sensitive actions (like PiP when leaving by gesture to home)
|
||||||
|
// so we use this notifier to propagate events as soon as received by the top widget `AvesApp`
|
||||||
|
static final ValueNotifier<AppLifecycleState> lifecycleStateNotifier = ValueNotifier(AppLifecycleState.detached);
|
||||||
|
|
||||||
// do not monitor all `ModalRoute`s, which would include popup menus,
|
// do not monitor all `ModalRoute`s, which would include popup menus,
|
||||||
// so that we can react to fullscreen `PageRoute`s only
|
// so that we can react to fullscreen `PageRoute`s only
|
||||||
static final RouteObserver<PageRoute> pageRouteObserver = RouteObserver<PageRoute>();
|
static final RouteObserver<PageRoute> pageRouteObserver = RouteObserver<PageRoute>();
|
||||||
|
@ -364,6 +369,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
reportService.log('Lifecycle ${state.name}');
|
reportService.log('Lifecycle ${state.name}');
|
||||||
|
AvesApp.lifecycleStateNotifier.value = state;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AppLifecycleState.inactive:
|
case AppLifecycleState.inactive:
|
||||||
switch (_appModeNotifier.value) {
|
switch (_appModeNotifier.value) {
|
||||||
|
|
|
@ -62,7 +62,7 @@ class EntryViewerStack extends StatefulWidget {
|
||||||
State<EntryViewerStack> createState() => _EntryViewerStackState();
|
State<EntryViewerStack> createState() => _EntryViewerStackState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewControllerMixin, FeedbackMixin, SingleTickerProviderStateMixin, WidgetsBindingObserver {
|
class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewControllerMixin, FeedbackMixin, SingleTickerProviderStateMixin {
|
||||||
final Floating _floating = Floating();
|
final Floating _floating = Floating();
|
||||||
late int _currentEntryIndex;
|
late int _currentEntryIndex;
|
||||||
late ValueNotifier<int> _currentVerticalPage;
|
late ValueNotifier<int> _currentVerticalPage;
|
||||||
|
@ -155,7 +155,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
);
|
);
|
||||||
initEntryControllers(entry);
|
initEntryControllers(entry);
|
||||||
_registerWidget(widget);
|
_registerWidget(widget);
|
||||||
WidgetsBinding.instance.addObserver(this);
|
AvesApp.lifecycleStateNotifier.addListener(_onAppLifecycleStateChanged);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _initOverlay());
|
WidgetsBinding.instance.addPostFrameCallback((_) => _initOverlay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
_verticalPager.dispose();
|
_verticalPager.dispose();
|
||||||
_heroInfoNotifier.dispose();
|
_heroInfoNotifier.dispose();
|
||||||
_stopOverlayHidingTimer();
|
_stopOverlayHidingTimer();
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
AvesApp.lifecycleStateNotifier.removeListener(_onAppLifecycleStateChanged);
|
||||||
_unregisterWidget(widget);
|
_unregisterWidget(widget);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -191,33 +191,6 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
widget.collection?.removeListener(_onCollectionChanged);
|
widget.collection?.removeListener(_onCollectionChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
|
||||||
switch (state) {
|
|
||||||
case AppLifecycleState.inactive:
|
|
||||||
_onAppInactive();
|
|
||||||
break;
|
|
||||||
case AppLifecycleState.paused:
|
|
||||||
case AppLifecycleState.detached:
|
|
||||||
pauseVideoControllers();
|
|
||||||
break;
|
|
||||||
case AppLifecycleState.resumed:
|
|
||||||
availability.onResume();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onAppInactive() async {
|
|
||||||
viewerController.autopilot = false;
|
|
||||||
bool enabledPip = false;
|
|
||||||
if (settings.videoBackgroundMode == VideoBackgroundMode.pip) {
|
|
||||||
enabledPip |= await _enablePictureInPicture();
|
|
||||||
}
|
|
||||||
if (!enabledPip) {
|
|
||||||
await pauseVideoControllers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final viewStateConductor = context.read<ViewStateConductor>();
|
final viewStateConductor = context.read<ViewStateConductor>();
|
||||||
|
@ -292,6 +265,36 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onAppLifecycleStateChanged() {
|
||||||
|
switch (AvesApp.lifecycleStateNotifier.value) {
|
||||||
|
case AppLifecycleState.inactive:
|
||||||
|
_onAppInactive();
|
||||||
|
break;
|
||||||
|
case AppLifecycleState.paused:
|
||||||
|
case AppLifecycleState.detached:
|
||||||
|
pauseVideoControllers();
|
||||||
|
break;
|
||||||
|
case AppLifecycleState.resumed:
|
||||||
|
availability.onResume();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onAppInactive() async {
|
||||||
|
final playingController = context.read<VideoConductor>().getPlayingController();
|
||||||
|
viewerController.autopilot = false;
|
||||||
|
bool enabledPip = false;
|
||||||
|
if (settings.videoBackgroundMode == VideoBackgroundMode.pip) {
|
||||||
|
enabledPip |= await _enablePictureInPicture();
|
||||||
|
}
|
||||||
|
if (enabledPip) {
|
||||||
|
// ensure playback, in case lifecycle paused/resumed events happened when switching to PiP
|
||||||
|
await playingController?.play();
|
||||||
|
} else {
|
||||||
|
await pauseVideoControllers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _decorateOverlay(Widget overlay) {
|
Widget _decorateOverlay(Widget overlay) {
|
||||||
return ValueListenableBuilder<double>(
|
return ValueListenableBuilder<double>(
|
||||||
valueListenable: _overlayAnimationController,
|
valueListenable: _overlayAnimationController,
|
||||||
|
|
Loading…
Reference in a new issue