albums/countries/tags: sort by entry count

This commit is contained in:
Thibault Deckers 2020-10-16 18:45:07 +09:00
parent 2236be7d60
commit ae2f8d3ae7
6 changed files with 90 additions and 62 deletions

View file

@ -1,6 +1,6 @@
enum Activity { browse, select }
enum ChipSortFactor { date, name }
enum ChipSortFactor { date, name, count }
enum EntrySortFactor { date, size, name }

View file

@ -62,42 +62,56 @@ class AlbumListPage extends StatelessWidget {
final pinned = settings.pinnedFilters.whereType<AlbumFilter>().map((f) => f.album);
final entriesByDate = source.sortedEntriesForFilterList;
switch (settings.albumSortFactor) {
case ChipSortFactor.date:
final allAlbumMapEntries = source.sortedAlbums.map((album) => MapEntry(
album,
entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null),
));
final byPin = groupBy<MapEntry<String, ImageEntry>, bool>(allAlbumMapEntries, (e) => pinned.contains(e.key));
final pinnedMapEntries = (byPin[true] ?? [])..sort(FilterNavigationPage.compareChipsByDate);
final unpinnedMapEntries = (byPin[false] ?? [])..sort(FilterNavigationPage.compareChipsByDate);
return Map.fromEntries([...pinnedMapEntries, ...unpinnedMapEntries]);
case ChipSortFactor.name:
default:
final pinnedAlbums = <String>[], regularAlbums = <String>[], appAlbums = <String>[], specialAlbums = <String>[];
for (var album in source.sortedAlbums) {
if (pinned.contains(album)) {
pinnedAlbums.add(album);
} else {
switch (androidFileUtils.getAlbumType(album)) {
case AlbumType.regular:
regularAlbums.add(album);
break;
case AlbumType.app:
appAlbums.add(album);
break;
default:
specialAlbums.add(album);
break;
}
// albums are initially sorted by name at the source level
var sortedAlbums = source.sortedAlbums;
if (settings.albumSortFactor == ChipSortFactor.name) {
final pinnedAlbums = <String>[], regularAlbums = <String>[], appAlbums = <String>[], specialAlbums = <String>[];
for (var album in sortedAlbums) {
if (pinned.contains(album)) {
pinnedAlbums.add(album);
} else {
switch (androidFileUtils.getAlbumType(album)) {
case AlbumType.regular:
regularAlbums.add(album);
break;
case AlbumType.app:
appAlbums.add(album);
break;
default:
specialAlbums.add(album);
break;
}
}
return Map.fromEntries([...pinnedAlbums, ...specialAlbums, ...appAlbums, ...regularAlbums].map((album) {
return MapEntry(
album,
entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null),
);
}));
}
return Map.fromEntries([...pinnedAlbums, ...specialAlbums, ...appAlbums, ...regularAlbums].map((album) {
return MapEntry(
album,
entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null),
);
}));
}
if (settings.albumSortFactor == ChipSortFactor.count) {
CollectionFilter _buildFilter(String album) => AlbumFilter(album, source.getUniqueAlbumName(album));
var filtersWithCount = List.of(sortedAlbums.map((s) => MapEntry(s, source.count(_buildFilter(s)))));
filtersWithCount.sort(FilterNavigationPage.compareChipsByEntryCount);
sortedAlbums = filtersWithCount.map((kv) => kv.key).toList();
}
final allMapEntries = sortedAlbums.map((album) => MapEntry(
album,
entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null),
));
final byPin = groupBy<MapEntry<String, ImageEntry>, bool>(allMapEntries, (e) => pinned.contains(e.key));
final pinnedMapEntries = (byPin[true] ?? []);
final unpinnedMapEntries = (byPin[false] ?? []);
if (settings.albumSortFactor == ChipSortFactor.date) {
pinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
unpinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
}
return Map.fromEntries([...pinnedMapEntries, ...unpinnedMapEntries]);
}
}

View file

@ -46,6 +46,7 @@ abstract class ChipSetActionDelegate {
options: {
ChipSortFactor.date: 'By date',
ChipSortFactor.name: 'By name',
ChipSortFactor.count: 'By entry count',
},
title: 'Sort',
),

View file

@ -153,6 +153,11 @@ class FilterNavigationPage extends StatelessWidget {
final c = b.value.bestDate?.compareTo(a.value.bestDate) ?? -1;
return c != 0 ? c : compareAsciiUpperCase(a.key, b.key);
}
static int compareChipsByEntryCount(MapEntry<String, num> a, MapEntry<String, num> b) {
final c = b.value.compareTo(a.value) ?? -1;
return c != 0 ? c : compareAsciiUpperCase(a.key, b.key);
}
}
class FilterGridPage extends StatelessWidget {

View file

@ -39,7 +39,7 @@ class CountryListPage extends StatelessWidget {
settings.pinnedFilters.contains(filter) ? ChipAction.unpin : ChipAction.pin,
],
filterEntries: _getCountryEntries(),
filterBuilder: (s) => LocationFilter(LocationLevel.country, s),
filterBuilder: _buildFilter,
emptyBuilder: () => EmptyContent(
icon: AIcons.location,
text: 'No countries',
@ -50,12 +50,22 @@ class CountryListPage extends StatelessWidget {
);
}
CollectionFilter _buildFilter(String location) => LocationFilter(LocationLevel.country, location);
Map<String, ImageEntry> _getCountryEntries() {
final pinned = settings.pinnedFilters.whereType<LocationFilter>().map((f) => f.countryNameAndCode);
final entriesByDate = source.sortedEntriesForFilterList;
// countries are initially sorted by name at the source level
var sortedCountries = source.sortedCountries;
if (settings.countrySortFactor == ChipSortFactor.count) {
var filtersWithCount = List.of(sortedCountries.map((s) => MapEntry(s, source.count(_buildFilter(s)))));
filtersWithCount.sort(FilterNavigationPage.compareChipsByEntryCount);
sortedCountries = filtersWithCount.map((kv) => kv.key).toList();
}
final locatedEntries = entriesByDate.where((entry) => entry.isLocated);
final allMapEntries = source.sortedCountries.map((countryNameAndCode) {
final allMapEntries = sortedCountries.map((countryNameAndCode) {
final split = countryNameAndCode.split(LocationFilter.locationSeparator);
ImageEntry entry;
if (split.length > 1) {
@ -63,21 +73,16 @@ class CountryListPage extends StatelessWidget {
entry = locatedEntries.firstWhere((entry) => entry.addressDetails.countryCode == countryCode, orElse: () => null);
}
return MapEntry(countryNameAndCode, entry);
}).toList();
});
final byPin = groupBy<MapEntry<String, ImageEntry>, bool>(allMapEntries, (e) => pinned.contains(e.key));
final pinnedMapEntries = (byPin[true] ?? []);
final unpinnedMapEntries = (byPin[false] ?? []);
switch (settings.countrySortFactor) {
case ChipSortFactor.date:
pinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
unpinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
break;
case ChipSortFactor.name:
// already sorted by name at the source level
break;
if (settings.countrySortFactor == ChipSortFactor.date) {
pinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
unpinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
}
return Map.fromEntries([...pinnedMapEntries, ...unpinnedMapEntries]);
}
}

View file

@ -39,7 +39,7 @@ class TagListPage extends StatelessWidget {
settings.pinnedFilters.contains(filter) ? ChipAction.unpin : ChipAction.pin,
],
filterEntries: _getTagEntries(),
filterBuilder: (s) => TagFilter(s),
filterBuilder: _buildFilter,
emptyBuilder: () => EmptyContent(
icon: AIcons.tag,
text: 'No tags',
@ -50,30 +50,33 @@ class TagListPage extends StatelessWidget {
);
}
CollectionFilter _buildFilter(String tag) => TagFilter(tag);
Map<String, ImageEntry> _getTagEntries() {
final pinned = settings.pinnedFilters.whereType<TagFilter>().map((f) => f.tag);
final entriesByDate = source.sortedEntriesForFilterList;
final allMapEntries = source.sortedTags
.map((tag) => MapEntry(
tag,
entriesByDate.firstWhere((entry) => entry.xmpSubjects.contains(tag), orElse: () => null),
))
.toList();
// tags are initially sorted by name at the source level
var sortedTags = source.sortedTags;
if (settings.tagSortFactor == ChipSortFactor.count) {
var filtersWithCount = List.of(sortedTags.map((s) => MapEntry(s, source.count(_buildFilter(s)))));
filtersWithCount.sort(FilterNavigationPage.compareChipsByEntryCount);
sortedTags = filtersWithCount.map((kv) => kv.key).toList();
}
final allMapEntries = sortedTags.map((tag) => MapEntry(
tag,
entriesByDate.firstWhere((entry) => entry.xmpSubjects.contains(tag), orElse: () => null),
));
final byPin = groupBy<MapEntry<String, ImageEntry>, bool>(allMapEntries, (e) => pinned.contains(e.key));
final pinnedMapEntries = (byPin[true] ?? []);
final unpinnedMapEntries = (byPin[false] ?? []);
switch (settings.tagSortFactor) {
case ChipSortFactor.date:
pinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
unpinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
break;
case ChipSortFactor.name:
// already sorted by name at the source level
break;
if (settings.tagSortFactor == ChipSortFactor.date) {
pinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
unpinnedMapEntries.sort(FilterNavigationPage.compareChipsByDate);
}
return Map.fromEntries([...pinnedMapEntries, ...unpinnedMapEntries]);
}
}