From 5b960d0a9043082dd5c4bd32ae6408966ffb3b6d Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 25 Oct 2022 19:23:33 +0200 Subject: [PATCH] #361 #329 info: edit location by copying from other item --- CHANGELOG.md | 3 +- lib/l10n/app_de.arb | 4 +- lib/l10n/app_el.arb | 4 +- lib/l10n/app_en.arb | 3 +- lib/l10n/app_es.arb | 4 +- lib/l10n/app_fr.arb | 4 +- lib/l10n/app_id.arb | 4 +- lib/l10n/app_it.arb | 4 +- lib/l10n/app_ja.arb | 4 +- lib/l10n/app_ko.arb | 4 +- lib/l10n/app_nb.arb | 4 +- lib/l10n/app_nl.arb | 4 +- lib/l10n/app_pt.arb | 4 +- lib/l10n/app_ru.arb | 4 +- lib/l10n/app_tr.arb | 4 +- lib/l10n/app_zh.arb | 4 +- lib/model/entry_metadata_edition.dart | 3 +- lib/model/metadata/date_modifier.dart | 2 +- .../metadata/enums/date_edit_action.dart | 22 + .../metadata/enums/date_field_source.dart | 36 ++ lib/model/metadata/enums/enums.dart | 46 ++ .../metadata/enums/location_edit_action.dart | 18 + .../{enums.dart => enums/metadata_type.dart} | 59 +-- lib/model/metadata/fields.dart | 2 +- .../metadata/metadata_edit_service.dart | 3 +- .../common/action_mixins/entry_editor.dart | 6 +- .../common/action_mixins/entry_storage.dart | 2 +- .../entry_editors/edit_date_dialog.dart | 60 +-- .../entry_editors/edit_location_dialog.dart | 292 +++++++---- .../entry_editors/remove_metadata_dialog.dart | 3 +- untranslated.json | 491 +++++++++++++++++- 31 files changed, 865 insertions(+), 242 deletions(-) create mode 100644 lib/model/metadata/enums/date_edit_action.dart create mode 100644 lib/model/metadata/enums/date_field_source.dart create mode 100644 lib/model/metadata/enums/enums.dart create mode 100644 lib/model/metadata/enums/location_edit_action.dart rename lib/model/metadata/{enums.dart => enums/metadata_type.dart} (52%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c08c86547..b9caf9a0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ All notable changes to this project will be documented in this file. ### Added -- Collection / Info: edit MP4 metadata (date / location / title / description / rating / tags / rotation) +- Info: edit MP4 metadata (date / location / title / description / rating / tags / rotation) +- Info: edit location by copying from other item - Widget: option to open collection on tap ### Changed diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 0bb8859d8..b3cadec16 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -423,8 +423,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Standort", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Auf Karte wählen", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Auf Karte wählen", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Breitengrad", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Längengrad", diff --git a/lib/l10n/app_el.arb b/lib/l10n/app_el.arb index bc115d245..4ce65dfb3 100644 --- a/lib/l10n/app_el.arb +++ b/lib/l10n/app_el.arb @@ -423,8 +423,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Τοποθεσια", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Επιλογή στο χάρτη", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Επιλογή στο χάρτη", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Γεωγραφικό πλάτος", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Γεωγραφικό μήκος", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8547df6ca..b550afe67 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -389,7 +389,8 @@ "durationDialogSeconds": "Seconds", "editEntryLocationDialogTitle": "Location", - "editEntryLocationDialogChooseOnMapTooltip": "Choose on map", + "editEntryLocationDialogSetCustom": "Set custom location", + "editEntryLocationDialogChooseOnMap": "Choose on map", "editEntryLocationDialogLatitude": "Latitude", "editEntryLocationDialogLongitude": "Longitude", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 71207ff5b..f8e703b4d 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -405,8 +405,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Ubicación", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Elegir en el mapa", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Elegir en el mapa", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Latitud", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Longitud", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index ba91525be..2f51dc8b9 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -427,8 +427,8 @@ "@durationDialogSeconds": {}, "editEntryLocationDialogTitle": "Lieu", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Sélectionner sur la carte", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Sélectionner sur la carte", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Latitude", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Longitude", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 0d8ecea7c..aa6795688 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -413,8 +413,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Lokasi", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Pilih di peta", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Pilih di peta", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Garis lintang", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Garis bujur", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index e10f12ae3..f0a89124b 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -423,8 +423,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Posizione", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Scegli sulla mappa", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Scegli sulla mappa", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Latitudine", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Longitudine", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 9be5470fd..d5edd97a1 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -405,8 +405,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "位置情報", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "地図上で選択", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "地図上で選択", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "緯度", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "経度", diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index f74e0c978..5d0fb62b5 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -427,8 +427,8 @@ "@durationDialogSeconds": {}, "editEntryLocationDialogTitle": "위치", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "지도에서 선택", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "지도에서 선택", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "위도", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "경도", diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index e1f252d26..4ff98958f 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -549,8 +549,8 @@ "@editEntryDialogCopyFromItem": {}, "durationDialogMinutes": "Minutter", "@durationDialogMinutes": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Velg på kartet", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Velg på kartet", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryRatingDialogTitle": "Vurdering", "@editEntryRatingDialogTitle": {}, "removeEntryMetadataDialogTitle": "Metadatafjerning", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 124f8bbc8..048e0b368 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -421,8 +421,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Locatie", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Kies op kaart", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Kies op kaart", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Breedtegraad", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Lengtegraad", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 359a55dc0..40190d034 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -423,8 +423,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Localização", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Escolha no mapa", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Escolha no mapa", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Latitude", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Longitude", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 17c799031..e9f829220 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -423,8 +423,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Местоположение", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Выбрать на карте", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Выбрать на карте", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Широта", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Долгота", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index ffed60dce..9bd204037 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -379,8 +379,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "Konum", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "Harita üzerinde seç", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "Harita üzerinde seç", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "Enlem", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "Boylam", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index f7a0d5256..8b5feacb7 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -423,8 +423,8 @@ "@durationDialogMinutes": {}, "editEntryLocationDialogTitle": "位置", "@editEntryLocationDialogTitle": {}, - "editEntryLocationDialogChooseOnMapTooltip": "从地图上选择", - "@editEntryLocationDialogChooseOnMapTooltip": {}, + "editEntryLocationDialogChooseOnMap": "从地图上选择", + "@editEntryLocationDialogChooseOnMap": {}, "editEntryLocationDialogLatitude": "纬度", "@editEntryLocationDialogLatitude": {}, "editEntryLocationDialogLongitude": "经度", diff --git a/lib/model/entry_metadata_edition.dart b/lib/model/entry_metadata_edition.dart index ef1f42a2a..0c5b60298 100644 --- a/lib/model/entry_metadata_edition.dart +++ b/lib/model/entry_metadata_edition.dart @@ -3,7 +3,8 @@ import 'dart:io'; import 'package:aves/model/entry.dart'; import 'package:aves/model/metadata/date_modifier.dart'; -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/date_field_source.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; import 'package:aves/model/metadata/fields.dart'; import 'package:aves/ref/exif.dart'; import 'package:aves/ref/iptc.dart'; diff --git a/lib/model/metadata/date_modifier.dart b/lib/model/metadata/date_modifier.dart index 53be123cd..7f373ac50 100644 --- a/lib/model/metadata/date_modifier.dart +++ b/lib/model/metadata/date_modifier.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; import 'package:aves/model/metadata/fields.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; diff --git a/lib/model/metadata/enums/date_edit_action.dart b/lib/model/metadata/enums/date_edit_action.dart new file mode 100644 index 000000000..4d48b4f0e --- /dev/null +++ b/lib/model/metadata/enums/date_edit_action.dart @@ -0,0 +1,22 @@ +import 'package:aves/model/metadata/enums/enums.dart'; +import 'package:aves/widgets/common/extensions/build_context.dart'; +import 'package:flutter/widgets.dart'; + +extension ExtraDateEditAction on DateEditAction { + String getText(BuildContext context) { + switch (this) { + case DateEditAction.setCustom: + return context.l10n.editEntryDateDialogSetCustom; + case DateEditAction.copyField: + return context.l10n.editEntryDateDialogCopyField; + case DateEditAction.copyItem: + return context.l10n.editEntryDialogCopyFromItem; + case DateEditAction.extractFromTitle: + return context.l10n.editEntryDateDialogExtractFromTitle; + case DateEditAction.shift: + return context.l10n.editEntryDateDialogShift; + case DateEditAction.remove: + return context.l10n.actionRemove; + } + } +} diff --git a/lib/model/metadata/enums/date_field_source.dart b/lib/model/metadata/enums/date_field_source.dart new file mode 100644 index 000000000..3f3d12a25 --- /dev/null +++ b/lib/model/metadata/enums/date_field_source.dart @@ -0,0 +1,36 @@ +import 'package:aves/model/metadata/enums/enums.dart'; +import 'package:aves/model/metadata/fields.dart'; +import 'package:aves/widgets/common/extensions/build_context.dart'; +import 'package:flutter/widgets.dart'; + +extension ExtraDateFieldSource on DateFieldSource { + String getText(BuildContext context) { + switch (this) { + case DateFieldSource.fileModifiedDate: + return context.l10n.editEntryDateDialogSourceFileModifiedDate; + case DateFieldSource.exifDate: + return 'Exif date'; + case DateFieldSource.exifDateOriginal: + return 'Exif original date'; + case DateFieldSource.exifDateDigitized: + return 'Exif digitized date'; + case DateFieldSource.exifGpsDate: + return 'Exif GPS date'; + } + } + + MetadataField? toMetadataField() { + switch (this) { + case DateFieldSource.fileModifiedDate: + return null; + case DateFieldSource.exifDate: + return MetadataField.exifDate; + case DateFieldSource.exifDateOriginal: + return MetadataField.exifDateOriginal; + case DateFieldSource.exifDateDigitized: + return MetadataField.exifDateDigitized; + case DateFieldSource.exifGpsDate: + return MetadataField.exifGpsDatestamp; + } + } +} diff --git a/lib/model/metadata/enums/enums.dart b/lib/model/metadata/enums/enums.dart new file mode 100644 index 000000000..7d8a54ec6 --- /dev/null +++ b/lib/model/metadata/enums/enums.dart @@ -0,0 +1,46 @@ +enum DateEditAction { + setCustom, + copyField, + copyItem, + extractFromTitle, + shift, + remove, +} + +enum DateFieldSource { + fileModifiedDate, + exifDate, + exifDateOriginal, + exifDateDigitized, + exifGpsDate, +} + +enum LocationEditAction { + chooseOnMap, + copyItem, + setCustom, + remove, +} + +enum MetadataType { + // JPEG COM marker or GIF comment + comment, + // Exif: https://en.wikipedia.org/wiki/Exif + exif, + // ICC profile: https://en.wikipedia.org/wiki/ICC_profile + iccProfile, + // IPTC: https://en.wikipedia.org/wiki/IPTC_Information_Interchange_Model + iptc, + // JPEG APP0 / JFIF: https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format + jfif, + // JPEG APP14 / Adobe: https://www.exiftool.org/TagNames/JPEG.html#Adobe + jpegAdobe, + // JPEG APP12 / Ducky: https://www.exiftool.org/TagNames/APP12.html#Ducky + jpegDucky, + // ISO User Data box content, etc. + mp4, + // Photoshop IRB: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ + photoshopIrb, + // XMP: https://en.wikipedia.org/wiki/Extensible_Metadata_Platform + xmp, +} diff --git a/lib/model/metadata/enums/location_edit_action.dart b/lib/model/metadata/enums/location_edit_action.dart new file mode 100644 index 000000000..5c0f25424 --- /dev/null +++ b/lib/model/metadata/enums/location_edit_action.dart @@ -0,0 +1,18 @@ +import 'package:aves/model/metadata/enums/enums.dart'; +import 'package:aves/widgets/common/extensions/build_context.dart'; +import 'package:flutter/widgets.dart'; + +extension ExtraLocationEditAction on LocationEditAction { + String getText(BuildContext context) { + switch (this) { + case LocationEditAction.chooseOnMap: + return context.l10n.editEntryLocationDialogChooseOnMap; + case LocationEditAction.copyItem: + return context.l10n.editEntryDialogCopyFromItem; + case LocationEditAction.setCustom: + return context.l10n.editEntryLocationDialogSetCustom; + case LocationEditAction.remove: + return context.l10n.actionRemove; + } + } +} diff --git a/lib/model/metadata/enums.dart b/lib/model/metadata/enums/metadata_type.dart similarity index 52% rename from lib/model/metadata/enums.dart rename to lib/model/metadata/enums/metadata_type.dart index dead66e4f..e7481d5ae 100644 --- a/lib/model/metadata/enums.dart +++ b/lib/model/metadata/enums/metadata_type.dart @@ -1,44 +1,4 @@ -import 'package:aves/model/metadata/fields.dart'; - -enum DateEditAction { - setCustom, - copyField, - copyItem, - extractFromTitle, - shift, - remove, -} - -enum DateFieldSource { - fileModifiedDate, - exifDate, - exifDateOriginal, - exifDateDigitized, - exifGpsDate, -} - -enum MetadataType { - // JPEG COM marker or GIF comment - comment, - // Exif: https://en.wikipedia.org/wiki/Exif - exif, - // ICC profile: https://en.wikipedia.org/wiki/ICC_profile - iccProfile, - // IPTC: https://en.wikipedia.org/wiki/IPTC_Information_Interchange_Model - iptc, - // JPEG APP0 / JFIF: https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format - jfif, - // JPEG APP14 / Adobe: https://www.exiftool.org/TagNames/JPEG.html#Adobe - jpegAdobe, - // JPEG APP12 / Ducky: https://www.exiftool.org/TagNames/APP12.html#Ducky - jpegDucky, - // ISO User Data box content, etc. - mp4, - // Photoshop IRB: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ - photoshopIrb, - // XMP: https://en.wikipedia.org/wiki/Extensible_Metadata_Platform - xmp, -} +import 'package:aves/model/metadata/enums/enums.dart'; class MetadataTypes { static const main = { @@ -114,20 +74,3 @@ extension ExtraMetadataType on MetadataType { } } } - -extension ExtraDateFieldSource on DateFieldSource { - MetadataField? toMetadataField() { - switch (this) { - case DateFieldSource.fileModifiedDate: - return null; - case DateFieldSource.exifDate: - return MetadataField.exifDate; - case DateFieldSource.exifDateOriginal: - return MetadataField.exifDateOriginal; - case DateFieldSource.exifDateDigitized: - return MetadataField.exifDateDigitized; - case DateFieldSource.exifGpsDate: - return MetadataField.exifGpsDatestamp; - } - } -} diff --git a/lib/model/metadata/fields.dart b/lib/model/metadata/fields.dart index b6b279226..552909243 100644 --- a/lib/model/metadata/fields.dart +++ b/lib/model/metadata/fields.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; enum MetadataField { exifDate, diff --git a/lib/services/metadata/metadata_edit_service.dart b/lib/services/metadata/metadata_edit_service.dart index 1ab75766b..aeb8aec66 100644 --- a/lib/services/metadata/metadata_edit_service.dart +++ b/lib/services/metadata/metadata_edit_service.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:aves/model/entry.dart'; import 'package:aves/model/metadata/date_modifier.dart'; -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; +import 'package:aves/model/metadata/enums/metadata_type.dart'; import 'package:aves/model/metadata/fields.dart'; import 'package:aves/services/common/services.dart'; import 'package:collection/collection.dart'; diff --git a/lib/widgets/common/action_mixins/entry_editor.dart b/lib/widgets/common/action_mixins/entry_editor.dart index fab741142..612b0cacf 100644 --- a/lib/widgets/common/action_mixins/entry_editor.dart +++ b/lib/widgets/common/action_mixins/entry_editor.dart @@ -1,7 +1,7 @@ import 'package:aves/model/entry.dart'; import 'package:aves/model/entry_metadata_edition.dart'; import 'package:aves/model/metadata/date_modifier.dart'; -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/ref/mime_types.dart'; import 'package:aves/services/common/services.dart'; @@ -33,12 +33,12 @@ mixin EntryEditorMixin { Future selectLocation(BuildContext context, Set entries, CollectionLens? collection) async { if (entries.isEmpty) return null; - final initialLocation = entries.firstWhereOrNull((entry) => entry.hasGps)?.latLng; + final entry = entries.firstWhereOrNull((entry) => entry.hasGps) ?? entries.first; return showDialog( context: context, builder: (context) => EditEntryLocationDialog( - initialLocation: initialLocation, + entry: entry, collection: collection, ), ); diff --git a/lib/widgets/common/action_mixins/entry_storage.dart b/lib/widgets/common/action_mixins/entry_storage.dart index c5aaaa7e9..03ec5bc2c 100644 --- a/lib/widgets/common/action_mixins/entry_storage.dart +++ b/lib/widgets/common/action_mixins/entry_storage.dart @@ -8,7 +8,7 @@ import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/trash.dart'; import 'package:aves/model/highlight.dart'; import 'package:aves/model/metadata/date_modifier.dart'; -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; diff --git a/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart b/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart index 1a2a0b936..11d2fed61 100644 --- a/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart +++ b/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart @@ -1,6 +1,8 @@ import 'package:aves/model/entry.dart'; import 'package:aves/model/metadata/date_modifier.dart'; -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/date_edit_action.dart'; +import 'package:aves/model/metadata/enums/date_field_source.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; import 'package:aves/model/metadata/fields.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/theme/durations.dart'; @@ -36,7 +38,7 @@ class _EditEntryDateDialogState extends State { DateEditAction _action = DateEditAction.setCustom; DateFieldSource _copyFieldSource = DateFieldSource.fileModifiedDate; late AvesEntry _copyItemSource; - late DateTime _setDateTime; + late DateTime _customDateTime; late ValueNotifier _shiftHour, _shiftMinute; late ValueNotifier _shiftSign; bool _showOptions = false; @@ -47,13 +49,13 @@ class _EditEntryDateDialogState extends State { @override void initState() { super.initState(); - _initSet(); + _initCustom(); _initCopyItem(); _initShift(minutesInHour); } - void _initSet() { - _setDateTime = widget.entry.bestDate ?? DateTime.now(); + void _initCustom() { + _customDateTime = widget.entry.bestDate ?? DateTime.now(); } void _initCopyItem() { @@ -84,7 +86,7 @@ class _EditEntryDateDialogState extends State { padding: const EdgeInsets.only(left: 16, top: 8, right: 16), child: TextDropdownButton( values: DateEditAction.values, - valueText: (v) => _actionText(context, v), + valueText: (v) => v.getText(context), value: _action, onChanged: (v) => setState(() => _action = v!), isExpanded: true, @@ -143,7 +145,7 @@ class _EditEntryDateDialogState extends State { padding: const EdgeInsetsDirectional.only(start: 16, end: 8), child: Row( children: [ - Expanded(child: Text(formatDateTime(_setDateTime, locale, use24hour))), + Expanded(child: Text(formatDateTime(_customDateTime, locale, use24hour))), IconButton( icon: const Icon(AIcons.edit), onPressed: _editDate, @@ -159,7 +161,7 @@ class _EditEntryDateDialogState extends State { padding: const EdgeInsets.only(left: 16, top: 0, right: 16), child: TextDropdownButton( values: DateFieldSource.values, - valueText: (v) => _setSourceText(context, v), + valueText: (v) => v.getText(context), value: _copyFieldSource, onChanged: (v) => setState(() => _copyFieldSource = v!), isExpanded: true, @@ -280,44 +282,10 @@ class _EditEntryDateDialogState extends State { ); } - String _actionText(BuildContext context, DateEditAction action) { - final l10n = context.l10n; - switch (action) { - case DateEditAction.setCustom: - return l10n.editEntryDateDialogSetCustom; - case DateEditAction.copyField: - return l10n.editEntryDateDialogCopyField; - case DateEditAction.copyItem: - return l10n.editEntryDialogCopyFromItem; - case DateEditAction.extractFromTitle: - return l10n.editEntryDateDialogExtractFromTitle; - case DateEditAction.shift: - return l10n.editEntryDateDialogShift; - case DateEditAction.remove: - return l10n.actionRemove; - } - } - - String _setSourceText(BuildContext context, DateFieldSource source) { - final l10n = context.l10n; - switch (source) { - case DateFieldSource.fileModifiedDate: - return l10n.editEntryDateDialogSourceFileModifiedDate; - case DateFieldSource.exifDate: - return 'Exif date'; - case DateFieldSource.exifDateOriginal: - return 'Exif original date'; - case DateFieldSource.exifDateDigitized: - return 'Exif digitized date'; - case DateFieldSource.exifGpsDate: - return 'Exif GPS date'; - } - } - Future _editDate() async { final _date = await showDatePicker( context: context, - initialDate: _setDateTime, + initialDate: _customDateTime, firstDate: DateTime(0), lastDate: DateTime(2100), confirmText: context.l10n.nextButtonLabel, @@ -326,11 +294,11 @@ class _EditEntryDateDialogState extends State { final _time = await showTimePicker( context: context, - initialTime: TimeOfDay.fromDateTime(_setDateTime), + initialTime: TimeOfDay.fromDateTime(_customDateTime), ); if (_time == null) return; - setState(() => _setDateTime = DateTime( + setState(() => _customDateTime = DateTime( _date.year, _date.month, _date.day, @@ -366,7 +334,7 @@ class _EditEntryDateDialogState extends State { // whether each item supports Exif edition switch (_action) { case DateEditAction.setCustom: - return DateModifier.setCustom(const {}, _setDateTime); + return DateModifier.setCustom(const {}, _customDateTime); case DateEditAction.copyField: return DateModifier.copyField(_copyFieldSource); case DateEditAction.copyItem: diff --git a/lib/widgets/dialogs/entry_editors/edit_location_dialog.dart b/lib/widgets/dialogs/entry_editors/edit_location_dialog.dart index c490b9ee8..fd169f457 100644 --- a/lib/widgets/dialogs/entry_editors/edit_location_dialog.dart +++ b/lib/widgets/dialogs/entry_editors/edit_location_dialog.dart @@ -1,22 +1,32 @@ +import 'package:aves/model/entry.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; +import 'package:aves/model/metadata/enums/location_edit_action.dart'; +import 'package:aves/model/settings/enums/coordinate_format.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; +import 'package:aves/theme/durations.dart'; import 'package:aves/theme/icons.dart'; +import 'package:aves/theme/themes.dart'; import 'package:aves/utils/constants.dart'; +import 'package:aves/widgets/common/basic/text_dropdown_button.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; import 'package:aves/widgets/dialogs/aves_dialog.dart'; +import 'package:aves/widgets/dialogs/item_pick_dialog.dart'; +import 'package:aves/widgets/dialogs/item_picker.dart'; import 'package:aves/widgets/dialogs/location_pick_dialog.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:latlong2/latlong.dart'; +import 'package:provider/provider.dart'; class EditEntryLocationDialog extends StatefulWidget { - final LatLng? initialLocation; + final AvesEntry entry; final CollectionLens? collection; const EditEntryLocationDialog({ super.key, - required this.initialLocation, + required this.entry, this.collection, }); @@ -25,9 +35,10 @@ class EditEntryLocationDialog extends StatefulWidget { } class _EditEntryLocationDialogState extends State { - _LocationAction _action = _LocationAction.set; + LocationEditAction _action = LocationEditAction.chooseOnMap; + LatLng? _mapCoordinates; + late AvesEntry _copyItemSource; final TextEditingController _latitudeController = TextEditingController(), _longitudeController = TextEditingController(); - final FocusNode _latitudeFocusNode = FocusNode(), _longitudeFocusNode = FocusNode(); final ValueNotifier _isValidNotifier = ValueNotifier(false); NumberFormat get coordinateFormatter => NumberFormat('0.000000', context.l10n.localeName); @@ -35,15 +46,35 @@ class _EditEntryLocationDialogState extends State { @override void initState() { super.initState(); - _latitudeFocusNode.addListener(_onLatLngFocusChange); - _longitudeFocusNode.addListener(_onLatLngFocusChange); - WidgetsBinding.instance.addPostFrameCallback((_) => _setLocation(context, widget.initialLocation)); + _initMapCoordinates(); + _initCopyItem(); + _initCustom(); + } + + void _initMapCoordinates() { + _mapCoordinates = widget.entry.latLng; + } + + void _initCopyItem() { + _copyItemSource = widget.entry; + } + + void _initCustom() { + WidgetsBinding.instance.addPostFrameCallback((_) { + final latLng = widget.entry.latLng; + if (latLng != null) { + _latitudeController.text = coordinateFormatter.format(latLng.latitude); + _longitudeController.text = coordinateFormatter.format(latLng.longitude); + } else { + _latitudeController.text = ''; + _longitudeController.text = ''; + } + setState(_validate); + }); } @override void dispose() { - _latitudeFocusNode.removeListener(_onLatLngFocusChange); - _longitudeFocusNode.removeListener(_onLatLngFocusChange); _latitudeController.dispose(); _longitudeController.dispose(); super.dispose(); @@ -62,64 +93,36 @@ class _EditEntryLocationDialogState extends State { return AvesDialog( title: l10n.editEntryLocationDialogTitle, scrollableContent: [ - RadioListTile<_LocationAction>( - value: _LocationAction.set, - groupValue: _action, - onChanged: (v) => setState(() { - _action = v!; - _validate(); - }), - title: Row( - crossAxisAlignment: CrossAxisAlignment.start, + Padding( + padding: const EdgeInsets.only(left: 16, top: 8, right: 16), + child: TextDropdownButton( + values: LocationEditAction.values, + valueText: (v) => v.getText(context), + value: _action, + onChanged: (v) => setState(() { + _action = v!; + _validate(); + }), + isExpanded: true, + dropdownColor: Themes.thirdLayerColor(context), + ), + ), + AnimatedSwitcher( + duration: context.read().formTransition, + switchInCurve: Curves.easeInOutCubic, + switchOutCurve: Curves.easeInOutCubic, + transitionBuilder: _formTransitionBuilder, + child: Column( + key: ValueKey(_action), + mainAxisSize: MainAxisSize.min, children: [ - Expanded( - child: Column( - children: [ - TextField( - controller: _latitudeController, - focusNode: _latitudeFocusNode, - decoration: InputDecoration( - labelText: l10n.editEntryLocationDialogLatitude, - hintText: coordinateFormatter.format(Constants.pointNemo.latitude), - ), - onChanged: (_) => _validate(), - ), - TextField( - controller: _longitudeController, - focusNode: _longitudeFocusNode, - decoration: InputDecoration( - labelText: l10n.editEntryLocationDialogLongitude, - hintText: coordinateFormatter.format(Constants.pointNemo.longitude), - ), - onChanged: (_) => _validate(), - ), - ], - ), - ), - const SizedBox(width: 8), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: IconButton( - icon: const Icon(AIcons.map), - onPressed: _pickLocation, - tooltip: l10n.editEntryLocationDialogChooseOnMapTooltip, - ), - ), + if (_action == LocationEditAction.chooseOnMap) _buildChooseOnMapContent(context), + if (_action == LocationEditAction.copyItem) _buildCopyItemContent(context), + if (_action == LocationEditAction.setCustom) _buildSetCustomContent(context), ], ), - contentPadding: const EdgeInsetsDirectional.only(start: 16, end: 8), - ), - RadioListTile<_LocationAction>( - value: _LocationAction.remove, - groupValue: _action, - onChanged: (v) => setState(() { - _action = v!; - _latitudeFocusNode.unfocus(); - _longitudeFocusNode.unfocus(); - _validate(); - }), - title: Text(l10n.actionRemove), ), + const SizedBox(height: 8), ], actions: [ TextButton( @@ -142,22 +145,32 @@ class _EditEntryLocationDialogState extends State { ); } - void _onLatLngFocusChange() { - if (_latitudeFocusNode.hasFocus || _longitudeFocusNode.hasFocus) { - setState(() { - _action = _LocationAction.set; - _validate(); - }); - } - } + Widget _formTransitionBuilder(Widget child, Animation animation) => FadeTransition( + opacity: animation, + child: SizeTransition( + sizeFactor: animation, + axisAlignment: -1, + child: child, + ), + ); - void _setLocation(BuildContext context, LatLng? latLng) { - _latitudeController.text = latLng != null ? coordinateFormatter.format(latLng.latitude) : ''; - _longitudeController.text = latLng != null ? coordinateFormatter.format(latLng.longitude) : ''; - setState(() { - _action = _LocationAction.set; - _validate(); - }); + Widget _buildChooseOnMapContent(BuildContext context) { + final l10n = context.l10n; + + return Padding( + padding: const EdgeInsetsDirectional.only(start: 16, end: 8), + child: Row( + children: [ + Expanded(child: _toText(context, _mapCoordinates)), + const SizedBox(width: 8), + IconButton( + icon: const Icon(AIcons.map), + onPressed: _pickLocation, + tooltip: l10n.editEntryLocationDialogChooseOnMap, + ), + ], + ), + ); } Future _pickLocation() async { @@ -176,7 +189,7 @@ class _EditEntryLocationDialogState extends State { : null; return LocationPickDialog( collection: mapCollection, - initialLocation: _parseLatLng(), + initialLocation: _mapCoordinates, ); }, fullscreenDialog: true, @@ -184,7 +197,102 @@ class _EditEntryLocationDialogState extends State { ); if (latLng != null) { settings.mapDefaultCenter = latLng; - _setLocation(context, latLng); + setState(() { + _mapCoordinates = latLng; + _validate(); + }); + } + } + + Widget _buildCopyItemContent(BuildContext context) { + return Padding( + padding: const EdgeInsetsDirectional.only(start: 16, end: 8), + child: Row( + children: [ + Expanded(child: _toText(context, _copyItemSource.latLng)), + const SizedBox(width: 8), + ItemPicker( + extent: 48, + entry: _copyItemSource, + onTap: _pickCopyItemSource, + ), + ], + ), + ); + } + + Future _pickCopyItemSource() async { + final _collection = widget.collection; + if (_collection == null) return; + + final entry = await Navigator.push( + context, + MaterialPageRoute( + settings: const RouteSettings(name: ItemPickDialog.routeName), + builder: (context) => ItemPickDialog( + collection: CollectionLens( + source: _collection.source, + ), + ), + fullscreenDialog: true, + ), + ); + if (entry != null) { + setState(() { + _copyItemSource = entry; + _validate(); + }); + } + } + + Widget _buildSetCustomContent(BuildContext context) { + final l10n = context.l10n; + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + children: [ + TextField( + controller: _latitudeController, + decoration: InputDecoration( + labelText: l10n.editEntryLocationDialogLatitude, + hintText: coordinateFormatter.format(Constants.pointNemo.latitude), + ), + onChanged: (_) => _validate(), + ), + TextField( + controller: _longitudeController, + decoration: InputDecoration( + labelText: l10n.editEntryLocationDialogLongitude, + hintText: coordinateFormatter.format(Constants.pointNemo.longitude), + ), + onChanged: (_) => _validate(), + ), + ], + ), + ), + ], + ), + ); + } + + Text _toText(BuildContext context, LatLng? latLng) { + final l10n = context.l10n; + if (latLng != null) { + return Text( + ExtraCoordinateFormat.toDMS(l10n, latLng).join('\n'), + ); + } else { + return Text( + l10n.viewerInfoUnknown, + style: TextStyle( + color: Theme.of(context).textTheme.bodySmall!.color, + ), + ); } } @@ -205,12 +313,18 @@ class _EditEntryLocationDialogState extends State { return LatLng(lat, lng); } - Future _validate() async { + void _validate() { switch (_action) { - case _LocationAction.set: + case LocationEditAction.chooseOnMap: + _isValidNotifier.value = _mapCoordinates != null; + break; + case LocationEditAction.copyItem: + _isValidNotifier.value = _copyItemSource.hasGps; + break; + case LocationEditAction.setCustom: _isValidNotifier.value = _parseLatLng() != null; break; - case _LocationAction.remove: + case LocationEditAction.remove: _isValidNotifier.value = true; break; } @@ -218,14 +332,18 @@ class _EditEntryLocationDialogState extends State { void _submit(BuildContext context) { switch (_action) { - case _LocationAction.set: + case LocationEditAction.chooseOnMap: + Navigator.pop(context, _mapCoordinates); + break; + case LocationEditAction.copyItem: + Navigator.pop(context, _copyItemSource.latLng); + break; + case LocationEditAction.setCustom: Navigator.pop(context, _parseLatLng()); break; - case _LocationAction.remove: + case LocationEditAction.remove: Navigator.pop(context, LatLng(0, 0)); break; } } } - -enum _LocationAction { set, remove } diff --git a/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart b/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart index 1cb08eec6..027d69406 100644 --- a/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart +++ b/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart @@ -1,4 +1,5 @@ -import 'package:aves/model/metadata/enums.dart'; +import 'package:aves/model/metadata/enums/enums.dart'; +import 'package:aves/model/metadata/enums/metadata_type.dart'; import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/ref/brand_colors.dart'; diff --git a/untranslated.json b/untranslated.json index 1a79ac754..e00e4cc87 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1,12 +1,17 @@ { "de": [ - "widgetOpenPageCollection", - "durationDialogSeconds" + "editEntryLocationDialogSetCustom" ], "el": [ + "editEntryLocationDialogSetCustom" + ], + + "es": [ + "widgetOpenPageHome", "widgetOpenPageCollection", - "durationDialogSeconds" + "widgetOpenPageViewer", + "editEntryLocationDialogSetCustom" ], "fa": [ @@ -212,11 +217,11 @@ "exportEntryDialogWidth", "exportEntryDialogHeight", "renameEntryDialogLabel", + "editEntryDialogCopyFromItem", "editEntryDialogTargetFieldsHeader", "editEntryDateDialogTitle", "editEntryDateDialogSetCustom", "editEntryDateDialogCopyField", - "editEntryDialogCopyFromItem", "editEntryDateDialogExtractFromTitle", "editEntryDateDialogShift", "editEntryDateDialogSourceFileModifiedDate", @@ -224,7 +229,457 @@ "durationDialogMinutes", "durationDialogSeconds", "editEntryLocationDialogTitle", - "editEntryLocationDialogChooseOnMapTooltip", + "editEntryLocationDialogSetCustom", + "editEntryLocationDialogChooseOnMap", + "editEntryLocationDialogLatitude", + "editEntryLocationDialogLongitude", + "locationPickerUseThisLocationButton", + "editEntryRatingDialogTitle", + "removeEntryMetadataDialogTitle", + "removeEntryMetadataDialogMore", + "removeEntryMetadataMotionPhotoXmpWarningDialogMessage", + "convertMotionPhotoToStillImageWarningDialogMessage", + "videoSpeedDialogLabel", + "videoStreamSelectionDialogVideo", + "videoStreamSelectionDialogAudio", + "videoStreamSelectionDialogText", + "videoStreamSelectionDialogOff", + "videoStreamSelectionDialogTrack", + "videoStreamSelectionDialogNoSelection", + "genericSuccessFeedback", + "genericFailureFeedback", + "menuActionConfigureView", + "menuActionSelect", + "menuActionSelectAll", + "menuActionSelectNone", + "menuActionMap", + "menuActionSlideshow", + "menuActionStats", + "viewDialogSortSectionTitle", + "viewDialogGroupSectionTitle", + "viewDialogLayoutSectionTitle", + "viewDialogReverseSortOrder", + "tileLayoutMosaic", + "tileLayoutGrid", + "tileLayoutList", + "coverDialogTabCover", + "coverDialogTabApp", + "coverDialogTabColor", + "appPickDialogTitle", + "appPickDialogNone", + "aboutPageTitle", + "aboutLinkLicense", + "aboutLinkPolicy", + "aboutBugSectionTitle", + "aboutBugSaveLogInstruction", + "aboutBugCopyInfoInstruction", + "aboutBugCopyInfoButton", + "aboutBugReportInstruction", + "aboutBugReportButton", + "aboutCreditsSectionTitle", + "aboutCreditsWorldAtlas1", + "aboutCreditsWorldAtlas2", + "aboutTranslatorsSectionTitle", + "aboutLicensesSectionTitle", + "aboutLicensesBanner", + "aboutLicensesAndroidLibrariesSectionTitle", + "aboutLicensesFlutterPluginsSectionTitle", + "aboutLicensesFlutterPackagesSectionTitle", + "aboutLicensesDartPackagesSectionTitle", + "aboutLicensesShowAllButtonLabel", + "policyPageTitle", + "collectionPageTitle", + "collectionPickPageTitle", + "collectionSelectPageTitle", + "collectionActionShowTitleSearch", + "collectionActionHideTitleSearch", + "collectionActionAddShortcut", + "collectionActionEmptyBin", + "collectionActionCopy", + "collectionActionMove", + "collectionActionRescan", + "collectionActionEdit", + "collectionSearchTitlesHintText", + "collectionGroupAlbum", + "collectionGroupMonth", + "collectionGroupDay", + "collectionGroupNone", + "sectionUnknown", + "dateToday", + "dateYesterday", + "dateThisMonth", + "collectionDeleteFailureFeedback", + "collectionCopyFailureFeedback", + "collectionMoveFailureFeedback", + "collectionRenameFailureFeedback", + "collectionEditFailureFeedback", + "collectionExportFailureFeedback", + "collectionCopySuccessFeedback", + "collectionMoveSuccessFeedback", + "collectionRenameSuccessFeedback", + "collectionEditSuccessFeedback", + "collectionEmptyFavourites", + "collectionEmptyVideos", + "collectionEmptyImages", + "collectionEmptyGrantAccessButtonLabel", + "collectionSelectSectionTooltip", + "collectionDeselectSectionTooltip", + "drawerAboutButton", + "drawerSettingsButton", + "drawerCollectionAll", + "drawerCollectionFavourites", + "drawerCollectionImages", + "drawerCollectionVideos", + "drawerCollectionAnimated", + "drawerCollectionMotionPhotos", + "drawerCollectionPanoramas", + "drawerCollectionRaws", + "drawerCollectionSphericalVideos", + "drawerAlbumPage", + "drawerCountryPage", + "drawerTagPage", + "sortByDate", + "sortByName", + "sortByItemCount", + "sortBySize", + "sortByAlbumFileName", + "sortByRating", + "sortOrderNewestFirst", + "sortOrderOldestFirst", + "sortOrderAtoZ", + "sortOrderZtoA", + "sortOrderHighestFirst", + "sortOrderLowestFirst", + "sortOrderLargestFirst", + "sortOrderSmallestFirst", + "albumGroupTier", + "albumGroupType", + "albumGroupVolume", + "albumGroupNone", + "albumMimeTypeMixed", + "albumPickPageTitleCopy", + "albumPickPageTitleExport", + "albumPickPageTitleMove", + "albumPickPageTitlePick", + "albumCamera", + "albumDownload", + "albumScreenshots", + "albumScreenRecordings", + "albumVideoCaptures", + "albumPageTitle", + "albumEmpty", + "createAlbumTooltip", + "createAlbumButtonLabel", + "newFilterBanner", + "countryPageTitle", + "countryEmpty", + "tagPageTitle", + "tagEmpty", + "binPageTitle", + "searchCollectionFieldHint", + "searchRecentSectionTitle", + "searchDateSectionTitle", + "searchAlbumsSectionTitle", + "searchCountriesSectionTitle", + "searchPlacesSectionTitle", + "searchTagsSectionTitle", + "searchRatingSectionTitle", + "searchMetadataSectionTitle", + "settingsPageTitle", + "settingsSystemDefault", + "settingsDefault", + "settingsDisabled", + "settingsSearchFieldLabel", + "settingsSearchEmpty", + "settingsActionExport", + "settingsActionExportDialogTitle", + "settingsActionImport", + "settingsActionImportDialogTitle", + "appExportCovers", + "appExportFavourites", + "appExportSettings", + "settingsNavigationSectionTitle", + "settingsHomeTile", + "settingsHomeDialogTitle", + "settingsShowBottomNavigationBar", + "settingsKeepScreenOnTile", + "settingsKeepScreenOnDialogTitle", + "settingsDoubleBackExit", + "settingsConfirmationTile", + "settingsConfirmationDialogTitle", + "settingsConfirmationBeforeDeleteItems", + "settingsConfirmationBeforeMoveToBinItems", + "settingsConfirmationBeforeMoveUndatedItems", + "settingsConfirmationAfterMoveToBinItems", + "settingsNavigationDrawerTile", + "settingsNavigationDrawerEditorPageTitle", + "settingsNavigationDrawerBanner", + "settingsNavigationDrawerTabTypes", + "settingsNavigationDrawerTabAlbums", + "settingsNavigationDrawerTabPages", + "settingsNavigationDrawerAddAlbum", + "settingsThumbnailSectionTitle", + "settingsThumbnailOverlayTile", + "settingsThumbnailOverlayPageTitle", + "settingsThumbnailShowFavouriteIcon", + "settingsThumbnailShowTagIcon", + "settingsThumbnailShowLocationIcon", + "settingsThumbnailShowMotionPhotoIcon", + "settingsThumbnailShowRating", + "settingsThumbnailShowRawIcon", + "settingsThumbnailShowVideoDuration", + "settingsCollectionQuickActionsTile", + "settingsCollectionQuickActionEditorPageTitle", + "settingsCollectionQuickActionTabBrowsing", + "settingsCollectionQuickActionTabSelecting", + "settingsCollectionBrowsingQuickActionEditorBanner", + "settingsCollectionSelectionQuickActionEditorBanner", + "settingsViewerSectionTitle", + "settingsViewerGestureSideTapNext", + "settingsViewerUseCutout", + "settingsViewerMaximumBrightness", + "settingsMotionPhotoAutoPlay", + "settingsImageBackground", + "settingsViewerQuickActionsTile", + "settingsViewerQuickActionEditorPageTitle", + "settingsViewerQuickActionEditorBanner", + "settingsViewerQuickActionEditorDisplayedButtonsSectionTitle", + "settingsViewerQuickActionEditorAvailableButtonsSectionTitle", + "settingsViewerQuickActionEmpty", + "settingsViewerOverlayTile", + "settingsViewerOverlayPageTitle", + "settingsViewerShowOverlayOnOpening", + "settingsViewerShowMinimap", + "settingsViewerShowInformation", + "settingsViewerShowInformationSubtitle", + "settingsViewerShowShootingDetails", + "settingsViewerShowOverlayThumbnails", + "settingsViewerEnableOverlayBlurEffect", + "settingsViewerSlideshowTile", + "settingsViewerSlideshowPageTitle", + "settingsSlideshowRepeat", + "settingsSlideshowShuffle", + "settingsSlideshowFillScreen", + "settingsSlideshowAnimatedZoomEffect", + "settingsSlideshowTransitionTile", + "settingsSlideshowIntervalTile", + "settingsSlideshowVideoPlaybackTile", + "settingsSlideshowVideoPlaybackDialogTitle", + "settingsVideoPageTitle", + "settingsVideoSectionTitle", + "settingsVideoShowVideos", + "settingsVideoEnableHardwareAcceleration", + "settingsVideoAutoPlay", + "settingsVideoLoopModeTile", + "settingsVideoLoopModeDialogTitle", + "settingsSubtitleThemeTile", + "settingsSubtitleThemePageTitle", + "settingsSubtitleThemeSample", + "settingsSubtitleThemeTextAlignmentTile", + "settingsSubtitleThemeTextAlignmentDialogTitle", + "settingsSubtitleThemeTextSize", + "settingsSubtitleThemeShowOutline", + "settingsSubtitleThemeTextColor", + "settingsSubtitleThemeTextOpacity", + "settingsSubtitleThemeBackgroundColor", + "settingsSubtitleThemeBackgroundOpacity", + "settingsSubtitleThemeTextAlignmentLeft", + "settingsSubtitleThemeTextAlignmentCenter", + "settingsSubtitleThemeTextAlignmentRight", + "settingsVideoControlsTile", + "settingsVideoControlsPageTitle", + "settingsVideoButtonsTile", + "settingsVideoGestureDoubleTapTogglePlay", + "settingsVideoGestureSideDoubleTapSeek", + "settingsPrivacySectionTitle", + "settingsAllowInstalledAppAccess", + "settingsAllowInstalledAppAccessSubtitle", + "settingsAllowErrorReporting", + "settingsSaveSearchHistory", + "settingsEnableBin", + "settingsEnableBinSubtitle", + "settingsHiddenItemsTile", + "settingsHiddenItemsPageTitle", + "settingsHiddenItemsTabFilters", + "settingsHiddenFiltersBanner", + "settingsHiddenFiltersEmpty", + "settingsHiddenItemsTabPaths", + "settingsHiddenPathsBanner", + "addPathTooltip", + "settingsStorageAccessTile", + "settingsStorageAccessPageTitle", + "settingsStorageAccessBanner", + "settingsStorageAccessEmpty", + "settingsStorageAccessRevokeTooltip", + "settingsAccessibilitySectionTitle", + "settingsRemoveAnimationsTile", + "settingsRemoveAnimationsDialogTitle", + "settingsTimeToTakeActionTile", + "settingsDisplaySectionTitle", + "settingsThemeBrightnessTile", + "settingsThemeBrightnessDialogTitle", + "settingsThemeColorHighlights", + "settingsThemeEnableDynamicColor", + "settingsDisplayRefreshRateModeTile", + "settingsDisplayRefreshRateModeDialogTitle", + "settingsLanguageSectionTitle", + "settingsLanguageTile", + "settingsLanguagePageTitle", + "settingsCoordinateFormatTile", + "settingsCoordinateFormatDialogTitle", + "settingsUnitSystemTile", + "settingsUnitSystemDialogTitle", + "settingsScreenSaverPageTitle", + "settingsWidgetPageTitle", + "settingsWidgetShowOutline", + "settingsWidgetOpenPage", + "settingsCollectionTile", + "statsPageTitle", + "statsWithGps", + "statsTopCountriesSectionTitle", + "statsTopPlacesSectionTitle", + "statsTopTagsSectionTitle", + "statsTopAlbumsSectionTitle", + "viewerOpenPanoramaButtonLabel", + "viewerSetWallpaperButtonLabel", + "viewerErrorUnknown", + "viewerErrorDoesNotExist", + "viewerInfoPageTitle", + "viewerInfoBackToViewerTooltip", + "viewerInfoUnknown", + "viewerInfoLabelDescription", + "viewerInfoLabelTitle", + "viewerInfoLabelDate", + "viewerInfoLabelResolution", + "viewerInfoLabelSize", + "viewerInfoLabelUri", + "viewerInfoLabelPath", + "viewerInfoLabelDuration", + "viewerInfoLabelOwner", + "viewerInfoLabelCoordinates", + "viewerInfoLabelAddress", + "mapStyleDialogTitle", + "mapStyleTooltip", + "mapZoomInTooltip", + "mapZoomOutTooltip", + "mapPointNorthUpTooltip", + "mapAttributionOsmHot", + "mapAttributionStamen", + "openMapPageTooltip", + "mapEmptyRegion", + "viewerInfoOpenEmbeddedFailureFeedback", + "viewerInfoOpenLinkText", + "viewerInfoViewXmlLinkText", + "viewerInfoSearchFieldLabel", + "viewerInfoSearchEmpty", + "viewerInfoSearchSuggestionDate", + "viewerInfoSearchSuggestionDescription", + "viewerInfoSearchSuggestionDimensions", + "viewerInfoSearchSuggestionResolution", + "viewerInfoSearchSuggestionRights", + "wallpaperUseScrollEffect", + "tagEditorPageTitle", + "tagEditorPageNewTagFieldLabel", + "tagEditorPageAddTagTooltip", + "tagEditorSectionRecent", + "panoramaEnableSensorControl", + "panoramaDisableSensorControl", + "sourceViewerPageTitle", + "filePickerShowHiddenFiles", + "filePickerDoNotShowHiddenFiles", + "filePickerOpenFrom", + "filePickerNoItems", + "filePickerUseThisFolder" + ], + + "fr": [ + "editEntryLocationDialogSetCustom" + ], + + "gl": [ + "accessibilityAnimationsRemove", + "accessibilityAnimationsKeep", + "displayRefreshRatePreferHighest", + "displayRefreshRatePreferLowest", + "videoPlaybackSkip", + "videoPlaybackMuted", + "videoPlaybackWithSound", + "themeBrightnessLight", + "themeBrightnessDark", + "themeBrightnessBlack", + "viewerTransitionSlide", + "viewerTransitionParallax", + "viewerTransitionFade", + "viewerTransitionZoomIn", + "viewerTransitionNone", + "wallpaperTargetHome", + "wallpaperTargetLock", + "wallpaperTargetHomeLock", + "widgetOpenPageHome", + "widgetOpenPageCollection", + "widgetOpenPageViewer", + "albumTierNew", + "albumTierPinned", + "albumTierSpecial", + "albumTierApps", + "albumTierRegular", + "storageVolumeDescriptionFallbackPrimary", + "storageVolumeDescriptionFallbackNonPrimary", + "rootDirectoryDescription", + "otherDirectoryDescription", + "storageAccessDialogMessage", + "restrictedAccessDialogMessage", + "notEnoughSpaceDialogMessage", + "missingSystemFilePickerDialogMessage", + "unsupportedTypeDialogMessage", + "nameConflictDialogSingleSourceMessage", + "nameConflictDialogMultipleSourceMessage", + "addShortcutDialogLabel", + "addShortcutButtonLabel", + "noMatchingAppDialogMessage", + "binEntriesConfirmationDialogMessage", + "deleteEntriesConfirmationDialogMessage", + "moveUndatedConfirmationDialogMessage", + "moveUndatedConfirmationDialogSetDate", + "videoResumeDialogMessage", + "videoStartOverButtonLabel", + "videoResumeButtonLabel", + "setCoverDialogLatest", + "setCoverDialogAuto", + "setCoverDialogCustom", + "hideFilterConfirmationDialogMessage", + "newAlbumDialogTitle", + "newAlbumDialogNameLabel", + "newAlbumDialogNameLabelAlreadyExistsHelper", + "newAlbumDialogStorageLabel", + "renameAlbumDialogLabel", + "renameAlbumDialogLabelAlreadyExistsHelper", + "renameEntrySetPageTitle", + "renameEntrySetPagePatternFieldLabel", + "renameEntrySetPageInsertTooltip", + "renameEntrySetPagePreviewSectionTitle", + "renameProcessorCounter", + "renameProcessorName", + "deleteSingleAlbumConfirmationDialogMessage", + "deleteMultiAlbumConfirmationDialogMessage", + "exportEntryDialogFormat", + "exportEntryDialogWidth", + "exportEntryDialogHeight", + "renameEntryDialogLabel", + "editEntryDialogCopyFromItem", + "editEntryDialogTargetFieldsHeader", + "editEntryDateDialogTitle", + "editEntryDateDialogSetCustom", + "editEntryDateDialogCopyField", + "editEntryDateDialogExtractFromTitle", + "editEntryDateDialogShift", + "editEntryDateDialogSourceFileModifiedDate", + "durationDialogHours", + "durationDialogMinutes", + "durationDialogSeconds", + "editEntryLocationDialogTitle", + "editEntryLocationDialogSetCustom", + "editEntryLocationDialogChooseOnMap", "editEntryLocationDialogLatitude", "editEntryLocationDialogLongitude", "locationPickerUseThisLocationButton", @@ -594,6 +1049,7 @@ "widgetOpenPageCollection", "widgetOpenPageViewer", "durationDialogSeconds", + "editEntryLocationDialogSetCustom", "tileLayoutMosaic", "albumGroupType", "albumMimeTypeMixed", @@ -605,8 +1061,7 @@ ], "it": [ - "widgetOpenPageCollection", - "durationDialogSeconds" + "editEntryLocationDialogSetCustom" ], "ja": [ @@ -621,6 +1076,7 @@ "widgetOpenPageCollection", "widgetOpenPageViewer", "durationDialogSeconds", + "editEntryLocationDialogSetCustom", "viewDialogReverseSortOrder", "tileLayoutMosaic", "sortOrderNewestFirst", @@ -644,6 +1100,10 @@ "wallpaperUseScrollEffect" ], + "ko": [ + "editEntryLocationDialogSetCustom" + ], + "nb": [ "videoActionCaptureFrame", "videoActionSelectStreams", @@ -672,6 +1132,7 @@ "editEntryDateDialogShift", "editEntryDateDialogSourceFileModifiedDate", "editEntryLocationDialogTitle", + "editEntryLocationDialogSetCustom", "locationPickerUseThisLocationButton", "removeEntryMetadataMotionPhotoXmpWarningDialogMessage", "videoStreamSelectionDialogText", @@ -756,6 +1217,7 @@ "widgetOpenPageCollection", "widgetOpenPageViewer", "durationDialogSeconds", + "editEntryLocationDialogSetCustom", "aboutLinkPolicy", "policyPageTitle" ], @@ -870,11 +1332,11 @@ "exportEntryDialogWidth", "exportEntryDialogHeight", "renameEntryDialogLabel", + "editEntryDialogCopyFromItem", "editEntryDialogTargetFieldsHeader", "editEntryDateDialogTitle", "editEntryDateDialogSetCustom", "editEntryDateDialogCopyField", - "editEntryDialogCopyFromItem", "editEntryDateDialogExtractFromTitle", "editEntryDateDialogShift", "editEntryDateDialogSourceFileModifiedDate", @@ -882,7 +1344,8 @@ "durationDialogMinutes", "durationDialogSeconds", "editEntryLocationDialogTitle", - "editEntryLocationDialogChooseOnMapTooltip", + "editEntryLocationDialogSetCustom", + "editEntryLocationDialogChooseOnMap", "editEntryLocationDialogLatitude", "editEntryLocationDialogLongitude", "locationPickerUseThisLocationButton", @@ -1245,7 +1708,11 @@ ], "pt": [ - "durationDialogSeconds" + "editEntryLocationDialogSetCustom" + ], + + "ru": [ + "editEntryLocationDialogSetCustom" ], "tr": [ @@ -1273,6 +1740,7 @@ "widgetOpenPageCollection", "widgetOpenPageViewer", "durationDialogSeconds", + "editEntryLocationDialogSetCustom", "menuActionSlideshow", "viewDialogReverseSortOrder", "tileLayoutMosaic", @@ -1310,7 +1778,6 @@ ], "zh": [ - "widgetOpenPageCollection", - "durationDialogSeconds" + "editEntryLocationDialogSetCustom" ] }