#70 states page from country selection

This commit is contained in:
Thibault Deckers 2023-03-26 13:15:54 +02:00
parent 89deed98cd
commit df0a3e8961
12 changed files with 452 additions and 29 deletions

View file

@ -2,12 +2,24 @@ import 'package:aves/ref/unicode.dart';
import 'package:country_code/country_code.dart'; import 'package:country_code/country_code.dart';
class GeoStates { class GeoStates {
static final aus = CountryCode.AU.alpha2;
static final gbr = CountryCode.GB.alpha2;
static final ind = CountryCode.IN.alpha2;
static final usa = CountryCode.US.alpha2;
static final Set<String> stateCountryCodes = { static final Set<String> stateCountryCodes = {
CountryCode.AU, aus,
CountryCode.GB, gbr,
CountryCode.IN, ind,
CountryCode.US, usa,
}.map((v) => v.alpha2).toSet(); };
static final stateCodesByCountryCode = {
aus: EmojiStateCodes.aus,
gbr: EmojiStateCodes.gbr,
ind: EmojiStateCodes.ind,
usa: EmojiStateCodes.usa,
};
static const stateCodeByName = { static const stateCodeByName = {
..._australiaEnglish, ..._australiaEnglish,

View file

@ -84,6 +84,7 @@
"chipActionUnpin": "Unpin from top", "chipActionUnpin": "Unpin from top",
"chipActionRename": "Rename", "chipActionRename": "Rename",
"chipActionSetCover": "Set cover", "chipActionSetCover": "Set cover",
"chipActionShowCountryStates": "Show states",
"chipActionCreateAlbum": "Create album", "chipActionCreateAlbum": "Create album",
"chipActionCreateVault": "Create vault", "chipActionCreateVault": "Create vault",
"chipActionConfigureVault": "Configure vault", "chipActionConfigureVault": "Configure vault",
@ -679,6 +680,9 @@
"countryPageTitle": "Countries", "countryPageTitle": "Countries",
"countryEmpty": "No countries", "countryEmpty": "No countries",
"statePageTitle": "States",
"stateEmpty": "No states",
"placePageTitle": "Places", "placePageTitle": "Places",
"placeEmpty": "No places", "placeEmpty": "No places",

View file

@ -23,6 +23,7 @@ enum ChipSetAction {
pin, pin,
unpin, unpin,
lockVault, lockVault,
showCountryStates,
// selecting (single filter) // selecting (single filter)
rename, rename,
setCover, setCover,
@ -57,6 +58,7 @@ class ChipSetActions {
ChipSetAction.unpin, ChipSetAction.unpin,
ChipSetAction.delete, ChipSetAction.delete,
ChipSetAction.rename, ChipSetAction.rename,
ChipSetAction.showCountryStates,
ChipSetAction.hide, ChipSetAction.hide,
null, null,
ChipSetAction.map, ChipSetAction.map,
@ -108,6 +110,8 @@ extension ExtraChipSetAction on ChipSetAction {
return context.l10n.chipActionUnpin; return context.l10n.chipActionUnpin;
case ChipSetAction.lockVault: case ChipSetAction.lockVault:
return context.l10n.chipActionLock; return context.l10n.chipActionLock;
case ChipSetAction.showCountryStates:
return context.l10n.chipActionShowCountryStates;
// selecting (single filter) // selecting (single filter)
case ChipSetAction.rename: case ChipSetAction.rename:
return context.l10n.chipActionRename; return context.l10n.chipActionRename;
@ -159,6 +163,8 @@ extension ExtraChipSetAction on ChipSetAction {
return AIcons.unpin; return AIcons.unpin;
case ChipSetAction.lockVault: case ChipSetAction.lockVault:
return AIcons.vaultLock; return AIcons.vaultLock;
case ChipSetAction.showCountryStates:
return AIcons.state;
// selecting (single filter) // selecting (single filter)
case ChipSetAction.rename: case ChipSetAction.rename:
return AIcons.name; return AIcons.name;

View file

@ -66,10 +66,7 @@ class SettingsDefaults {
// filter grids // filter grids
static const albumGroupFactor = AlbumChipGroupFactor.importance; static const albumGroupFactor = AlbumChipGroupFactor.importance;
static const albumSortFactor = ChipSortFactor.name; static const chipListSortFactor = ChipSortFactor.name;
static const countrySortFactor = ChipSortFactor.name;
static const placeSortFactor = ChipSortFactor.name;
static const tagSortFactor = ChipSortFactor.name;
// viewer // viewer
static const viewerQuickActions = [ static const viewerQuickActions = [

View file

@ -110,10 +110,12 @@ class Settings extends ChangeNotifier {
static const albumGroupFactorKey = 'album_group_factor'; static const albumGroupFactorKey = 'album_group_factor';
static const albumSortFactorKey = 'album_sort_factor'; static const albumSortFactorKey = 'album_sort_factor';
static const countrySortFactorKey = 'country_sort_factor'; static const countrySortFactorKey = 'country_sort_factor';
static const stateSortFactorKey = 'state_sort_factor';
static const placeSortFactorKey = 'place_sort_factor'; static const placeSortFactorKey = 'place_sort_factor';
static const tagSortFactorKey = 'tag_sort_factor'; static const tagSortFactorKey = 'tag_sort_factor';
static const albumSortReverseKey = 'album_sort_reverse'; static const albumSortReverseKey = 'album_sort_reverse';
static const countrySortReverseKey = 'country_sort_reverse'; static const countrySortReverseKey = 'country_sort_reverse';
static const stateSortReverseKey = 'state_sort_reverse';
static const placeSortReverseKey = 'place_sort_reverse'; static const placeSortReverseKey = 'place_sort_reverse';
static const tagSortReverseKey = 'tag_sort_reverse'; static const tagSortReverseKey = 'tag_sort_reverse';
static const pinnedFiltersKey = 'pinned_filters'; static const pinnedFiltersKey = 'pinned_filters';
@ -560,19 +562,23 @@ class Settings extends ChangeNotifier {
set albumGroupFactor(AlbumChipGroupFactor newValue) => _set(albumGroupFactorKey, newValue.toString()); set albumGroupFactor(AlbumChipGroupFactor newValue) => _set(albumGroupFactorKey, newValue.toString());
ChipSortFactor get albumSortFactor => getEnumOrDefault(albumSortFactorKey, SettingsDefaults.albumSortFactor, ChipSortFactor.values); ChipSortFactor get albumSortFactor => getEnumOrDefault(albumSortFactorKey, SettingsDefaults.chipListSortFactor, ChipSortFactor.values);
set albumSortFactor(ChipSortFactor newValue) => _set(albumSortFactorKey, newValue.toString()); set albumSortFactor(ChipSortFactor newValue) => _set(albumSortFactorKey, newValue.toString());
ChipSortFactor get countrySortFactor => getEnumOrDefault(countrySortFactorKey, SettingsDefaults.countrySortFactor, ChipSortFactor.values); ChipSortFactor get countrySortFactor => getEnumOrDefault(countrySortFactorKey, SettingsDefaults.chipListSortFactor, ChipSortFactor.values);
set countrySortFactor(ChipSortFactor newValue) => _set(countrySortFactorKey, newValue.toString()); set countrySortFactor(ChipSortFactor newValue) => _set(countrySortFactorKey, newValue.toString());
ChipSortFactor get placeSortFactor => getEnumOrDefault(placeSortFactorKey, SettingsDefaults.placeSortFactor, ChipSortFactor.values); ChipSortFactor get stateSortFactor => getEnumOrDefault(stateSortFactorKey, SettingsDefaults.chipListSortFactor, ChipSortFactor.values);
set stateSortFactor(ChipSortFactor newValue) => _set(stateSortFactorKey, newValue.toString());
ChipSortFactor get placeSortFactor => getEnumOrDefault(placeSortFactorKey, SettingsDefaults.chipListSortFactor, ChipSortFactor.values);
set placeSortFactor(ChipSortFactor newValue) => _set(placeSortFactorKey, newValue.toString()); set placeSortFactor(ChipSortFactor newValue) => _set(placeSortFactorKey, newValue.toString());
ChipSortFactor get tagSortFactor => getEnumOrDefault(tagSortFactorKey, SettingsDefaults.tagSortFactor, ChipSortFactor.values); ChipSortFactor get tagSortFactor => getEnumOrDefault(tagSortFactorKey, SettingsDefaults.chipListSortFactor, ChipSortFactor.values);
set tagSortFactor(ChipSortFactor newValue) => _set(tagSortFactorKey, newValue.toString()); set tagSortFactor(ChipSortFactor newValue) => _set(tagSortFactorKey, newValue.toString());
@ -584,6 +590,10 @@ class Settings extends ChangeNotifier {
set countrySortReverse(bool newValue) => _set(countrySortReverseKey, newValue); set countrySortReverse(bool newValue) => _set(countrySortReverseKey, newValue);
bool get stateSortReverse => getBool(stateSortReverseKey) ?? false;
set stateSortReverse(bool newValue) => _set(stateSortReverseKey, newValue);
bool get placeSortReverse => getBool(placeSortReverseKey) ?? false; bool get placeSortReverse => getBool(placeSortReverseKey) ?? false;
set placeSortReverse(bool newValue) => _set(placeSortReverseKey, newValue); set placeSortReverse(bool newValue) => _set(placeSortReverseKey, newValue);
@ -1085,6 +1095,7 @@ class Settings extends ChangeNotifier {
case showThumbnailVideoDurationKey: case showThumbnailVideoDurationKey:
case albumSortReverseKey: case albumSortReverseKey:
case countrySortReverseKey: case countrySortReverseKey:
case stateSortReverseKey:
case placeSortReverseKey: case placeSortReverseKey:
case tagSortReverseKey: case tagSortReverseKey:
case showOverlayOnOpeningKey: case showOverlayOnOpeningKey:
@ -1133,6 +1144,7 @@ class Settings extends ChangeNotifier {
case albumGroupFactorKey: case albumGroupFactorKey:
case albumSortFactorKey: case albumSortFactorKey:
case countrySortFactorKey: case countrySortFactorKey:
case stateSortFactorKey:
case placeSortFactorKey: case placeSortFactorKey:
case tagSortFactorKey: case tagSortFactorKey:
case imageBackgroundKey: case imageBackgroundKey:

View file

@ -34,12 +34,30 @@ class EmojiStateCodes {
static const auVictoria = 'auvic'; static const auVictoria = 'auvic';
static const auWesternAustralia = 'auwa'; static const auWesternAustralia = 'auwa';
static const aus = {
auAustralianCapitalTerritory,
auNewSouthWales,
auNorthernTerritory,
auQueensland,
auSouthAustralia,
auTasmania,
auVictoria,
auWesternAustralia,
};
// GB // GB
static const gbEngland = 'gbeng'; static const gbEngland = 'gbeng';
static const gbNorthernIreland = 'gbnir'; static const gbNorthernIreland = 'gbnir';
static const gbScotland = 'gbsct'; static const gbScotland = 'gbsct';
static const gbWales = 'gbwls'; static const gbWales = 'gbwls';
static const gbr = {
gbEngland,
gbNorthernIreland,
gbScotland,
gbWales,
};
// IN // IN
static const inAndamanAndNicobarIslands = 'inan'; static const inAndamanAndNicobarIslands = 'inan';
static const inAndhraPradesh = 'inap'; static const inAndhraPradesh = 'inap';
@ -78,6 +96,45 @@ class EmojiStateCodes {
static const inUttarakhand = 'inut'; static const inUttarakhand = 'inut';
static const inWestBengal = 'inwb'; static const inWestBengal = 'inwb';
static const ind = {
inAndamanAndNicobarIslands,
inAndhraPradesh,
inArunachalPradesh,
inAssam,
inBihar,
inChandigarh,
inChhattisgarh,
inDamanAndDiu,
inDelhi,
inDadraAndNagarHaveli,
inGoa,
inGujarat,
inHimachalPradesh,
inHaryana,
inJharkhand,
inJammuAndKashmir,
inKarnataka,
inKerala,
inLakshadweep,
inMaharashtra,
inMeghalaya,
inManipur,
inMadhyaPradesh,
inMizoram,
inNagaland,
inOdisha,
inPunjab,
inPuducherry,
inRajasthan,
inSikkim,
inTelangana,
inTamilNadu,
inTripura,
inUttarPradesh,
inUttarakhand,
inWestBengal,
};
// US // US
static const usAlabama = 'usal'; static const usAlabama = 'usal';
static const usAlaska = 'usak'; static const usAlaska = 'usak';
@ -129,4 +186,57 @@ class EmojiStateCodes {
static const usWestVirginia = 'uswv'; static const usWestVirginia = 'uswv';
static const usWisconsin = 'uswi'; static const usWisconsin = 'uswi';
static const usWyoming = 'uswy'; static const usWyoming = 'uswy';
static const usa = {
usAlabama,
usAlaska,
usArizona,
usArkansas,
usCalifornia,
usColorado,
usConnecticut,
usDelaware,
usFlorida,
usGeorgia,
usHawaii,
usIdaho,
usIllinois,
usIndiana,
usIowa,
usKansas,
usKentucky,
usLouisiana,
usMaine,
usMaryland,
usMassachusetts,
usMichigan,
usMinnesota,
usMississippi,
usMissouri,
usMontana,
usNebraska,
usNevada,
usNewHampshire,
usNewJersey,
usNewMexico,
usNewYork,
usNorthCarolina,
usNorthDakota,
usOhio,
usOklahoma,
usOregon,
usPennsylvania,
usRhodeIsland,
usSouthCarolina,
usSouthDakota,
usTennessee,
usUtah,
usVermont,
usVirginia,
usWashington,
usWashingtonDC,
usWestVirginia,
usWisconsin,
usWyoming,
};
} }

View file

@ -8,7 +8,6 @@ import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/album.dart';
import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/highlight.dart'; import 'package:aves/model/highlight.dart';
import 'package:aves/model/selection.dart';
import 'package:aves/model/settings/enums/enums.dart'; import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
@ -162,7 +161,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
break; break;
case ChipSetAction.lockVault: case ChipSetAction.lockVault:
lockFilters(filters); lockFilters(filters);
_browse(context); browse(context);
break; break;
// single filter // single filter
case ChipSetAction.rename: case ChipSetAction.rename:
@ -177,8 +176,6 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
super.onActionSelected(context, filters, action); super.onActionSelected(context, filters, action);
} }
void _browse(BuildContext context) => context.read<Selection<FilterGridItem<AlbumFilter>>>().browse();
@override @override
Future<void> configureView(BuildContext context) async { Future<void> configureView(BuildContext context) async {
final initialValue = Tuple4( final initialValue = Tuple4(
@ -284,7 +281,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
filters: kv.value.toSet(), filters: kv.value.toSet(),
enableBin: kv.key, enableBin: kv.key,
)); ));
_browse(context); browse(context);
} }
Future<void> _doDelete({ Future<void> _doDelete({
@ -308,7 +305,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
onSuccess: () { onSuccess: () {
source.forgetNewAlbums(todoAlbums); source.forgetNewAlbums(todoAlbums);
source.cleanEmptyAlbums(emptyAlbums); source.cleanEmptyAlbums(emptyAlbums);
_browse(context); browse(context);
}, },
); );
return; return;
@ -370,7 +367,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
final deletedOps = successOps.where((e) => !e.skipped).toSet(); final deletedOps = successOps.where((e) => !e.skipped).toSet();
final deletedUris = deletedOps.map((event) => event.uri).toSet(); final deletedUris = deletedOps.map((event) => event.uri).toSet();
await source.removeEntries(deletedUris, includeTrash: true); await source.removeEntries(deletedUris, includeTrash: true);
_browse(context); browse(context);
source.resumeMonitoring(); source.resumeMonitoring();
final successCount = successOps.length; final successCount = successOps.length;
@ -449,7 +446,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
final successOps = processed.where((e) => e.success).toSet(); final successOps = processed.where((e) => e.success).toSet();
final movedOps = successOps.where((e) => !e.skipped).toSet(); final movedOps = successOps.where((e) => !e.skipped).toSet();
await source.renameAlbum(album, destinationAlbum, todoEntries, movedOps); await source.renameAlbum(album, destinationAlbum, todoEntries, movedOps);
_browse(context); browse(context);
source.resumeMonitoring(); source.resumeMonitoring();
final successCount = successOps.length; final successCount = successOps.length;
@ -495,7 +492,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
await _doRename(context, filter, newName); await _doRename(context, filter, newName);
} else { } else {
await vaults.update(newDetails); await vaults.update(newDetails);
_browse(context); browse(context);
} }
} }
} }

View file

@ -105,6 +105,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
return hasSelection && settings.pinnedFilters.containsAll(selectedFilters); return hasSelection && settings.pinnedFilters.containsAll(selectedFilters);
case ChipSetAction.delete: case ChipSetAction.delete:
case ChipSetAction.lockVault: case ChipSetAction.lockVault:
case ChipSetAction.showCountryStates:
return false; return false;
// selecting (single filter) // selecting (single filter)
case ChipSetAction.setCover: case ChipSetAction.setCover:
@ -148,6 +149,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
case ChipSetAction.pin: case ChipSetAction.pin:
case ChipSetAction.unpin: case ChipSetAction.unpin:
case ChipSetAction.lockVault: case ChipSetAction.lockVault:
case ChipSetAction.showCountryStates:
return hasSelection; return hasSelection;
// selecting (single filter) // selecting (single filter)
case ChipSetAction.rename: case ChipSetAction.rename:
@ -199,14 +201,15 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
break; break;
case ChipSetAction.pin: case ChipSetAction.pin:
settings.pinnedFilters = settings.pinnedFilters..addAll(filters); settings.pinnedFilters = settings.pinnedFilters..addAll(filters);
_browse(context); browse(context);
break; break;
case ChipSetAction.unpin: case ChipSetAction.unpin:
settings.pinnedFilters = settings.pinnedFilters..removeAll(filters); settings.pinnedFilters = settings.pinnedFilters..removeAll(filters);
_browse(context); browse(context);
break; break;
case ChipSetAction.delete: case ChipSetAction.delete:
case ChipSetAction.lockVault: case ChipSetAction.lockVault:
case ChipSetAction.showCountryStates:
break; break;
// selecting (single filter) // selecting (single filter)
case ChipSetAction.setCover: case ChipSetAction.setCover:
@ -218,9 +221,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
} }
} }
void _browse(BuildContext context) { void browse(BuildContext context) => context.read<Selection<FilterGridItem<T>>?>()?.browse();
context.read<Selection<FilterGridItem<T>>?>()?.browse();
}
Iterable<AvesEntry> _selectedEntries(BuildContext context, Set<dynamic> filters) { Iterable<AvesEntry> _selectedEntries(BuildContext context, Set<dynamic> filters) {
final source = context.read<CollectionSource>(); final source = context.read<CollectionSource>();
@ -332,7 +333,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
settings.changeFilterVisibility(filters, false); settings.changeFilterVisibility(filters, false);
_browse(context); browse(context);
} }
void _setCover(BuildContext context, T filter) async { void _setCover(BuildContext context, T filter) async {
@ -367,6 +368,6 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
color: selectedColor, color: selectedColor,
); );
_browse(context); browse(context);
} }
} }

View file

@ -1,9 +1,16 @@
import 'package:aves/app_mode.dart';
import 'package:aves/geo/states.dart';
import 'package:aves/model/actions/chip_set.dart';
import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/filters/location.dart'; import 'package:aves/model/filters/location.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/enums/enums.dart'; import 'package:aves/model/source/enums/enums.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart'; import 'package:aves/widgets/filter_grids/common/action_delegates/chip_set.dart';
import 'package:aves/widgets/filter_grids/countries_page.dart'; import 'package:aves/widgets/filter_grids/countries_page.dart';
import 'package:aves/widgets/filter_grids/states_page.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
class CountryChipSetActionDelegate extends ChipSetActionDelegate<LocationFilter> { class CountryChipSetActionDelegate extends ChipSetActionDelegate<LocationFilter> {
final Iterable<FilterGridItem<LocationFilter>> _items; final Iterable<FilterGridItem<LocationFilter>> _items;
@ -30,4 +37,71 @@ class CountryChipSetActionDelegate extends ChipSetActionDelegate<LocationFilter>
@override @override
set tileLayout(TileLayout tileLayout) => settings.setTileLayout(CountryListPage.routeName, tileLayout); set tileLayout(TileLayout tileLayout) => settings.setTileLayout(CountryListPage.routeName, tileLayout);
@override
bool isVisible(
ChipSetAction action, {
required AppMode appMode,
required bool isSelecting,
required int itemCount,
required Set<LocationFilter> selectedFilters,
}) {
switch (action) {
case ChipSetAction.showCountryStates:
return isSelecting;
default:
return super.isVisible(
action,
appMode: appMode,
isSelecting: isSelecting,
itemCount: itemCount,
selectedFilters: selectedFilters,
);
}
}
@override
bool canApply(
ChipSetAction action, {
required bool isSelecting,
required int itemCount,
required Set<LocationFilter> selectedFilters,
}) {
switch (action) {
case ChipSetAction.showCountryStates:
return selectedFilters.any((v) => GeoStates.stateCountryCodes.contains(v.code));
default:
return super.canApply(
action,
isSelecting: isSelecting,
itemCount: itemCount,
selectedFilters: selectedFilters,
);
}
}
@override
void onActionSelected(BuildContext context, Set<LocationFilter> filters, ChipSetAction action) {
reportService.log('$action');
switch (action) {
// single/multiple filters
case ChipSetAction.showCountryStates:
_showStates(context, filters);
browse(context);
break;
default:
break;
}
super.onActionSelected(context, filters, action);
}
void _showStates(BuildContext context, Set<LocationFilter> filters) {
final countryCodes = filters.map((v) => v.code).where(GeoStates.stateCountryCodes.contains).whereNotNull().toSet();
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: StateListPage.routeName),
builder: (_) => StateListPage(countryCodes: countryCodes),
),
);
}
} }

View file

@ -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/states_page.dart';
class StateChipSetActionDelegate extends ChipSetActionDelegate<LocationFilter> {
final Iterable<FilterGridItem<LocationFilter>> _items;
StateChipSetActionDelegate(Iterable<FilterGridItem<LocationFilter>> items) : _items = items;
@override
Iterable<FilterGridItem<LocationFilter>> get allItems => _items;
@override
ChipSortFactor get sortFactor => settings.stateSortFactor;
@override
set sortFactor(ChipSortFactor factor) => settings.stateSortFactor = factor;
@override
bool get sortReverse => settings.stateSortReverse;
@override
set sortReverse(bool value) => settings.stateSortReverse = value;
@override
TileLayout get tileLayout => settings.getTileLayout(StateListPage.routeName);
@override
set tileLayout(TileLayout tileLayout) => settings.setTileLayout(StateListPage.routeName, tileLayout);
}

View file

@ -0,0 +1,87 @@
import 'package:aves/geo/states.dart';
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/state_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 StateListPage extends StatelessWidget {
static const routeName = '/states';
final Set<String> countryCodes;
const StateListPage({
super.key,
required this.countryCodes,
});
@override
Widget build(BuildContext context) {
final source = context.read<CollectionSource>();
return Selector<Settings, Tuple3<ChipSortFactor, bool, Set<CollectionFilter>>>(
selector: (context, s) => Tuple3(s.stateSortFactor, s.stateSortReverse, 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, StateChipSetActionDelegate>(
source: source,
title: context.l10n.statePageTitle,
sortFactor: settings.stateSortFactor,
actionDelegate: StateChipSetActionDelegate(gridItems),
filterSections: _groupToSections(gridItems),
applyQuery: applyQuery,
emptyBuilder: () => EmptyContent(
icon: AIcons.state,
text: context.l10n.stateEmpty,
),
);
},
);
},
);
}
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 selectedStateCodes = countryCodes.expand((v) => GeoStates.stateCodesByCountryCode[v] ?? <String>{}).toSet();
final filters = source.sortedStates.where((v) => selectedStateCodes.any(v.endsWith)).map((location) => LocationFilter(LocationLevel.state, location)).toSet();
return FilterNavigationPage.sort(settings.stateSortFactor, settings.stateSortReverse, 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,
],
};
}
}

View file

@ -24,6 +24,7 @@
"chipActionUnpin", "chipActionUnpin",
"chipActionRename", "chipActionRename",
"chipActionSetCover", "chipActionSetCover",
"chipActionShowCountryStates",
"chipActionCreateAlbum", "chipActionCreateAlbum",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
@ -380,6 +381,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -610,6 +613,7 @@
"ckb": [ "ckb": [
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionShowCountryStates",
"entryActionRotateCCW", "entryActionRotateCCW",
"entryActionRotateCW", "entryActionRotateCW",
"entryActionFlip", "entryActionFlip",
@ -943,6 +947,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -1185,9 +1191,12 @@
], ],
"cs": [ "cs": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"settingsVideoEnablePip", "settingsVideoEnablePip",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode", "settingsVideoBackgroundMode",
@ -1198,6 +1207,7 @@
"de": [ "de": [
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -1225,6 +1235,8 @@
"vaultBinUsageDialogMessage", "vaultBinUsageDialogMessage",
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsConfirmationVaultDataLoss", "settingsConfirmationVaultDataLoss",
@ -1238,6 +1250,7 @@
"el": [ "el": [
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"vaultLockTypePattern", "vaultLockTypePattern",
@ -1246,6 +1259,8 @@
"patternDialogConfirm", "patternDialogConfirm",
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
@ -1256,16 +1271,22 @@
], ],
"es": [ "es": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"tagPlaceholderState" "tagPlaceholderState"
], ],
"eu": [ "eu": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"tagPlaceholderState" "tagPlaceholderState"
@ -1275,6 +1296,7 @@
"clearTooltip", "clearTooltip",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"videoActionPause", "videoActionPause",
@ -1515,6 +1537,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -1751,8 +1775,11 @@
], ],
"fr": [ "fr": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"tagPlaceholderState" "tagPlaceholderState"
], ],
@ -1760,6 +1787,7 @@
"columnCount", "columnCount",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"entryActionShareImageOnly", "entryActionShareImageOnly",
@ -2026,6 +2054,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -2310,6 +2340,7 @@
"chipActionUnpin", "chipActionUnpin",
"chipActionRename", "chipActionRename",
"chipActionSetCover", "chipActionSetCover",
"chipActionShowCountryStates",
"chipActionCreateAlbum", "chipActionCreateAlbum",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
@ -2666,6 +2697,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -2930,6 +2963,7 @@
"chipActionUnpin", "chipActionUnpin",
"chipActionRename", "chipActionRename",
"chipActionSetCover", "chipActionSetCover",
"chipActionShowCountryStates",
"chipActionCreateAlbum", "chipActionCreateAlbum",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
@ -3286,6 +3320,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -3528,16 +3564,22 @@
], ],
"id": [ "id": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"tagPlaceholderState" "tagPlaceholderState"
], ],
"it": [ "it": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"tagPlaceholderState" "tagPlaceholderState"
@ -3548,6 +3590,7 @@
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionFilterIn", "chipActionFilterIn",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -3584,6 +3627,8 @@
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"tooManyItemsErrorDialogMessage", "tooManyItemsErrorDialogMessage",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsModificationWarningDialogMessage", "settingsModificationWarningDialogMessage",
@ -3602,8 +3647,11 @@
], ],
"ko": [ "ko": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"tagPlaceholderState" "tagPlaceholderState"
], ],
@ -3611,6 +3659,7 @@
"columnCount", "columnCount",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -3642,6 +3691,8 @@
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"tooManyItemsErrorDialogMessage", "tooManyItemsErrorDialogMessage",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsModificationWarningDialogMessage", "settingsModificationWarningDialogMessage",
@ -3659,12 +3710,15 @@
], ],
"nb": [ "nb": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"vaultLockTypePattern", "vaultLockTypePattern",
"settingsVideoEnablePip", "settingsVideoEnablePip",
"patternDialogEnter", "patternDialogEnter",
"patternDialogConfirm", "patternDialogConfirm",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundMode", "settingsVideoBackgroundMode",
@ -3676,6 +3730,7 @@
"columnCount", "columnCount",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"entryActionShareImageOnly", "entryActionShareImageOnly",
@ -3718,6 +3773,8 @@
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"tooManyItemsErrorDialogMessage", "tooManyItemsErrorDialogMessage",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsModificationWarningDialogMessage", "settingsModificationWarningDialogMessage",
@ -3743,6 +3800,7 @@
"sourceStateCataloguing", "sourceStateCataloguing",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -3886,6 +3944,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -4064,16 +4124,22 @@
], ],
"pl": [ "pl": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"tagPlaceholderState" "tagPlaceholderState"
], ],
"pt": [ "pt": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"settingsVideoBackgroundModeDialogTitle", "settingsVideoBackgroundModeDialogTitle",
@ -4081,8 +4147,11 @@
], ],
"ro": [ "ro": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"tagPlaceholderState" "tagPlaceholderState"
@ -4090,6 +4159,7 @@
"ru": [ "ru": [
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"vaultLockTypePattern", "vaultLockTypePattern",
@ -4101,6 +4171,8 @@
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"tooManyItemsErrorDialogMessage", "tooManyItemsErrorDialogMessage",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placeEmpty", "placeEmpty",
"settingsConfirmationVaultDataLoss", "settingsConfirmationVaultDataLoss",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
@ -4117,6 +4189,7 @@
"timeSeconds", "timeSeconds",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -4298,6 +4371,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -4549,6 +4624,7 @@
"applyButtonLabel", "applyButtonLabel",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -4661,6 +4737,8 @@
"newFilterBanner", "newFilterBanner",
"countryPageTitle", "countryPageTitle",
"countryEmpty", "countryEmpty",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"tagPageTitle", "tagPageTitle",
@ -4905,6 +4983,7 @@
"tr": [ "tr": [
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -4932,6 +5011,8 @@
"vaultBinUsageDialogMessage", "vaultBinUsageDialogMessage",
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsConfirmationVaultDataLoss", "settingsConfirmationVaultDataLoss",
@ -4944,8 +5025,11 @@
], ],
"uk": [ "uk": [
"chipActionShowCountryStates",
"viewerActionLock", "viewerActionLock",
"viewerActionUnlock", "viewerActionUnlock",
"statePageTitle",
"stateEmpty",
"settingsCollectionBurstPatternsTile", "settingsCollectionBurstPatternsTile",
"settingsCollectionBurstPatternsNone", "settingsCollectionBurstPatternsNone",
"tagPlaceholderState" "tagPlaceholderState"
@ -4954,6 +5038,7 @@
"zh": [ "zh": [
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -4984,6 +5069,8 @@
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"tooManyItemsErrorDialogMessage", "tooManyItemsErrorDialogMessage",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsModificationWarningDialogMessage", "settingsModificationWarningDialogMessage",
@ -5004,6 +5091,7 @@
"columnCount", "columnCount",
"chipActionGoToPlacePage", "chipActionGoToPlacePage",
"chipActionLock", "chipActionLock",
"chipActionShowCountryStates",
"chipActionCreateVault", "chipActionCreateVault",
"chipActionConfigureVault", "chipActionConfigureVault",
"viewerActionLock", "viewerActionLock",
@ -5034,6 +5122,8 @@
"exportEntryDialogWriteMetadata", "exportEntryDialogWriteMetadata",
"tooManyItemsErrorDialogMessage", "tooManyItemsErrorDialogMessage",
"drawerPlacePage", "drawerPlacePage",
"statePageTitle",
"stateEmpty",
"placePageTitle", "placePageTitle",
"placeEmpty", "placeEmpty",
"settingsModificationWarningDialogMessage", "settingsModificationWarningDialogMessage",