#533 places: page, navigation
This commit is contained in:
parent
300ce4f1bd
commit
af6fd8f11b
27 changed files with 505 additions and 91 deletions
|
@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## <a id="unreleased"></a>[Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Places: page & navigation entry
|
||||
|
||||
### Fixed
|
||||
|
||||
- replacing when moving item to vault
|
||||
- exporting item to vault
|
||||
|
||||
## <a id="v1.8.1"></a>[v1.8.1] - 2023-02-21
|
||||
|
||||
### Added
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
"chipActionDelete": "Delete",
|
||||
"chipActionGoToAlbumPage": "Show in Albums",
|
||||
"chipActionGoToCountryPage": "Show in Countries",
|
||||
"chipActionGoToPlacePage": "Show in Places",
|
||||
"chipActionGoToTagPage": "Show in Tags",
|
||||
"chipActionFilterOut": "Filter out",
|
||||
"chipActionFilterIn": "Filter in",
|
||||
|
@ -621,6 +622,7 @@
|
|||
"drawerCollectionSphericalVideos": "360° Videos",
|
||||
"drawerAlbumPage": "Albums",
|
||||
"drawerCountryPage": "Countries",
|
||||
"drawerPlacePage": "Places",
|
||||
"drawerTagPage": "Tags",
|
||||
|
||||
"sortByDate": "By date",
|
||||
|
@ -665,6 +667,9 @@
|
|||
"countryPageTitle": "Countries",
|
||||
"countryEmpty": "No countries",
|
||||
|
||||
"placePageTitle": "Places",
|
||||
"placeEmpty": "No places",
|
||||
|
||||
"tagPageTitle": "Tags",
|
||||
"tagEmpty": "No tags",
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:flutter/widgets.dart';
|
|||
enum ChipAction {
|
||||
goToAlbumPage,
|
||||
goToCountryPage,
|
||||
goToPlacePage,
|
||||
goToTagPage,
|
||||
reverse,
|
||||
hide,
|
||||
|
@ -18,6 +19,8 @@ extension ExtraChipAction on ChipAction {
|
|||
return context.l10n.chipActionGoToAlbumPage;
|
||||
case ChipAction.goToCountryPage:
|
||||
return context.l10n.chipActionGoToCountryPage;
|
||||
case ChipAction.goToPlacePage:
|
||||
return context.l10n.chipActionGoToPlacePage;
|
||||
case ChipAction.goToTagPage:
|
||||
return context.l10n.chipActionGoToTagPage;
|
||||
case ChipAction.reverse:
|
||||
|
@ -37,7 +40,9 @@ extension ExtraChipAction on ChipAction {
|
|||
case ChipAction.goToAlbumPage:
|
||||
return AIcons.album;
|
||||
case ChipAction.goToCountryPage:
|
||||
return AIcons.location;
|
||||
return AIcons.country;
|
||||
case ChipAction.goToPlacePage:
|
||||
return AIcons.place;
|
||||
case ChipAction.goToTagPage:
|
||||
return AIcons.tag;
|
||||
case ChipAction.reverse:
|
||||
|
|
|
@ -51,6 +51,8 @@ class LocationFilter extends CoveredCollectionFilter {
|
|||
|
||||
String? get countryCode => _countryCode;
|
||||
|
||||
String get place => _location;
|
||||
|
||||
@override
|
||||
EntryFilter get positiveTest => _test;
|
||||
|
||||
|
@ -65,17 +67,25 @@ class LocationFilter extends CoveredCollectionFilter {
|
|||
|
||||
@override
|
||||
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true}) {
|
||||
if (_countryCode != null && device.canRenderFlagEmojis) {
|
||||
final flag = countryCodeToFlag(_countryCode);
|
||||
if (flag != null) {
|
||||
return Text(
|
||||
flag,
|
||||
style: TextStyle(fontSize: size),
|
||||
textScaleFactor: 1.0,
|
||||
);
|
||||
}
|
||||
if (_location.isEmpty) {
|
||||
return Icon(AIcons.locationUnlocated, size: size);
|
||||
}
|
||||
switch (level) {
|
||||
case LocationLevel.place:
|
||||
return Icon(AIcons.place, size: size);
|
||||
case LocationLevel.country:
|
||||
if (_countryCode != null && device.canRenderFlagEmojis) {
|
||||
final flag = countryCodeToFlag(_countryCode);
|
||||
if (flag != null) {
|
||||
return Text(
|
||||
flag,
|
||||
style: TextStyle(fontSize: size),
|
||||
textScaleFactor: 1.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
return Icon(AIcons.country, size: size);
|
||||
}
|
||||
return Icon(_location.isEmpty ? AIcons.locationUnlocated : AIcons.location, size: size);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -23,8 +23,10 @@ class PlaceholderFilter extends CollectionFilter {
|
|||
PlaceholderFilter._private(this.placeholder) : super(reversed: false) {
|
||||
switch (placeholder) {
|
||||
case _country:
|
||||
_icon = AIcons.country;
|
||||
break;
|
||||
case _place:
|
||||
_icon = AIcons.location;
|
||||
_icon = AIcons.place;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:aves/model/settings/enums/enums.dart';
|
|||
import 'package:aves/model/source/enums/enums.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
@ -40,6 +41,7 @@ class SettingsDefaults {
|
|||
static const drawerPageBookmarks = [
|
||||
AlbumListPage.routeName,
|
||||
CountryListPage.routeName,
|
||||
PlaceListPage.routeName,
|
||||
TagListPage.routeName,
|
||||
];
|
||||
|
||||
|
@ -65,6 +67,7 @@ class SettingsDefaults {
|
|||
static const albumGroupFactor = AlbumChipGroupFactor.importance;
|
||||
static const albumSortFactor = ChipSortFactor.name;
|
||||
static const countrySortFactor = ChipSortFactor.name;
|
||||
static const placeSortFactor = ChipSortFactor.name;
|
||||
static const tagSortFactor = ChipSortFactor.name;
|
||||
|
||||
// viewer
|
||||
|
|
|
@ -18,10 +18,9 @@ extension ExtraThumbnailOverlayLocationIcon on ThumbnailOverlayLocationIcon {
|
|||
|
||||
IconData getIcon(BuildContext context) {
|
||||
switch (this) {
|
||||
case ThumbnailOverlayLocationIcon.located:
|
||||
return AIcons.location;
|
||||
case ThumbnailOverlayLocationIcon.unlocated:
|
||||
return AIcons.locationUnlocated;
|
||||
case ThumbnailOverlayLocationIcon.located:
|
||||
case ThumbnailOverlayLocationIcon.none:
|
||||
return AIcons.location;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import 'package:aves/widgets/aves_app.dart';
|
|||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
@ -106,9 +107,11 @@ class Settings extends ChangeNotifier {
|
|||
static const albumGroupFactorKey = 'album_group_factor';
|
||||
static const albumSortFactorKey = 'album_sort_factor';
|
||||
static const countrySortFactorKey = 'country_sort_factor';
|
||||
static const placeSortFactorKey = 'place_sort_factor';
|
||||
static const tagSortFactorKey = 'tag_sort_factor';
|
||||
static const albumSortReverseKey = 'album_sort_reverse';
|
||||
static const countrySortReverseKey = 'country_sort_reverse';
|
||||
static const placeSortReverseKey = 'place_sort_reverse';
|
||||
static const tagSortReverseKey = 'tag_sort_reverse';
|
||||
static const pinnedFiltersKey = 'pinned_filters';
|
||||
static const hiddenFiltersKey = 'hidden_filters';
|
||||
|
@ -265,6 +268,7 @@ class Settings extends ChangeNotifier {
|
|||
drawerPageBookmarks = [
|
||||
AlbumListPage.routeName,
|
||||
CountryListPage.routeName,
|
||||
PlaceListPage.routeName,
|
||||
TagListPage.routeName,
|
||||
SearchPage.routeName,
|
||||
];
|
||||
|
@ -543,6 +547,10 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set countrySortFactor(ChipSortFactor newValue) => _set(countrySortFactorKey, newValue.toString());
|
||||
|
||||
ChipSortFactor get placeSortFactor => getEnumOrDefault(placeSortFactorKey, SettingsDefaults.placeSortFactor, ChipSortFactor.values);
|
||||
|
||||
set placeSortFactor(ChipSortFactor newValue) => _set(placeSortFactorKey, newValue.toString());
|
||||
|
||||
ChipSortFactor get tagSortFactor => getEnumOrDefault(tagSortFactorKey, SettingsDefaults.tagSortFactor, ChipSortFactor.values);
|
||||
|
||||
set tagSortFactor(ChipSortFactor newValue) => _set(tagSortFactorKey, newValue.toString());
|
||||
|
@ -555,6 +563,10 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set countrySortReverse(bool newValue) => _set(countrySortReverseKey, newValue);
|
||||
|
||||
bool get placeSortReverse => getBool(placeSortReverseKey) ?? false;
|
||||
|
||||
set placeSortReverse(bool newValue) => _set(placeSortReverseKey, newValue);
|
||||
|
||||
bool get tagSortReverse => getBool(tagSortReverseKey) ?? false;
|
||||
|
||||
set tagSortReverse(bool newValue) => _set(tagSortReverseKey, newValue);
|
||||
|
@ -1038,6 +1050,7 @@ class Settings extends ChangeNotifier {
|
|||
case showThumbnailVideoDurationKey:
|
||||
case albumSortReverseKey:
|
||||
case countrySortReverseKey:
|
||||
case placeSortReverseKey:
|
||||
case tagSortReverseKey:
|
||||
case showOverlayOnOpeningKey:
|
||||
case showOverlayMinimapKey:
|
||||
|
@ -1084,6 +1097,7 @@ class Settings extends ChangeNotifier {
|
|||
case albumGroupFactorKey:
|
||||
case albumSortFactorKey:
|
||||
case countrySortFactorKey:
|
||||
case placeSortFactorKey:
|
||||
case tagSortFactorKey:
|
||||
case imageBackgroundKey:
|
||||
case videoAutoPlayModeKey:
|
||||
|
|
|
@ -14,7 +14,7 @@ import 'package:aves/model/filters/trash.dart';
|
|||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/events.dart';
|
||||
import 'package:aves/model/source/location.dart';
|
||||
import 'package:aves/model/source/location/location.dart';
|
||||
import 'package:aves/model/source/section_keys.dart';
|
||||
import 'package:aves/model/source/tag.dart';
|
||||
import 'package:aves/utils/change_notifier.dart';
|
||||
|
|
|
@ -15,7 +15,9 @@ import 'package:aves/model/source/album.dart';
|
|||
import 'package:aves/model/source/analysis_controller.dart';
|
||||
import 'package:aves/model/source/enums/enums.dart';
|
||||
import 'package:aves/model/source/events.dart';
|
||||
import 'package:aves/model/source/location.dart';
|
||||
import 'package:aves/model/source/location/country.dart';
|
||||
import 'package:aves/model/source/location/location.dart';
|
||||
import 'package:aves/model/source/location/place.dart';
|
||||
import 'package:aves/model/source/tag.dart';
|
||||
import 'package:aves/model/source/trash.dart';
|
||||
import 'package:aves/model/vaults/vaults.dart';
|
||||
|
@ -54,7 +56,7 @@ mixin SourceBase {
|
|||
void invalidateEntries();
|
||||
}
|
||||
|
||||
abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagMixin, TrashMixin {
|
||||
abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, PlaceMixin, LocationMixin, TagMixin, TrashMixin {
|
||||
CollectionSource() {
|
||||
settings.updateStream.where((event) => event.key == Settings.localeKey).listen((_) => invalidateAlbumDisplayNames());
|
||||
settings.updateStream.where((event) => event.key == Settings.hiddenFiltersKey).listen((event) {
|
||||
|
@ -136,6 +138,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
|
|||
invalidateEntries();
|
||||
invalidateAlbumFilterSummary(entries: entries, notify: notify);
|
||||
invalidateCountryFilterSummary(entries: entries, notify: notify);
|
||||
invalidatePlaceFilterSummary(entries: entries, notify: notify);
|
||||
invalidateTagFilterSummary(entries: entries, notify: notify);
|
||||
}
|
||||
|
||||
|
@ -501,21 +504,42 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
|
|||
|
||||
int count(CollectionFilter filter) {
|
||||
if (filter is AlbumFilter) return albumEntryCount(filter);
|
||||
if (filter is LocationFilter) return countryEntryCount(filter);
|
||||
if (filter is LocationFilter) {
|
||||
switch (filter.level) {
|
||||
case LocationLevel.country:
|
||||
return countryEntryCount(filter);
|
||||
case LocationLevel.place:
|
||||
return placeEntryCount(filter);
|
||||
}
|
||||
}
|
||||
if (filter is TagFilter) return tagEntryCount(filter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int size(CollectionFilter filter) {
|
||||
if (filter is AlbumFilter) return albumSize(filter);
|
||||
if (filter is LocationFilter) return countrySize(filter);
|
||||
if (filter is LocationFilter) {
|
||||
switch (filter.level) {
|
||||
case LocationLevel.country:
|
||||
return countrySize(filter);
|
||||
case LocationLevel.place:
|
||||
return placeSize(filter);
|
||||
}
|
||||
}
|
||||
if (filter is TagFilter) return tagSize(filter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AvesEntry? recentEntry(CollectionFilter filter) {
|
||||
if (filter is AlbumFilter) return albumRecentEntry(filter);
|
||||
if (filter is LocationFilter) return countryRecentEntry(filter);
|
||||
if (filter is LocationFilter) {
|
||||
switch (filter.level) {
|
||||
case LocationLevel.country:
|
||||
return countryRecentEntry(filter);
|
||||
case LocationLevel.place:
|
||||
return placeRecentEntry(filter);
|
||||
}
|
||||
}
|
||||
if (filter is TagFilter) return tagRecentEntry(filter);
|
||||
return null;
|
||||
}
|
||||
|
|
66
lib/model/source/location/country.dart
Normal file
66
lib/model/source/location/country.dart
Normal file
|
@ -0,0 +1,66 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/utils/collection_utils.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
mixin CountryMixin on SourceBase {
|
||||
// filter summary
|
||||
|
||||
// by country code
|
||||
final Map<String, int> _filterEntryCountMap = {}, _filterSizeMap = {};
|
||||
final Map<String, AvesEntry?> _filterRecentEntryMap = {};
|
||||
|
||||
void invalidateCountryFilterSummary({
|
||||
Set<AvesEntry>? entries,
|
||||
Set<String>? countryCodes,
|
||||
bool notify = true,
|
||||
}) {
|
||||
if (_filterEntryCountMap.isEmpty && _filterSizeMap.isEmpty && _filterRecentEntryMap.isEmpty) return;
|
||||
|
||||
if (entries == null && countryCodes == null) {
|
||||
_filterEntryCountMap.clear();
|
||||
_filterSizeMap.clear();
|
||||
_filterRecentEntryMap.clear();
|
||||
} else {
|
||||
countryCodes ??= {};
|
||||
if (entries != null) {
|
||||
countryCodes.addAll(entries.where((entry) => entry.hasAddress).map((entry) => entry.addressDetails?.countryCode).whereNotNull());
|
||||
}
|
||||
countryCodes.forEach((countryCode) {
|
||||
_filterEntryCountMap.remove(countryCode);
|
||||
_filterSizeMap.remove(countryCode);
|
||||
_filterRecentEntryMap.remove(countryCode);
|
||||
});
|
||||
}
|
||||
if (notify) {
|
||||
eventBus.fire(CountrySummaryInvalidatedEvent(countryCodes));
|
||||
}
|
||||
}
|
||||
|
||||
int countryEntryCount(LocationFilter filter) {
|
||||
final countryCode = filter.countryCode;
|
||||
if (countryCode == null) return 0;
|
||||
return _filterEntryCountMap.putIfAbsent(countryCode, () => visibleEntries.where(filter.test).length);
|
||||
}
|
||||
|
||||
int countrySize(LocationFilter filter) {
|
||||
final countryCode = filter.countryCode;
|
||||
if (countryCode == null) return 0;
|
||||
return _filterSizeMap.putIfAbsent(countryCode, () => visibleEntries.where(filter.test).map((v) => v.sizeBytes).sum);
|
||||
}
|
||||
|
||||
AvesEntry? countryRecentEntry(LocationFilter filter) {
|
||||
final countryCode = filter.countryCode;
|
||||
if (countryCode == null) return null;
|
||||
return _filterRecentEntryMap.putIfAbsent(countryCode, () => sortedEntriesByDate.firstWhereOrNull(filter.test));
|
||||
}
|
||||
}
|
||||
|
||||
class CountriesChangedEvent {}
|
||||
|
||||
class CountrySummaryInvalidatedEvent {
|
||||
final Set<String>? countryCodes;
|
||||
|
||||
const CountrySummaryInvalidatedEvent(this.countryCodes);
|
||||
}
|
|
@ -6,15 +6,15 @@ import 'package:aves/model/filters/location.dart';
|
|||
import 'package:aves/model/metadata/address.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/analysis_controller.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/enums/enums.dart';
|
||||
import 'package:aves/model/source/location/country.dart';
|
||||
import 'package:aves/model/source/location/place.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/utils/collection_utils.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
mixin LocationMixin on SourceBase {
|
||||
mixin LocationMixin on CountryMixin, PlaceMixin {
|
||||
static const commitCountThreshold = 200;
|
||||
static const _stopCheckCountThreshold = 50;
|
||||
|
||||
|
@ -150,7 +150,7 @@ mixin LocationMixin on SourceBase {
|
|||
}
|
||||
|
||||
void updateLocations() {
|
||||
final locations = visibleEntries.where((entry) => entry.hasAddress).map((entry) => entry.addressDetails).whereNotNull().toList();
|
||||
final locations = visibleEntries.map((entry) => entry.addressDetails).whereNotNull().toList();
|
||||
final updatedPlaces = locations.map((address) => address.place).whereNotNull().where((v) => v.isNotEmpty).toSet().toList()..sort(compareAsciiUpperCase);
|
||||
if (!listEquals(updatedPlaces, sortedPlaces)) {
|
||||
sortedPlaces = List.unmodifiable(updatedPlaces);
|
||||
|
@ -177,67 +177,6 @@ mixin LocationMixin on SourceBase {
|
|||
eventBus.fire(CountriesChangedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
// filter summary
|
||||
|
||||
// by country code
|
||||
final Map<String, int> _filterEntryCountMap = {}, _filterSizeMap = {};
|
||||
final Map<String, AvesEntry?> _filterRecentEntryMap = {};
|
||||
|
||||
void invalidateCountryFilterSummary({
|
||||
Set<AvesEntry>? entries,
|
||||
Set<String>? countryCodes,
|
||||
bool notify = true,
|
||||
}) {
|
||||
if (_filterEntryCountMap.isEmpty && _filterSizeMap.isEmpty && _filterRecentEntryMap.isEmpty) return;
|
||||
|
||||
if (entries == null && countryCodes == null) {
|
||||
_filterEntryCountMap.clear();
|
||||
_filterSizeMap.clear();
|
||||
_filterRecentEntryMap.clear();
|
||||
} else {
|
||||
countryCodes ??= {};
|
||||
if (entries != null) {
|
||||
countryCodes.addAll(entries.where((entry) => entry.hasAddress).map((entry) => entry.addressDetails?.countryCode).whereNotNull());
|
||||
}
|
||||
countryCodes.forEach((countryCode) {
|
||||
_filterEntryCountMap.remove(countryCode);
|
||||
_filterSizeMap.remove(countryCode);
|
||||
_filterRecentEntryMap.remove(countryCode);
|
||||
});
|
||||
}
|
||||
if (notify) {
|
||||
eventBus.fire(CountrySummaryInvalidatedEvent(countryCodes));
|
||||
}
|
||||
}
|
||||
|
||||
int countryEntryCount(LocationFilter filter) {
|
||||
final countryCode = filter.countryCode;
|
||||
if (countryCode == null) return 0;
|
||||
return _filterEntryCountMap.putIfAbsent(countryCode, () => visibleEntries.where(filter.test).length);
|
||||
}
|
||||
|
||||
int countrySize(LocationFilter filter) {
|
||||
final countryCode = filter.countryCode;
|
||||
if (countryCode == null) return 0;
|
||||
return _filterSizeMap.putIfAbsent(countryCode, () => visibleEntries.where(filter.test).map((v) => v.sizeBytes).sum);
|
||||
}
|
||||
|
||||
AvesEntry? countryRecentEntry(LocationFilter filter) {
|
||||
final countryCode = filter.countryCode;
|
||||
if (countryCode == null) return null;
|
||||
return _filterRecentEntryMap.putIfAbsent(countryCode, () => sortedEntriesByDate.firstWhereOrNull(filter.test));
|
||||
}
|
||||
}
|
||||
|
||||
class AddressMetadataChangedEvent {}
|
||||
|
||||
class PlacesChangedEvent {}
|
||||
|
||||
class CountriesChangedEvent {}
|
||||
|
||||
class CountrySummaryInvalidatedEvent {
|
||||
final Set<String>? countryCodes;
|
||||
|
||||
const CountrySummaryInvalidatedEvent(this.countryCodes);
|
||||
}
|
60
lib/model/source/location/place.dart
Normal file
60
lib/model/source/location/place.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/utils/collection_utils.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
mixin PlaceMixin on SourceBase {
|
||||
// filter summary
|
||||
|
||||
// by place
|
||||
final Map<String, int> _filterEntryCountMap = {}, _filterSizeMap = {};
|
||||
final Map<String, AvesEntry?> _filterRecentEntryMap = {};
|
||||
|
||||
void invalidatePlaceFilterSummary({
|
||||
Set<AvesEntry>? entries,
|
||||
Set<String>? places,
|
||||
bool notify = true,
|
||||
}) {
|
||||
if (_filterEntryCountMap.isEmpty && _filterSizeMap.isEmpty && _filterRecentEntryMap.isEmpty) return;
|
||||
|
||||
if (entries == null && places == null) {
|
||||
_filterEntryCountMap.clear();
|
||||
_filterSizeMap.clear();
|
||||
_filterRecentEntryMap.clear();
|
||||
} else {
|
||||
places ??= {};
|
||||
if (entries != null) {
|
||||
places.addAll(entries.map((entry) => entry.addressDetails?.place).whereNotNull());
|
||||
}
|
||||
places.forEach((place) {
|
||||
_filterEntryCountMap.remove(place);
|
||||
_filterSizeMap.remove(place);
|
||||
_filterRecentEntryMap.remove(place);
|
||||
});
|
||||
}
|
||||
if (notify) {
|
||||
eventBus.fire(PlaceSummaryInvalidatedEvent(places));
|
||||
}
|
||||
}
|
||||
|
||||
int placeEntryCount(LocationFilter filter) {
|
||||
return _filterEntryCountMap.putIfAbsent(filter.place, () => visibleEntries.where(filter.test).length);
|
||||
}
|
||||
|
||||
int placeSize(LocationFilter filter) {
|
||||
return _filterSizeMap.putIfAbsent(filter.place, () => visibleEntries.where(filter.test).map((v) => v.sizeBytes).sum);
|
||||
}
|
||||
|
||||
AvesEntry? placeRecentEntry(LocationFilter filter) {
|
||||
return _filterRecentEntryMap.putIfAbsent(filter.place, () => sortedEntriesByDate.firstWhereOrNull(filter.test));
|
||||
}
|
||||
}
|
||||
|
||||
class PlacesChangedEvent {}
|
||||
|
||||
class PlaceSummaryInvalidatedEvent {
|
||||
final Set<String>? places;
|
||||
|
||||
const PlaceSummaryInvalidatedEvent(this.places);
|
||||
}
|
|
@ -36,6 +36,8 @@ class AIcons {
|
|||
static const IconData language = Icons.translate_outlined;
|
||||
static const IconData location = Icons.place_outlined;
|
||||
static const IconData locationUnlocated = Icons.location_off_outlined;
|
||||
static const IconData country = Icons.flag_outlined;
|
||||
static const IconData place = Icons.place_outlined;
|
||||
static const IconData mainStorage = Icons.smartphone_outlined;
|
||||
static const IconData mimeType = Icons.code_outlined;
|
||||
static const IconData opacity = Icons.opacity;
|
||||
|
|
|
@ -96,6 +96,7 @@ class AvesFilterChip extends StatefulWidget {
|
|||
final actions = [
|
||||
if (filter is AlbumFilter) ChipAction.goToAlbumPage,
|
||||
if ((filter is LocationFilter && filter.level == LocationLevel.country)) ChipAction.goToCountryPage,
|
||||
if ((filter is LocationFilter && filter.level == LocationLevel.place)) ChipAction.goToPlacePage,
|
||||
if (filter is TagFilter) ChipAction.goToTagPage,
|
||||
ChipAction.reverse,
|
||||
ChipAction.hide,
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:aves/widgets/collection/collection_page.dart';
|
|||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves/widgets/viewer/info/common.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -51,6 +52,7 @@ class DebugSettingsSection extends StatelessWidget {
|
|||
'tileExtent - Collection': '${settings.getTileExtent(CollectionPage.routeName)}',
|
||||
'tileExtent - Albums': '${settings.getTileExtent(AlbumListPage.routeName)}',
|
||||
'tileExtent - Countries': '${settings.getTileExtent(CountryListPage.routeName)}',
|
||||
'tileExtent - Places': '${settings.getTileExtent(PlaceListPage.routeName)}',
|
||||
'tileExtent - Tags': '${settings.getTileExtent(TagListPage.routeName)}',
|
||||
'infoMapZoom': '${settings.infoMapZoom}',
|
||||
'collectionSelectionQuickActions': '${settings.collectionSelectionQuickActions}',
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
|||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -23,6 +24,7 @@ class ChipActionDelegate with FeedbackMixin, VaultAwareMixin {
|
|||
switch (action) {
|
||||
case ChipAction.goToAlbumPage:
|
||||
case ChipAction.goToCountryPage:
|
||||
case ChipAction.goToPlacePage:
|
||||
case ChipAction.goToTagPage:
|
||||
case ChipAction.reverse:
|
||||
return true;
|
||||
|
@ -42,6 +44,9 @@ class ChipActionDelegate with FeedbackMixin, VaultAwareMixin {
|
|||
case ChipAction.goToCountryPage:
|
||||
_goTo(context, filter, CountryListPage.routeName, (context) => const CountryListPage());
|
||||
break;
|
||||
case ChipAction.goToPlacePage:
|
||||
_goTo(context, filter, PlaceListPage.routeName, (context) => const PlaceListPage());
|
||||
break;
|
||||
case ChipAction.goToTagPage:
|
||||
_goTo(context, filter, TagListPage.routeName, (context) => const TagListPage());
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/enums/enums.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
|
||||
class PlaceChipSetActionDelegate extends ChipSetActionDelegate<LocationFilter> {
|
||||
final Iterable<FilterGridItem<LocationFilter>> _items;
|
||||
|
||||
PlaceChipSetActionDelegate(Iterable<FilterGridItem<LocationFilter>> items) : _items = items;
|
||||
|
||||
@override
|
||||
Iterable<FilterGridItem<LocationFilter>> get allItems => _items;
|
||||
|
||||
@override
|
||||
ChipSortFactor get sortFactor => settings.placeSortFactor;
|
||||
|
||||
@override
|
||||
set sortFactor(ChipSortFactor factor) => settings.placeSortFactor = factor;
|
||||
|
||||
@override
|
||||
bool get sortReverse => settings.placeSortReverse;
|
||||
|
||||
@override
|
||||
set sortReverse(bool value) => settings.placeSortReverse = value;
|
||||
|
||||
@override
|
||||
TileLayout get tileLayout => settings.getTileLayout(PlaceListPage.routeName);
|
||||
|
||||
@override
|
||||
set tileLayout(TileLayout tileLayout) => settings.setTileLayout(PlaceListPage.routeName, tileLayout);
|
||||
}
|
|
@ -7,7 +7,7 @@ import 'package:aves/model/filters/location.dart';
|
|||
import 'package:aves/model/filters/tag.dart';
|
||||
import 'package:aves/model/source/album.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/location.dart';
|
||||
import 'package:aves/model/source/location/country.dart';
|
||||
import 'package:aves/model/source/tag.dart';
|
||||
import 'package:aves/model/vaults/vaults.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:aves/model/filters/location.dart';
|
|||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/enums/enums.dart';
|
||||
import 'package:aves/model/source/location.dart';
|
||||
import 'package:aves/model/source/location/country.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/identity/empty.dart';
|
||||
|
@ -43,7 +43,7 @@ class CountryListPage extends StatelessWidget {
|
|||
filterSections: _groupToSections(gridItems),
|
||||
applyQuery: applyQuery,
|
||||
emptyBuilder: () => EmptyContent(
|
||||
icon: AIcons.location,
|
||||
icon: AIcons.country,
|
||||
text: context.l10n.countryEmpty,
|
||||
),
|
||||
);
|
||||
|
|
80
lib/widgets/filter_grids/places_page.dart
Normal file
80
lib/widgets/filter_grids/places_page.dart
Normal file
|
@ -0,0 +1,80 @@
|
|||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/enums/enums.dart';
|
||||
import 'package:aves/model/source/location/place.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/identity/empty.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/action_delegates/place_set.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/filter_nav_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/section_keys.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class PlaceListPage extends StatelessWidget {
|
||||
static const routeName = '/places';
|
||||
|
||||
const PlaceListPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final source = context.read<CollectionSource>();
|
||||
return Selector<Settings, Tuple3<ChipSortFactor, bool, Set<CollectionFilter>>>(
|
||||
selector: (context, s) => Tuple3(s.placeSortFactor, s.placeSortReverse, s.pinnedFilters),
|
||||
shouldRebuild: (t1, t2) {
|
||||
// `Selector` by default uses `DeepCollectionEquality`, which does not go deep in collections within `TupleN`
|
||||
const eq = DeepCollectionEquality();
|
||||
return !(eq.equals(t1.item1, t2.item1) && eq.equals(t1.item2, t2.item2) && eq.equals(t1.item3, t2.item3));
|
||||
},
|
||||
builder: (context, s, child) {
|
||||
return StreamBuilder(
|
||||
stream: source.eventBus.on<PlacesChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final gridItems = _getGridItems(source);
|
||||
return FilterNavigationPage<LocationFilter, PlaceChipSetActionDelegate>(
|
||||
source: source,
|
||||
title: context.l10n.placePageTitle,
|
||||
sortFactor: settings.placeSortFactor,
|
||||
actionDelegate: PlaceChipSetActionDelegate(gridItems),
|
||||
filterSections: _groupToSections(gridItems),
|
||||
applyQuery: applyQuery,
|
||||
emptyBuilder: () => EmptyContent(
|
||||
icon: AIcons.place,
|
||||
text: context.l10n.placeEmpty,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<FilterGridItem<LocationFilter>> applyQuery(BuildContext context, List<FilterGridItem<LocationFilter>> filters, String query) {
|
||||
return filters.where((item) => item.filter.getLabel(context).toUpperCase().contains(query)).toList();
|
||||
}
|
||||
|
||||
List<FilterGridItem<LocationFilter>> _getGridItems(CollectionSource source) {
|
||||
final filters = source.sortedPlaces.map((location) => LocationFilter(LocationLevel.place, location)).toSet();
|
||||
|
||||
return FilterNavigationPage.sort(settings.placeSortFactor, settings.placeSortReverse, source, filters);
|
||||
}
|
||||
|
||||
static Map<ChipSectionKey, List<FilterGridItem<LocationFilter>>> _groupToSections(Iterable<FilterGridItem<LocationFilter>> sortedMapEntries) {
|
||||
final pinned = settings.pinnedFilters.whereType<LocationFilter>();
|
||||
final byPin = groupBy<FilterGridItem<LocationFilter>, bool>(sortedMapEntries, (e) => pinned.contains(e.filter));
|
||||
final pinnedMapEntries = (byPin[true] ?? []);
|
||||
final unpinnedMapEntries = (byPin[false] ?? []);
|
||||
|
||||
return {
|
||||
if (pinnedMapEntries.isNotEmpty || unpinnedMapEntries.isNotEmpty)
|
||||
const ChipSectionKey(): [
|
||||
...pinnedMapEntries,
|
||||
...unpinnedMapEntries,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@ import 'package:aves/model/settings/settings.dart';
|
|||
import 'package:aves/model/source/album.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/location.dart';
|
||||
import 'package:aves/model/source/location/country.dart';
|
||||
import 'package:aves/model/source/location/place.dart';
|
||||
import 'package:aves/model/source/tag.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
|
@ -19,6 +20,7 @@ import 'package:aves/widgets/common/identity/aves_logo.dart';
|
|||
import 'package:aves/widgets/debug/app_debug_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves/widgets/navigation/drawer/collection_nav_tile.dart';
|
||||
import 'package:aves/widgets/navigation/drawer/page_nav_tile.dart';
|
||||
|
@ -242,6 +244,12 @@ class _AppDrawerState extends State<AppDrawer> {
|
|||
builder: (context, _) => Text('${source.sortedCountries.length}'),
|
||||
);
|
||||
break;
|
||||
case PlaceListPage.routeName:
|
||||
trailing = StreamBuilder(
|
||||
stream: source.eventBus.on<PlacesChangedEvent>(),
|
||||
builder: (context, _) => Text('${source.sortedPlaces.length}'),
|
||||
);
|
||||
break;
|
||||
case TagListPage.routeName:
|
||||
trailing = StreamBuilder(
|
||||
stream: source.eventBus.on<TagsChangedEvent>(),
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:aves/widgets/common/search/route.dart';
|
|||
import 'package:aves/widgets/debug/app_debug_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves/widgets/navigation/drawer/tile.dart';
|
||||
import 'package:aves/widgets/search/search_delegate.dart';
|
||||
|
@ -88,6 +89,8 @@ class PageNavTile extends StatelessWidget {
|
|||
return (_) => const AlbumListPage();
|
||||
case CountryListPage.routeName:
|
||||
return (_) => const CountryListPage();
|
||||
case PlaceListPage.routeName:
|
||||
return (_) => const PlaceListPage();
|
||||
case TagListPage.routeName:
|
||||
return (_) => const TagListPage();
|
||||
case SettingsPage.routeName:
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:aves/widgets/common/search/page.dart';
|
|||
import 'package:aves/widgets/debug/app_debug_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves/widgets/settings/settings_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -35,6 +36,8 @@ class NavigationDisplay {
|
|||
return l10n.drawerAlbumPage;
|
||||
case CountryListPage.routeName:
|
||||
return l10n.drawerCountryPage;
|
||||
case PlaceListPage.routeName:
|
||||
return l10n.drawerPlacePage;
|
||||
case TagListPage.routeName:
|
||||
return l10n.drawerTagPage;
|
||||
case SettingsPage.routeName:
|
||||
|
@ -55,7 +58,9 @@ class NavigationDisplay {
|
|||
case AlbumListPage.routeName:
|
||||
return AIcons.album;
|
||||
case CountryListPage.routeName:
|
||||
return AIcons.location;
|
||||
return AIcons.country;
|
||||
case PlaceListPage.routeName:
|
||||
return AIcons.place;
|
||||
case TagListPage.routeName:
|
||||
return AIcons.tag;
|
||||
case SettingsPage.routeName:
|
||||
|
|
|
@ -15,7 +15,8 @@ import 'package:aves/model/settings/settings.dart';
|
|||
import 'package:aves/model/source/album.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/model/source/location.dart';
|
||||
import 'package:aves/model/source/location/country.dart';
|
||||
import 'package:aves/model/source/location/place.dart';
|
||||
import 'package:aves/model/source/tag.dart';
|
||||
import 'package:aves/ref/mime_types.dart';
|
||||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
|||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/places_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves/widgets/navigation/drawer/app_drawer.dart';
|
||||
import 'package:aves/widgets/navigation/drawer/tile.dart';
|
||||
|
@ -40,6 +41,7 @@ class _NavigationDrawerEditorPageState extends State<NavigationDrawerEditorPage>
|
|||
static const Set<String> _pageOptions = {
|
||||
AlbumListPage.routeName,
|
||||
CountryListPage.routeName,
|
||||
PlaceListPage.routeName,
|
||||
TagListPage.routeName,
|
||||
SearchPage.routeName,
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"chipActionDelete",
|
||||
"chipActionGoToAlbumPage",
|
||||
"chipActionGoToCountryPage",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionGoToTagPage",
|
||||
"chipActionFilterOut",
|
||||
"chipActionFilterIn",
|
||||
|
@ -334,6 +335,7 @@
|
|||
"drawerCollectionSphericalVideos",
|
||||
"drawerAlbumPage",
|
||||
"drawerCountryPage",
|
||||
"drawerPlacePage",
|
||||
"drawerTagPage",
|
||||
"sortByDate",
|
||||
"sortByName",
|
||||
|
@ -369,6 +371,8 @@
|
|||
"newFilterBanner",
|
||||
"countryPageTitle",
|
||||
"countryEmpty",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"tagPageTitle",
|
||||
"tagEmpty",
|
||||
"binPageTitle",
|
||||
|
@ -591,6 +595,7 @@
|
|||
],
|
||||
|
||||
"cs": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -609,11 +614,15 @@
|
|||
"authenticateToConfigureVault",
|
||||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsDisablingBinWarningDialogMessage"
|
||||
],
|
||||
|
||||
"de": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -632,11 +641,29 @@
|
|||
"authenticateToConfigureVault",
|
||||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsDisablingBinWarningDialogMessage"
|
||||
],
|
||||
|
||||
"el": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"es": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"eu": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -655,12 +682,16 @@
|
|||
"authenticateToConfigureVault",
|
||||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsDisablingBinWarningDialogMessage"
|
||||
],
|
||||
|
||||
"fa": [
|
||||
"clearTooltip",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -858,6 +889,7 @@
|
|||
"drawerCollectionSphericalVideos",
|
||||
"drawerAlbumPage",
|
||||
"drawerCountryPage",
|
||||
"drawerPlacePage",
|
||||
"drawerTagPage",
|
||||
"sortByDate",
|
||||
"sortByName",
|
||||
|
@ -892,6 +924,8 @@
|
|||
"newFilterBanner",
|
||||
"countryPageTitle",
|
||||
"countryEmpty",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"tagPageTitle",
|
||||
"tagEmpty",
|
||||
"binPageTitle",
|
||||
|
@ -1120,8 +1154,16 @@
|
|||
"filePickerUseThisFolder"
|
||||
],
|
||||
|
||||
"fr": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"gl": [
|
||||
"columnCount",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -1344,6 +1386,7 @@
|
|||
"drawerCollectionSphericalVideos",
|
||||
"drawerAlbumPage",
|
||||
"drawerCountryPage",
|
||||
"drawerPlacePage",
|
||||
"drawerTagPage",
|
||||
"sortByDate",
|
||||
"sortByName",
|
||||
|
@ -1379,6 +1422,8 @@
|
|||
"newFilterBanner",
|
||||
"countryPageTitle",
|
||||
"countryEmpty",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"tagPageTitle",
|
||||
"tagEmpty",
|
||||
"binPageTitle",
|
||||
|
@ -1646,6 +1691,7 @@
|
|||
"chipActionDelete",
|
||||
"chipActionGoToAlbumPage",
|
||||
"chipActionGoToCountryPage",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionGoToTagPage",
|
||||
"chipActionFilterOut",
|
||||
"chipActionFilterIn",
|
||||
|
@ -1966,6 +2012,7 @@
|
|||
"drawerCollectionSphericalVideos",
|
||||
"drawerAlbumPage",
|
||||
"drawerCountryPage",
|
||||
"drawerPlacePage",
|
||||
"drawerTagPage",
|
||||
"sortByDate",
|
||||
"sortByName",
|
||||
|
@ -2001,6 +2048,8 @@
|
|||
"newFilterBanner",
|
||||
"countryPageTitle",
|
||||
"countryEmpty",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"tagPageTitle",
|
||||
"tagEmpty",
|
||||
"binPageTitle",
|
||||
|
@ -2235,7 +2284,15 @@
|
|||
"filePickerUseThisFolder"
|
||||
],
|
||||
|
||||
"id": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"it": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2254,12 +2311,16 @@
|
|||
"authenticateToConfigureVault",
|
||||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsDisablingBinWarningDialogMessage"
|
||||
],
|
||||
|
||||
"ja": [
|
||||
"columnCount",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionFilterIn",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
|
@ -2288,6 +2349,9 @@
|
|||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"tooManyItemsErrorDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsViewerShowDescription",
|
||||
|
@ -2298,8 +2362,16 @@
|
|||
"settingsWidgetDisplayedItem"
|
||||
],
|
||||
|
||||
"ko": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"lt": [
|
||||
"columnCount",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2322,6 +2394,9 @@
|
|||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"tooManyItemsErrorDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsViewerShowDescription",
|
||||
|
@ -2332,6 +2407,7 @@
|
|||
],
|
||||
|
||||
"nb": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2350,12 +2426,16 @@
|
|||
"authenticateToConfigureVault",
|
||||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsDisablingBinWarningDialogMessage"
|
||||
],
|
||||
|
||||
"nl": [
|
||||
"columnCount",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2389,6 +2469,9 @@
|
|||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"tooManyItemsErrorDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsViewerShowRatingTags",
|
||||
|
@ -2405,6 +2488,7 @@
|
|||
"nn": [
|
||||
"columnCount",
|
||||
"sourceStateCataloguing",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2504,6 +2588,7 @@
|
|||
"drawerCollectionSphericalVideos",
|
||||
"drawerAlbumPage",
|
||||
"drawerCountryPage",
|
||||
"drawerPlacePage",
|
||||
"drawerTagPage",
|
||||
"sortByDate",
|
||||
"sortByName",
|
||||
|
@ -2539,6 +2624,8 @@
|
|||
"newFilterBanner",
|
||||
"countryPageTitle",
|
||||
"countryEmpty",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"tagPageTitle",
|
||||
"tagEmpty",
|
||||
"binPageTitle",
|
||||
|
@ -2709,8 +2796,16 @@
|
|||
"wallpaperUseScrollEffect"
|
||||
],
|
||||
|
||||
"pl": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"pt": [
|
||||
"columnCount",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2730,12 +2825,23 @@
|
|||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"tooManyItemsErrorDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsVideoGestureVerticalDragBrightnessVolume",
|
||||
"settingsDisablingBinWarningDialogMessage"
|
||||
],
|
||||
|
||||
"ro": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"ru": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2757,6 +2863,9 @@
|
|||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"tooManyItemsErrorDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsVideoGestureVerticalDragBrightnessVolume",
|
||||
|
@ -2768,6 +2877,7 @@
|
|||
"itemCount",
|
||||
"columnCount",
|
||||
"timeSeconds",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -2905,6 +3015,7 @@
|
|||
"drawerCollectionSphericalVideos",
|
||||
"drawerAlbumPage",
|
||||
"drawerCountryPage",
|
||||
"drawerPlacePage",
|
||||
"drawerTagPage",
|
||||
"sortByDate",
|
||||
"sortByName",
|
||||
|
@ -2940,6 +3051,8 @@
|
|||
"newFilterBanner",
|
||||
"countryPageTitle",
|
||||
"countryEmpty",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"tagPageTitle",
|
||||
"tagEmpty",
|
||||
"binPageTitle",
|
||||
|
@ -3182,6 +3295,7 @@
|
|||
"timeDays",
|
||||
"focalLength",
|
||||
"applyButtonLabel",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -3250,6 +3364,7 @@
|
|||
"drawerCollectionSphericalVideos",
|
||||
"drawerAlbumPage",
|
||||
"drawerCountryPage",
|
||||
"drawerPlacePage",
|
||||
"drawerTagPage",
|
||||
"sortByDate",
|
||||
"sortByName",
|
||||
|
@ -3285,6 +3400,8 @@
|
|||
"newFilterBanner",
|
||||
"countryPageTitle",
|
||||
"countryEmpty",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"tagPageTitle",
|
||||
"tagEmpty",
|
||||
"binPageTitle",
|
||||
|
@ -3520,6 +3637,7 @@
|
|||
],
|
||||
|
||||
"tr": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -3538,11 +3656,22 @@
|
|||
"authenticateToConfigureVault",
|
||||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsDisablingBinWarningDialogMessage"
|
||||
],
|
||||
|
||||
"uk": [
|
||||
"chipActionGoToPlacePage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty"
|
||||
],
|
||||
|
||||
"zh": [
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -3564,6 +3693,9 @@
|
|||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"tooManyItemsErrorDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsViewerShowDescription",
|
||||
|
@ -3575,6 +3707,7 @@
|
|||
|
||||
"zh_Hant": [
|
||||
"columnCount",
|
||||
"chipActionGoToPlacePage",
|
||||
"chipActionLock",
|
||||
"chipActionCreateVault",
|
||||
"chipActionConfigureVault",
|
||||
|
@ -3596,6 +3729,9 @@
|
|||
"authenticateToUnlockVault",
|
||||
"vaultBinUsageDialogMessage",
|
||||
"tooManyItemsErrorDialogMessage",
|
||||
"drawerPlacePage",
|
||||
"placePageTitle",
|
||||
"placeEmpty",
|
||||
"settingsModificationWarningDialogMessage",
|
||||
"settingsConfirmationVaultDataLoss",
|
||||
"settingsViewerShowDescription",
|
||||
|
|
Loading…
Reference in a new issue