#1554 Collection: sort by storage path
This commit is contained in:
parent
eaa4fe3317
commit
a6c1fd52a6
11 changed files with 38 additions and 7 deletions
|
@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Albums: groups
|
- Albums: groups
|
||||||
|
- Collection: sort by storage path
|
||||||
- Search: week day filters
|
- Search: week day filters
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -43,4 +43,10 @@ class AvesEntrySort {
|
||||||
final c = (b.durationMillis ?? 0).compareTo(a.durationMillis ?? 0);
|
final c = (b.durationMillis ?? 0).compareTo(a.durationMillis ?? 0);
|
||||||
return c != 0 ? c : compareByDate(a, b);
|
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 ?? '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ mixin AlbumMixin on SourceBase {
|
||||||
|
|
||||||
Set<StoredAlbumFilter> getNewAlbumFilters(BuildContext context) => Set.unmodifiable(_newAlbums.map((v) => StoredAlbumFilter(v, getStoredAlbumDisplayName(context, v))));
|
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) {
|
int compareAlbumsByName(String? a, String? b) {
|
||||||
a ??= '';
|
a ??= '';
|
||||||
b ??= '';
|
b ??= '';
|
||||||
|
|
|
@ -157,6 +157,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case EntrySortFactor.name:
|
case EntrySortFactor.name:
|
||||||
|
case EntrySortFactor.path:
|
||||||
return showAlbumHeaders();
|
return showAlbumHeaders();
|
||||||
case EntrySortFactor.rating:
|
case EntrySortFactor.rating:
|
||||||
return !filters.any((f) => f is RatingFilter);
|
return !filters.any((f) => f is RatingFilter);
|
||||||
|
@ -266,6 +267,8 @@ class CollectionLens with ChangeNotifier {
|
||||||
_filteredSortedEntries.sort(AvesEntrySort.compareBySize);
|
_filteredSortedEntries.sort(AvesEntrySort.compareBySize);
|
||||||
case EntrySortFactor.duration:
|
case EntrySortFactor.duration:
|
||||||
_filteredSortedEntries.sort(AvesEntrySort.compareByDuration);
|
_filteredSortedEntries.sort(AvesEntrySort.compareByDuration);
|
||||||
|
case EntrySortFactor.path:
|
||||||
|
_filteredSortedEntries.sort(AvesEntrySort.compareByPath);
|
||||||
}
|
}
|
||||||
if (sortReverse) {
|
if (sortReverse) {
|
||||||
_filteredSortedEntries = _filteredSortedEntries.reversed.toList();
|
_filteredSortedEntries = _filteredSortedEntries.reversed.toList();
|
||||||
|
@ -303,6 +306,10 @@ class CollectionLens with ChangeNotifier {
|
||||||
sections = Map.fromEntries([
|
sections = Map.fromEntries([
|
||||||
MapEntry(const SectionKey(), _filteredSortedEntries),
|
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);
|
sections = Map.unmodifiable(sections);
|
||||||
|
|
|
@ -81,7 +81,7 @@ class AIcons {
|
||||||
static const place = Symbols.place;
|
static const place = Symbols.place;
|
||||||
|
|
||||||
// view
|
// view
|
||||||
static const section = Symbols.group_work;
|
static const section = Symbols.subheader;
|
||||||
static const layout = Symbols.grid_view;
|
static const layout = Symbols.grid_view;
|
||||||
static const layoutMosaic = Symbols.view_comfy;
|
static const layoutMosaic = Symbols.view_comfy;
|
||||||
static const layoutGrid = Symbols.view_compact;
|
static const layoutGrid = Symbols.view_compact;
|
||||||
|
|
|
@ -12,6 +12,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
|
||||||
EntrySortFactor.rating => l10n.sortByRating,
|
EntrySortFactor.rating => l10n.sortByRating,
|
||||||
EntrySortFactor.size => l10n.sortBySize,
|
EntrySortFactor.size => l10n.sortBySize,
|
||||||
EntrySortFactor.duration => l10n.sortByDuration,
|
EntrySortFactor.duration => l10n.sortByDuration,
|
||||||
|
EntrySortFactor.path => l10n.sortByPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
|
||||||
EntrySortFactor.rating => AIcons.rating,
|
EntrySortFactor.rating => AIcons.rating,
|
||||||
EntrySortFactor.size => AIcons.size,
|
EntrySortFactor.size => AIcons.size,
|
||||||
EntrySortFactor.duration => AIcons.duration,
|
EntrySortFactor.duration => AIcons.duration,
|
||||||
|
EntrySortFactor.path => AIcons.path,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ extension ExtraEntrySortFactorView on EntrySortFactor {
|
||||||
EntrySortFactor.rating => reverse ? l10n.sortOrderLowestFirst : l10n.sortOrderHighestFirst,
|
EntrySortFactor.rating => reverse ? l10n.sortOrderLowestFirst : l10n.sortOrderHighestFirst,
|
||||||
EntrySortFactor.size => reverse ? l10n.sortOrderSmallestFirst : l10n.sortOrderLargestFirst,
|
EntrySortFactor.size => reverse ? l10n.sortOrderSmallestFirst : l10n.sortOrderLargestFirst,
|
||||||
EntrySortFactor.duration => reverse ? l10n.sortOrderShortestFirst : l10n.sortOrderLongestFirst,
|
EntrySortFactor.duration => reverse ? l10n.sortOrderShortestFirst : l10n.sortOrderLongestFirst,
|
||||||
|
EntrySortFactor.path => reverse ? l10n.sortOrderZtoA : l10n.sortOrderAtoZ,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
EntrySortFactor.name,
|
EntrySortFactor.name,
|
||||||
EntrySortFactor.rating,
|
EntrySortFactor.rating,
|
||||||
EntrySortFactor.duration,
|
EntrySortFactor.duration,
|
||||||
|
EntrySortFactor.path,
|
||||||
];
|
];
|
||||||
|
|
||||||
static const _sectionOptions = [
|
static const _sectionOptions = [
|
||||||
|
|
|
@ -726,6 +726,7 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> with Widge
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EntrySortFactor.name:
|
case EntrySortFactor.name:
|
||||||
|
case EntrySortFactor.path:
|
||||||
addAlbums(collection, sectionLayouts, crumbs);
|
addAlbums(collection, sectionLayouts, crumbs);
|
||||||
case EntrySortFactor.rating:
|
case EntrySortFactor.rating:
|
||||||
case EntrySortFactor.size:
|
case EntrySortFactor.size:
|
||||||
|
|
|
@ -27,26 +27,28 @@ class CollectionDraggableThumbLabel extends StatelessWidget {
|
||||||
lineBuilder: (context, entry) {
|
lineBuilder: (context, entry) {
|
||||||
switch (collection.sortFactor) {
|
switch (collection.sortFactor) {
|
||||||
case EntrySortFactor.date:
|
case EntrySortFactor.date:
|
||||||
|
final date = entry.bestDate;
|
||||||
switch (collection.sectionFactor) {
|
switch (collection.sectionFactor) {
|
||||||
case EntrySectionFactor.album:
|
case EntrySectionFactor.album:
|
||||||
return [
|
return [
|
||||||
DraggableThumbLabel.formatMonthThumbLabel(context, entry.bestDate),
|
DraggableThumbLabel.formatMonthThumbLabel(context, date),
|
||||||
if (_showAlbumName(context, entry)) _getAlbumName(context, entry),
|
if (_showAlbumName(context, entry)) _getAlbumName(context, entry),
|
||||||
];
|
];
|
||||||
case EntrySectionFactor.month:
|
case EntrySectionFactor.month:
|
||||||
case EntrySectionFactor.none:
|
case EntrySectionFactor.none:
|
||||||
return [
|
return [
|
||||||
DraggableThumbLabel.formatMonthThumbLabel(context, entry.bestDate),
|
DraggableThumbLabel.formatMonthThumbLabel(context, date),
|
||||||
];
|
];
|
||||||
case EntrySectionFactor.day:
|
case EntrySectionFactor.day:
|
||||||
return [
|
return [
|
||||||
DraggableThumbLabel.formatDayThumbLabel(context, entry.bestDate),
|
DraggableThumbLabel.formatDayThumbLabel(context, date),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case EntrySortFactor.name:
|
case EntrySortFactor.name:
|
||||||
|
final entryTitle = entry.bestTitle;
|
||||||
return [
|
return [
|
||||||
if (_showAlbumName(context, entry)) _getAlbumName(context, entry),
|
if (_showAlbumName(context, entry)) _getAlbumName(context, entry),
|
||||||
if (entry.bestTitle != null) entry.bestTitle!,
|
if (entryTitle != null) entryTitle,
|
||||||
];
|
];
|
||||||
case EntrySortFactor.rating:
|
case EntrySortFactor.rating:
|
||||||
return [
|
return [
|
||||||
|
@ -54,13 +56,20 @@ class CollectionDraggableThumbLabel extends StatelessWidget {
|
||||||
DraggableThumbLabel.formatMonthThumbLabel(context, entry.bestDate),
|
DraggableThumbLabel.formatMonthThumbLabel(context, entry.bestDate),
|
||||||
];
|
];
|
||||||
case EntrySortFactor.size:
|
case EntrySortFactor.size:
|
||||||
|
final sizeBytes = entry.sizeBytes;
|
||||||
return [
|
return [
|
||||||
if (entry.sizeBytes != null) formatFileSize(context.locale, entry.sizeBytes!, round: 0),
|
if (sizeBytes != null) formatFileSize(context.locale, sizeBytes, round: 0),
|
||||||
];
|
];
|
||||||
case EntrySortFactor.duration:
|
case EntrySortFactor.duration:
|
||||||
return [
|
return [
|
||||||
if (entry.durationMillis != null) entry.durationText,
|
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,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -58,6 +58,7 @@ class CollectionSectionHeader extends StatelessWidget {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EntrySortFactor.name:
|
case EntrySortFactor.name:
|
||||||
|
case EntrySortFactor.path:
|
||||||
return _buildAlbumHeader(context);
|
return _buildAlbumHeader(context);
|
||||||
case EntrySortFactor.rating:
|
case EntrySortFactor.rating:
|
||||||
return RatingSectionHeader<AvesEntry>(
|
return RatingSectionHeader<AvesEntry>(
|
||||||
|
|
|
@ -4,7 +4,7 @@ enum ChipSortFactor { date, name, count, size, path }
|
||||||
|
|
||||||
enum AlbumChipSectionFactor { none, importance, mimeType, volume }
|
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 }
|
enum EntrySectionFactor { none, album, month, day }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue