Compare commits

...

1 Commits

Author SHA1 Message Date
shenlong-tanwen
19c9f932ea fix: handle missing assets gracefully 2025-07-23 19:40:23 +05:30
4 changed files with 23 additions and 17 deletions

View File

@@ -10,6 +10,7 @@ import 'package:immich_mobile/domain/services/setting.service.dart';
import 'package:immich_mobile/domain/utils/event_stream.dart';
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
import 'package:immich_mobile/utils/async_mutex.dart';
import 'package:logging/logging.dart';
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
int index,
@@ -77,6 +78,7 @@ class TimelineService {
int _bufferOffset = 0;
List<BaseAsset> _buffer = [];
StreamSubscription? _bucketSubscription;
final _log = Logger('TimelineService');
int _totalAssets = 0;
int get totalAssets => _totalAssets;
@@ -128,10 +130,10 @@ class TimelineService {
Stream<List<Bucket>> Function() get watchBuckets => _bucketSource;
Future<List<BaseAsset>> loadAssets(int index, int count) =>
Future<List<BaseAsset>?> loadAssets(int index, int count) =>
_mutex.run(() => _loadAssets(index, count));
Future<List<BaseAsset>> _loadAssets(int index, int count) async {
Future<List<BaseAsset>?> _loadAssets(int index, int count) async {
if (hasRange(index, count)) {
return getAssets(index, count);
}
@@ -169,9 +171,10 @@ class TimelineService {
index + count <= _bufferOffset + _buffer.length &&
index + count <= _totalAssets;
List<BaseAsset> getAssets(int index, int count) {
List<BaseAsset>? getAssets(int index, int count) {
if (!hasRange(index, count)) {
throw RangeError('TimelineService::getAssets Index out of range');
_log.warning('TimelineService::getAssets Index out of range');
return null;
}
int start = index - _bufferOffset;
return _buffer.slice(start, start + count);

View File

@@ -107,19 +107,22 @@ class _FixedSegmentRow extends ConsumerWidget {
}
if (timelineService.hasRange(assetIndex, assetCount)) {
return _buildAssetRow(
context,
timelineService.getAssets(assetIndex, assetCount),
);
final assets = timelineService.getAssets(assetIndex, assetCount);
if (assets == null) {
return _buildPlaceholder(context);
}
return _buildAssetRow(context, assets);
}
return FutureBuilder<List<BaseAsset>>(
return FutureBuilder<List<BaseAsset>?>(
future: timelineService.loadAssets(assetIndex, assetCount),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
if (snapshot.connectionState != ConnectionState.done ||
snapshot.data == null) {
return _buildPlaceholder(context);
}
return _buildAssetRow(context, snapshot.requireData);
return _buildAssetRow(context, snapshot.data!);
},
);
}

View File

@@ -112,8 +112,9 @@ class _BulkSelectIconButton extends ConsumerWidget {
List<BaseAsset> bucketAssets;
try {
bucketAssets = ref
.watch(timelineServiceProvider)
.getAssets(assetOffset, bucket.assetCount);
.watch(timelineServiceProvider)
.getAssets(assetOffset, bucket.assetCount) ??
[];
} catch (e) {
bucketAssets = <BaseAsset>[];
}

View File

@@ -1,6 +1,5 @@
import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
@@ -130,7 +129,7 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
final assets = await _timelineService.loadAssets(offset, bucketCount);
final selectedAssets = state.selectedAssets.toSet();
selectedAssets.addAll(assets);
selectedAssets.addAll(assets ?? []);
state = state.copyWith(
selectedAssets: selectedAssets,
@@ -141,14 +140,14 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
final assets = await _timelineService.loadAssets(offset, bucketCount);
final selectedAssets = state.selectedAssets.toSet();
selectedAssets.removeAll(assets);
selectedAssets.removeAll(assets ?? []);
state = state.copyWith(selectedAssets: selectedAssets);
}
void toggleBucketSelection(int offset, int bucketCount) async {
final assets = await _timelineService.loadAssets(offset, bucketCount);
toggleBucketSelectionByAssets(assets);
toggleBucketSelectionByAssets(assets ?? []);
}
void toggleBucketSelectionByAssets(List<BaseAsset> bucketAssets) {