feat: show "appears in" albums on asset viewer bottom sheet (#21925)

* feat: show "appears in" albums on asset viewer bottom sheet

fix: multiple RemoteAlbumPages in navigation stack

this also allows us to not have to set the current album before navigating to RemoteAlbumPage

chore: clarification comments

handle nested album pages

fix: hide "appears in" when an asset is not in any albums

fix: way more bottom padding

for some reason we can't query the safe area here :/

* fix: bottom sheet now is usable when navigating to another asset viewer

* fix: rebase conflict

* fix: restore ancestors album to currentRemoteAlbumProvider when popping

* fix: view flashing when dismissing a album viewer

* chore: code review changes

* fix: styling and padding

* chore: rework currentRemoteAlbumProvider to be scoped by the Remote album page

* fix: override remote album provider on required pages

* chore: convert query to all SQL calls instead of matching in Dart

* fix: album query

* fix: unawaited future

* Update deep_link.service.dart

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Brandon Wees
2025-10-28 11:52:01 -05:00
committed by GitHub
parent 74f2c10a5a
commit e0c2cdddd4
19 changed files with 401 additions and 212 deletions

View File

@@ -1,4 +1,5 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/services/local_album.service.dart';
@@ -40,3 +41,7 @@ final remoteAlbumProvider = NotifierProvider<RemoteAlbumNotifier, RemoteAlbumSta
RemoteAlbumNotifier.new,
dependencies: [remoteAlbumServiceProvider],
);
final albumsContainingAssetProvider = FutureProvider.family<List<RemoteAlbum>, String>(
(ref, assetId) => ref.watch(remoteAlbumServiceProvider).getAlbumsContainingAsset(assetId),
);

View File

@@ -1,36 +1,30 @@
import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
final currentRemoteAlbumProvider = AutoDisposeNotifierProvider<CurrentAlbumNotifier, RemoteAlbum?>(
final currentRemoteAlbumScopedProvider = Provider<RemoteAlbum?>((ref) => null);
final currentRemoteAlbumProvider = NotifierProvider<CurrentAlbumNotifier, RemoteAlbum?>(
CurrentAlbumNotifier.new,
dependencies: [currentRemoteAlbumScopedProvider, remoteAlbumServiceProvider],
);
class CurrentAlbumNotifier extends AutoDisposeNotifier<RemoteAlbum?> {
KeepAliveLink? _keepAliveLink;
StreamSubscription<RemoteAlbum?>? _assetSubscription;
class CurrentAlbumNotifier extends Notifier<RemoteAlbum?> {
@override
RemoteAlbum? build() => null;
RemoteAlbum? build() {
final album = ref.watch(currentRemoteAlbumScopedProvider);
void setAlbum(RemoteAlbum album) {
_keepAliveLink?.close();
_assetSubscription?.cancel();
state = album;
if (album == null) {
return null;
}
_assetSubscription = ref.watch(remoteAlbumServiceProvider).watchAlbum(album.id).listen((updatedAlbum) {
final watcher = ref.watch(remoteAlbumServiceProvider).watchAlbum(album.id).listen((updatedAlbum) {
if (updatedAlbum != null) {
state = updatedAlbum;
}
});
_keepAliveLink = ref.keepAlive();
}
void dispose() {
_keepAliveLink?.close();
_assetSubscription?.cancel();
state = null;
ref.onDispose(watcher.cancel);
return album;
}
}