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 Activity { browse, select }
enum ChipSortFactor { date, name } enum ChipSortFactor { date, name, count }
enum EntrySortFactor { date, size, name } 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 pinned = settings.pinnedFilters.whereType<AlbumFilter>().map((f) => f.album);
final entriesByDate = source.sortedEntriesForFilterList; final entriesByDate = source.sortedEntriesForFilterList;
switch (settings.albumSortFactor) { // albums are initially sorted by name at the source level
case ChipSortFactor.date: var sortedAlbums = source.sortedAlbums;
final allAlbumMapEntries = source.sortedAlbums.map((album) => MapEntry(
album, if (settings.albumSortFactor == ChipSortFactor.name) {
entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null), final pinnedAlbums = <String>[], regularAlbums = <String>[], appAlbums = <String>[], specialAlbums = <String>[];
)); for (var album in sortedAlbums) {
final byPin = groupBy<MapEntry<String, ImageEntry>, bool>(allAlbumMapEntries, (e) => pinned.contains(e.key)); if (pinned.contains(album)) {
final pinnedMapEntries = (byPin[true] ?? [])..sort(FilterNavigationPage.compareChipsByDate); pinnedAlbums.add(album);
final unpinnedMapEntries = (byPin[false] ?? [])..sort(FilterNavigationPage.compareChipsByDate); } else {
return Map.fromEntries([...pinnedMapEntries, ...unpinnedMapEntries]); switch (androidFileUtils.getAlbumType(album)) {
case ChipSortFactor.name: case AlbumType.regular:
default: regularAlbums.add(album);
final pinnedAlbums = <String>[], regularAlbums = <String>[], appAlbums = <String>[], specialAlbums = <String>[]; break;
for (var album in source.sortedAlbums) { case AlbumType.app:
if (pinned.contains(album)) { appAlbums.add(album);
pinnedAlbums.add(album); break;
} else { default:
switch (androidFileUtils.getAlbumType(album)) { specialAlbums.add(album);
case AlbumType.regular: break;
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( return Map.fromEntries([...pinnedAlbums, ...specialAlbums, ...appAlbums, ...regularAlbums].map((album) {
album, return MapEntry(
entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null), 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: { options: {
ChipSortFactor.date: 'By date', ChipSortFactor.date: 'By date',
ChipSortFactor.name: 'By name', ChipSortFactor.name: 'By name',
ChipSortFactor.count: 'By entry count',
}, },
title: 'Sort', title: 'Sort',
), ),

View file

@ -153,6 +153,11 @@ class FilterNavigationPage extends StatelessWidget {
final c = b.value.bestDate?.compareTo(a.value.bestDate) ?? -1; final c = b.value.bestDate?.compareTo(a.value.bestDate) ?? -1;
return c != 0 ? c : compareAsciiUpperCase(a.key, b.key); 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 { class FilterGridPage extends StatelessWidget {

View file

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

View file

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