1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 15:11:58 +00:00

higher res placeholder for local videos

This commit is contained in:
mertalev 2024-11-08 21:19:12 -05:00
parent 5766551447
commit 64e23a3b5c
No known key found for this signature in database
GPG key ID: CA85EF6600C9E8AD
5 changed files with 75 additions and 37 deletions

View file

@ -100,7 +100,11 @@ class GalleryViewerPage extends HookConsumerWidget {
if (index < totalAssets.value && index >= 0) {
final asset = loadAsset(index);
await precacheImage(
ImmichImage.imageProvider(asset: asset),
ImmichImage.imageProvider(
asset: asset,
width: context.width,
height: context.height,
),
context,
onError: onError,
);
@ -313,7 +317,11 @@ class GalleryViewerPage extends HookConsumerWidget {
asset: asset,
placeholder: Image(
key: ValueKey(asset),
image: ImmichImage.imageProvider(asset: asset),
image: ImmichImage.imageProvider(
asset: asset,
width: context.width,
height: context.height,
),
fit: BoxFit.contain,
height: context.height,
width: context.width,
@ -396,12 +404,7 @@ class GalleryViewerPage extends HookConsumerWidget {
stackIndex.value = -1;
isPlayingMotionVideo.value = false;
// Delay setting the new asset to avoid a stutter in the page change animation
// TODO: make the scroll animation finish more quickly, and ideally have a callback for when it's done
ref.read(currentAssetProvider.notifier).set(newAsset);
// Timer(const Duration(milliseconds: 450), () {
// ref.read(currentAssetProvider.notifier).set(newAsset);
// });
// Wait for page change animation to finish, then precache the next image
Timer(const Duration(milliseconds: 400), () {

View file

@ -113,11 +113,15 @@ class MemoryPage extends HookConsumerWidget {
}
// Precache the asset
final size = MediaQuery.sizeOf(context);
await precacheImage(
ImmichImage.imageProvider(
asset: asset,
width: size.width,
height: size.height,
),
context,
size: size,
);
}

View file

@ -7,14 +7,21 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:logging/logging.dart';
import 'package:photo_manager/photo_manager.dart' show ThumbnailSize;
/// The local image provider for an asset
class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> {
final Asset asset;
// only used for videos
final double width;
final double height;
final Logger log = Logger('ImmichLocalImageProvider');
ImmichLocalImageProvider({
required this.asset,
required this.width,
required this.height,
}) : assert(asset.local != null, 'Only usable when asset.local is set');
/// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key
@ -42,38 +49,57 @@ class ImmichLocalImageProvider extends ImageProvider<ImmichLocalImageProvider> {
// Streams in each stage of the image as we ask for it
Stream<ui.Codec> _codec(
Asset key,
Asset asset,
ImageDecoderCallback decode,
StreamController<ImageChunkEvent> chunkEvents,
) async* {
// Load a small thumbnail
final thumbBytes = await asset.local?.thumbnailDataWithSize(
const ThumbnailSize.square(256),
quality: 80,
);
if (thumbBytes != null) {
final buffer = await ui.ImmutableBuffer.fromUint8List(thumbBytes);
final codec = await decode(buffer);
yield codec;
} else {
debugPrint("Loading thumb for ${asset.fileName} failed");
}
if (asset.isImage) {
final File? file = await asset.local?.originFile;
if (file == null) {
throw StateError("Opening file for asset ${asset.fileName} failed");
ui.ImmutableBuffer? buffer;
try {
final local = asset.local;
if (local == null) {
throw StateError('Asset ${asset.fileName} has no local data');
}
try {
final buffer = await ui.ImmutableBuffer.fromFilePath(file.path);
final codec = await decode(buffer);
yield codec;
} catch (error) {
throw StateError("Loading asset ${asset.fileName} failed");
}
}
chunkEvents.close();
var thumbBytes = await local
.thumbnailDataWithSize(const ThumbnailSize.square(256), quality: 80);
if (thumbBytes == null) {
throw StateError("Loading thumbnail for ${asset.fileName} failed");
}
buffer = await ui.ImmutableBuffer.fromUint8List(thumbBytes);
thumbBytes = null;
yield await decode(buffer);
buffer = null;
switch (asset.type) {
case AssetType.image:
final File? file = await local.originFile;
if (file == null) {
throw StateError("Opening file for asset ${asset.fileName} failed");
}
buffer = await ui.ImmutableBuffer.fromFilePath(file.path);
yield await decode(buffer);
buffer = null;
break;
case AssetType.video:
final size = ThumbnailSize(width.ceil(), height.ceil());
thumbBytes = await local.thumbnailDataWithSize(size);
if (thumbBytes == null) {
throw StateError("Failed to load preview for ${asset.fileName}");
}
buffer = await ui.ImmutableBuffer.fromUint8List(thumbBytes);
thumbBytes = null;
yield await decode(buffer);
buffer = null;
break;
default:
throw StateError('Unsupported asset type ${asset.type}');
}
} catch (error, stack) {
log.severe('Error loading local image ${asset.fileName}', error, stack);
buffer?.dispose();
} finally {
chunkEvents.close();
}
}
@override

View file

@ -28,12 +28,11 @@ class ImmichImage extends StatelessWidget {
// either by using the asset ID or the asset itself
/// [asset] is the Asset to request, or else use [assetId] to get a remote
/// image provider
/// Use [isThumbnail] and [thumbnailSize] if you'd like to request a thumbnail
/// The size of the square thumbnail to request. Ignored if isThumbnail
/// is not true
static ImageProvider imageProvider({
Asset? asset,
String? assetId,
double width = 1080,
double height = 1920,
}) {
if (asset == null && assetId == null) {
throw Exception('Must supply either asset or assetId');
@ -48,6 +47,8 @@ class ImmichImage extends StatelessWidget {
if (useLocal(asset)) {
return ImmichLocalImageProvider(
asset: asset,
width: width,
height: height,
);
} else {
return ImmichRemoteImageProvider(
@ -87,6 +88,8 @@ class ImmichImage extends StatelessWidget {
},
image: ImmichImage.imageProvider(
asset: asset,
width: context.width,
height: context.height,
),
width: width,
height: height,

View file

@ -136,6 +136,8 @@ class _BlurredBackdrop extends HookWidget {
image: DecorationImage(
image: ImmichImage.imageProvider(
asset: asset,
height: context.height,
width: context.width,
),
fit: BoxFit.cover,
),