diff --git a/lib/model/entry.dart b/lib/model/entry.dart index 6589e4362..ee392c4b8 100644 --- a/lib/model/entry.dart +++ b/lib/model/entry.dart @@ -738,7 +738,12 @@ class AvesEntry { } // when the MIME type or the image itself changed (e.g. after rotation) - Future _onVisualFieldChanged(String oldMimeType, int? oldDateModifiedSecs, int oldRotationDegrees, bool oldIsFlipped) async { + Future _onVisualFieldChanged( + String oldMimeType, + int? oldDateModifiedSecs, + int oldRotationDegrees, + bool oldIsFlipped, + ) async { if ((!MimeTypes.refersToSameType(oldMimeType, mimeType) && !MimeTypes.isVideo(oldMimeType)) || oldDateModifiedSecs != dateModifiedSecs || oldRotationDegrees != rotationDegrees || oldIsFlipped != isFlipped) { await EntryCache.evict(uri, oldMimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped); imageChangeNotifier.notify(); diff --git a/lib/widgets/viewer/entry_viewer_stack.dart b/lib/widgets/viewer/entry_viewer_stack.dart index 85920157d..14f8918b4 100644 --- a/lib/widgets/viewer/entry_viewer_stack.dart +++ b/lib/widgets/viewer/entry_viewer_stack.dart @@ -71,6 +71,9 @@ class _EntryViewerStackState extends State with EntryViewContr final ValueNotifier _heroInfoNotifier = ValueNotifier(null); bool _isEntryTracked = true; + @override + bool get isViewingImage => _currentVerticalPage.value == imagePage; + @override late final ValueNotifier entryNotifier; diff --git a/lib/widgets/viewer/visual/controller_mixin.dart b/lib/widgets/viewer/visual/controller_mixin.dart index 8b353d4f3..b00031a61 100644 --- a/lib/widgets/viewer/visual/controller_mixin.dart +++ b/lib/widgets/viewer/visual/controller_mixin.dart @@ -14,8 +14,11 @@ import 'package:provider/provider.dart'; // state controllers/monitors mixin EntryViewControllerMixin on State { + final Map _metadataChangeListeners = {}; final Map Function()> _multiPageControllerPageListeners = {}; + bool get isViewingImage; + ValueNotifier get entryNotifier; Future initEntryControllers(AvesEntry? entry) async { @@ -27,16 +30,29 @@ mixin EntryViewControllerMixin on State { if (entry.isMultiPage) { await _initMultiPageController(entry); } + void listener() => _onMetadataChange(entry); + _metadataChangeListeners[entry] = listener; + entry.metadataChangeNotifier.addListener(listener); } void cleanEntryControllers(AvesEntry? entry) { if (entry == null) return; + final listener = _metadataChangeListeners.remove(entry); + if (listener != null) { + entry.metadataChangeNotifier.removeListener(listener); + } if (entry.isMultiPage) { _cleanMultiPageController(entry); } } + void _onMetadataChange(AvesEntry entry) { + debugPrint('reinitialize controllers for entry=$entry because metadata changed'); + cleanEntryControllers(entry); + initEntryControllers(entry); + } + SlideshowVideoPlayback? get videoPlaybackOverride { if (!mounted) return null; final appMode = context.read>().value; @@ -50,7 +66,9 @@ mixin EntryViewControllerMixin on State { } } - bool _shouldAutoPlay(BuildContext context) { + bool _shouldAutoPlayVideo(BuildContext context) { + if (!isViewingImage) return false; + switch (videoPlaybackOverride) { case SlideshowVideoPlayback.skip: return false; @@ -62,11 +80,17 @@ mixin EntryViewControllerMixin on State { } } + bool _shouldAutoPlayMotionPhoto(BuildContext context) { + if (!isViewingImage) return false; + + return settings.enableMotionPhotoAutoPlay; + } + Future _initVideoController(AvesEntry entry) async { final controller = context.read().getOrCreateController(entry); setState(() {}); - if (_shouldAutoPlay(context)) { + if (_shouldAutoPlayVideo(context)) { final resumeTimeMillis = await controller.getResumeTime(context); await _playVideo(controller, () => entry == entryNotifier.value, resumeTimeMillis: resumeTimeMillis); } @@ -93,7 +117,7 @@ mixin EntryViewControllerMixin on State { // auto play/pause when changing page Future _onPageChange() async { await pauseVideoControllers(); - if (_shouldAutoPlay(context) || (entry.isMotionPhoto && settings.enableMotionPhotoAutoPlay)) { + if (_shouldAutoPlayVideo(context) || (entry.isMotionPhoto && _shouldAutoPlayMotionPhoto(context))) { final page = multiPageController.page; final pageInfo = multiPageInfo.getByIndex(page)!; if (pageInfo.isVideo) { @@ -111,7 +135,7 @@ mixin EntryViewControllerMixin on State { multiPageController.pageNotifier.addListener(_onPageChange); await _onPageChange(); - if (entry.isMotionPhoto && settings.enableMotionPhotoAutoPlay) { + if (entry.isMotionPhoto && _shouldAutoPlayMotionPhoto(context)) { await Future.delayed(Durations.motionPhotoAutoPlayDelay); if (entry == entryNotifier.value) { multiPageController.page = 1; diff --git a/lib/widgets/wallpaper_page.dart b/lib/widgets/wallpaper_page.dart index 1673f352e..1b04229b2 100644 --- a/lib/widgets/wallpaper_page.dart +++ b/lib/widgets/wallpaper_page.dart @@ -75,6 +75,9 @@ class _EntryEditorState extends State with EntryViewControllerMixin late VideoActionDelegate _videoActionDelegate; late final ViewerController _viewerController; + @override + bool get isViewingImage => true; + @override final ValueNotifier entryNotifier = ValueNotifier(null);