2 Commits
Author SHA1 Message Date
FreeTLab cd77ec256e fix(escuchar): restore the prototype's 132px hero artwork
Audit 1.3: the hero art shipped at 84 where the prototype draws 132
(t4 line 56), with a 24 corner radius rather than the shared radiusMd.

Adds a dimension guard. Every existing test on this screen asserts
behaviour only, which is why an artwork 36% too small went unnoticed.
2026-07-29 23:04:40 +02:00
FreeTLab 615a5aac92 fix(eq): restore the prototype's band height and brand-teal fill
Audit 11.4 and 11.6: the band column was 152 instead of 280 (t4 line
581), leaving the sliders 46% short, and the fill read liveGreen -- the
LIVE badge colour -- instead of brand teal (t4 line 585).

Adds two guards. The existing tests only asserted the band COUNT, which
is exactly why both values could drift unnoticed.
2026-07-29 23:01:20 +02:00
4 changed files with 103 additions and 8 deletions
+5 -2
View File
@@ -307,12 +307,15 @@ class _ArteEscuchar extends StatelessWidget {
final Emisora emisora; final Emisora emisora;
static const _lado = 84.0; /// Audit 1.3: the prototype's Escuchar hero art is 132 (t4 line 56), and
/// its corner radius is 24 rather than the shared `radiusMd`.
static const _lado = 132.0;
static const _radio = 24.0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final radius = BorderRadius.circular(context.pluriTokens.radiusMd); final radius = BorderRadius.circular(_radio);
return PluriGlassSurface( return PluriGlassSurface(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
borderRadius: radius, borderRadius: radius,
+12 -6
View File
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import '../l10n/gen/app_localizations.dart'; import '../l10n/gen/app_localizations.dart';
import '../modelos/preset_ecualizador.dart'; import '../modelos/preset_ecualizador.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';
class EcualizadorWidget extends StatefulWidget { class EcualizadorWidget extends StatefulWidget {
@@ -87,7 +88,9 @@ class _EcualizadorWidgetState extends State<EcualizadorWidget> {
child: Column( child: Column(
children: [ children: [
SizedBox( SizedBox(
height: 152, // Audit 11.4: the prototype draws the band column at
// 280 (t4 line 581); 152 left the sliders 46% short.
height: 280,
child: Semantics( child: Semantics(
slider: true, slider: true,
enabled: widget.habilitado, enabled: widget.habilitado,
@@ -100,13 +103,16 @@ class _EcualizadorWidgetState extends State<EcualizadorWidget> {
child: SliderTheme( child: SliderTheme(
data: SliderTheme.of(context).copyWith( data: SliderTheme.of(context).copyWith(
trackHeight: 5, trackHeight: 5,
activeTrackColor: tokens.liveGreen, // Audit 11.6: the prototype's band fill is
thumbColor: tokens.liveGreen, // brand teal (t4 line 585). `liveGreen` is
// the LIVE badge colour and reading it here
// put the sliders in the wrong colour family.
activeTrackColor: PluriWaveTokens.brand,
thumbColor: PluriWaveTokens.brand,
inactiveTrackColor: inactiveTrackColor:
theme.colorScheme.surfaceContainerHighest, theme.colorScheme.surfaceContainerHighest,
overlayColor: tokens.liveGreen.withValues( overlayColor: PluriWaveTokens.brand
alpha: 0.15, .withValues(alpha: 0.15),
),
), ),
child: Slider( child: Slider(
value: _bandas[i], value: _bandas[i],
+42
View File
@@ -122,6 +122,48 @@ void main() {
reason: 'switches tabs — must NOT push a new route', reason: 'switches tabs — must NOT push a new route',
); );
}); });
testWidgets('visual fidelity (audit 1.3): the hero art is 132 square', (
tester,
) async {
// The redesign shipped this at 84 — the prototype draws 132 (t4 line
// 56). Nothing caught it because every existing test here asserts
// behaviour, never dimensions. This is the guard that would have.
_setLargeSurfaceSize(tester);
final favoritos = FakeServicioFavoritos();
final estado = EstadoRadio(
audio: FakeServicioAudio(),
favoritos: favoritos,
radio: FakeServicioRadio(),
servicioEcualizador: FakeServicioEcualizador(),
servicioGrabacion: FakeServicioGrabacionRadio(),
resolverArchivoCustom: _archivoCustomVacio,
iniciarAutomaticamente: false,
);
addTearDown(estado.dispose);
await tester.runAsync(estado.inicializar);
final sonando = emisoraDemo(uuid: 'f1', nombre: 'Favorita Uno');
await favoritos.agregar(sonando);
await estado.cargarFavoritos();
// The hero only renders when a station is active — `emisoraActual` is
// what gates it. Without this the assertion below passes vacuously.
await tester.runAsync(() => estado.reproducir(sonando));
await tester.pumpWidget(
_conProviders(estado, _testApp(const PantallaInicio())),
);
await _pumpBounded(tester);
final cuadrados = tester
.widgetList<SizedBox>(find.byType(SizedBox))
.where((s) => s.width == 132 && s.height == 132);
expect(
cuadrados,
isNotEmpty,
reason: 'prototype t4 line 56 sizes the Escuchar hero artwork at 132',
);
});
} }
/// Mirrors the app.dart wiring: EstadoRadio owns the domain notifiers and /// Mirrors the app.dart wiring: EstadoRadio owns the domain notifiers and
+44
View File
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pluriwave/l10n/gen/app_localizations.dart'; import 'package:pluriwave/l10n/gen/app_localizations.dart';
import 'package:pluriwave/modelos/preset_ecualizador.dart'; import 'package:pluriwave/modelos/preset_ecualizador.dart';
import 'package:pluriwave/tema/pluriwave_tokens.dart';
import 'package:pluriwave/widgets/ecualizador_widget.dart'; import 'package:pluriwave/widgets/ecualizador_widget.dart';
/// WU13 task 13.1 — first-class regression guard (design ADR-5, spec /// WU13 task 13.1 — first-class regression guard (design ADR-5, spec
@@ -92,4 +93,47 @@ void main() {
expect(slider.onChanged, isNotNull); expect(slider.onChanged, isNotNull);
} }
}); });
// Visual-fidelity guards (audit id 2521, items 11.4 and 11.6). These two
// values drifted silently once already: the whole point of the fidelity
// pass was that behavioural tests ("renders 5 sliders") never noticed the
// sliders were 46% too short and painted in the wrong colour family.
testWidgets('each band column is 280 tall, as the prototype draws it', (
tester,
) async {
await tester.pumpWidget(buildWidget());
final columnas = tester.widgetList<SizedBox>(
find.descendant(
of: find.byType(EcualizadorWidget),
matching: find.byType(SizedBox),
),
);
expect(
columnas.where((c) => c.height == 280),
hasLength(5),
reason:
'prototype t4 line 581 sizes the band column at 280; 152 left the '
'sliders 46% short',
);
});
testWidgets('band fill uses the brand teal, not the LIVE-badge green', (
tester,
) async {
await tester.pumpWidget(buildWidget());
final tema = SliderTheme.of(tester.element(find.byType(Slider).first));
expect(tema.activeTrackColor, PluriWaveTokens.brand);
expect(tema.thumbColor, PluriWaveTokens.brand);
expect(
tema.activeTrackColor,
isNot(PluriWaveTokens.dark.liveGreen),
reason:
'liveGreen (#7EE4C2) is the LIVE badge colour; the prototype fills '
'EQ bands with brand teal #21D4D9 (t4 line 585)',
);
});
} }