hidden filters: refresh metadata of newly visible items

This commit is contained in:
Thibault Deckers 2021-02-09 14:53:35 +09:00
parent 7fb40c0810
commit dcfc07ff00
13 changed files with 37 additions and 34 deletions

View file

@ -32,7 +32,7 @@ class AlbumFilter extends CollectionFilter {
}; };
@override @override
EntryFilter get filter => (entry) => entry.directory == album; EntryFilter get test => (entry) => entry.directory == album;
@override @override
String get label => uniqueName ?? album.split(separator).last; String get label => uniqueName ?? album.split(separator).last;

View file

@ -12,7 +12,7 @@ class FavouriteFilter extends CollectionFilter {
}; };
@override @override
EntryFilter get filter => (entry) => entry.isFavourite; EntryFilter get test => (entry) => entry.isFavourite;
@override @override
String get label => 'Favourite'; String get label => 'Favourite';

View file

@ -49,7 +49,7 @@ abstract class CollectionFilter implements Comparable<CollectionFilter> {
String toJson() => jsonEncode(toMap()); String toJson() => jsonEncode(toMap());
EntryFilter get filter; EntryFilter get test;
bool get isUnique => true; bool get isUnique => true;
@ -75,7 +75,6 @@ abstract class CollectionFilter implements Comparable<CollectionFilter> {
} }
} }
// TODO TLAD replace this by adding getters to CollectionFilter, with cached entry/count coming from Source
class FilterGridItem<T extends CollectionFilter> { class FilterGridItem<T extends CollectionFilter> {
final T filter; final T filter;
final AvesEntry entry; final AvesEntry entry;

View file

@ -11,7 +11,7 @@ class LocationFilter extends CollectionFilter {
final LocationLevel level; final LocationLevel level;
String _location; String _location;
String _countryCode; String _countryCode;
EntryFilter _filter; EntryFilter _test;
LocationFilter(this.level, this._location) { LocationFilter(this.level, this._location) {
final split = _location.split(locationSeparator); final split = _location.split(locationSeparator);
@ -19,11 +19,11 @@ class LocationFilter extends CollectionFilter {
if (split.length > 1) _countryCode = split[1]; if (split.length > 1) _countryCode = split[1];
if (_location.isEmpty) { if (_location.isEmpty) {
_filter = (entry) => !entry.isLocated; _test = (entry) => !entry.isLocated;
} else if (level == LocationLevel.country) { } else if (level == LocationLevel.country) {
_filter = (entry) => entry.addressDetails?.countryCode == _countryCode; _test = (entry) => entry.addressDetails?.countryCode == _countryCode;
} else if (level == LocationLevel.place) { } else if (level == LocationLevel.place) {
_filter = (entry) => entry.addressDetails?.place == _location; _test = (entry) => entry.addressDetails?.place == _location;
} }
} }
@ -45,7 +45,7 @@ class LocationFilter extends CollectionFilter {
String get countryCode => _countryCode; String get countryCode => _countryCode;
@override @override
EntryFilter get filter => _filter; EntryFilter get test => _test;
@override @override
String get label => _location.isEmpty ? emptyLabel : _location; String get label => _location.isEmpty ? emptyLabel : _location;

View file

@ -14,31 +14,31 @@ class MimeFilter extends CollectionFilter {
static const geotiff = 'aves/geotiff'; // subset of `image/tiff` static const geotiff = 'aves/geotiff'; // subset of `image/tiff`
final String mime; final String mime;
EntryFilter _filter; EntryFilter _test;
String _label; String _label;
IconData _icon; IconData _icon;
MimeFilter(this.mime) { MimeFilter(this.mime) {
var lowMime = mime.toLowerCase(); var lowMime = mime.toLowerCase();
if (mime == animated) { if (mime == animated) {
_filter = (entry) => entry.isAnimated; _test = (entry) => entry.isAnimated;
_label = 'Animated'; _label = 'Animated';
_icon = AIcons.animated; _icon = AIcons.animated;
} else if (mime == panorama) { } else if (mime == panorama) {
_filter = (entry) => entry.isImage && entry.is360; _test = (entry) => entry.isImage && entry.is360;
_label = 'Panorama'; _label = 'Panorama';
_icon = AIcons.threesixty; _icon = AIcons.threesixty;
} else if (mime == sphericalVideo) { } else if (mime == sphericalVideo) {
_filter = (entry) => entry.isVideo && entry.is360; _test = (entry) => entry.isVideo && entry.is360;
_label = '360° Video'; _label = '360° Video';
_icon = AIcons.threesixty; _icon = AIcons.threesixty;
} else if (mime == geotiff) { } else if (mime == geotiff) {
_filter = (entry) => entry.isGeotiff; _test = (entry) => entry.isGeotiff;
_label = 'GeoTIFF'; _label = 'GeoTIFF';
_icon = AIcons.geo; _icon = AIcons.geo;
} else if (lowMime.endsWith('/*')) { } else if (lowMime.endsWith('/*')) {
lowMime = lowMime.substring(0, lowMime.length - 2); lowMime = lowMime.substring(0, lowMime.length - 2);
_filter = (entry) => entry.mimeType.startsWith(lowMime); _test = (entry) => entry.mimeType.startsWith(lowMime);
if (lowMime == 'video') { if (lowMime == 'video') {
_label = 'Video'; _label = 'Video';
_icon = AIcons.video; _icon = AIcons.video;
@ -48,7 +48,7 @@ class MimeFilter extends CollectionFilter {
} }
_label ??= lowMime.split('/')[0].toUpperCase(); _label ??= lowMime.split('/')[0].toUpperCase();
} else { } else {
_filter = (entry) => entry.mimeType == lowMime; _test = (entry) => entry.mimeType == lowMime;
_label = MimeUtils.displayType(lowMime); _label = MimeUtils.displayType(lowMime);
} }
_icon ??= AIcons.vector; _icon ??= AIcons.vector;
@ -66,7 +66,7 @@ class MimeFilter extends CollectionFilter {
}; };
@override @override
EntryFilter get filter => _filter; EntryFilter get test => _test;
@override @override
String get label => _label; String get label => _label;

View file

@ -12,7 +12,7 @@ class QueryFilter extends CollectionFilter {
final String query; final String query;
final bool colorful; final bool colorful;
EntryFilter _filter; EntryFilter _test;
QueryFilter(this.query, {this.colorful = true}) { QueryFilter(this.query, {this.colorful = true}) {
var upQuery = query.toUpperCase(); var upQuery = query.toUpperCase();
@ -29,7 +29,7 @@ class QueryFilter extends CollectionFilter {
upQuery = matches.first.group(1); upQuery = matches.first.group(1);
} }
_filter = not ? (entry) => !entry.search(upQuery) : (entry) => entry.search(upQuery); _test = not ? (entry) => !entry.search(upQuery) : (entry) => entry.search(upQuery);
} }
QueryFilter.fromMap(Map<String, dynamic> json) QueryFilter.fromMap(Map<String, dynamic> json)
@ -44,7 +44,7 @@ class QueryFilter extends CollectionFilter {
}; };
@override @override
EntryFilter get filter => _filter; EntryFilter get test => _test;
@override @override
bool get isUnique => false; bool get isUnique => false;

View file

@ -8,13 +8,13 @@ class TagFilter extends CollectionFilter {
static const emptyLabel = 'untagged'; static const emptyLabel = 'untagged';
final String tag; final String tag;
EntryFilter _filter; EntryFilter _test;
TagFilter(this.tag) { TagFilter(this.tag) {
if (tag.isEmpty) { if (tag.isEmpty) {
_filter = (entry) => entry.xmpSubjects.isEmpty; _test = (entry) => entry.xmpSubjects.isEmpty;
} else { } else {
_filter = (entry) => entry.xmpSubjects.contains(tag); _test = (entry) => entry.xmpSubjects.contains(tag);
} }
} }
@ -30,7 +30,7 @@ class TagFilter extends CollectionFilter {
}; };
@override @override
EntryFilter get filter => _filter; EntryFilter get test => _test;
@override @override
bool get isUnique => false; bool get isUnique => false;

View file

@ -122,11 +122,11 @@ mixin AlbumMixin on SourceBase {
} }
int albumEntryCount(AlbumFilter filter) { int albumEntryCount(AlbumFilter filter) {
return _filterEntryCountMap.putIfAbsent(filter.album, () => visibleEntries.where((entry) => filter.filter(entry)).length); return _filterEntryCountMap.putIfAbsent(filter.album, () => visibleEntries.where(filter.test).length);
} }
AvesEntry albumRecentEntry(AlbumFilter filter) { AvesEntry albumRecentEntry(AlbumFilter filter) {
return _filterRecentEntryMap.putIfAbsent(filter.album, () => sortedEntriesByDate.firstWhere((entry) => filter.filter(entry), orElse: () => null)); return _filterRecentEntryMap.putIfAbsent(filter.album, () => sortedEntriesByDate.firstWhere(filter.test, orElse: () => null));
} }
} }

View file

@ -123,7 +123,7 @@ class CollectionLens with ChangeNotifier, CollectionActivityMixin {
void _applyFilters() { void _applyFilters() {
final entries = source.visibleEntries; final entries = source.visibleEntries;
_filteredSortedEntries = List.of(filters.isEmpty ? entries : entries.where((entry) => filters.fold(true, (prev, filter) => prev && filter.filter(entry)))); _filteredSortedEntries = List.of(filters.isEmpty ? entries : entries.where((entry) => filters.every((filter) => filter.test(entry))));
} }
void _applySort() { void _applySort() {

View file

@ -70,7 +70,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
Iterable<AvesEntry> _applyHiddenFilters(Iterable<AvesEntry> entries) { Iterable<AvesEntry> _applyHiddenFilters(Iterable<AvesEntry> entries) {
final hiddenFilters = settings.hiddenFilters; final hiddenFilters = settings.hiddenFilters;
return hiddenFilters.isEmpty ? entries : entries.where((entry) => !hiddenFilters.any((filter) => filter.filter(entry))); return hiddenFilters.isEmpty ? entries : entries.where((entry) => !hiddenFilters.any((filter) => filter.test(entry)));
} }
void _invalidate([Set<AvesEntry> entries]) { void _invalidate([Set<AvesEntry> entries]) {
@ -247,6 +247,10 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
updateDirectories(); updateDirectories();
updateLocations(); updateLocations();
updateTags(); updateTags();
if (visible) {
refreshMetadata(visibleEntries.where(filter.test).toSet());
}
} }
} }

View file

@ -121,11 +121,11 @@ mixin LocationMixin on SourceBase {
} }
int countryEntryCount(LocationFilter filter) { int countryEntryCount(LocationFilter filter) {
return _filterEntryCountMap.putIfAbsent(filter.countryCode, () => visibleEntries.where((entry) => filter.filter(entry)).length); return _filterEntryCountMap.putIfAbsent(filter.countryCode, () => visibleEntries.where(filter.test).length);
} }
AvesEntry countryRecentEntry(LocationFilter filter) { AvesEntry countryRecentEntry(LocationFilter filter) {
return _filterRecentEntryMap.putIfAbsent(filter.countryCode, () => sortedEntriesByDate.firstWhere((entry) => filter.filter(entry), orElse: () => null)); return _filterRecentEntryMap.putIfAbsent(filter.countryCode, () => sortedEntriesByDate.firstWhere(filter.test, orElse: () => null));
} }
} }

View file

@ -79,11 +79,11 @@ mixin TagMixin on SourceBase {
} }
int tagEntryCount(TagFilter filter) { int tagEntryCount(TagFilter filter) {
return _filterEntryCountMap.putIfAbsent(filter.tag, () => visibleEntries.where((entry) => filter.filter(entry)).length); return _filterEntryCountMap.putIfAbsent(filter.tag, () => visibleEntries.where(filter.test).length);
} }
AvesEntry tagRecentEntry(TagFilter filter) { AvesEntry tagRecentEntry(TagFilter filter) {
return _filterRecentEntryMap.putIfAbsent(filter.tag, () => sortedEntriesByDate.firstWhere((entry) => filter.filter(entry), orElse: () => null)); return _filterRecentEntryMap.putIfAbsent(filter.tag, () => sortedEntriesByDate.firstWhere(filter.test, orElse: () => null));
} }
} }

View file

@ -60,7 +60,7 @@ class AlbumChipActionDelegate extends ChipActionDelegate with FeedbackMixin, Per
} }
Future<void> _showDeleteDialog(BuildContext context, AlbumFilter filter) async { Future<void> _showDeleteDialog(BuildContext context, AlbumFilter filter) async {
final selection = source.visibleEntries.where(filter.filter).toSet(); final selection = source.visibleEntries.where(filter.test).toSet();
final count = selection.length; final count = selection.length;
final confirmed = await showDialog<bool>( final confirmed = await showDialog<bool>(
@ -115,7 +115,7 @@ class AlbumChipActionDelegate extends ChipActionDelegate with FeedbackMixin, Per
if (!await checkStoragePermissionForAlbums(context, {album})) return; if (!await checkStoragePermissionForAlbums(context, {album})) return;
final todoEntries = source.visibleEntries.where(filter.filter).toSet(); final todoEntries = source.visibleEntries.where(filter.test).toSet();
final destinationAlbum = path.join(path.dirname(album), newName); final destinationAlbum = path.join(path.dirname(album), newName);
if (!await checkFreeSpaceForMove(context, todoEntries, destinationAlbum, MoveType.move)) return; if (!await checkFreeSpaceForMove(context, todoEntries, destinationAlbum, MoveType.move)) return;