diff --git a/lib/widgets/tarjeta_emisora.dart b/lib/widgets/tarjeta_emisora.dart index 9e26236..40af058 100644 --- a/lib/widgets/tarjeta_emisora.dart +++ b/lib/widgets/tarjeta_emisora.dart @@ -8,7 +8,6 @@ import '../l10n/display_names.dart'; import '../l10n/gen/app_localizations.dart'; import '../modelos/emisora.dart'; import '../tema/pluriwave_theme.dart'; -import '../tema/pluriwave_tokens.dart'; import 'pluri_glass_surface.dart'; import 'pluri_icon.dart'; @@ -183,35 +182,13 @@ class _TarjetaEmisoraState extends State { ), child: Row( children: [ - Stack( - alignment: Alignment.center, - children: [ - Container( - width: 58, - height: 58, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: SweepGradient( - colors: [ - t.electricMagenta, - PluriWaveTokens.brightCyan, - t.warmCoral, - t.electricMagenta, - ], - ), - boxShadow: [ - BoxShadow( - color: t.glowColor.withValues(alpha: 0.24), - blurRadius: 22, - ), - ], - ), - ), - ClipRRect( - borderRadius: BorderRadius.circular(18), - child: SizedBox(width: 50, height: 50, child: _logo(24)), - ), - ], + // S6 (Tier 1 visual fidelity): the prototype's station thumbnail + // is a plain square, radius 11/12, with NO ring or glow (t4 lines + // 84, 175, 227, 302, 614) — was a 58x58 circle wrapped in a + // SweepGradient ring and a 22-blur glow. + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: SizedBox(width: 48, height: 48, child: _logo(22)), ), SizedBox(width: t.spacingSm), Expanded( @@ -454,7 +431,9 @@ class TarjetaEmisoraShimmer extends StatelessWidget { esCompacta ? Row( children: [ - bloque(width: 58, height: 58, shape: BoxShape.circle), + // S6: matches the real square thumbnail (48x48, radius 12) + // — was a 58x58 circle block. + bloque(width: 48, height: 48, radius: 12), const SizedBox(width: 10), Expanded( child: Column( diff --git a/test/widgets/tarjeta_emisora_thumbnail_test.dart b/test/widgets/tarjeta_emisora_thumbnail_test.dart new file mode 100644 index 0000000..34eda32 --- /dev/null +++ b/test/widgets/tarjeta_emisora_thumbnail_test.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pluriwave/estado/estado_radio.dart'; +import 'package:pluriwave/l10n/gen/app_localizations.dart'; +import 'package:pluriwave/widgets/tarjeta_emisora.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../helpers/fakes.dart'; + +/// S6 (Tier 1 visual fidelity): the prototype's station thumbnail is a +/// plain 44-48px square, radius 11/12, with NO ring or glow (t4 lines 84 +/// `44px/radius 11`, 175 `46px/radius 12`, 227 `48px/radius 12`, 302 +/// `48px/radius 12`, 614 `44px/radius 12`). The compact row variant used to +/// paint a 58x58 circle with a `SweepGradient` ring and a 22-blur glow +/// behind a 50x50 `ClipRRect(18)`. +void main() { + setUp(() { + SharedPreferences.setMockInitialValues({}); + }); + + Widget host(Widget child) { + final estado = EstadoRadio( + audio: FakeServicioAudio(), + favoritos: FakeServicioFavoritos(), + radio: FakeServicioRadio(), + servicioEcualizador: FakeServicioEcualizador(), + iniciarAutomaticamente: false, + ); + addTearDown(estado.dispose); + return ChangeNotifierProvider.value( + value: estado, + child: MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold(body: Center(child: child)), + ), + ); + } + + bool isRingContainer(Widget w) => + w is Container && + w.decoration is BoxDecoration && + (w.decoration as BoxDecoration).shape == BoxShape.circle && + (w.decoration as BoxDecoration).gradient is SweepGradient; + + testWidgets('esCompacta (row) thumbnail is a 48x48 square, radius 12, no ' + 'ring/glow', (tester) async { + await tester.pumpWidget( + host( + SizedBox( + width: 320, + child: TarjetaEmisora( + emisora: emisoraDemo(uuid: 'row', nombre: 'Row FM'), + esCompacta: true, + ), + ), + ), + ); + await tester.pump(); + + expect(find.byWidgetPredicate(isRingContainer), findsNothing); + + // Not `.first` — the outer PluriGlassSurface also renders its own + // ClipRRect (radius 14, the row surface radius from S4), so the + // thumbnail's own clip must be found by its distinct radius instead of + // tree order. + final thumbnailClip = find.byWidgetPredicate( + (w) => w is ClipRRect && w.borderRadius == BorderRadius.circular(12), + ); + expect(thumbnailClip, findsOneWidget); + expect(tester.getSize(thumbnailClip), const Size(48, 48)); + }); + + testWidgets('esCompacta shimmer placeholder is a square block, not a ' + 'circle', (tester) async { + await tester.pumpWidget( + host(const TarjetaEmisoraShimmer(esCompacta: true)), + ); + await tester.pump(); + + expect(find.byWidgetPredicate(isRingContainer), findsNothing); + final circles = tester + .widgetList(find.byType(Container)) + .where( + (c) => + c.decoration is BoxDecoration && + (c.decoration as BoxDecoration).shape == BoxShape.circle, + ); + expect( + circles, + isEmpty, + reason: 'the real thumbnail is square now — its shimmer must match', + ); + }); +}