fix: downsample local artwork in offline grids
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -408,10 +407,12 @@ class _EpisodeCardState extends State<EpisodeCard> {
|
||||
|
||||
Widget _buildEpisodeThumbnail() {
|
||||
if (widget.isOffline && widget.localPosterPath != null) {
|
||||
return Image.file(
|
||||
File(widget.localPosterPath!),
|
||||
return PlexOptimizedImage.thumb(
|
||||
client: null,
|
||||
imagePath: null,
|
||||
localFilePath: widget.localPosterPath,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) =>
|
||||
errorWidget: (context, url, error) =>
|
||||
const PlaceholderContainer(child: AppIcon(Symbols.movie_rounded, fill: 1, size: 32)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -261,32 +261,21 @@ class PlexOptimizedImage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Check for local file first
|
||||
if (localFilePath != null) {
|
||||
final file = File(localFilePath!);
|
||||
if (file.existsSync()) {
|
||||
return blurArtwork(
|
||||
Image.file(
|
||||
file,
|
||||
width: width,
|
||||
height: height,
|
||||
fit: fit,
|
||||
filterQuality: filterQuality,
|
||||
alignment: alignment,
|
||||
errorBuilder: (context, error, stackTrace) => _buildErrorWidget(context, error),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
final localFile = localFilePath != null ? File(localFilePath!) : null;
|
||||
final hasLocal = localFile != null && localFile.existsSync();
|
||||
|
||||
// Return empty container if no image path
|
||||
if (imagePath == null || imagePath!.isEmpty) {
|
||||
// No local file and no network path → fallback
|
||||
if (!hasLocal && (imagePath == null || imagePath!.isEmpty)) {
|
||||
return _buildFallback(context);
|
||||
}
|
||||
|
||||
// Fast path: skip LayoutBuilder when both dimensions are explicitly known
|
||||
if (_hasKnownDimensions) {
|
||||
return blurArtwork(_buildCachedImage(context, width!, height!));
|
||||
return blurArtwork(
|
||||
hasLocal
|
||||
? _buildLocalFileImage(context, localFile, width!, height!)
|
||||
: _buildCachedImage(context, width!, height!),
|
||||
);
|
||||
}
|
||||
|
||||
return blurArtwork(
|
||||
@@ -294,12 +283,49 @@ class PlexOptimizedImage extends StatelessWidget {
|
||||
builder: (context, constraints) {
|
||||
final effectiveWidth = _resolvedDimension(width, constraints.maxWidth, 300.0);
|
||||
final effectiveHeight = _resolvedDimension(height, constraints.maxHeight, 450.0);
|
||||
return _buildCachedImage(context, effectiveWidth, effectiveHeight);
|
||||
return hasLocal
|
||||
? _buildLocalFileImage(context, localFile, effectiveWidth, effectiveHeight)
|
||||
: _buildCachedImage(context, effectiveWidth, effectiveHeight);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLocalFileImage(
|
||||
BuildContext context,
|
||||
File file,
|
||||
double effectiveWidth,
|
||||
double effectiveHeight,
|
||||
) {
|
||||
final dpr = PlexImageHelper.effectiveDevicePixelRatio(context);
|
||||
final scaledWidth = effectiveWidth * dpr;
|
||||
final scaledHeight = effectiveHeight * dpr;
|
||||
final (_, memHeight) = PlexImageHelper.getMemCacheDimensions(
|
||||
displayWidth: scaledWidth.isFinite && scaledWidth > 0 ? scaledWidth.round() : 0,
|
||||
displayHeight: scaledHeight.isFinite && scaledHeight > 0 ? scaledHeight.round() : 0,
|
||||
imageType: imageType,
|
||||
);
|
||||
|
||||
return Image.file(
|
||||
file,
|
||||
width: width,
|
||||
height: height,
|
||||
// Only cacheHeight: leaving cacheWidth null preserves decode aspect
|
||||
// ratio, mirroring the network branch which only passes maxHeight to
|
||||
// CachedNetworkImageProvider.
|
||||
cacheHeight: memHeight > 0 ? memHeight : null,
|
||||
fit: fit,
|
||||
filterQuality: filterQuality,
|
||||
alignment: alignment,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
if (errorWidget != null) {
|
||||
return errorWidget!(context, file.path, error);
|
||||
}
|
||||
return _buildErrorWidget(context, error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static double _resolvedDimension(double? explicit, double constraintMax, double fallback) {
|
||||
// Pick the explicit size when it's a finite positive number, otherwise
|
||||
// fall back to the constraint or a sensible default so we don't end up
|
||||
|
||||
Reference in New Issue
Block a user