diff --git a/CHANGELOG.md b/CHANGELOG.md index acf5448cc..07e5763a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,19 @@ All notable changes to this project will be documented in this file. ### Added +- Collection / Albums / Countries / Tags: list view (scalable like the grid view) - moving, editing or deleting multiple items can be cancelled +- Viewer: option to auto play motion photos (after a small delay to show first the high-res photo) ### Changed - upgraded Flutter to stable v2.8.1 +### Fixed + +- Collection: more consistent scroll bar thumb position to match the viewport +- Settings: fixed file selection to import settings on older devices + ## [v1.5.7] - 2021-12-01 ### Added diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt index 2811f3f22..4e4a305d1 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/MediaStoreImageProvider.kt @@ -565,6 +565,7 @@ class MediaStoreImageProvider : ImageProvider() { throw Exception("unsupported Android version") } + Log.d(LOG_TAG, "rename content at uri=$mediaUri") val uri = StorageUtils.getMediaStoreScopedStorageSafeUri(mediaUri, mimeType) // `IS_PENDING` is necessary for `TITLE`, not for `DISPLAY_NAME` diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 816a4468c..8de93e51d 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -816,6 +816,8 @@ "@settingsViewerUseCutout": {}, "settingsViewerMaximumBrightness": "Maximum brightness", "@settingsViewerMaximumBrightness": {}, + "settingsMotionPhotoAutoPlay": "Auto play motion photos", + "@settingsMotionPhotoAutoPlay": {}, "settingsImageBackground": "Image background", "@settingsImageBackground": {}, diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index e25a14c4d..965aa0ce9 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -381,6 +381,7 @@ "settingsSectionViewer": "Visionneuse", "settingsViewerUseCutout": "Utiliser la zone d’encoche", "settingsViewerMaximumBrightness": "Luminosité maximale", + "settingsMotionPhotoAutoPlay": "Lecture automatique des photos animées", "settingsImageBackground": "Arrière-plan de l’image", "settingsViewerQuickActionsTile": "Actions rapides", diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 6dc73b269..5ec0b4db0 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -381,6 +381,7 @@ "settingsSectionViewer": "뷰어", "settingsViewerUseCutout": "컷아웃 영역 사용", "settingsViewerMaximumBrightness": "최대 밝기", + "settingsMotionPhotoAutoPlay": "모션 포토 자동 재생", "settingsImageBackground": "이미지 배경", "settingsViewerQuickActionsTile": "빠른 작업", diff --git a/lib/model/settings/defaults.dart b/lib/model/settings/defaults.dart index cf13171fd..96ff24077 100644 --- a/lib/model/settings/defaults.dart +++ b/lib/model/settings/defaults.dart @@ -67,6 +67,7 @@ class SettingsDefaults { static const enableOverlayBlurEffect = true; // `enableOverlayBlurEffect` has a contextual default value static const viewerUseCutout = true; static const viewerMaxBrightness = false; + static const enableMotionPhotoAutoPlay = false; // video static const videoQuickActions = [ diff --git a/lib/model/settings/settings.dart b/lib/model/settings/settings.dart index f5b9ac2c2..3716eb79e 100644 --- a/lib/model/settings/settings.dart +++ b/lib/model/settings/settings.dart @@ -83,6 +83,8 @@ class Settings extends ChangeNotifier { static const enableOverlayBlurEffectKey = 'enable_overlay_blur_effect'; static const viewerUseCutoutKey = 'viewer_use_cutout'; static const viewerMaxBrightnessKey = 'viewer_max_brightness'; + static const enableMotionPhotoAutoPlayKey = 'motion_photo_auto_play'; + static const imageBackgroundKey = 'image_background'; // video static const videoQuickActionsKey = 'video_quick_actions'; @@ -104,9 +106,6 @@ class Settings extends ChangeNotifier { static const coordinateFormatKey = 'coordinates_format'; static const unitSystemKey = 'unit_system'; - // rendering - static const imageBackgroundKey = 'image_background'; - // search static const saveSearchHistoryKey = 'save_search_history'; static const searchHistoryKey = 'search_history'; @@ -365,6 +364,14 @@ class Settings extends ChangeNotifier { set viewerMaxBrightness(bool newValue) => setAndNotify(viewerMaxBrightnessKey, newValue); + bool get enableMotionPhotoAutoPlay => getBoolOrDefault(enableMotionPhotoAutoPlayKey, SettingsDefaults.enableMotionPhotoAutoPlay); + + set enableMotionPhotoAutoPlay(bool newValue) => setAndNotify(enableMotionPhotoAutoPlayKey, newValue); + + EntryBackground get imageBackground => getEnumOrDefault(imageBackgroundKey, SettingsDefaults.imageBackground, EntryBackground.values); + + set imageBackground(EntryBackground newValue) => setAndNotify(imageBackgroundKey, newValue.toString()); + // video List get videoQuickActions => getEnumListOrDefault(videoQuickActionsKey, SettingsDefaults.videoQuickActions, VideoAction.values); @@ -427,12 +434,6 @@ class Settings extends ChangeNotifier { set unitSystem(UnitSystem newValue) => setAndNotify(unitSystemKey, newValue.toString()); - // rendering - - EntryBackground get imageBackground => getEnumOrDefault(imageBackgroundKey, SettingsDefaults.imageBackground, EntryBackground.values); - - set imageBackground(EntryBackground newValue) => setAndNotify(imageBackgroundKey, newValue.toString()); - // search bool get saveSearchHistory => getBoolOrDefault(saveSearchHistoryKey, SettingsDefaults.saveSearchHistory); @@ -613,6 +614,7 @@ class Settings extends ChangeNotifier { case enableOverlayBlurEffectKey: case viewerUseCutoutKey: case viewerMaxBrightnessKey: + case enableMotionPhotoAutoPlayKey: case enableVideoHardwareAccelerationKey: case enableVideoAutoPlayKey: case subtitleShowOutlineKey: @@ -633,12 +635,12 @@ class Settings extends ChangeNotifier { case albumSortFactorKey: case countrySortFactorKey: case tagSortFactorKey: + case imageBackgroundKey: case videoLoopModeKey: case subtitleTextAlignmentKey: case infoMapStyleKey: case coordinateFormatKey: case unitSystemKey: - case imageBackgroundKey: case accessibilityAnimationsKey: case timeToTakeActionKey: if (value is String) { diff --git a/lib/theme/durations.dart b/lib/theme/durations.dart index b071be57c..33060b455 100644 --- a/lib/theme/durations.dart +++ b/lib/theme/durations.dart @@ -59,6 +59,7 @@ class Durations { static const collectionScrollMonitoringTimerDelay = Duration(milliseconds: 100); static const highlightJumpDelay = Duration(milliseconds: 400); static const highlightScrollInitDelay = Duration(milliseconds: 800); + static const motionPhotoAutoPlayDelay = Duration(milliseconds: 700); static const videoOverlayHideDelay = Duration(milliseconds: 500); static const videoProgressTimerInterval = Duration(milliseconds: 300); static const doubleBackTimerDelay = Duration(milliseconds: 1000); diff --git a/lib/widgets/settings/viewer/viewer.dart b/lib/widgets/settings/viewer/viewer.dart index ec62009e8..3e0ddb026 100644 --- a/lib/widgets/settings/viewer/viewer.dart +++ b/lib/widgets/settings/viewer/viewer.dart @@ -42,6 +42,14 @@ class ViewerSection extends StatelessWidget { title: Text(context.l10n.settingsViewerMaximumBrightness), ), ), + Selector( + selector: (context, s) => s.enableMotionPhotoAutoPlay, + builder: (context, current, child) => SwitchListTile( + value: current, + onChanged: (v) => settings.enableMotionPhotoAutoPlay = v, + title: Text(context.l10n.settingsMotionPhotoAutoPlay), + ), + ), Selector( selector: (context, s) => s.imageBackground, builder: (context, current, child) => ListTile( diff --git a/lib/widgets/viewer/entry_viewer_stack.dart b/lib/widgets/viewer/entry_viewer_stack.dart index fbac83b33..f9004e3ba 100644 --- a/lib/widgets/viewer/entry_viewer_stack.dart +++ b/lib/widgets/viewer/entry_viewer_stack.dart @@ -630,7 +630,7 @@ class _EntryViewerStackState extends State with FeedbackMixin, // auto play/pause when changing page Future _onPageChange() async { await _pauseVideoControllers(); - if (settings.enableVideoAutoPlay) { + if (settings.enableVideoAutoPlay || (entry.isMotionPhoto && settings.enableMotionPhotoAutoPlay)) { final page = multiPageController.page; final pageInfo = multiPageInfo.getByIndex(page)!; if (pageInfo.isVideo) { @@ -644,6 +644,13 @@ class _EntryViewerStackState extends State with FeedbackMixin, _multiPageControllerPageListeners[multiPageController] = _onPageChange; multiPageController.pageNotifier.addListener(_onPageChange); await _onPageChange(); + + if (entry.isMotionPhoto && settings.enableMotionPhotoAutoPlay) { + await Future.delayed(Durations.motionPhotoAutoPlayDelay); + if (entry == _entryNotifier.value) { + multiPageController.page = 1; + } + } } } diff --git a/lib/widgets/viewer/visual/entry_page_view.dart b/lib/widgets/viewer/visual/entry_page_view.dart index 0d9666b5f..38a05b853 100644 --- a/lib/widgets/viewer/visual/entry_page_view.dart +++ b/lib/widgets/viewer/visual/entry_page_view.dart @@ -63,6 +63,9 @@ class _EntryPageViewState extends State { AvesEntry get entry => widget.pageEntry; + // use the high res photo as cover for the video part of a motion photo + ImageProvider get videoCoverUriImage => mainEntry.isMotionPhoto ? mainEntry.uriImage : entry.uriImage; + static const initialScale = ScaleLevel(ref: ScaleReference.contained); static const minScale = ScaleLevel(ref: ScaleReference.contained); static const maxScale = ScaleLevel(factor: 2.0); @@ -98,7 +101,7 @@ class _EntryPageViewState extends State { _subscriptions.add(_magnifierController.scaleBoundariesStream.listen(_onViewScaleBoundariesChanged)); if (entry.isVideo) { _videoCoverStreamListener = ImageStreamListener((image, _) => _videoCoverInfoNotifier.value = image); - _videoCoverStream = entry.uriImage.resolve(ImageConfiguration.empty); + _videoCoverStream = videoCoverUriImage.resolve(ImageConfiguration.empty); _videoCoverStream!.addListener(_videoCoverStreamListener); } } @@ -248,7 +251,7 @@ class _EntryPageViewState extends State { controller: coverController, displaySize: coverSize, child: Image( - image: entry.uriImage, + image: videoCoverUriImage, ), ); } diff --git a/untranslated.json b/untranslated.json index c783aff7e..4d2157c53 100644 --- a/untranslated.json +++ b/untranslated.json @@ -3,6 +3,7 @@ "menuActionConfigureView", "viewDialogTabLayout", "tileLayoutGrid", - "tileLayoutList" + "tileLayoutList", + "settingsMotionPhotoAutoPlay" ] }