hidden filters: refresh metadata of newly visible items
This commit is contained in:
parent
7fb40c0810
commit
dcfc07ff00
13 changed files with 37 additions and 34 deletions
|
@ -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;
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue