pr feedback

This commit is contained in:
Alex Tran
2026-05-12 21:49:55 -05:00
parent cbe85fac1b
commit e748524153
7 changed files with 127 additions and 26 deletions
@@ -12,15 +12,28 @@ class PendingAlbumUpload {
PendingAlbumUpload(asset: asset, progress: progress ?? this.progress, failed: failed ?? this.failed);
}
class AlbumPendingUploadsNotifier extends FamilyNotifier<List<PendingAlbumUpload>, String> {
class AlbumPendingUploadsNotifier extends AutoDisposeFamilyNotifier<List<PendingAlbumUpload>, String> {
KeepAliveLink? _keepAliveLink;
@override
List<PendingAlbumUpload> build(String albumId) => const [];
List<PendingAlbumUpload> build(String albumId) {
ref.onDispose(() {
_keepAliveLink?.close();
_keepAliveLink = null;
});
return const [];
}
void enqueue(Iterable<LocalAsset> assets) {
if (assets.isEmpty) return;
if (assets.isEmpty) {
return;
}
final existingIds = state.map((e) => e.asset.id).toSet();
final additions = assets.where((a) => !existingIds.contains(a.id)).map((a) => PendingAlbumUpload(asset: a));
state = [...state, ...additions];
_syncKeepAlive();
}
void updateProgress(String localAssetId, double progress) {
@@ -28,6 +41,7 @@ class AlbumPendingUploadsNotifier extends FamilyNotifier<List<PendingAlbumUpload
for (final entry in state)
if (entry.asset.id == localAssetId) entry.copyWith(progress: progress, failed: false) else entry,
];
_syncKeepAlive();
}
void markFailed(String localAssetId) {
@@ -35,18 +49,33 @@ class AlbumPendingUploadsNotifier extends FamilyNotifier<List<PendingAlbumUpload
for (final entry in state)
if (entry.asset.id == localAssetId) entry.copyWith(failed: true) else entry,
];
_syncKeepAlive();
}
void markAllFailed() {
state = [for (final entry in state) entry.copyWith(failed: true)];
_syncKeepAlive();
}
void remove(String localAssetId) {
state = state.where((e) => e.asset.id != localAssetId).toList();
_syncKeepAlive();
}
void clearFailed() {
state = state.where((e) => !e.failed).toList();
_syncKeepAlive();
}
void _syncKeepAlive() {
if (state.isEmpty) {
_keepAliveLink?.close();
_keepAliveLink = null;
} else {
_keepAliveLink ??= ref.keepAlive();
}
}
}
final pendingAlbumUploadsProvider =
NotifierProvider.family<AlbumPendingUploadsNotifier, List<PendingAlbumUpload>, String>(
AlbumPendingUploadsNotifier.new,
);
final pendingAlbumUploadsProvider = NotifierProvider.autoDispose
.family<AlbumPendingUploadsNotifier, List<PendingAlbumUpload>, String>(AlbumPendingUploadsNotifier.new);
@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
@@ -108,8 +110,8 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
}
/// Creates an album from a heterogeneous asset selection. Already-remote
/// assets seed the album immediately; local-only assets are uploaded and
/// linked one-by-one as each upload completes.
/// assets seed the album immediately; local-only assets are uploaded in the
/// background and linked one-by-one as each upload completes.
Future<RemoteAlbum?> createAlbumWithAssets({
required String title,
String? description,
@@ -122,20 +124,22 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
}
final candidates = RemoteAlbumService.categorizeCandidates(assets);
final album = await _remoteAlbumService.createAlbumWithAssets(
final album = await _remoteAlbumService.createAlbum(
title: title,
owner: currentUser,
description: description,
candidates: candidates,
assetIds: candidates.remoteAssetIds,
);
state = state.copyWith(albums: [...state.albums, album]);
// The createAlbum API returns the album with its initial asset count, but
// any local-only assets are uploaded and linked afterward — re-read to
// pick up the post-upload junction rows.
if (candidates.localAssetsToUpload.isNotEmpty) {
await _refreshAlbumInState(album.id);
unawaited(
addAssetsToAlbum(
album.id,
candidates.localAssetsToUpload,
).then<void>((_) {}).catchError((Object _, StackTrace _) {}),
);
}
return album;
@@ -236,6 +240,9 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
}
return added;
} catch (error, stack) {
if (candidates.localAssetsToUpload.isNotEmpty) {
pendingNotifier.markAllFailed();
}
_logger.severe('Failed to add assets to album $albumId', error, stack);
rethrow;
}
@@ -246,7 +253,10 @@ class RemoteAlbumNotifier extends Notifier<RemoteAlbumState> {
/// latest junction-table changes without a full `refresh()`.
Future<void> _refreshAlbumInState(String albumId) async {
final updated = await _remoteAlbumService.get(albumId);
if (updated == null) return;
if (updated == null) {
return;
}
state = state.copyWith(albums: state.albums.map((album) => album.id == albumId ? updated : album).toList());
}