mirror of
https://github.com/immich-app/immich.git
synced 2025-07-31 15:08:44 -04:00
fix: mobile storage status check (#19986)
* fix: _shouldUseLocalAsset check * show storage indicators in local album view * update local thumb provider to work with remote asset * update checks * do not show upload button when selection is only merged assets --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
parent
03ff425664
commit
2046dcc5b4
@ -165,15 +165,25 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
_db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(
|
||||
_db.remoteAssetEntity,
|
||||
_db.localAssetEntity.checksum
|
||||
.equalsExp(_db.remoteAssetEntity.checksum),
|
||||
useColumns: false,
|
||||
),
|
||||
],
|
||||
)
|
||||
..addColumns([_db.remoteAssetEntity.id])
|
||||
..where(_db.localAlbumAssetEntity.albumId.equals(albumId))
|
||||
..orderBy([OrderingTerm.desc(_db.localAssetEntity.createdAt)])
|
||||
..limit(count, offset: offset);
|
||||
|
||||
return query
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto())
|
||||
.get();
|
||||
return query.map((row) {
|
||||
final asset = row.readTable(_db.localAssetEntity).toDto();
|
||||
return asset.copyWith(
|
||||
remoteId: row.read(_db.remoteAssetEntity.id),
|
||||
);
|
||||
}).get();
|
||||
}
|
||||
|
||||
TimelineQuery remoteAlbum(String albumId, GroupAssetsBy groupBy) => (
|
||||
|
@ -30,6 +30,7 @@ class LocalTimelinePage extends StatelessWidget {
|
||||
child: Timeline(
|
||||
appBar: MesmerizingSliverAppBar(title: album.name),
|
||||
bottomSheet: const LocalAlbumBottomSheet(),
|
||||
showStorageIndicator: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class _SheetLocationDetailsState extends ConsumerState<SheetLocationDetails> {
|
||||
|
||||
// Guard no lat/lng
|
||||
if (!hasCoordinates ||
|
||||
(asset is LocalAsset && !(asset as LocalAsset).hasRemote)) {
|
||||
(asset != null && asset is LocalAsset && asset!.hasRemote)) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,13 @@ ImageProvider getFullImageProvider(
|
||||
// Create new provider and cache it
|
||||
final ImageProvider provider;
|
||||
if (_shouldUseLocalAsset(asset)) {
|
||||
provider = LocalFullImageProvider(asset: asset as LocalAsset, size: size);
|
||||
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).localId!;
|
||||
provider = LocalFullImageProvider(
|
||||
id: id,
|
||||
name: asset.name,
|
||||
size: size,
|
||||
type: asset.type,
|
||||
);
|
||||
} else {
|
||||
final String assetId;
|
||||
if (asset is LocalAsset && asset.hasRemote) {
|
||||
@ -43,7 +49,13 @@ ImageProvider getThumbnailImageProvider({
|
||||
}
|
||||
|
||||
if (_shouldUseLocalAsset(asset!)) {
|
||||
return LocalThumbProvider(asset: asset as LocalAsset, size: size);
|
||||
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).localId!;
|
||||
return LocalThumbProvider(
|
||||
id: id,
|
||||
updatedAt: asset.updatedAt,
|
||||
name: asset.name,
|
||||
size: size,
|
||||
);
|
||||
}
|
||||
|
||||
final String assetId;
|
||||
@ -59,5 +71,5 @@ ImageProvider getThumbnailImageProvider({
|
||||
}
|
||||
|
||||
bool _shouldUseLocalAsset(BaseAsset asset) =>
|
||||
asset is LocalAsset &&
|
||||
asset.hasLocal &&
|
||||
(!asset.hasRemote || !AppSetting.get(Setting.preferRemoteImage));
|
||||
|
@ -21,11 +21,15 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
|
||||
const AssetMediaRepository();
|
||||
final CacheManager? cacheManager;
|
||||
|
||||
final LocalAsset asset;
|
||||
final String id;
|
||||
final DateTime updatedAt;
|
||||
final String name;
|
||||
final Size size;
|
||||
|
||||
const LocalThumbProvider({
|
||||
required this.asset,
|
||||
required this.id,
|
||||
required this.updatedAt,
|
||||
required this.name,
|
||||
this.size = const Size.square(kTimelineFixedTileExtent),
|
||||
this.cacheManager,
|
||||
});
|
||||
@ -46,7 +50,10 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
|
||||
scale: 1.0,
|
||||
informationCollector: () => <DiagnosticsNode>[
|
||||
DiagnosticsProperty<ImageProvider>('Image provider', this),
|
||||
DiagnosticsProperty<LocalAsset>('Asset', key.asset),
|
||||
DiagnosticsProperty<String>('Id', key.id),
|
||||
DiagnosticsProperty<DateTime>('Updated at', key.updatedAt),
|
||||
DiagnosticsProperty<String>('Name', key.name),
|
||||
DiagnosticsProperty<Size>('Size', key.size),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -57,7 +64,7 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
|
||||
ImageDecoderCallback decode,
|
||||
) async {
|
||||
final cacheKey =
|
||||
'${key.asset.id}-${key.asset.updatedAt}-${key.size.width}x${key.size.height}';
|
||||
'${key.id}-${key.updatedAt}-${key.size.width}x${key.size.height}';
|
||||
|
||||
final fileFromCache = await cache.getFileFromCache(cacheKey);
|
||||
if (fileFromCache != null) {
|
||||
@ -69,11 +76,11 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
|
||||
}
|
||||
|
||||
final thumbnailBytes =
|
||||
await _assetMediaRepository.getThumbnail(key.asset.id, size: key.size);
|
||||
await _assetMediaRepository.getThumbnail(key.id, size: key.size);
|
||||
if (thumbnailBytes == null) {
|
||||
PaintingBinding.instance.imageCache.evict(key);
|
||||
throw StateError(
|
||||
"Loading thumb for local photo ${key.asset.name} failed",
|
||||
"Loading thumb for local photo ${key.name} failed",
|
||||
);
|
||||
}
|
||||
|
||||
@ -86,14 +93,13 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is LocalThumbProvider) {
|
||||
return asset.id == other.asset.id &&
|
||||
asset.updatedAt == other.asset.updatedAt;
|
||||
return id == other.id && updatedAt == other.updatedAt;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => asset.id.hashCode ^ asset.updatedAt.hashCode;
|
||||
int get hashCode => id.hashCode ^ updatedAt.hashCode;
|
||||
}
|
||||
|
||||
class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
@ -101,12 +107,16 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
const AssetMediaRepository();
|
||||
final StorageRepository _storageRepository = const StorageRepository();
|
||||
|
||||
final LocalAsset asset;
|
||||
final String id;
|
||||
final String name;
|
||||
final Size size;
|
||||
final AssetType type;
|
||||
|
||||
const LocalFullImageProvider({
|
||||
required this.asset,
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.size,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -123,7 +133,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
codec: _codec(key, decode),
|
||||
scale: 1.0,
|
||||
informationCollector: () sync* {
|
||||
yield ErrorDescription(asset.name);
|
||||
yield ErrorDescription(name);
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -134,24 +144,24 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
ImageDecoderCallback decode,
|
||||
) async* {
|
||||
try {
|
||||
switch (key.asset.type) {
|
||||
switch (key.type) {
|
||||
case AssetType.image:
|
||||
yield* _decodeProgressive(key, decode);
|
||||
break;
|
||||
case AssetType.video:
|
||||
final codec = await _getThumbnailCodec(key, decode);
|
||||
if (codec == null) {
|
||||
throw StateError("Failed to load preview for ${key.asset.name}");
|
||||
throw StateError("Failed to load preview for ${key.name}");
|
||||
}
|
||||
yield codec;
|
||||
break;
|
||||
case AssetType.other:
|
||||
case AssetType.audio:
|
||||
throw StateError('Unsupported asset type ${key.asset.type}');
|
||||
throw StateError('Unsupported asset type ${key.type}');
|
||||
}
|
||||
} catch (error, stack) {
|
||||
Logger('ImmichLocalImageProvider')
|
||||
.severe('Error loading local image ${key.asset.name}', error, stack);
|
||||
.severe('Error loading local image ${key.name}', error, stack);
|
||||
throw const ImageLoadingException(
|
||||
'Could not load image from local storage',
|
||||
);
|
||||
@ -163,7 +173,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
ImageDecoderCallback decode,
|
||||
) async {
|
||||
final thumbBytes =
|
||||
await _assetMediaRepository.getThumbnail(key.asset.id, size: key.size);
|
||||
await _assetMediaRepository.getThumbnail(key.id, size: key.size);
|
||||
if (thumbBytes == null) {
|
||||
return null;
|
||||
}
|
||||
@ -175,9 +185,9 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
LocalFullImageProvider key,
|
||||
ImageDecoderCallback decode,
|
||||
) async* {
|
||||
final file = await _storageRepository.getFileForAsset(key.asset.id);
|
||||
final file = await _storageRepository.getFileForAsset(key.id);
|
||||
if (file == null) {
|
||||
throw StateError("Opening file for asset ${key.asset.name} failed");
|
||||
throw StateError("Opening file for asset ${key.name} failed");
|
||||
}
|
||||
|
||||
final fileSize = await file.length();
|
||||
@ -195,7 +205,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
(key.size.height * progressiveMultiplier).clamp(256, 1024),
|
||||
);
|
||||
final mediumThumb =
|
||||
await _assetMediaRepository.getThumbnail(key.asset.id, size: size);
|
||||
await _assetMediaRepository.getThumbnail(key.id, size: size);
|
||||
if (mediumThumb != null) {
|
||||
final mediumBuffer = await ImmutableBuffer.fromUint8List(mediumThumb);
|
||||
yield await decode(mediumBuffer);
|
||||
@ -212,7 +222,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
(key.size.height * progressiveMultiplier).clamp(512, 2048),
|
||||
);
|
||||
final highThumb =
|
||||
await _assetMediaRepository.getThumbnail(key.asset.id, size: size);
|
||||
await _assetMediaRepository.getThumbnail(key.id, size: size);
|
||||
if (highThumb != null) {
|
||||
final highBuffer = await ImmutableBuffer.fromUint8List(highThumb);
|
||||
yield await decode(highBuffer);
|
||||
@ -228,14 +238,15 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is LocalFullImageProvider) {
|
||||
return asset.id == other.asset.id &&
|
||||
asset.updatedAt == other.asset.updatedAt &&
|
||||
size == other.size;
|
||||
return id == other.id &&
|
||||
size == other.size &&
|
||||
type == other.type &&
|
||||
name == other.name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
asset.id.hashCode ^ asset.updatedAt.hashCode ^ size.hashCode;
|
||||
id.hashCode ^ size.hashCode ^ type.hashCode ^ name.hashCode;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user