mirror of
https://github.com/immich-app/immich.git
synced 2026-02-07 11:33:45 -05:00
feat(mobile): enhance album sorting functionality with order handling (#24816)
* feat: enhance album sorting functionality with effective order handling * mobile: formatting * test: align album sorting order in unit tests with defaultSortOrder * test(mobile): add reverse order validation for album sorting * chore(PR): remove OppositeSortOrder Extension and move it directly into SortOrder enum * refactor: return sorted list directly in album sorting function * refactor: remove sort_order_extensions.dart
This commit is contained in:
parent
57483a1e7f
commit
354dd3cc3c
@ -1,4 +1,11 @@
|
||||
enum SortOrder { asc, desc }
|
||||
enum SortOrder {
|
||||
asc,
|
||||
desc;
|
||||
|
||||
SortOrder reverse() {
|
||||
return this == SortOrder.asc ? SortOrder.desc : SortOrder.asc;
|
||||
}
|
||||
}
|
||||
|
||||
enum TextSearchType { context, filename, description, ocr }
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
@ -36,6 +37,7 @@ class RemoteAlbumService {
|
||||
AlbumSortMode sortMode, {
|
||||
bool isReverse = false,
|
||||
}) async {
|
||||
// list of albums sorted ascendingly according to the selected sort mode
|
||||
final List<RemoteAlbum> sorted = switch (sortMode) {
|
||||
AlbumSortMode.created => albums.sortedBy((album) => album.createdAt),
|
||||
AlbumSortMode.title => albums.sortedBy((album) => album.name),
|
||||
@ -44,8 +46,9 @@ class RemoteAlbumService {
|
||||
AlbumSortMode.mostRecent => await _sortByNewestAsset(albums),
|
||||
AlbumSortMode.mostOldest => await _sortByOldestAsset(albums),
|
||||
};
|
||||
final effectiveOrder = isReverse ? sortMode.defaultOrder.reverse() : sortMode.defaultOrder;
|
||||
|
||||
return (isReverse ? sorted.reversed : sorted).toList();
|
||||
return (effectiveOrder == SortOrder.asc ? sorted : sorted.reversed).toList();
|
||||
}
|
||||
|
||||
List<RemoteAlbum> searchAlbums(
|
||||
@ -209,6 +212,6 @@ class RemoteAlbumService {
|
||||
return aDate.compareTo(bDate);
|
||||
});
|
||||
|
||||
return sorted.reversed.toList();
|
||||
return sorted;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
@ -281,6 +282,8 @@ class _SortButtonState extends ConsumerState<_SortButton> {
|
||||
setState(() {
|
||||
albumSortOption = sortMode;
|
||||
isSorting = true;
|
||||
// reset sort order to default state when switching option
|
||||
albumSortIsReverse = false;
|
||||
});
|
||||
}
|
||||
|
||||
@ -293,6 +296,7 @@ class _SortButtonState extends ConsumerState<_SortButton> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveOrder = albumSortOption.effectiveOrder(albumSortIsReverse);
|
||||
return MenuAnchor(
|
||||
controller: widget.controller,
|
||||
style: MenuStyle(
|
||||
@ -307,7 +311,7 @@ class _SortButtonState extends ConsumerState<_SortButton> {
|
||||
.map(
|
||||
(sortMode) => MenuItemButton(
|
||||
leadingIcon: albumSortOption == sortMode
|
||||
? albumSortIsReverse
|
||||
? effectiveOrder == SortOrder.desc
|
||||
? Icon(
|
||||
Icons.keyboard_arrow_down,
|
||||
color: albumSortOption == sortMode
|
||||
@ -355,7 +359,7 @@ class _SortButtonState extends ConsumerState<_SortButton> {
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 5),
|
||||
child: albumSortIsReverse
|
||||
child: effectiveOrder == SortOrder.desc
|
||||
? Icon(Icons.keyboard_arrow_down, color: context.colorScheme.onSurface)
|
||||
: Icon(Icons.keyboard_arrow_up_rounded, color: context.colorScheme.onSurface),
|
||||
),
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
@ -73,18 +74,21 @@ class _AlbumSortHandlers {
|
||||
|
||||
// Store index allows us to re-arrange the values without affecting the saved prefs
|
||||
enum AlbumSortMode {
|
||||
title(1, "library_page_sort_title", _AlbumSortHandlers.title),
|
||||
assetCount(4, "library_page_sort_asset_count", _AlbumSortHandlers.assetCount),
|
||||
lastModified(3, "library_page_sort_last_modified", _AlbumSortHandlers.lastModified),
|
||||
created(0, "library_page_sort_created", _AlbumSortHandlers.created),
|
||||
mostRecent(2, "sort_recent", _AlbumSortHandlers.mostRecent),
|
||||
mostOldest(5, "sort_oldest", _AlbumSortHandlers.mostOldest);
|
||||
title(1, "library_page_sort_title", _AlbumSortHandlers.title, SortOrder.asc),
|
||||
assetCount(4, "library_page_sort_asset_count", _AlbumSortHandlers.assetCount, SortOrder.desc),
|
||||
lastModified(3, "library_page_sort_last_modified", _AlbumSortHandlers.lastModified, SortOrder.desc),
|
||||
created(0, "library_page_sort_created", _AlbumSortHandlers.created, SortOrder.desc),
|
||||
mostRecent(2, "sort_recent", _AlbumSortHandlers.mostRecent, SortOrder.desc),
|
||||
mostOldest(5, "sort_oldest", _AlbumSortHandlers.mostOldest, SortOrder.asc);
|
||||
|
||||
final int storeIndex;
|
||||
final String label;
|
||||
final AlbumSortFn sortFn;
|
||||
final SortOrder defaultOrder;
|
||||
|
||||
const AlbumSortMode(this.storeIndex, this.label, this.sortFn);
|
||||
const AlbumSortMode(this.storeIndex, this.label, this.sortFn, this.defaultOrder);
|
||||
|
||||
SortOrder effectiveOrder(bool isReverse) => isReverse ? defaultOrder.reverse() : defaultOrder;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
||||
@ -85,35 +85,47 @@ void main() {
|
||||
final albums = [albumB, albumA];
|
||||
|
||||
final result = await sut.sortAlbums(albums, AlbumSortMode.created);
|
||||
expect(result, [albumA, albumB]);
|
||||
expect(result, [albumB, albumA]);
|
||||
});
|
||||
|
||||
test('should sort correctly based on updatedAt', () async {
|
||||
final albums = [albumB, albumA];
|
||||
|
||||
final result = await sut.sortAlbums(albums, AlbumSortMode.lastModified);
|
||||
expect(result, [albumA, albumB]);
|
||||
expect(result, [albumB, albumA]);
|
||||
});
|
||||
|
||||
test('should sort correctly based on assetCount', () async {
|
||||
final albums = [albumB, albumA];
|
||||
|
||||
final result = await sut.sortAlbums(albums, AlbumSortMode.assetCount);
|
||||
expect(result, [albumA, albumB]);
|
||||
expect(result, [albumB, albumA]);
|
||||
});
|
||||
|
||||
test('should sort correctly based on newestAssetTimestamp', () async {
|
||||
final albums = [albumB, albumA];
|
||||
|
||||
final result = await sut.sortAlbums(albums, AlbumSortMode.mostRecent);
|
||||
expect(result, [albumA, albumB]);
|
||||
expect(result, [albumB, albumA]);
|
||||
});
|
||||
|
||||
test('should sort correctly based on oldestAssetTimestamp', () async {
|
||||
final albums = [albumB, albumA];
|
||||
|
||||
final result = await sut.sortAlbums(albums, AlbumSortMode.mostOldest);
|
||||
expect(result, [albumB, albumA]);
|
||||
expect(result, [albumA, albumB]);
|
||||
});
|
||||
|
||||
test('should flip order when isReverse is true for all modes', () async {
|
||||
final albums = [albumB, albumA];
|
||||
|
||||
for (final mode in AlbumSortMode.values) {
|
||||
final normal = await sut.sortAlbums(albums, mode, isReverse: false);
|
||||
final reversed = await sut.sortAlbums(albums, mode, isReverse: true);
|
||||
|
||||
// reversed should be the exact inverse of normal
|
||||
expect(reversed, normal.reversed.toList(), reason: 'Mode: $mode');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user