diff --git a/lib/utils/media_image_helper.dart b/lib/utils/media_image_helper.dart index 8ab5b731..b430d4da 100644 --- a/lib/utils/media_image_helper.dart +++ b/lib/utils/media_image_helper.dart @@ -19,8 +19,8 @@ enum ImageType { thumb, // 16:9 episode thumbnails logo, // Variable ratio clear logos heroLogo, // Large hero clear logos - avatar, // Square-ish user avatars - square, // 1:1 music artwork (albums, artists, tracks) + avatar, // Small square-ish avatars (user profiles, inline person headers) + square, // 1:1 grid-cell artwork (albums, artists, tracks, cast cards) } /// Backend-neutral image URL helper. diff --git a/lib/widgets/cast_member_strip.dart b/lib/widgets/cast_member_strip.dart index 1679f282..eb780e45 100644 --- a/lib/widgets/cast_member_strip.dart +++ b/lib/widgets/cast_member_strip.dart @@ -214,7 +214,7 @@ class CastMemberStripState extends State { width: imageSize, height: imageSize, fit: BoxFit.cover, - imageType: ImageType.avatar, + imageType: ImageType.square, fallbackIcon: Symbols.person_rounded, ), ), diff --git a/lib/widgets/tv_browse_rail.dart b/lib/widgets/tv_browse_rail.dart index fe5801cf..88cacf4e 100644 --- a/lib/widgets/tv_browse_rail.dart +++ b/lib/widgets/tv_browse_rail.dart @@ -1564,7 +1564,7 @@ class TvBrowseRailState extends State { width: cardWidth, height: imageSize, fit: BoxFit.cover, - imageType: ImageType.avatar, + imageType: ImageType.square, fallbackIcon: Symbols.person_rounded, ), RasterizedGradient( @@ -1631,7 +1631,7 @@ class TvBrowseRailState extends State { width: imageSize, height: imageSize, fit: BoxFit.cover, - imageType: ImageType.avatar, + imageType: ImageType.square, fallbackIcon: Symbols.person_rounded, ), ), diff --git a/test/utils/media_image_helper_test.dart b/test/utils/media_image_helper_test.dart index 4af84b23..bb18404b 100644 --- a/test/utils/media_image_helper_test.dart +++ b/test/utils/media_image_helper_test.dart @@ -158,6 +158,21 @@ void main() { ); }); + test('square keeps a grid-cell decode budget while avatar stays small', () { + DevicePerformance.debugReset(autoReduced: false, override: VisualEffectsSetting.auto); + + // Cast cards fill poster-width grid cells (issue #1591): a retina cell + // needs well over the avatar cap, so they use the square budget. + expect( + MediaImageHelper.getMemCacheDimensions(displayWidth: 4000, displayHeight: 4000, imageType: ImageType.square), + (720, 720), + ); + expect( + MediaImageHelper.getMemCacheDimensions(displayWidth: 4000, displayHeight: 4000, imageType: ImageType.avatar), + (300, 300), + ); + }); + test('card artwork follows square, wide, and poster media shapes', () { for (final kind in [MediaKind.artist, MediaKind.album, MediaKind.track]) { expect( diff --git a/test/widgets/cast_member_strip_test.dart b/test/widgets/cast_member_strip_test.dart index 6734218b..927fb2b4 100644 --- a/test/widgets/cast_member_strip_test.dart +++ b/test/widgets/cast_member_strip_test.dart @@ -3,8 +3,10 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:plezy/services/settings_service.dart'; import 'package:plezy/theme/mono_theme.dart'; +import 'package:plezy/utils/media_image_helper.dart'; import 'package:plezy/utils/platform_detector.dart'; import 'package:plezy/widgets/cast_member_strip.dart'; +import 'package:plezy/widgets/optimized_media_image.dart'; import '../test_helpers/prefs.dart'; @@ -68,6 +70,23 @@ void main() { expect(navigatedDown, 1); }); + testWidgets('renders member images with the square grid-cell decode budget', (tester) async { + // Cast cards are poster-cell sized; the small avatar budget decodes them + // below retina resolution and blurs them (issue #1591). + await tester.pumpWidget( + MaterialApp( + theme: monoTheme(dark: true), + home: Scaffold(body: CastMemberStrip(members: _members)), + ), + ); + + final images = tester.widgetList(find.byType(OptimizedMediaImage)); + expect(images, hasLength(_members.length)); + for (final image in images) { + expect(image.imageType, ImageType.square); + } + }); + testWidgets('clamps its focus index when the member list changes', (tester) async { final key = GlobalKey(); var members = _members;