#603 fixed switching to PiP when going home with gesture navigation

This commit is contained in:
Thibault Deckers 2023-04-27 23:25:07 +02:00
parent 192cae3c1b
commit e7985c5ea5
3 changed files with 40 additions and 30 deletions

View file

@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
### Fixed
- Video: switching to PiP when going home with gesture navigation
- Viewer: multi-page context update when removing burst entries
- prevent editing item when Exif editing changes mime type
- parsing videos with skippable boxes in `meta` box

View file

@ -61,6 +61,11 @@ class AvesApp extends StatefulWidget {
static final List<Locale> supportedLocales = AppLocalizations.supportedLocales.where((v) => !_unsupportedLocales.contains(v)).toList();
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,
// so that we can react to fullscreen `PageRoute`s only
static final RouteObserver<PageRoute> pageRouteObserver = RouteObserver<PageRoute>();
@ -364,6 +369,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
reportService.log('Lifecycle ${state.name}');
AvesApp.lifecycleStateNotifier.value = state;
switch (state) {
case AppLifecycleState.inactive:
switch (_appModeNotifier.value) {

View file

@ -62,7 +62,7 @@ class EntryViewerStack extends StatefulWidget {
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();
late int _currentEntryIndex;
late ValueNotifier<int> _currentVerticalPage;
@ -155,7 +155,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
);
initEntryControllers(entry);
_registerWidget(widget);
WidgetsBinding.instance.addObserver(this);
AvesApp.lifecycleStateNotifier.addListener(_onAppLifecycleStateChanged);
WidgetsBinding.instance.addPostFrameCallback((_) => _initOverlay());
}
@ -178,7 +178,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
_verticalPager.dispose();
_heroInfoNotifier.dispose();
_stopOverlayHidingTimer();
WidgetsBinding.instance.removeObserver(this);
AvesApp.lifecycleStateNotifier.removeListener(_onAppLifecycleStateChanged);
_unregisterWidget(widget);
super.dispose();
}
@ -191,33 +191,6 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
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
Widget build(BuildContext context) {
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) {
return ValueListenableBuilder<double>(
valueListenable: _overlayAnimationController,