viewer: reset multipage controllers when entry metadata change

This commit is contained in:
Thibault Deckers 2022-09-05 15:50:33 +02:00
parent b6af664f52
commit 7ef87c125c
4 changed files with 40 additions and 5 deletions

View file

@ -738,7 +738,12 @@ class AvesEntry {
} }
// when the MIME type or the image itself changed (e.g. after rotation) // when the MIME type or the image itself changed (e.g. after rotation)
Future<void> _onVisualFieldChanged(String oldMimeType, int? oldDateModifiedSecs, int oldRotationDegrees, bool oldIsFlipped) async { Future<void> _onVisualFieldChanged(
String oldMimeType,
int? oldDateModifiedSecs,
int oldRotationDegrees,
bool oldIsFlipped,
) async {
if ((!MimeTypes.refersToSameType(oldMimeType, mimeType) && !MimeTypes.isVideo(oldMimeType)) || oldDateModifiedSecs != dateModifiedSecs || oldRotationDegrees != rotationDegrees || oldIsFlipped != isFlipped) { if ((!MimeTypes.refersToSameType(oldMimeType, mimeType) && !MimeTypes.isVideo(oldMimeType)) || oldDateModifiedSecs != dateModifiedSecs || oldRotationDegrees != rotationDegrees || oldIsFlipped != isFlipped) {
await EntryCache.evict(uri, oldMimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped); await EntryCache.evict(uri, oldMimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
imageChangeNotifier.notify(); imageChangeNotifier.notify();

View file

@ -71,6 +71,9 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
final ValueNotifier<HeroInfo?> _heroInfoNotifier = ValueNotifier(null); final ValueNotifier<HeroInfo?> _heroInfoNotifier = ValueNotifier(null);
bool _isEntryTracked = true; bool _isEntryTracked = true;
@override
bool get isViewingImage => _currentVerticalPage.value == imagePage;
@override @override
late final ValueNotifier<AvesEntry?> entryNotifier; late final ValueNotifier<AvesEntry?> entryNotifier;

View file

@ -14,8 +14,11 @@ import 'package:provider/provider.dart';
// state controllers/monitors // state controllers/monitors
mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> { mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
final Map<AvesEntry, VoidCallback> _metadataChangeListeners = {};
final Map<MultiPageController, Future<void> Function()> _multiPageControllerPageListeners = {}; final Map<MultiPageController, Future<void> Function()> _multiPageControllerPageListeners = {};
bool get isViewingImage;
ValueNotifier<AvesEntry?> get entryNotifier; ValueNotifier<AvesEntry?> get entryNotifier;
Future<void> initEntryControllers(AvesEntry? entry) async { Future<void> initEntryControllers(AvesEntry? entry) async {
@ -27,16 +30,29 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
if (entry.isMultiPage) { if (entry.isMultiPage) {
await _initMultiPageController(entry); await _initMultiPageController(entry);
} }
void listener() => _onMetadataChange(entry);
_metadataChangeListeners[entry] = listener;
entry.metadataChangeNotifier.addListener(listener);
} }
void cleanEntryControllers(AvesEntry? entry) { void cleanEntryControllers(AvesEntry? entry) {
if (entry == null) return; if (entry == null) return;
final listener = _metadataChangeListeners.remove(entry);
if (listener != null) {
entry.metadataChangeNotifier.removeListener(listener);
}
if (entry.isMultiPage) { if (entry.isMultiPage) {
_cleanMultiPageController(entry); _cleanMultiPageController(entry);
} }
} }
void _onMetadataChange(AvesEntry entry) {
debugPrint('reinitialize controllers for entry=$entry because metadata changed');
cleanEntryControllers(entry);
initEntryControllers(entry);
}
SlideshowVideoPlayback? get videoPlaybackOverride { SlideshowVideoPlayback? get videoPlaybackOverride {
if (!mounted) return null; if (!mounted) return null;
final appMode = context.read<ValueNotifier<AppMode>>().value; final appMode = context.read<ValueNotifier<AppMode>>().value;
@ -50,7 +66,9 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
} }
} }
bool _shouldAutoPlay(BuildContext context) { bool _shouldAutoPlayVideo(BuildContext context) {
if (!isViewingImage) return false;
switch (videoPlaybackOverride) { switch (videoPlaybackOverride) {
case SlideshowVideoPlayback.skip: case SlideshowVideoPlayback.skip:
return false; return false;
@ -62,11 +80,17 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
} }
} }
bool _shouldAutoPlayMotionPhoto(BuildContext context) {
if (!isViewingImage) return false;
return settings.enableMotionPhotoAutoPlay;
}
Future<void> _initVideoController(AvesEntry entry) async { Future<void> _initVideoController(AvesEntry entry) async {
final controller = context.read<VideoConductor>().getOrCreateController(entry); final controller = context.read<VideoConductor>().getOrCreateController(entry);
setState(() {}); setState(() {});
if (_shouldAutoPlay(context)) { if (_shouldAutoPlayVideo(context)) {
final resumeTimeMillis = await controller.getResumeTime(context); final resumeTimeMillis = await controller.getResumeTime(context);
await _playVideo(controller, () => entry == entryNotifier.value, resumeTimeMillis: resumeTimeMillis); await _playVideo(controller, () => entry == entryNotifier.value, resumeTimeMillis: resumeTimeMillis);
} }
@ -93,7 +117,7 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
// auto play/pause when changing page // auto play/pause when changing page
Future<void> _onPageChange() async { Future<void> _onPageChange() async {
await pauseVideoControllers(); await pauseVideoControllers();
if (_shouldAutoPlay(context) || (entry.isMotionPhoto && settings.enableMotionPhotoAutoPlay)) { if (_shouldAutoPlayVideo(context) || (entry.isMotionPhoto && _shouldAutoPlayMotionPhoto(context))) {
final page = multiPageController.page; final page = multiPageController.page;
final pageInfo = multiPageInfo.getByIndex(page)!; final pageInfo = multiPageInfo.getByIndex(page)!;
if (pageInfo.isVideo) { if (pageInfo.isVideo) {
@ -111,7 +135,7 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
multiPageController.pageNotifier.addListener(_onPageChange); multiPageController.pageNotifier.addListener(_onPageChange);
await _onPageChange(); await _onPageChange();
if (entry.isMotionPhoto && settings.enableMotionPhotoAutoPlay) { if (entry.isMotionPhoto && _shouldAutoPlayMotionPhoto(context)) {
await Future.delayed(Durations.motionPhotoAutoPlayDelay); await Future.delayed(Durations.motionPhotoAutoPlayDelay);
if (entry == entryNotifier.value) { if (entry == entryNotifier.value) {
multiPageController.page = 1; multiPageController.page = 1;

View file

@ -75,6 +75,9 @@ class _EntryEditorState extends State<EntryEditor> with EntryViewControllerMixin
late VideoActionDelegate _videoActionDelegate; late VideoActionDelegate _videoActionDelegate;
late final ViewerController _viewerController; late final ViewerController _viewerController;
@override
bool get isViewingImage => true;
@override @override
final ValueNotifier<AvesEntry?> entryNotifier = ValueNotifier(null); final ValueNotifier<AvesEntry?> entryNotifier = ValueNotifier(null);