diff --git a/lib/widgets/cached_cover_image.dart b/lib/widgets/cached_cover_image.dart index 37427e15..19992976 100644 --- a/lib/widgets/cached_cover_image.dart +++ b/lib/widgets/cached_cover_image.dart @@ -41,10 +41,38 @@ class CachedCoverImage extends StatelessWidget { @override Widget build(BuildContext context) { - final autoMemCacheWidth = + if (width != null || + height != null || + memCacheWidth != null || + memCacheHeight != null) { + return _buildImage(context, const BoxConstraints()); + } + // Grid cells size their children through constraints rather than explicit + // width/height. Use those bounds for decoding as well as explicit sizes. + return LayoutBuilder( + builder: (context, constraints) => _buildImage(context, constraints), + ); + } + + Widget _buildImage(BuildContext context, BoxConstraints constraints) { + var autoMemCacheWidth = memCacheWidth ?? _cacheExtentForLogicalSize(context, width); - final autoMemCacheHeight = + var autoMemCacheHeight = memCacheHeight ?? _cacheExtentForLogicalSize(context, height); + if (autoMemCacheWidth == null && autoMemCacheHeight == null) { + // Infer one axis to preserve the source aspect ratio and respect any + // explicit decode override used by large artwork/header consumers. + autoMemCacheWidth = _cacheExtentForLogicalSize( + context, + constraints.maxWidth, + ); + if (autoMemCacheWidth == null) { + autoMemCacheHeight = _cacheExtentForLogicalSize( + context, + constraints.maxHeight, + ); + } + } final diskCacheWidth = resizeDiskCache ? autoMemCacheWidth : null; final diskCacheHeight = resizeDiskCache ? autoMemCacheHeight : null; final image = CachedNetworkImage( diff --git a/test/cached_cover_decode_test.dart b/test/cached_cover_decode_test.dart new file mode 100644 index 00000000..a0f883b4 --- /dev/null +++ b/test/cached_cover_decode_test.dart @@ -0,0 +1,43 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:spotiflac_android/widgets/cached_cover_image.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + for (final explicit in [false, true]) { + testWidgets( + 'grid decode follows constraints, explicit override=$explicit', + (tester) async { + await tester.pumpWidget( + MaterialApp( + home: MediaQuery( + data: const MediaQueryData(devicePixelRatio: 2), + child: Center( + child: SizedBox.square( + dimension: 180, + child: CachedCoverImage( + imageUrl: 'https://example.invalid/cover.png', + memCacheWidth: explicit ? 1200 : null, + errorWidget: (_, _, _) => const SizedBox(), + ), + ), + ), + ), + ), + ); + final image = tester.widget( + find.byType(CachedNetworkImage), + ); + expect(image.memCacheWidth, explicit ? 1200 : 360); + expect(image.memCacheHeight, isNull); + expect(image.maxWidthDiskCache, isNull); + expect( + tester.getSize(find.byType(CachedCoverImage)), + const Size(180, 180), + ); + await tester.pumpWidget(const SizedBox()); + }, + ); + } +}