This commit is contained in:
parent
1ef9d75b0b
commit
6014677451
14 changed files with 182 additions and 23 deletions
|
@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="unreleased"></a>[Unreleased]
|
## <a id="unreleased"></a>[Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Viewer: optionally show description on overlay
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- editing description writes XMP `dc:description`, and clears Exif `ImageDescription` / `UserComment`
|
||||||
|
|
||||||
## <a id="v1.7.8"></a>[v1.7.8] - 2022-12-20
|
## <a id="v1.7.8"></a>[v1.7.8] - 2022-12-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -615,7 +615,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (!metadataMap.containsKey(KEY_XMP_TITLE) || !metadataMap.containsKey(KEY_XMP_SUBJECTS)) {
|
if (!metadataMap.containsKey(KEY_XMP_TITLE) || !metadataMap.containsKey(KEY_XMP_SUBJECTS)) {
|
||||||
for (dir in metadata.getDirectoriesOfType(IptcDirectory::class.java)) {
|
for (dir in metadata.getDirectoriesOfType(IptcDirectory::class.java)) {
|
||||||
if (!metadataMap.containsKey(KEY_XMP_TITLE)) {
|
if (!metadataMap.containsKey(KEY_XMP_TITLE)) {
|
||||||
dir.getSafeString(IptcDirectory.TAG_OBJECT_NAME) { metadataMap[KEY_XMP_TITLE] = it }
|
dir.getSafeString(IptcDirectory.TAG_OBJECT_NAME, acceptBlank = false) { metadataMap[KEY_XMP_TITLE] = it }
|
||||||
}
|
}
|
||||||
if (!metadataMap.containsKey(KEY_XMP_SUBJECTS)) {
|
if (!metadataMap.containsKey(KEY_XMP_SUBJECTS)) {
|
||||||
dir.keywords?.let { metadataMap[KEY_XMP_SUBJECTS] = it.joinToString(XMP_SUBJECTS_SEPARATOR) }
|
dir.keywords?.let { metadataMap[KEY_XMP_SUBJECTS] = it.joinToString(XMP_SUBJECTS_SEPARATOR) }
|
||||||
|
@ -1151,6 +1151,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
// return description from these fields (by precedence):
|
// return description from these fields (by precedence):
|
||||||
// - XMP / dc:description
|
// - XMP / dc:description
|
||||||
// - IPTC / caption-abstract
|
// - IPTC / caption-abstract
|
||||||
|
// - Exif / UserComment
|
||||||
// - Exif / ImageDescription
|
// - Exif / ImageDescription
|
||||||
private fun getDescription(call: MethodCall, result: MethodChannel.Result) {
|
private fun getDescription(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val mimeType = call.argument<String>("mimeType")
|
val mimeType = call.argument<String>("mimeType")
|
||||||
|
@ -1171,7 +1172,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
val xmpMeta = dir.xmpMeta
|
val xmpMeta = dir.xmpMeta
|
||||||
try {
|
try {
|
||||||
if (xmpMeta.doesPropExist(XMP.DC_DESCRIPTION_PROP_NAME)) {
|
if (xmpMeta.doesPropExist(XMP.DC_DESCRIPTION_PROP_NAME)) {
|
||||||
xmpMeta.getSafeLocalizedText(XMP.DC_DESCRIPTION_PROP_NAME) { description = it }
|
xmpMeta.getSafeLocalizedText(XMP.DC_DESCRIPTION_PROP_NAME, acceptBlank = false) { description = it }
|
||||||
}
|
}
|
||||||
} catch (e: XMPException) {
|
} catch (e: XMPException) {
|
||||||
Log.w(LOG_TAG, "failed to read XMP directory for uri=$uri", e)
|
Log.w(LOG_TAG, "failed to read XMP directory for uri=$uri", e)
|
||||||
|
@ -1179,12 +1180,23 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
if (description == null) {
|
if (description == null) {
|
||||||
for (dir in metadata.getDirectoriesOfType(IptcDirectory::class.java)) {
|
for (dir in metadata.getDirectoriesOfType(IptcDirectory::class.java)) {
|
||||||
dir.getSafeString(IptcDirectory.TAG_CAPTION) { description = it }
|
dir.getSafeString(IptcDirectory.TAG_CAPTION, acceptBlank = false) { description = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (description == null) {
|
||||||
|
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
||||||
|
// user comment field specifies encoding, unlike other string fields
|
||||||
|
if (dir.containsTag(ExifSubIFDDirectory.TAG_USER_COMMENT)) {
|
||||||
|
val string = dir.getDescription(ExifSubIFDDirectory.TAG_USER_COMMENT)
|
||||||
|
if (string.isNotBlank()) {
|
||||||
|
description = string
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (description == null) {
|
if (description == null) {
|
||||||
for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) {
|
for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) {
|
||||||
dir.getSafeString(ExifIFD0Directory.TAG_IMAGE_DESCRIPTION) { description = it }
|
dir.getSafeString(ExifIFD0Directory.TAG_IMAGE_DESCRIPTION, acceptBlank = false) { description = it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,8 +117,13 @@ object Helper {
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
|
|
||||||
fun Directory.getSafeString(tag: Int, save: (value: String) -> Unit) {
|
fun Directory.getSafeString(tag: Int, acceptBlank: Boolean = true, save: (value: String) -> Unit) {
|
||||||
if (this.containsTag(tag)) save(this.getString(tag))
|
if (this.containsTag(tag)) {
|
||||||
|
val string = this.getString(tag)
|
||||||
|
if (acceptBlank || string.isNotBlank()) {
|
||||||
|
save(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Directory.getSafeBoolean(tag: Int, save: (value: Boolean) -> Unit) {
|
fun Directory.getSafeBoolean(tag: Int, save: (value: Boolean) -> Unit) {
|
||||||
|
|
|
@ -731,6 +731,7 @@
|
||||||
"settingsViewerShowInformationSubtitle": "Show title, date, location, etc.",
|
"settingsViewerShowInformationSubtitle": "Show title, date, location, etc.",
|
||||||
"settingsViewerShowRatingTags": "Show rating & tags",
|
"settingsViewerShowRatingTags": "Show rating & tags",
|
||||||
"settingsViewerShowShootingDetails": "Show shooting details",
|
"settingsViewerShowShootingDetails": "Show shooting details",
|
||||||
|
"settingsViewerShowDescription": "Show description",
|
||||||
"settingsViewerShowOverlayThumbnails": "Show thumbnails",
|
"settingsViewerShowOverlayThumbnails": "Show thumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect": "Blur effect",
|
"settingsViewerEnableOverlayBlurEffect": "Blur effect",
|
||||||
|
|
||||||
|
|
|
@ -235,7 +235,10 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
final description = fields[DescriptionField.description];
|
final description = fields[DescriptionField.description];
|
||||||
|
|
||||||
if (canEditExif && editDescription) {
|
if (canEditExif && editDescription) {
|
||||||
metadata[MetadataType.exif] = {MetadataField.exifImageDescription.toPlatform!: description};
|
metadata[MetadataType.exif] = {
|
||||||
|
MetadataField.exifImageDescription.toPlatform!: null,
|
||||||
|
MetadataField.exifUserComment.toPlatform!: null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canEditIptc) {
|
if (canEditIptc) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ enum MetadataField {
|
||||||
exifGpsTrackRef,
|
exifGpsTrackRef,
|
||||||
exifGpsVersionId,
|
exifGpsVersionId,
|
||||||
exifImageDescription,
|
exifImageDescription,
|
||||||
|
exifUserComment,
|
||||||
mp4GpsCoordinates,
|
mp4GpsCoordinates,
|
||||||
mp4RotationDegrees,
|
mp4RotationDegrees,
|
||||||
mp4Xmp,
|
mp4Xmp,
|
||||||
|
@ -119,6 +120,7 @@ extension ExtraMetadataField on MetadataField {
|
||||||
case MetadataField.exifGpsTrackRef:
|
case MetadataField.exifGpsTrackRef:
|
||||||
case MetadataField.exifGpsVersionId:
|
case MetadataField.exifGpsVersionId:
|
||||||
case MetadataField.exifImageDescription:
|
case MetadataField.exifImageDescription:
|
||||||
|
case MetadataField.exifUserComment:
|
||||||
return MetadataType.exif;
|
return MetadataType.exif;
|
||||||
case MetadataField.mp4GpsCoordinates:
|
case MetadataField.mp4GpsCoordinates:
|
||||||
case MetadataField.mp4RotationDegrees:
|
case MetadataField.mp4RotationDegrees:
|
||||||
|
@ -220,6 +222,8 @@ extension ExtraMetadataField on MetadataField {
|
||||||
return 'GPSVersionID';
|
return 'GPSVersionID';
|
||||||
case MetadataField.exifImageDescription:
|
case MetadataField.exifImageDescription:
|
||||||
return 'ImageDescription';
|
return 'ImageDescription';
|
||||||
|
case MetadataField.exifUserComment:
|
||||||
|
return 'UserComment';
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ class SettingsDefaults {
|
||||||
static const showOverlayOnOpening = true;
|
static const showOverlayOnOpening = true;
|
||||||
static const showOverlayMinimap = false;
|
static const showOverlayMinimap = false;
|
||||||
static const showOverlayInfo = true;
|
static const showOverlayInfo = true;
|
||||||
|
static const showOverlayDescription = false;
|
||||||
static const showOverlayRatingTags = false;
|
static const showOverlayRatingTags = false;
|
||||||
static const showOverlayShootingDetails = false;
|
static const showOverlayShootingDetails = false;
|
||||||
static const showOverlayThumbnailPreview = false;
|
static const showOverlayThumbnailPreview = false;
|
||||||
|
|
|
@ -115,6 +115,7 @@ class Settings extends ChangeNotifier {
|
||||||
static const showOverlayOnOpeningKey = 'show_overlay_on_opening';
|
static const showOverlayOnOpeningKey = 'show_overlay_on_opening';
|
||||||
static const showOverlayMinimapKey = 'show_overlay_minimap';
|
static const showOverlayMinimapKey = 'show_overlay_minimap';
|
||||||
static const showOverlayInfoKey = 'show_overlay_info';
|
static const showOverlayInfoKey = 'show_overlay_info';
|
||||||
|
static const showOverlayDescriptionKey = 'show_overlay_description';
|
||||||
static const showOverlayRatingTagsKey = 'show_overlay_rating_tags';
|
static const showOverlayRatingTagsKey = 'show_overlay_rating_tags';
|
||||||
static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details';
|
static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details';
|
||||||
static const showOverlayThumbnailPreviewKey = 'show_overlay_thumbnail_preview';
|
static const showOverlayThumbnailPreviewKey = 'show_overlay_thumbnail_preview';
|
||||||
|
@ -563,6 +564,10 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
set showOverlayInfo(bool newValue) => setAndNotify(showOverlayInfoKey, newValue);
|
set showOverlayInfo(bool newValue) => setAndNotify(showOverlayInfoKey, newValue);
|
||||||
|
|
||||||
|
bool get showOverlayDescription => getBool(showOverlayDescriptionKey) ?? SettingsDefaults.showOverlayDescription;
|
||||||
|
|
||||||
|
set showOverlayDescription(bool newValue) => setAndNotify(showOverlayDescriptionKey, newValue);
|
||||||
|
|
||||||
bool get showOverlayRatingTags => getBool(showOverlayRatingTagsKey) ?? SettingsDefaults.showOverlayRatingTags;
|
bool get showOverlayRatingTags => getBool(showOverlayRatingTagsKey) ?? SettingsDefaults.showOverlayRatingTags;
|
||||||
|
|
||||||
set showOverlayRatingTags(bool newValue) => setAndNotify(showOverlayRatingTagsKey, newValue);
|
set showOverlayRatingTags(bool newValue) => setAndNotify(showOverlayRatingTagsKey, newValue);
|
||||||
|
@ -1002,6 +1007,7 @@ class Settings extends ChangeNotifier {
|
||||||
case showOverlayOnOpeningKey:
|
case showOverlayOnOpeningKey:
|
||||||
case showOverlayMinimapKey:
|
case showOverlayMinimapKey:
|
||||||
case showOverlayInfoKey:
|
case showOverlayInfoKey:
|
||||||
|
case showOverlayDescriptionKey:
|
||||||
case showOverlayRatingTagsKey:
|
case showOverlayRatingTagsKey:
|
||||||
case showOverlayShootingDetailsKey:
|
case showOverlayShootingDetailsKey:
|
||||||
case showOverlayThumbnailPreviewKey:
|
case showOverlayThumbnailPreviewKey:
|
||||||
|
|
|
@ -56,6 +56,18 @@ class ViewerOverlayPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
Selector<Settings, Tuple2<bool, bool>>(
|
||||||
|
selector: (context, s) => Tuple2(s.showOverlayInfo, s.showOverlayDescription),
|
||||||
|
builder: (context, s, child) {
|
||||||
|
final showInfo = s.item1;
|
||||||
|
final current = s.item2;
|
||||||
|
return SwitchListTile(
|
||||||
|
value: current,
|
||||||
|
onChanged: showInfo ? (v) => settings.showOverlayDescription = v : null,
|
||||||
|
title: Text(context.l10n.settingsViewerShowDescription),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
if (!device.isTelevision)
|
if (!device.isTelevision)
|
||||||
SettingsSwitchListTile(
|
SettingsSwitchListTile(
|
||||||
selector: (context, s) => s.showOverlayMinimap,
|
selector: (context, s) => s.showOverlayMinimap,
|
||||||
|
|
25
lib/widgets/viewer/overlay/details/description.dart
Normal file
25
lib/widgets/viewer/overlay/details/description.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/utils/constants.dart';
|
||||||
|
import 'package:aves/widgets/viewer/overlay/details/details.dart';
|
||||||
|
import 'package:decorated_icon/decorated_icon.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class OverlayDescriptionRow extends StatelessWidget {
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
const OverlayDescriptionRow({
|
||||||
|
super.key,
|
||||||
|
required this.description,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
DecoratedIcon(AIcons.description, size: ViewerDetailOverlayContent.iconSize, shadows: ViewerDetailOverlayContent.shadows(context)),
|
||||||
|
const SizedBox(width: ViewerDetailOverlayContent.iconPadding),
|
||||||
|
Expanded(child: Text(description, strutStyle: Constants.overflowStrutStyle)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/utils/constants.dart';
|
import 'package:aves/utils/constants.dart';
|
||||||
import 'package:aves/widgets/viewer/multipage/controller.dart';
|
import 'package:aves/widgets/viewer/multipage/controller.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/date.dart';
|
import 'package:aves/widgets/viewer/overlay/details/date.dart';
|
||||||
|
import 'package:aves/widgets/viewer/overlay/details/description.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/location.dart';
|
import 'package:aves/widgets/viewer/overlay/details/location.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/position_title.dart';
|
import 'package:aves/widgets/viewer/overlay/details/position_title.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/details/rating_tags.dart';
|
import 'package:aves/widgets/viewer/overlay/details/rating_tags.dart';
|
||||||
|
@ -43,9 +44,9 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
return index < entries.length ? entries[index] : null;
|
return index < entries.length ? entries[index] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
late Future<OverlayMetadata?> _detailLoader;
|
late Future<List<dynamic>?> _detailLoader;
|
||||||
AvesEntry? _lastEntry;
|
AvesEntry? _lastEntry;
|
||||||
OverlayMetadata? _lastDetails;
|
List<dynamic>? _lastDetails;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -63,7 +64,14 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
|
|
||||||
void _initDetailLoader() {
|
void _initDetailLoader() {
|
||||||
final requestEntry = entry;
|
final requestEntry = entry;
|
||||||
_detailLoader = requestEntry != null ? metadataFetchService.getOverlayMetadata(requestEntry) : SynchronousFuture(null);
|
if (requestEntry == null) {
|
||||||
|
_detailLoader = SynchronousFuture(null);
|
||||||
|
} else {
|
||||||
|
_detailLoader = Future.wait([
|
||||||
|
settings.showOverlayShootingDetails ? metadataFetchService.getOverlayMetadata(requestEntry) : Future.value(null),
|
||||||
|
settings.showOverlayDescription ? metadataFetchService.getDescription(requestEntry) : Future.value(null),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -75,7 +83,7 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final availableWidth = constraints.maxWidth;
|
final availableWidth = constraints.maxWidth;
|
||||||
|
|
||||||
return FutureBuilder<OverlayMetadata?>(
|
return FutureBuilder<List<dynamic>?>(
|
||||||
future: _detailLoader,
|
future: _detailLoader,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
|
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
|
||||||
|
@ -85,10 +93,14 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
if (_lastEntry == null) return const SizedBox();
|
if (_lastEntry == null) return const SizedBox();
|
||||||
final mainEntry = _lastEntry!;
|
final mainEntry = _lastEntry!;
|
||||||
|
|
||||||
|
final shootingDetails = _lastDetails![0];
|
||||||
|
final description = _lastDetails![1];
|
||||||
|
|
||||||
final multiPageController = widget.multiPageController;
|
final multiPageController = widget.multiPageController;
|
||||||
Widget _buildContent({AvesEntry? pageEntry}) => ViewerDetailOverlayContent(
|
Widget _buildContent({AvesEntry? pageEntry}) => ViewerDetailOverlayContent(
|
||||||
pageEntry: pageEntry ?? mainEntry,
|
pageEntry: pageEntry ?? mainEntry,
|
||||||
details: _lastDetails,
|
shootingDetails: shootingDetails,
|
||||||
|
description: description,
|
||||||
position: widget.hasCollection ? '${widget.index + 1}/${entries.length}' : null,
|
position: widget.hasCollection ? '${widget.index + 1}/${entries.length}' : null,
|
||||||
availableWidth: availableWidth,
|
availableWidth: availableWidth,
|
||||||
multiPageController: multiPageController,
|
multiPageController: multiPageController,
|
||||||
|
@ -110,7 +122,8 @@ class _ViewerDetailOverlayState extends State<ViewerDetailOverlay> {
|
||||||
|
|
||||||
class ViewerDetailOverlayContent extends StatelessWidget {
|
class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
final AvesEntry pageEntry;
|
final AvesEntry pageEntry;
|
||||||
final OverlayMetadata? details;
|
final OverlayMetadata? shootingDetails;
|
||||||
|
final String? description;
|
||||||
final String? position;
|
final String? position;
|
||||||
final double availableWidth;
|
final double availableWidth;
|
||||||
final MultiPageController? multiPageController;
|
final MultiPageController? multiPageController;
|
||||||
|
@ -126,7 +139,8 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
const ViewerDetailOverlayContent({
|
const ViewerDetailOverlayContent({
|
||||||
super.key,
|
super.key,
|
||||||
required this.pageEntry,
|
required this.pageEntry,
|
||||||
required this.details,
|
required this.shootingDetails,
|
||||||
|
required this.description,
|
||||||
required this.position,
|
required this.position,
|
||||||
required this.availableWidth,
|
required this.availableWidth,
|
||||||
required this.multiPageController,
|
required this.multiPageController,
|
||||||
|
@ -136,7 +150,8 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final infoMaxWidth = availableWidth - padding.horizontal;
|
final infoMaxWidth = availableWidth - padding.horizontal;
|
||||||
final showRatingTags = settings.showOverlayRatingTags;
|
final showRatingTags = settings.showOverlayRatingTags;
|
||||||
final showShooting = settings.showOverlayShootingDetails;
|
final showShootingDetails = settings.showOverlayShootingDetails;
|
||||||
|
final showDescription = settings.showOverlayDescription;
|
||||||
|
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: pageEntry.metadataChangeNotifier,
|
animation: pageEntry.metadataChangeNotifier,
|
||||||
|
@ -156,8 +171,8 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
builder: (context, orientation, child) {
|
builder: (context, orientation, child) {
|
||||||
final twoColumns = orientation == Orientation.landscape && infoMaxWidth / 2 > _subRowMinWidth;
|
final twoColumns = orientation == Orientation.landscape && infoMaxWidth / 2 > _subRowMinWidth;
|
||||||
final subRowWidth = twoColumns ? min(_subRowMinWidth, infoMaxWidth / 2) : infoMaxWidth;
|
final subRowWidth = twoColumns ? min(_subRowMinWidth, infoMaxWidth / 2) : infoMaxWidth;
|
||||||
final collapsedShooting = twoColumns && showShooting;
|
final collapsedShooting = twoColumns && showShootingDetails;
|
||||||
final collapsedLocation = twoColumns && !showShooting;
|
final collapsedLocation = twoColumns && !showShootingDetails;
|
||||||
|
|
||||||
final rows = <Widget>[];
|
final rows = <Widget>[];
|
||||||
if (positionTitle.isNotEmpty) {
|
if (positionTitle.isNotEmpty) {
|
||||||
|
@ -176,7 +191,7 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
rows.add(_buildDateSubRow(subRowWidth));
|
rows.add(_buildDateSubRow(subRowWidth));
|
||||||
if (showShooting) {
|
if (showShootingDetails) {
|
||||||
rows.add(_buildShootingFullRow(context, subRowWidth));
|
rows.add(_buildShootingFullRow(context, subRowWidth));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,6 +201,9 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
if (showRatingTags) {
|
if (showRatingTags) {
|
||||||
rows.add(_buildRatingTagsFullRow(context));
|
rows.add(_buildRatingTagsFullRow(context));
|
||||||
}
|
}
|
||||||
|
if (showDescription) {
|
||||||
|
rows.add(_buildDescriptionFullRow(context));
|
||||||
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
@ -214,20 +232,26 @@ class ViewerDetailOverlayContent extends StatelessWidget {
|
||||||
builder: (context) => OverlayRatingTagsRow(entry: pageEntry),
|
builder: (context) => OverlayRatingTagsRow(entry: pageEntry),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Widget _buildDescriptionFullRow(BuildContext context) => _buildFullRowSwitcher(
|
||||||
|
context: context,
|
||||||
|
visible: description != null,
|
||||||
|
builder: (context) => OverlayDescriptionRow(description: description!),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher(
|
Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher(
|
||||||
context: context,
|
context: context,
|
||||||
visible: details != null && details!.isNotEmpty,
|
visible: shootingDetails != null && shootingDetails!.isNotEmpty,
|
||||||
builder: (context) => SizedBox(
|
builder: (context) => SizedBox(
|
||||||
width: subRowWidth,
|
width: subRowWidth,
|
||||||
child: OverlayShootingRow(details: details!),
|
child: OverlayShootingRow(details: shootingDetails!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildShootingSubRow(BuildContext context, double subRowWidth) => _buildSubRowSwitcher(
|
Widget _buildShootingSubRow(BuildContext context, double subRowWidth) => _buildSubRowSwitcher(
|
||||||
context: context,
|
context: context,
|
||||||
subRowWidth: subRowWidth,
|
subRowWidth: subRowWidth,
|
||||||
visible: details != null && details!.isNotEmpty,
|
visible: shootingDetails != null && shootingDetails!.isNotEmpty,
|
||||||
builder: (context) => OverlayShootingRow(details: details!),
|
builder: (context) => OverlayShootingRow(details: shootingDetails!),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLocationFullRow(BuildContext context) => _buildFullRowSwitcher(
|
Widget _buildLocationFullRow(BuildContext context) => _buildFullRowSwitcher(
|
||||||
|
|
|
@ -10,7 +10,10 @@ import 'package:intl/intl.dart';
|
||||||
class OverlayShootingRow extends StatelessWidget {
|
class OverlayShootingRow extends StatelessWidget {
|
||||||
final OverlayMetadata details;
|
final OverlayMetadata details;
|
||||||
|
|
||||||
const OverlayShootingRow({super.key, required this.details});
|
const OverlayShootingRow({
|
||||||
|
super.key,
|
||||||
|
required this.details,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -47,6 +47,7 @@ Future<void> configureAndLaunch() async {
|
||||||
..showOverlayOnOpening = true
|
..showOverlayOnOpening = true
|
||||||
..showOverlayMinimap = false
|
..showOverlayMinimap = false
|
||||||
..showOverlayInfo = true
|
..showOverlayInfo = true
|
||||||
|
..showOverlayDescription = false
|
||||||
..showOverlayRatingTags = false
|
..showOverlayRatingTags = false
|
||||||
..showOverlayShootingDetails = false
|
..showOverlayShootingDetails = false
|
||||||
..showOverlayThumbnailPreview = false
|
..showOverlayThumbnailPreview = false
|
||||||
|
|
|
@ -452,6 +452,7 @@
|
||||||
"settingsViewerShowInformationSubtitle",
|
"settingsViewerShowInformationSubtitle",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
"settingsViewerShowShootingDetails",
|
"settingsViewerShowShootingDetails",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsViewerShowOverlayThumbnails",
|
"settingsViewerShowOverlayThumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect",
|
"settingsViewerEnableOverlayBlurEffect",
|
||||||
"settingsViewerSlideshowTile",
|
"settingsViewerSlideshowTile",
|
||||||
|
@ -592,9 +593,18 @@
|
||||||
|
|
||||||
"de": [
|
"de": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"el": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
|
"es": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"fa": [
|
"fa": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"clearTooltip",
|
"clearTooltip",
|
||||||
|
@ -914,6 +924,7 @@
|
||||||
"settingsViewerShowInformationSubtitle",
|
"settingsViewerShowInformationSubtitle",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
"settingsViewerShowShootingDetails",
|
"settingsViewerShowShootingDetails",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsViewerShowOverlayThumbnails",
|
"settingsViewerShowOverlayThumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect",
|
"settingsViewerEnableOverlayBlurEffect",
|
||||||
"settingsViewerSlideshowTile",
|
"settingsViewerSlideshowTile",
|
||||||
|
@ -1059,6 +1070,10 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"fr": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"gl": [
|
"gl": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"entryActionShareImageOnly",
|
"entryActionShareImageOnly",
|
||||||
|
@ -1379,6 +1394,7 @@
|
||||||
"settingsViewerShowInformationSubtitle",
|
"settingsViewerShowInformationSubtitle",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
"settingsViewerShowShootingDetails",
|
"settingsViewerShowShootingDetails",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsViewerShowOverlayThumbnails",
|
"settingsViewerShowOverlayThumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect",
|
"settingsViewerEnableOverlayBlurEffect",
|
||||||
"settingsViewerSlideshowTile",
|
"settingsViewerSlideshowTile",
|
||||||
|
@ -1526,6 +1542,14 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"id": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
|
"it": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"ja": [
|
"ja": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"chipActionFilterIn",
|
"chipActionFilterIn",
|
||||||
|
@ -1535,13 +1559,19 @@
|
||||||
"keepScreenOnVideoPlayback",
|
"keepScreenOnVideoPlayback",
|
||||||
"subtitlePositionTop",
|
"subtitlePositionTop",
|
||||||
"subtitlePositionBottom",
|
"subtitlePositionBottom",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||||
"settingsWidgetDisplayedItem"
|
"settingsWidgetDisplayedItem"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"ko": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"lt": [
|
"lt": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"keepScreenOnVideoPlayback",
|
"keepScreenOnVideoPlayback",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -1551,6 +1581,7 @@
|
||||||
"entryActionShareVideoOnly",
|
"entryActionShareVideoOnly",
|
||||||
"entryInfoActionRemoveLocation",
|
"entryInfoActionRemoveLocation",
|
||||||
"keepScreenOnVideoPlayback",
|
"keepScreenOnVideoPlayback",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -1569,6 +1600,7 @@
|
||||||
"widgetDisplayedItemRandom",
|
"widgetDisplayedItemRandom",
|
||||||
"widgetDisplayedItemMostRecent",
|
"widgetDisplayedItemMostRecent",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsSubtitleThemeTextPositionTile",
|
"settingsSubtitleThemeTextPositionTile",
|
||||||
"settingsSubtitleThemeTextPositionDialogTitle",
|
"settingsSubtitleThemeTextPositionDialogTitle",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||||
|
@ -1878,6 +1910,7 @@
|
||||||
"settingsViewerShowInformationSubtitle",
|
"settingsViewerShowInformationSubtitle",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
"settingsViewerShowShootingDetails",
|
"settingsViewerShowShootingDetails",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsViewerShowOverlayThumbnails",
|
"settingsViewerShowOverlayThumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect",
|
"settingsViewerEnableOverlayBlurEffect",
|
||||||
"settingsViewerSlideshowTile",
|
"settingsViewerSlideshowTile",
|
||||||
|
@ -2385,6 +2418,7 @@
|
||||||
"settingsViewerShowInformationSubtitle",
|
"settingsViewerShowInformationSubtitle",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
"settingsViewerShowShootingDetails",
|
"settingsViewerShowShootingDetails",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsViewerShowOverlayThumbnails",
|
"settingsViewerShowOverlayThumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect",
|
"settingsViewerEnableOverlayBlurEffect",
|
||||||
"settingsViewerSlideshowTile",
|
"settingsViewerSlideshowTile",
|
||||||
|
@ -2547,12 +2581,21 @@
|
||||||
"widgetDisplayedItemRandom",
|
"widgetDisplayedItemRandom",
|
||||||
"widgetDisplayedItemMostRecent",
|
"widgetDisplayedItemMostRecent",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsSubtitleThemeTextPositionTile",
|
"settingsSubtitleThemeTextPositionTile",
|
||||||
"settingsSubtitleThemeTextPositionDialogTitle",
|
"settingsSubtitleThemeTextPositionDialogTitle",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives",
|
"settingsAccessibilityShowPinchGestureAlternatives",
|
||||||
"settingsWidgetDisplayedItem"
|
"settingsWidgetDisplayedItem"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"ro": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ru": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"th": [
|
"th": [
|
||||||
"itemCount",
|
"itemCount",
|
||||||
"columnCount",
|
"columnCount",
|
||||||
|
@ -2748,6 +2791,7 @@
|
||||||
"settingsViewerShowInformationSubtitle",
|
"settingsViewerShowInformationSubtitle",
|
||||||
"settingsViewerShowRatingTags",
|
"settingsViewerShowRatingTags",
|
||||||
"settingsViewerShowShootingDetails",
|
"settingsViewerShowShootingDetails",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsViewerShowOverlayThumbnails",
|
"settingsViewerShowOverlayThumbnails",
|
||||||
"settingsViewerEnableOverlayBlurEffect",
|
"settingsViewerEnableOverlayBlurEffect",
|
||||||
"settingsViewerSlideshowTile",
|
"settingsViewerSlideshowTile",
|
||||||
|
@ -2895,12 +2939,22 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"tr": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
|
"uk": [
|
||||||
|
"settingsViewerShowDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"zh": [
|
"zh": [
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||||
],
|
],
|
||||||
|
|
||||||
"zh_Hant": [
|
"zh_Hant": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
|
"settingsViewerShowDescription",
|
||||||
"settingsAccessibilityShowPinchGestureAlternatives"
|
"settingsAccessibilityShowPinchGestureAlternatives"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue