#1554 Collection: sort by storage path

This commit is contained in:
Thibault Deckers 2025-05-12 23:04:14 +02:00
parent eaa4fe3317
commit a6c1fd52a6
11 changed files with 38 additions and 7 deletions

View file

@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### Added
- Albums: groups
- Collection: sort by storage path
- Search: week day filters
### Changed

View file

@ -43,4 +43,10 @@ class AvesEntrySort {
final c = (b.durationMillis ?? 0).compareTo(a.durationMillis ?? 0);
return c != 0 ? c : compareByDate(a, b);
}
// compare by:
// 1) path ascending
static int compareByPath(AvesEntry a, AvesEntry b) {
return compareAsciiUpperCase(a.path ?? '', b.path ?? '');
}
}

View file

@ -21,6 +21,8 @@ mixin AlbumMixin on SourceBase {
Set<StoredAlbumFilter> getNewAlbumFilters(BuildContext context) => Set.unmodifiable(_newAlbums.map((v) => StoredAlbumFilter(v, getStoredAlbumDisplayName(context, v))));
int compareAlbumsByPath(String? a, String? b) => compareAsciiUpperCase(a ??= '', b ??= '');
int compareAlbumsByName(String? a, String? b) {
a ??= '';
b ??= '';

View file

@ -157,6 +157,7 @@ class CollectionLens with ChangeNotifier {
return true;
}
case EntrySortFactor.name:
case EntrySortFactor.path:
return showAlbumHeaders();
case EntrySortFactor.rating:
return !filters.any((f) => f is RatingFilter);
@ -266,6 +267,8 @@ class CollectionLens with ChangeNotifier {
_filteredSortedEntries.sort(AvesEntrySort.compareBySize);
case EntrySortFactor.duration:
_filteredSortedEntries.sort(AvesEntrySort.compareByDuration);
case EntrySortFactor.path:
_filteredSortedEntries.sort(AvesEntrySort.compareByPath);
}
if (sortReverse) {
_filteredSortedEntries = _filteredSortedEntries.reversed.toList();
@ -303,6 +306,10 @@ class CollectionLens with ChangeNotifier {
sections = Map.fromEntries([
MapEntry(const SectionKey(), _filteredSortedEntries),
]);
case EntrySortFactor.path:
final byAlbum = groupBy<AvesEntry, EntryAlbumSectionKey>(_filteredSortedEntries, (entry) => EntryAlbumSectionKey(entry.directory));
final int Function(EntryAlbumSectionKey, EntryAlbumSectionKey) compare = sortReverse ? (a, b) => source.compareAlbumsByPath(b.directory, a.directory) : (a, b) => source.compareAlbumsByPath(a.directory, b.directory);
sections = SplayTreeMap<EntryAlbumSectionKey, List<AvesEntry>>.of(byAlbum, compare);
}
}
sections = Map.unmodifiable(sections);

View file

@ -81,7 +81,7 @@ class AIcons {
static const place = Symbols.place;
// view
static const section = Symbols.group_work;
static const section = Symbols.subheader;
static const layout = Symbols.grid_view;
static const layoutMosaic = Symbols.view_comfy;
static const layoutGrid = Symbols.view_compact;

View file

@ -12,6 +12,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
EntrySortFactor.rating => l10n.sortByRating,
EntrySortFactor.size => l10n.sortBySize,
EntrySortFactor.duration => l10n.sortByDuration,
EntrySortFactor.path => l10n.sortByPath,
};
}
@ -22,6 +23,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
EntrySortFactor.rating => AIcons.rating,
EntrySortFactor.size => AIcons.size,
EntrySortFactor.duration => AIcons.duration,
EntrySortFactor.path => AIcons.path,
};
}
@ -33,6 +35,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
EntrySortFactor.rating => reverse ? l10n.sortOrderLowestFirst : l10n.sortOrderHighestFirst,
EntrySortFactor.size => reverse ? l10n.sortOrderSmallestFirst : l10n.sortOrderLargestFirst,
EntrySortFactor.duration => reverse ? l10n.sortOrderShortestFirst : l10n.sortOrderLongestFirst,
EntrySortFactor.path => reverse ? l10n.sortOrderZtoA : l10n.sortOrderAtoZ,
};
}
}

View file

@ -81,6 +81,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
EntrySortFactor.name,
EntrySortFactor.rating,
EntrySortFactor.duration,
EntrySortFactor.path,
];
static const _sectionOptions = [

View file

@ -726,6 +726,7 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> with Widge
break;
}
case EntrySortFactor.name:
case EntrySortFactor.path:
addAlbums(collection, sectionLayouts, crumbs);
case EntrySortFactor.rating:
case EntrySortFactor.size:

View file

@ -27,26 +27,28 @@ class CollectionDraggableThumbLabel extends StatelessWidget {
lineBuilder: (context, entry) {
switch (collection.sortFactor) {
case EntrySortFactor.date:
final date = entry.bestDate;
switch (collection.sectionFactor) {
case EntrySectionFactor.album:
return [
DraggableThumbLabel.formatMonthThumbLabel(context, entry.bestDate),
DraggableThumbLabel.formatMonthThumbLabel(context, date),
if (_showAlbumName(context, entry)) _getAlbumName(context, entry),
];
case EntrySectionFactor.month:
case EntrySectionFactor.none:
return [
DraggableThumbLabel.formatMonthThumbLabel(context, entry.bestDate),
DraggableThumbLabel.formatMonthThumbLabel(context, date),
];
case EntrySectionFactor.day:
return [
DraggableThumbLabel.formatDayThumbLabel(context, entry.bestDate),
DraggableThumbLabel.formatDayThumbLabel(context, date),
];
}
case EntrySortFactor.name:
final entryTitle = entry.bestTitle;
return [
if (_showAlbumName(context, entry)) _getAlbumName(context, entry),
if (entry.bestTitle != null) entry.bestTitle!,
if (entryTitle != null) entryTitle,
];
case EntrySortFactor.rating:
return [
@ -54,13 +56,20 @@ class CollectionDraggableThumbLabel extends StatelessWidget {
DraggableThumbLabel.formatMonthThumbLabel(context, entry.bestDate),
];
case EntrySortFactor.size:
final sizeBytes = entry.sizeBytes;
return [
if (entry.sizeBytes != null) formatFileSize(context.locale, entry.sizeBytes!, round: 0),
if (sizeBytes != null) formatFileSize(context.locale, sizeBytes, round: 0),
];
case EntrySortFactor.duration:
return [
if (entry.durationMillis != null) entry.durationText,
];
case EntrySortFactor.path:
final entryFilename = entry.filenameWithoutExtension;
return [
if (_showAlbumName(context, entry)) _getAlbumName(context, entry),
if (entryFilename != null) entryFilename,
];
}
},
);

View file

@ -58,6 +58,7 @@ class CollectionSectionHeader extends StatelessWidget {
break;
}
case EntrySortFactor.name:
case EntrySortFactor.path:
return _buildAlbumHeader(context);
case EntrySortFactor.rating:
return RatingSectionHeader<AvesEntry>(

View file

@ -4,7 +4,7 @@ enum ChipSortFactor { date, name, count, size, path }
enum AlbumChipSectionFactor { none, importance, mimeType, volume }
enum EntrySortFactor { date, name, rating, size, duration }
enum EntrySortFactor { date, name, rating, size, duration, path }
enum EntrySectionFactor { none, album, month, day }