diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 51be3194e..ca5c9bebe 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -652,6 +652,8 @@ "@settingsSectionThumbnails": {}, "settingsThumbnailShowLocationIcon": "Show location icon", "@settingsThumbnailShowLocationIcon": {}, + "settingsThumbnailShowMotionPhotoIcon": "Show motion photo icon", + "@settingsThumbnailShowMotionPhotoIcon": {}, "settingsThumbnailShowRawIcon": "Show raw icon", "@settingsThumbnailShowRawIcon": {}, "settingsThumbnailShowVideoDuration": "Show video duration", diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index ff446bcfa..c401ee7ff 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -314,6 +314,7 @@ "settingsSectionThumbnails": "섬네일", "settingsThumbnailShowLocationIcon": "위치 아이콘 표시", + "settingsThumbnailShowMotionPhotoIcon": "모션 포토 아이콘 표시", "settingsThumbnailShowRawIcon": "Raw 아이콘 표시", "settingsThumbnailShowVideoDuration": "동영상 길이 표시", diff --git a/lib/model/settings/defaults.dart b/lib/model/settings/defaults.dart index 7636c330d..781061c9e 100644 --- a/lib/model/settings/defaults.dart +++ b/lib/model/settings/defaults.dart @@ -38,6 +38,7 @@ class SettingsDefaults { EntrySetAction.delete, ]; static const showThumbnailLocation = true; + static const showThumbnailMotionPhoto = true; static const showThumbnailRaw = true; static const showThumbnailVideoDuration = true; diff --git a/lib/model/settings/settings.dart b/lib/model/settings/settings.dart index fa2484190..87fa14a61 100644 --- a/lib/model/settings/settings.dart +++ b/lib/model/settings/settings.dart @@ -57,6 +57,7 @@ class Settings extends ChangeNotifier { static const collectionSortFactorKey = 'collection_sort_factor'; static const collectionSelectionQuickActionsKey = 'collection_selection_quick_actions'; static const showThumbnailLocationKey = 'show_thumbnail_location'; + static const showThumbnailMotionPhotoKey = 'show_thumbnail_motion_photo'; static const showThumbnailRawKey = 'show_thumbnail_raw'; static const showThumbnailVideoDurationKey = 'show_thumbnail_video_duration'; @@ -241,6 +242,10 @@ class Settings extends ChangeNotifier { set showThumbnailLocation(bool newValue) => setAndNotify(showThumbnailLocationKey, newValue); + bool get showThumbnailMotionPhoto => getBoolOrDefault(showThumbnailMotionPhotoKey, SettingsDefaults.showThumbnailMotionPhoto); + + set showThumbnailMotionPhoto(bool newValue) => setAndNotify(showThumbnailMotionPhotoKey, newValue); + bool get showThumbnailRaw => getBoolOrDefault(showThumbnailRawKey, SettingsDefaults.showThumbnailRaw); set showThumbnailRaw(bool newValue) => setAndNotify(showThumbnailRawKey, newValue); @@ -494,6 +499,7 @@ class Settings extends ChangeNotifier { case isCrashlyticsEnabledKey: case mustBackTwiceToExitKey: case showThumbnailLocationKey: + case showThumbnailMotionPhotoKey: case showThumbnailRawKey: case showThumbnailVideoDurationKey: case showOverlayMinimapKey: diff --git a/lib/widgets/common/grid/overlay.dart b/lib/widgets/common/grid/overlay.dart index 2205cc3fe..dafa4fd7d 100644 --- a/lib/widgets/common/grid/overlay.dart +++ b/lib/widgets/common/grid/overlay.dart @@ -1,7 +1,6 @@ import 'package:aves/model/selection.dart'; import 'package:aves/theme/durations.dart'; import 'package:aves/theme/icons.dart'; -import 'package:aves/widgets/common/grid/theme.dart'; import 'package:aves/widgets/common/identity/aves_icons.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -31,7 +30,6 @@ class GridItemSelectionOverlay extends StatelessWidget { ? OverlayIcon( key: ValueKey(isSelected), icon: isSelected ? AIcons.selected : AIcons.unselected, - size: context.select((t) => t.iconSize), ) : const SizedBox.shrink(); child = AnimatedSwitcher( diff --git a/lib/widgets/common/grid/theme.dart b/lib/widgets/common/grid/theme.dart index 88d277ff0..992e68fba 100644 --- a/lib/widgets/common/grid/theme.dart +++ b/lib/widgets/common/grid/theme.dart @@ -28,6 +28,7 @@ class GridTheme extends StatelessWidget { fontSize: fontSize, highlightBorderWidth: highlightBorderWidth, showLocation: showLocation ?? settings.showThumbnailLocation, + showMotionPhoto: settings.showThumbnailMotionPhoto, showRaw: settings.showThumbnailRaw, showVideoDuration: settings.showThumbnailVideoDuration, ); @@ -39,13 +40,14 @@ class GridTheme extends StatelessWidget { class GridThemeData { final double iconSize, fontSize, highlightBorderWidth; - final bool showLocation, showRaw, showVideoDuration; + final bool showLocation, showMotionPhoto, showRaw, showVideoDuration; const GridThemeData({ required this.iconSize, required this.fontSize, required this.highlightBorderWidth, required this.showLocation, + required this.showMotionPhoto, required this.showRaw, required this.showVideoDuration, }); diff --git a/lib/widgets/common/identity/aves_icons.dart b/lib/widgets/common/identity/aves_icons.dart index a4192241a..92bc0f004 100644 --- a/lib/widgets/common/identity/aves_icons.dart +++ b/lib/widgets/common/identity/aves_icons.dart @@ -24,7 +24,6 @@ class VideoIcon extends StatelessWidget { final showDuration = gridTheme.showVideoDuration; Widget child = OverlayIcon( icon: entry.is360 ? AIcons.threeSixty : AIcons.videoThumb, - size: gridTheme.iconSize, text: showDuration ? entry.durationText : null, iconScale: entry.is360 && showDuration ? .9 : 1, ); @@ -44,12 +43,13 @@ class VideoIcon extends StatelessWidget { class AnimatedImageIcon extends StatelessWidget { const AnimatedImageIcon({Key? key}) : super(key: key); + static const scale = .8; + @override Widget build(BuildContext context) { - return OverlayIcon( + return const OverlayIcon( icon: AIcons.animated, - size: context.select((t) => t.iconSize), - iconScale: .8, + iconScale: scale, ); } } @@ -59,9 +59,8 @@ class GeotiffIcon extends StatelessWidget { @override Widget build(BuildContext context) { - return OverlayIcon( + return const OverlayIcon( icon: AIcons.geo, - size: context.select((t) => t.iconSize), ); } } @@ -71,9 +70,8 @@ class SphericalImageIcon extends StatelessWidget { @override Widget build(BuildContext context) { - return OverlayIcon( + return const OverlayIcon( icon: AIcons.threeSixty, - size: context.select((t) => t.iconSize), ); } } @@ -83,9 +81,8 @@ class GpsIcon extends StatelessWidget { @override Widget build(BuildContext context) { - return OverlayIcon( + return const OverlayIcon( icon: AIcons.location, - size: context.select((t) => t.iconSize), ); } } @@ -95,9 +92,22 @@ class RawIcon extends StatelessWidget { @override Widget build(BuildContext context) { - return OverlayIcon( + return const OverlayIcon( icon: AIcons.raw, - size: context.select((t) => t.iconSize), + ); + } +} + +class MotionPhotoIcon extends StatelessWidget { + const MotionPhotoIcon({Key? key}) : super(key: key); + + static const scale = .8; + + @override + Widget build(BuildContext context) { + return const OverlayIcon( + icon: AIcons.motionPhoto, + iconScale: scale, ); } } @@ -105,6 +115,8 @@ class RawIcon extends StatelessWidget { class MultiPageIcon extends StatelessWidget { final AvesEntry entry; + static const scale = .8; + const MultiPageIcon({ Key? key, required this.entry, @@ -112,27 +124,19 @@ class MultiPageIcon extends StatelessWidget { @override Widget build(BuildContext context) { - IconData icon; String? text; - if (entry.isMotionPhoto) { - icon = AIcons.motionPhoto; - } else { - if (entry.isBurst) { - text = '${entry.burstEntries?.length}'; - } - icon = AIcons.multiPage; + if (entry.isBurst) { + text = '${entry.burstEntries?.length}'; } - final gridTheme = context.watch(); final child = OverlayIcon( - icon: icon, - size: gridTheme.iconSize, - iconScale: .8, + icon: AIcons.multiPage, + iconScale: scale, text: text, ); return DefaultTextStyle( style: TextStyle( color: Colors.grey.shade200, - fontSize: gridTheme.fontSize, + fontSize: context.select((t) => t.fontSize), ), child: child, ); @@ -141,20 +145,19 @@ class MultiPageIcon extends StatelessWidget { class OverlayIcon extends StatelessWidget { final IconData icon; - final double size; final String? text; final double iconScale; const OverlayIcon({ Key? key, required this.icon, - required this.size, this.iconScale = 1, this.text, }) : super(key: key); @override Widget build(BuildContext context) { + final size = context.select((t) => t.iconSize); final iconChild = Icon(icon, size: size); final iconBox = SizedBox( width: size, diff --git a/lib/widgets/common/thumbnail/overlay.dart b/lib/widgets/common/thumbnail/overlay.dart index aa758f862..4e72d1c0e 100644 --- a/lib/widgets/common/thumbnail/overlay.dart +++ b/lib/widgets/common/thumbnail/overlay.dart @@ -31,7 +31,10 @@ class ThumbnailEntryOverlay extends StatelessWidget { if (entry.isGeotiff) const GeotiffIcon(), if (entry.is360) const SphericalImageIcon(), ], - if (entry.isMultiPage) MultiPageIcon(entry: entry), + if (entry.isMultiPage) ...[ + if (entry.isMotionPhoto && context.select((t) => t.showMotionPhoto)) const MotionPhotoIcon(), + if (!entry.isMotionPhoto) MultiPageIcon(entry: entry), + ], ]; if (children.isEmpty) return const SizedBox.shrink(); if (children.length == 1) return children.first; diff --git a/lib/widgets/settings/thumbnails/thumbnails.dart b/lib/widgets/settings/thumbnails/thumbnails.dart index 0670c13ac..9d8fd5434 100644 --- a/lib/widgets/settings/thumbnails/thumbnails.dart +++ b/lib/widgets/settings/thumbnails/thumbnails.dart @@ -4,6 +4,7 @@ import 'package:aves/theme/icons.dart'; import 'package:aves/utils/color_utils.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/aves_expansion_tile.dart'; +import 'package:aves/widgets/common/identity/aves_icons.dart'; import 'package:aves/widgets/settings/common/tile_leading.dart'; import 'package:aves/widgets/settings/thumbnails/selection_actions_editor.dart'; import 'package:flutter/material.dart'; @@ -20,6 +21,7 @@ class ThumbnailsSection extends StatelessWidget { @override Widget build(BuildContext context) { final currentShowThumbnailLocation = context.select((s) => s.showThumbnailLocation); + final currentShowThumbnailMotionPhoto = context.select((s) => s.showThumbnailMotionPhoto); final currentShowThumbnailRaw = context.select((s) => s.showThumbnailRaw); final currentShowThumbnailVideoDuration = context.select((s) => s.showThumbnailVideoDuration); @@ -53,6 +55,26 @@ class ThumbnailsSection extends StatelessWidget { ], ), ), + SwitchListTile( + value: currentShowThumbnailMotionPhoto, + onChanged: (v) => settings.showThumbnailMotionPhoto = v, + title: Row( + children: [ + Expanded(child: Text(context.l10n.settingsThumbnailShowMotionPhotoIcon)), + AnimatedOpacity( + opacity: opacityFor(currentShowThumbnailMotionPhoto), + duration: Durations.toggleableTransitionAnimation, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: iconSize * (1 - MotionPhotoIcon.scale) / 2), + child: Icon( + AIcons.motionPhoto, + size: iconSize * MotionPhotoIcon.scale, + ), + ), + ), + ], + ), + ), SwitchListTile( value: currentShowThumbnailRaw, onChanged: (v) => settings.showThumbnailRaw = v,