states: section in search/stats

This commit is contained in:
Thibault Deckers 2023-03-26 18:51:24 +02:00
parent df0a3e8961
commit aabe32adc7
10 changed files with 98 additions and 43 deletions

View file

@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
- Video: action to lock viewer
- Info: improved state/place display (requires rescan, limited to AU/GB/IN/US)
- Info: edit tags with state placeholder
- Countries: show states for selected countries
- improved support for system font scale
### Changed

View file

@ -696,6 +696,7 @@
"searchDateSectionTitle": "Date",
"searchAlbumsSectionTitle": "Albums",
"searchCountriesSectionTitle": "Countries",
"searchStatesSectionTitle": "States",
"searchPlacesSectionTitle": "Places",
"searchTagsSectionTitle": "Tags",
"searchRatingSectionTitle": "Ratings",
@ -901,6 +902,7 @@
}
},
"statsTopCountriesSectionTitle": "Top Countries",
"statsTopStatesSectionTitle": "Top States",
"statsTopPlacesSectionTitle": "Top Places",
"statsTopTagsSectionTitle": "Top Tags",
"statsTopAlbumsSectionTitle": "Top Albums",

View file

@ -12,6 +12,8 @@ import 'package:flutter/foundation.dart';
import 'package:latlong2/latlong.dart';
extension ExtraAvesEntryLocation on AvesEntry {
static final _invalidLocalityPattern = RegExp(r'^[-+\dA-Z]+$');
LatLng? get latLng => hasGps ? LatLng(catalogMetadata!.latitude!, catalogMetadata!.longitude!) : null;
Future<void> locate({required bool background, required bool force, required Locale geocoderLocale}) async {
@ -55,7 +57,7 @@ extension ExtraAvesEntryLocation on AvesEntry {
if (addresses.isNotEmpty) {
final v = addresses.first;
var locality = v.locality ?? v.subLocality ?? v.featureName;
if (locality == null || locality == v.subThoroughfare) {
if (locality == null || _invalidLocalityPattern.hasMatch(locality) || {v.subThoroughfare, v.countryName}.contains(locality)) {
locality = v.subAdminArea;
}
addressDetails = AddressDetails(

View file

@ -10,7 +10,7 @@ import 'package:provider/provider.dart';
class QueryFilter extends CollectionFilter {
static const type = 'query';
static final RegExp exactRegex = RegExp('^"(.*)"\$');
static final exactRegex = RegExp('^"(.*)"\$');
final String query;
final bool colorful, live;

View file

@ -83,6 +83,9 @@ class SourceStateSubtitle extends StatelessWidget {
]
],
),
softWrap: false,
overflow: TextOverflow.fade,
maxLines: 1,
);
},
),

View file

@ -136,6 +136,7 @@ class CollectionSearchDelegate extends AvesSearchDelegate with FeedbackMixin, Va
_buildDateFilters(context, containQuery),
_buildAlbumFilters(containQuery),
_buildCountryFilters(containQuery),
_buildStateFilters(containQuery),
_buildPlaceFilters(containQuery),
_buildTagFilters(containQuery),
_buildRatingFilters(context, containQuery),
@ -223,6 +224,19 @@ class CollectionSearchDelegate extends AvesSearchDelegate with FeedbackMixin, Va
);
}
Widget _buildStateFilters(_ContainQuery containQuery) {
return StreamBuilder(
stream: source.eventBus.on<PlacesChangedEvent>(),
builder: (context, snapshot) {
return _buildFilterRow(
context: context,
title: context.l10n.searchStatesSectionTitle,
filters: source.sortedStates.where(containQuery).map((s) => LocationFilter(LocationLevel.state, s)).toList(),
);
},
);
}
Widget _buildPlaceFilters(_ContainQuery containQuery) {
return StreamBuilder(
stream: source.eventBus.on<PlacesChangedEvent>(),
@ -230,10 +244,7 @@ class CollectionSearchDelegate extends AvesSearchDelegate with FeedbackMixin, Va
return _buildFilterRow(
context: context,
title: context.l10n.searchPlacesSectionTitle,
filters: [
...source.sortedStates.where(containQuery).map((s) => LocationFilter(LocationLevel.state, s)),
...source.sortedPlaces.where(containQuery).map((s) => LocationFilter(LocationLevel.place, s)),
].toList(),
filters: source.sortedPlaces.where(containQuery).map((s) => LocationFilter(LocationLevel.place, s)).toList(),
);
},
);

View file

@ -29,7 +29,6 @@ import 'package:aves/widgets/stats/filter_table.dart';
import 'package:aves/widgets/stats/mime_donut.dart';
import 'package:aves/widgets/stats/percent_text.dart';
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -55,8 +54,8 @@ class StatsPage extends StatefulWidget {
}
class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMixin {
final Map<String, int> _entryCountPerCountry = {}, _entryCountPerTag = {}, _entryCountPerAlbum = {};
final Map<_PlaceFilterKey, int> _entryCountPerPlace = {};
final Map<String, int> _entryCountPerCountry = {}, _entryCountPerState = {}, _entryCountPerPlace = {};
final Map<String, int> _entryCountPerTag = {}, _entryCountPerAlbum = {};
final Map<int, int> _entryCountPerRating = Map.fromEntries(List.generate(7, (i) => MapEntry(5 - i, 0)));
late final ValueNotifier<bool> _isPageAnimatingNotifier;
@ -83,13 +82,11 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
var state = address.stateName;
if (state != null && state.isNotEmpty) {
state += '${LocationFilter.locationSeparator}${address.stateCode}';
final key = _PlaceFilterKey(LocationLevel.state, state);
_entryCountPerPlace[key] = (_entryCountPerPlace[key] ?? 0) + 1;
_entryCountPerState[state] = (_entryCountPerState[state] ?? 0) + 1;
}
final place = address.place;
if (place != null && place.isNotEmpty) {
final key = _PlaceFilterKey(LocationLevel.place, place);
_entryCountPerPlace[key] = (_entryCountPerPlace[key] ?? 0) + 1;
_entryCountPerPlace[place] = (_entryCountPerPlace[place] ?? 0) + 1;
}
}
@ -219,7 +216,8 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
),
locationIndicator,
..._buildFilterSection<String>(context, l10n.statsTopCountriesSectionTitle, _entryCountPerCountry, (v) => LocationFilter(LocationLevel.country, v)),
..._buildFilterSection<_PlaceFilterKey>(context, l10n.statsTopPlacesSectionTitle, _entryCountPerPlace, (v) => LocationFilter(v.level, v.location)),
..._buildFilterSection<String>(context, l10n.statsTopStatesSectionTitle, _entryCountPerState, (v) => LocationFilter(LocationLevel.state, v)),
..._buildFilterSection<String>(context, l10n.statsTopPlacesSectionTitle, _entryCountPerPlace, (v) => LocationFilter(LocationLevel.place, v)),
..._buildFilterSection<String>(context, l10n.statsTopTagsSectionTitle, _entryCountPerTag, TagFilter.new),
..._buildFilterSection<String>(context, l10n.statsTopAlbumsSectionTitle, _entryCountPerAlbum, (v) => AlbumFilter(v, source.getAlbumDisplayName(context, v))),
if (showRatings) ..._buildFilterSection<int>(context, l10n.searchRatingSectionTitle, _entryCountPerRating, RatingFilter.new, sortByCount: false, maxRowCount: null),
@ -408,27 +406,3 @@ class StatsTopPage extends StatelessWidget {
);
}
}
@immutable
class _PlaceFilterKey extends Comparable<_PlaceFilterKey> with EquatableMixin {
final LocationLevel level;
final String location;
@override
List<Object?> get props => [level, location];
_PlaceFilterKey(this.level, this.location);
static const _levelOrder = [
LocationLevel.country,
LocationLevel.state,
LocationLevel.place,
];
@override
int compareTo(_PlaceFilterKey other) {
final c = _levelOrder.indexOf(level).compareTo(_levelOrder.indexOf(other.level));
if (c != 0) return c;
return location.compareTo(other.location);
}
}

View file

@ -4,6 +4,7 @@ import 'package:aves/model/settings/enums/coordinate_format.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/theme/styles.dart';
import 'package:aves/theme/text.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/viewer/overlay/details/details.dart';
import 'package:decorated_icon/decorated_icon.dart';
@ -19,22 +20,21 @@ class OverlayLocationRow extends AnimatedWidget {
@override
Widget build(BuildContext context) {
late final String location;
String? location;
if (entry.hasAddress) {
location = entry.shortAddress;
} else {
}
if (location == null || location.isEmpty) {
final latLng = entry.latLng;
if (latLng != null) {
location = settings.coordinateFormat.format(context.l10n, latLng);
} else {
location = '';
}
}
return Row(
children: [
DecoratedIcon(AIcons.location, size: ViewerDetailOverlayContent.iconSize, shadows: ViewerDetailOverlayContent.shadows(context)),
const SizedBox(width: ViewerDetailOverlayContent.iconPadding),
Expanded(child: Text(location, strutStyle: AStyles.overflowStrut)),
Expanded(child: Text(location ?? AText.valueNotAvailable, strutStyle: AStyles.overflowStrut)),
],
);
}

View file

@ -133,6 +133,8 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
}
Future<void> _initMultiPageController(AvesEntry entry) async {
if (!mounted) return;
final multiPageController = context.read<MultiPageConductor>().getOrCreateController(entry);
setState(() {});

View file

@ -393,6 +393,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -565,6 +566,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -959,6 +961,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -1131,6 +1134,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -1197,10 +1201,12 @@
"settingsVideoEnablePip",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode",
"settingsVideoBackgroundModeDialogTitle",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -1239,12 +1245,14 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode",
"settingsVideoBackgroundModeDialogTitle",
"settingsDisablingBinWarningDialogMessage",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -1263,10 +1271,12 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode",
"settingsVideoBackgroundModeDialogTitle",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -1276,8 +1286,10 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -1287,8 +1299,10 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -1549,6 +1563,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -1717,6 +1732,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -1780,6 +1796,8 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -2066,6 +2084,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -2238,6 +2257,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -2709,6 +2729,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -2881,6 +2902,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -3332,6 +3354,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -3504,6 +3527,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -3569,8 +3593,10 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -3580,8 +3606,10 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -3631,6 +3659,7 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsModificationWarningDialogMessage",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
@ -3643,6 +3672,7 @@
"settingsAccessibilityShowPinchGestureAlternatives",
"settingsDisplayUseTvInterface",
"settingsWidgetDisplayedItem",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -3652,6 +3682,8 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -3695,6 +3727,7 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsModificationWarningDialogMessage",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
@ -3706,6 +3739,7 @@
"settingsDisablingBinWarningDialogMessage",
"settingsAccessibilityShowPinchGestureAlternatives",
"settingsDisplayUseTvInterface",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -3719,10 +3753,12 @@
"patternDialogConfirm",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode",
"settingsVideoBackgroundModeDialogTitle",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -3777,6 +3813,7 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsModificationWarningDialogMessage",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
@ -3792,6 +3829,7 @@
"settingsAccessibilityShowPinchGestureAlternatives",
"settingsDisplayUseTvInterface",
"settingsWidgetDisplayedItem",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -3956,6 +3994,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -4112,6 +4151,7 @@
"settingsDisplayUseTvInterface",
"settingsWidgetOpenPage",
"statsWithGps",
"statsTopStatesSectionTitle",
"viewerInfoPageTitle",
"viewerInfoLabelDescription",
"mapPointNorthUpTooltip",
@ -4129,8 +4169,10 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -4140,9 +4182,11 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundModeDialogTitle",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -4152,8 +4196,10 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -4174,12 +4220,14 @@
"statePageTitle",
"stateEmpty",
"placeEmpty",
"searchStatesSectionTitle",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode",
"settingsVideoBackgroundModeDialogTitle",
"settingsVideoGestureVerticalDragBrightnessVolume",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -4383,6 +4431,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -4555,6 +4604,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -4749,6 +4799,7 @@
"searchDateSectionTitle",
"searchAlbumsSectionTitle",
"searchCountriesSectionTitle",
"searchStatesSectionTitle",
"searchPlacesSectionTitle",
"searchTagsSectionTitle",
"searchRatingSectionTitle",
@ -4921,6 +4972,7 @@
"statsPageTitle",
"statsWithGps",
"statsTopCountriesSectionTitle",
"statsTopStatesSectionTitle",
"statsTopPlacesSectionTitle",
"statsTopTagsSectionTitle",
"statsTopAlbumsSectionTitle",
@ -5015,12 +5067,14 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode",
"settingsVideoBackgroundModeDialogTitle",
"settingsDisablingBinWarningDialogMessage",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -5030,8 +5084,10 @@
"viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"searchStatesSectionTitle",
"settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -5073,6 +5129,7 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsModificationWarningDialogMessage",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
@ -5084,6 +5141,7 @@
"settingsDisablingBinWarningDialogMessage",
"settingsAccessibilityShowPinchGestureAlternatives",
"settingsDisplayUseTvInterface",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
],
@ -5126,6 +5184,7 @@
"stateEmpty",
"placePageTitle",
"placeEmpty",
"searchStatesSectionTitle",
"settingsModificationWarningDialogMessage",
"settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile",
@ -5137,6 +5196,7 @@
"settingsDisablingBinWarningDialogMessage",
"settingsAccessibilityShowPinchGestureAlternatives",
"settingsDisplayUseTvInterface",
"statsTopStatesSectionTitle",
"tagPlaceholderState"
]
}