#423 map: remove cluster location
This commit is contained in:
parent
0cf7eafca9
commit
eb48027540
8 changed files with 197 additions and 49 deletions
|
@ -123,6 +123,7 @@
|
|||
"entryInfoActionEditTags": "Edit tags",
|
||||
"entryInfoActionRemoveMetadata": "Remove metadata",
|
||||
"entryInfoActionExportMetadata": "Export metadata",
|
||||
"entryInfoActionRemoveLocation": "Remove location",
|
||||
|
||||
"filterAspectRatioLandscapeLabel": "Landscape",
|
||||
"filterAspectRatioPortraitLabel": "Portrait",
|
||||
|
|
30
lib/model/actions/map_cluster_actions.dart
Normal file
30
lib/model/actions/map_cluster_actions.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
enum MapClusterAction {
|
||||
editLocation,
|
||||
removeLocation,
|
||||
}
|
||||
|
||||
extension ExtraMapClusterAction on MapClusterAction {
|
||||
String getText(BuildContext context) {
|
||||
switch (this) {
|
||||
case MapClusterAction.editLocation:
|
||||
return context.l10n.entryInfoActionEditLocation;
|
||||
case MapClusterAction.removeLocation:
|
||||
return context.l10n.entryInfoActionRemoveLocation;
|
||||
}
|
||||
}
|
||||
|
||||
Widget getIcon() => Icon(_getIconData());
|
||||
|
||||
IconData _getIconData() {
|
||||
switch (this) {
|
||||
case MapClusterAction.editLocation:
|
||||
return AIcons.edit;
|
||||
case MapClusterAction.removeLocation:
|
||||
return AIcons.clear;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -83,6 +83,8 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
|||
return dataTypes;
|
||||
}
|
||||
|
||||
static final removalLocation = LatLng(0, 0);
|
||||
|
||||
Future<Set<EntryDataType>> editLocation(LatLng? latLng) async {
|
||||
final dataTypes = <EntryDataType>{};
|
||||
final metadata = <MetadataType, dynamic>{};
|
||||
|
@ -93,10 +95,9 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
|||
// clear every GPS field
|
||||
final exifFields = Map<MetadataField, dynamic>.fromEntries(MetadataFields.exifGpsFields.map((k) => MapEntry(k, null)));
|
||||
// add latitude & longitude, if any
|
||||
if (latLng != null) {
|
||||
if (latLng != null && latLng != removalLocation) {
|
||||
final latitude = latLng.latitude;
|
||||
final longitude = latLng.longitude;
|
||||
if (latitude != 0 && longitude != 0) {
|
||||
exifFields.addAll({
|
||||
MetadataField.exifGpsLatitude: latitude.abs(),
|
||||
MetadataField.exifGpsLatitudeRef: latitude >= 0 ? Exif.latitudeNorth : Exif.latitudeSouth,
|
||||
|
@ -104,7 +105,6 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
|||
MetadataField.exifGpsLongitudeRef: longitude >= 0 ? Exif.longitudeEast : Exif.longitudeWest,
|
||||
});
|
||||
}
|
||||
}
|
||||
metadata[MetadataType.exif] = Map<String, dynamic>.fromEntries(exifFields.entries.map((kv) => MapEntry(kv.key.toPlatform!, kv.value)));
|
||||
|
||||
if (canEditXmp && missingDate != null) {
|
||||
|
@ -119,16 +119,14 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
|||
final mp4Fields = <MetadataField, String?>{};
|
||||
|
||||
String? iso6709String;
|
||||
if (latLng != null) {
|
||||
if (latLng != null && latLng != removalLocation) {
|
||||
final latitude = latLng.latitude;
|
||||
final longitude = latLng.longitude;
|
||||
if (latitude != 0 && longitude != 0) {
|
||||
const locale = 'en_US';
|
||||
final isoLat = '${latitude >= 0 ? '+' : '-'}${NumberFormat('00.0000', locale).format(latitude.abs())}';
|
||||
final isoLon = '${longitude >= 0 ? '+' : '-'}${NumberFormat('000.0000', locale).format(longitude.abs())}';
|
||||
iso6709String = '$isoLat$isoLon/';
|
||||
}
|
||||
}
|
||||
mp4Fields[MetadataField.mp4GpsCoordinates] = iso6709String;
|
||||
|
||||
if (missingDate != null) {
|
||||
|
|
|
@ -509,7 +509,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
await _edit(context, entries, (entry) => entry.editLocation(location));
|
||||
}
|
||||
|
||||
Future<LatLng?> quickLocationByMap(BuildContext context, Set<AvesEntry> entries, LatLng clusterLocation, CollectionLens mapCollection) async {
|
||||
Future<LatLng?> editLocationByMap(BuildContext context, Set<AvesEntry> entries, LatLng clusterLocation, CollectionLens mapCollection) async {
|
||||
final editableEntries = await _getEditableItems(context, entries, canEdit: (entry) => entry.canEditLocation);
|
||||
if (editableEntries == null || editableEntries.isEmpty) return null;
|
||||
|
||||
|
@ -530,6 +530,33 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
return location;
|
||||
}
|
||||
|
||||
Future<void> removeLocation(BuildContext context, Set<AvesEntry> entries) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AvesDialog(
|
||||
content: Text(context.l10n.convertMotionPhotoToStillImageWarningDialogMessage),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: Text(context.l10n.applyButtonLabel),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
if (confirmed == null || !confirmed) return;
|
||||
|
||||
final editableEntries = await _getEditableItems(context, entries, canEdit: (entry) => entry.canEditLocation);
|
||||
if (editableEntries == null || editableEntries.isEmpty) return;
|
||||
|
||||
await _edit(context, editableEntries, (entry) => entry.editLocation(ExtraAvesEntryMetadataEdition.removalLocation));
|
||||
}
|
||||
|
||||
Future<void> _editTitleDescription(BuildContext context) async {
|
||||
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditTitleDescription);
|
||||
if (entries == null || entries.isEmpty) return;
|
||||
|
|
|
@ -38,8 +38,17 @@ class GeoMap extends StatefulWidget {
|
|||
final MapOverlay? overlayEntry;
|
||||
final UserZoomChangeCallback? onUserZoomChange;
|
||||
final MapTapCallback? onMapTap;
|
||||
final void Function(LatLng clusterLocation, AvesEntry markerEntry)? onMarkerTap;
|
||||
final void Function(Offset tapLocalPosition, Set<AvesEntry> clusterEntries, LatLng clusterLocation, WidgetBuilder markerBuilder)? onMarkerLongPress;
|
||||
final void Function(
|
||||
LatLng markerLocation,
|
||||
AvesEntry markerEntry,
|
||||
)? onMarkerTap;
|
||||
final void Function(
|
||||
LatLng markerLocation,
|
||||
AvesEntry markerEntry,
|
||||
Set<AvesEntry> clusterEntries,
|
||||
Offset tapLocalPosition,
|
||||
WidgetBuilder markerBuilder,
|
||||
)? onMarkerLongPress;
|
||||
final void Function(BuildContext context)? openMapPage;
|
||||
|
||||
const GeoMap({
|
||||
|
@ -360,15 +369,20 @@ class _GeoMapState extends State<GeoMap> {
|
|||
}
|
||||
|
||||
Fluster<GeoEntry<AvesEntry>> _buildFluster({int nodeSize = 64}) {
|
||||
final markers = entries.map((entry) {
|
||||
final latLng = entry.latLng!;
|
||||
return GeoEntry<AvesEntry>(
|
||||
final markers = entries
|
||||
.map((entry) {
|
||||
final latLng = entry.latLng;
|
||||
return latLng != null
|
||||
? GeoEntry<AvesEntry>(
|
||||
entry: entry,
|
||||
latitude: latLng.latitude,
|
||||
longitude: latLng.longitude,
|
||||
markerId: entry.uri,
|
||||
);
|
||||
}).toList();
|
||||
)
|
||||
: null;
|
||||
})
|
||||
.whereNotNull()
|
||||
.toList();
|
||||
|
||||
return Fluster<GeoEntry<AvesEntry>>(
|
||||
// we keep clustering on the whole range of zooms (including the maximum)
|
||||
|
@ -433,8 +447,8 @@ class _GeoMapState extends State<GeoMap> {
|
|||
}
|
||||
if (markerEntry == null) return;
|
||||
|
||||
final clusterLocation = LatLng(geoEntry.latitude!, geoEntry.longitude!);
|
||||
onTap(clusterLocation, markerEntry);
|
||||
final markerLocation = LatLng(geoEntry.latitude!, geoEntry.longitude!);
|
||||
onTap(markerLocation, markerEntry);
|
||||
}
|
||||
|
||||
Future<void> _onMarkerLongPress(GeoEntry<AvesEntry> geoEntry, LatLng tapLocation) async {
|
||||
|
@ -451,7 +465,7 @@ class _GeoMapState extends State<GeoMap> {
|
|||
} else {
|
||||
markerEntry = geoEntry.entry!;
|
||||
}
|
||||
final clusterLocation = LatLng(geoEntry.latitude!, geoEntry.longitude!);
|
||||
final markerLocation = LatLng(geoEntry.latitude!, geoEntry.longitude!);
|
||||
Widget markerBuilder(BuildContext context) => ImageMarker(
|
||||
count: geoEntry.pointsSize,
|
||||
drawArrow: false,
|
||||
|
@ -460,7 +474,13 @@ class _GeoMapState extends State<GeoMap> {
|
|||
extent: extent,
|
||||
),
|
||||
);
|
||||
onMarkerLongPress(tapLocalPosition, clusterEntries, clusterLocation, markerBuilder);
|
||||
onMarkerLongPress(
|
||||
markerLocation,
|
||||
markerEntry,
|
||||
clusterEntries,
|
||||
tapLocalPosition,
|
||||
markerBuilder,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _decorateMap(BuildContext context, Widget? child) => MapDecorator(child: child);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/entry_metadata_edition.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';
|
||||
|
@ -341,7 +342,7 @@ class _EditEntryLocationDialogState extends State<EditEntryLocationDialog> {
|
|||
Navigator.pop(context, _parseLatLng());
|
||||
break;
|
||||
case LocationEditAction.remove:
|
||||
Navigator.pop(context, LatLng(0, 0));
|
||||
Navigator.pop(context, ExtraAvesEntryMetadataEdition.removalLocation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/actions/entry_set_actions.dart';
|
||||
import 'package:aves/model/actions/map_cluster_actions.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/coordinate.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
@ -10,6 +10,7 @@ import 'package:aves/model/highlight.dart';
|
|||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/model/source/tag.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/utils/debouncer.dart';
|
||||
|
@ -102,6 +103,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
final ValueNotifier<bool> _overlayVisible = ValueNotifier(true);
|
||||
late AnimationController _overlayAnimationController;
|
||||
late Animation<double> _overlayScale, _scrollerSize;
|
||||
CoordinateFilter? _regionFilter;
|
||||
|
||||
CollectionLens? get regionCollection => _regionCollectionNotifier.value;
|
||||
|
||||
|
@ -119,7 +121,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
});
|
||||
}
|
||||
|
||||
_dotEntryNotifier.addListener(_updateInfoEntry);
|
||||
_dotEntryNotifier.addListener(_onSelectedEntryChanged);
|
||||
|
||||
_overlayAnimationController = AnimationController(
|
||||
duration: context.read<DurationsData>().viewerOverlayAnimation,
|
||||
|
@ -136,6 +138,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
_overlayVisible.addListener(_onOverlayVisibleChange);
|
||||
|
||||
_subscriptions.add(_mapController.idleUpdates.listen((event) => _onIdle(event.bounds)));
|
||||
_subscriptions.add(openingCollection.source.eventBus.on<CatalogMetadataChangedEvent>().listen((e) => _updateRegionCollection()));
|
||||
|
||||
_selectedIndexNotifier.addListener(_onThumbnailIndexChange);
|
||||
Future.delayed(Durations.pageTransitionAnimation * timeDilation + const Duration(seconds: 1), () {
|
||||
|
@ -158,12 +161,13 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
_subscriptions
|
||||
..forEach((sub) => sub.cancel())
|
||||
..clear();
|
||||
_dotEntryNotifier.removeListener(_updateInfoEntry);
|
||||
_dotEntryNotifier.value?.metadataChangeNotifier.removeListener(_onMarkerEntryMetadataChanged);
|
||||
_dotEntryNotifier.removeListener(_onSelectedEntryChanged);
|
||||
_overlayAnimationController.dispose();
|
||||
_overlayVisible.removeListener(_onOverlayVisibleChange);
|
||||
_mapController.dispose();
|
||||
_selectedIndexNotifier.removeListener(_onThumbnailIndexChange);
|
||||
_regionCollectionNotifier.value?.dispose();
|
||||
regionCollection?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -344,6 +348,14 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
}
|
||||
|
||||
void _onIdle(ZoomedBounds bounds) {
|
||||
_regionFilter = CoordinateFilter(bounds.sw, bounds.ne);
|
||||
_updateRegionCollection();
|
||||
}
|
||||
|
||||
void _updateRegionCollection() {
|
||||
final regionFilter = _regionFilter;
|
||||
if (regionFilter == null) return;
|
||||
|
||||
AvesEntry? selectedEntry;
|
||||
if (regionCollection != null) {
|
||||
final regionEntries = regionCollection!.sortedEntries;
|
||||
|
@ -351,11 +363,11 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
selectedEntry = selectedIndex != null && 0 <= selectedIndex && selectedIndex < regionEntries.length ? regionEntries[selectedIndex] : null;
|
||||
}
|
||||
|
||||
final oldRegionCollection = _regionCollectionNotifier.value;
|
||||
final oldRegionCollection = regionCollection;
|
||||
final newRegionCollection = openingCollection.copyWith(
|
||||
filters: {
|
||||
...openingCollection.filters.whereNot((v) => v is CoordinateFilter),
|
||||
CoordinateFilter(bounds.sw, bounds.ne),
|
||||
regionFilter,
|
||||
},
|
||||
);
|
||||
_regionCollectionNotifier.value = newRegionCollection;
|
||||
|
@ -389,11 +401,17 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
void _onThumbnailIndexChange() => _onEntrySelected(_getRegionEntry(_selectedIndexNotifier.value));
|
||||
|
||||
void _onEntrySelected(AvesEntry? selectedEntry) {
|
||||
_dotLocationNotifier.value = selectedEntry?.latLng;
|
||||
_dotEntryNotifier.value?.metadataChangeNotifier.removeListener(_onMarkerEntryMetadataChanged);
|
||||
_dotEntryNotifier.value = selectedEntry;
|
||||
selectedEntry?.metadataChangeNotifier.addListener(_onMarkerEntryMetadataChanged);
|
||||
_onMarkerEntryMetadataChanged();
|
||||
}
|
||||
|
||||
void _updateInfoEntry() {
|
||||
void _onMarkerEntryMetadataChanged() {
|
||||
_dotLocationNotifier.value = _dotEntryNotifier.value?.latLng;
|
||||
}
|
||||
|
||||
void _onSelectedEntryChanged() {
|
||||
final selectedEntry = _dotEntryNotifier.value;
|
||||
if (_infoEntryNotifier.value == null || selectedEntry == null) {
|
||||
_infoEntryNotifier.value = selectedEntry;
|
||||
|
@ -461,14 +479,15 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
// cluster context menu
|
||||
|
||||
Future<void> _onMarkerLongPress(
|
||||
Offset tapLocalPosition,
|
||||
LatLng markerLocation,
|
||||
AvesEntry markerEntry,
|
||||
Set<AvesEntry> clusterEntries,
|
||||
LatLng clusterLocation,
|
||||
Offset tapLocalPosition,
|
||||
WidgetBuilder markerBuilder,
|
||||
) async {
|
||||
final overlay = Overlay.of(context)!.context.findRenderObject() as RenderBox;
|
||||
const touchArea = Size(kMinInteractiveDimension, kMinInteractiveDimension);
|
||||
final selectedAction = await showMenu<EntrySetAction>(
|
||||
final selectedAction = await showMenu<MapClusterAction>(
|
||||
context: context,
|
||||
position: RelativeRect.fromRect(tapLocalPosition & touchArea, Offset.zero & overlay.size),
|
||||
items: [
|
||||
|
@ -483,26 +502,36 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
),
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
_buildMenuItem(EntrySetAction.editLocation),
|
||||
...[
|
||||
MapClusterAction.editLocation,
|
||||
MapClusterAction.removeLocation,
|
||||
].map(_buildMenuItem),
|
||||
],
|
||||
);
|
||||
if (selectedAction != null) {
|
||||
// wait for the popup menu to hide before proceeding with the action
|
||||
await Future.delayed(Durations.popupMenuAnimation * timeDilation);
|
||||
final delegate = EntrySetActionDelegate();
|
||||
switch (selectedAction) {
|
||||
case EntrySetAction.editLocation:
|
||||
final location = await EntrySetActionDelegate().quickLocationByMap(context, clusterEntries, clusterLocation, openingCollection);
|
||||
case MapClusterAction.editLocation:
|
||||
final regionEntries = regionCollection?.sortedEntries ?? [];
|
||||
final markerIndex = regionEntries.indexOf(markerEntry);
|
||||
final location = await delegate.editLocationByMap(context, clusterEntries, markerLocation, openingCollection);
|
||||
if (location != null) {
|
||||
if (markerIndex != -1) {
|
||||
_selectedIndexNotifier.value = markerIndex;
|
||||
}
|
||||
_mapController.moveTo(location);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case MapClusterAction.removeLocation:
|
||||
await delegate.removeLocation(context, clusterEntries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenuItem<EntrySetAction> _buildMenuItem(EntrySetAction action) {
|
||||
PopupMenuItem<MapClusterAction> _buildMenuItem(MapClusterAction action) {
|
||||
return PopupMenuItem(
|
||||
value: action,
|
||||
child: MenuIconTheme(
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
"entryInfoActionEditTags",
|
||||
"entryInfoActionRemoveMetadata",
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterBinLabel",
|
||||
|
@ -593,13 +594,22 @@
|
|||
"filePickerUseThisFolder"
|
||||
],
|
||||
|
||||
"de": [
|
||||
"entryInfoActionRemoveLocation"
|
||||
],
|
||||
|
||||
"el": [
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
"settingsViewerShowRatingTags"
|
||||
],
|
||||
|
||||
"es": [
|
||||
"entryInfoActionRemoveLocation"
|
||||
],
|
||||
|
||||
"fa": [
|
||||
"appName",
|
||||
"welcomeMessage",
|
||||
|
@ -687,6 +697,7 @@
|
|||
"entryInfoActionEditTags",
|
||||
"entryInfoActionRemoveMetadata",
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterBinLabel",
|
||||
|
@ -1194,8 +1205,13 @@
|
|||
"filePickerUseThisFolder"
|
||||
],
|
||||
|
||||
"fr": [
|
||||
"entryInfoActionRemoveLocation"
|
||||
],
|
||||
|
||||
"gl": [
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -1657,6 +1673,7 @@
|
|||
|
||||
"id": [
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -1671,6 +1688,7 @@
|
|||
],
|
||||
|
||||
"it": [
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -1680,6 +1698,7 @@
|
|||
"ja": [
|
||||
"chipActionFilterIn",
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -1693,8 +1712,21 @@
|
|||
"settingsWidgetDisplayedItem"
|
||||
],
|
||||
|
||||
"ko": [
|
||||
"entryInfoActionRemoveLocation"
|
||||
],
|
||||
|
||||
"lt": [
|
||||
"entryInfoActionRemoveLocation"
|
||||
],
|
||||
|
||||
"nb": [
|
||||
"entryInfoActionRemoveLocation"
|
||||
],
|
||||
|
||||
"nl": [
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -1715,6 +1747,7 @@
|
|||
"timeDays",
|
||||
"focalLength",
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -2211,6 +2244,7 @@
|
|||
|
||||
"pt": [
|
||||
"entryInfoActionExportMetadata",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -2225,6 +2259,7 @@
|
|||
],
|
||||
|
||||
"ro": [
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -2232,6 +2267,7 @@
|
|||
],
|
||||
|
||||
"ru": [
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -2247,6 +2283,7 @@
|
|||
"applyButtonLabel",
|
||||
"entryActionShowGeoTiffOnMap",
|
||||
"videoActionCaptureFrame",
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
@ -2612,7 +2649,12 @@
|
|||
"filePickerUseThisFolder"
|
||||
],
|
||||
|
||||
"tr": [
|
||||
"entryInfoActionRemoveLocation"
|
||||
],
|
||||
|
||||
"zh": [
|
||||
"entryInfoActionRemoveLocation",
|
||||
"filterAspectRatioLandscapeLabel",
|
||||
"filterAspectRatioPortraitLabel",
|
||||
"filterNoAddressLabel",
|
||||
|
|
Loading…
Reference in a new issue