From f02bc73f2c87c65f0fce34da10b39aeeb2abde19 Mon Sep 17 00:00:00 2001 From: Yaros Date: Tue, 16 Sep 2025 23:39:58 +0200 Subject: [PATCH] fix(mobile): persist album sorting in settings --- .../widgets/album/album_selector.widget.dart | 66 +++++++++++++++++-- mobile/lib/utils/album_filter.utils.dart | 35 ++++++++++ 2 files changed, 96 insertions(+), 5 deletions(-) diff --git a/mobile/lib/presentation/widgets/album/album_selector.widget.dart b/mobile/lib/presentation/widgets/album/album_selector.widget.dart index f79b4bd7b1..d2f983ee7d 100644 --- a/mobile/lib/presentation/widgets/album/album_selector.widget.dart +++ b/mobile/lib/presentation/widgets/album/album_selector.widget.dart @@ -18,6 +18,9 @@ import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/utils/album_filter.utils.dart'; import 'package:immich_mobile/widgets/common/confirm_dialog.dart'; @@ -52,8 +55,20 @@ class _AlbumSelectorState extends ConsumerState { void initState() { super.initState(); - // Load albums when component mounts WidgetsBinding.instance.addPostFrameCallback((_) { + final appSettings = ref.read(appSettingsServiceProvider); + final savedSortMode = appSettings.getSetting(AppSettingsEnum.selectedAlbumSortOrder); + final savedIsReverse = appSettings.getSetting(AppSettingsEnum.selectedAlbumSortReverse); + + final albumSortMode = AlbumSortMode.values.firstWhere( + (e) => e.storeIndex == savedSortMode, + orElse: () => AlbumSortMode.lastModified, + ); + + setState(() { + sort = AlbumSort(mode: toRemoteAlbumSortMode(albumSortMode), isReverse: savedIsReverse); + }); + ref.read(remoteAlbumProvider.notifier).refresh(); }); @@ -98,6 +113,11 @@ class _AlbumSelectorState extends ConsumerState { this.sort = sort; }); + final appSettings = ref.read(appSettingsServiceProvider); + final albumSortMode = toAlbumSortMode(sort.mode); + await appSettings.setSetting(AppSettingsEnum.selectedAlbumSortOrder, albumSortMode.storeIndex); + await appSettings.setSetting(AppSettingsEnum.selectedAlbumSortReverse, sort.isReverse); + await sortAlbums(); } @@ -182,6 +202,8 @@ class _AlbumSelectorState extends ConsumerState { onToggleViewMode: toggleViewMode, onSortChanged: changeSort, controller: menuController, + currentSortMode: sort.mode, + currentIsReverse: sort.isReverse, ), isGrid ? _AlbumGrid(albums: shownAlbums, userId: userId, onAlbumSelected: widget.onAlbumSelected) @@ -193,20 +215,45 @@ class _AlbumSelectorState extends ConsumerState { } class _SortButton extends ConsumerStatefulWidget { - const _SortButton(this.onSortChanged, {this.controller}); + const _SortButton( + this.onSortChanged, { + required this.initialSortMode, + required this.initialIsReverse, + this.controller, + }); final Future Function(AlbumSort) onSortChanged; final MenuController? controller; + final RemoteAlbumSortMode initialSortMode; + final bool initialIsReverse; @override ConsumerState<_SortButton> createState() => _SortButtonState(); } class _SortButtonState extends ConsumerState<_SortButton> { - RemoteAlbumSortMode albumSortOption = RemoteAlbumSortMode.lastModified; - bool albumSortIsReverse = true; + late RemoteAlbumSortMode albumSortOption; + late bool albumSortIsReverse; bool isSorting = false; + @override + void initState() { + super.initState(); + albumSortOption = widget.initialSortMode; + albumSortIsReverse = widget.initialIsReverse; + } + + @override + void didUpdateWidget(_SortButton oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.initialSortMode != widget.initialSortMode || oldWidget.initialIsReverse != widget.initialIsReverse) { + setState(() { + albumSortOption = widget.initialSortMode; + albumSortIsReverse = widget.initialIsReverse; + }); + } + } + Future onMenuTapped(RemoteAlbumSortMode sortMode) async { final selected = albumSortOption == sortMode; // Switch direction @@ -466,6 +513,8 @@ class _QuickSortAndViewMode extends StatelessWidget { required this.isGrid, required this.onToggleViewMode, required this.onSortChanged, + required this.currentSortMode, + required this.currentIsReverse, this.controller, }); @@ -473,6 +522,8 @@ class _QuickSortAndViewMode extends StatelessWidget { final VoidCallback onToggleViewMode; final MenuController? controller; final Future Function(AlbumSort) onSortChanged; + final RemoteAlbumSortMode currentSortMode; + final bool currentIsReverse; @override Widget build(BuildContext context) { @@ -482,7 +533,12 @@ class _QuickSortAndViewMode extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _SortButton(onSortChanged, controller: controller), + _SortButton( + onSortChanged, + controller: controller, + initialSortMode: currentSortMode, + initialIsReverse: currentIsReverse, + ), IconButton( icon: Icon(isGrid ? Icons.view_list_outlined : Icons.grid_view_outlined, size: 24), onPressed: onToggleViewMode, diff --git a/mobile/lib/utils/album_filter.utils.dart b/mobile/lib/utils/album_filter.utils.dart index 02142b1571..f475f9ebc0 100644 --- a/mobile/lib/utils/album_filter.utils.dart +++ b/mobile/lib/utils/album_filter.utils.dart @@ -1,5 +1,6 @@ import 'package:immich_mobile/domain/services/remote_album.service.dart'; import 'package:immich_mobile/models/albums/album_search.model.dart'; +import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart'; class AlbumFilter { String? userId; @@ -23,3 +24,37 @@ class AlbumSort { return AlbumSort(mode: mode ?? this.mode, isReverse: isReverse ?? this.isReverse); } } + +RemoteAlbumSortMode toRemoteAlbumSortMode(AlbumSortMode mode) { + switch (mode) { + case AlbumSortMode.title: + return RemoteAlbumSortMode.title; + case AlbumSortMode.assetCount: + return RemoteAlbumSortMode.assetCount; + case AlbumSortMode.lastModified: + return RemoteAlbumSortMode.lastModified; + case AlbumSortMode.created: + return RemoteAlbumSortMode.created; + case AlbumSortMode.mostRecent: + return RemoteAlbumSortMode.mostRecent; + case AlbumSortMode.mostOldest: + return RemoteAlbumSortMode.mostOldest; + } +} + +AlbumSortMode toAlbumSortMode(RemoteAlbumSortMode mode) { + switch (mode) { + case RemoteAlbumSortMode.title: + return AlbumSortMode.title; + case RemoteAlbumSortMode.assetCount: + return AlbumSortMode.assetCount; + case RemoteAlbumSortMode.lastModified: + return AlbumSortMode.lastModified; + case RemoteAlbumSortMode.created: + return AlbumSortMode.created; + case RemoteAlbumSortMode.mostRecent: + return AlbumSortMode.mostRecent; + case RemoteAlbumSortMode.mostOldest: + return AlbumSortMode.mostOldest; + } +}