fix(stations): replace the ringed circle thumbnail with a plain square
The prototype's station thumbnail is a plain 44-48px square, radius 11/12, with no ring or glow (t4 lines 84, 175, 227, 302, 614). TarjetaEmisora's compact row variant instead painted a 58x58 circle wrapped in a SweepGradient ring (magenta/cyan/coral) and a 22-blur glow behind a 50x50 ClipRRect(18). Replace it with a 48x48 ClipRRect(12) square. Update the loading shimmer placeholder to match (was also a 58x58 circle block). S6, Tier 1 visual-fidelity pass (audit id 2521).
This commit is contained in:
@@ -8,7 +8,6 @@ import '../l10n/display_names.dart';
|
|||||||
import '../l10n/gen/app_localizations.dart';
|
import '../l10n/gen/app_localizations.dart';
|
||||||
import '../modelos/emisora.dart';
|
import '../modelos/emisora.dart';
|
||||||
import '../tema/pluriwave_theme.dart';
|
import '../tema/pluriwave_theme.dart';
|
||||||
import '../tema/pluriwave_tokens.dart';
|
|
||||||
import 'pluri_glass_surface.dart';
|
import 'pluri_glass_surface.dart';
|
||||||
import 'pluri_icon.dart';
|
import 'pluri_icon.dart';
|
||||||
|
|
||||||
@@ -183,35 +182,13 @@ class _TarjetaEmisoraState extends State<TarjetaEmisora> {
|
|||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Stack(
|
// S6 (Tier 1 visual fidelity): the prototype's station thumbnail
|
||||||
alignment: Alignment.center,
|
// is a plain square, radius 11/12, with NO ring or glow (t4 lines
|
||||||
children: [
|
// 84, 175, 227, 302, 614) — was a 58x58 circle wrapped in a
|
||||||
Container(
|
// SweepGradient ring and a 22-blur glow.
|
||||||
width: 58,
|
ClipRRect(
|
||||||
height: 58,
|
borderRadius: BorderRadius.circular(12),
|
||||||
decoration: BoxDecoration(
|
child: SizedBox(width: 48, height: 48, child: _logo(22)),
|
||||||
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)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
SizedBox(width: t.spacingSm),
|
SizedBox(width: t.spacingSm),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -454,7 +431,9 @@ class TarjetaEmisoraShimmer extends StatelessWidget {
|
|||||||
esCompacta
|
esCompacta
|
||||||
? Row(
|
? Row(
|
||||||
children: [
|
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),
|
const SizedBox(width: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -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<EstadoRadio>.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<Container>(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',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user