diff --git a/lib/pantallas/ajustes/widgets/fila_ajuste.dart b/lib/pantallas/ajustes/widgets/fila_ajuste.dart index fea804a..6e87f05 100644 --- a/lib/pantallas/ajustes/widgets/fila_ajuste.dart +++ b/lib/pantallas/ajustes/widgets/fila_ajuste.dart @@ -34,7 +34,9 @@ class GrupoAjustes extends StatelessWidget { Text(titulo, style: type.eyebrowLabel), const SizedBox(height: 4), for (var i = 0; i < filas.length; i++) ...[ - if (i > 0) const Divider(height: 1), + // S10 (Tier 4 visual fidelity): the prototype insets its row + // divider by 47px (t4 line 516), not full-bleed. + if (i > 0) const Divider(height: 1, indent: 47), filas[i], ], ], @@ -72,8 +74,14 @@ class FilaAjuste extends StatelessWidget { final valorActual = valor; return ListTile( contentPadding: EdgeInsets.zero, - leading: Icon(icon), - title: Text(titulo, style: type.cardTitle), + // 10.6 (Tier 4 visual fidelity): the prototype's row icon is 21px (t4 + // line 514), not Material's 24px default. + leading: Icon(icon, size: 21), + // 10.8 (Tier 4 visual fidelity): the prototype's row title is + // 14px/w700 (t4 line 514); cardTitle is 14.5/w700 — a one-off + // override, not a new PluriWaveTypography style (mirrors the + // precedent set for the ringing screen's station name, audit 9.7). + title: Text(titulo, style: type.cardTitle.copyWith(fontSize: 14)), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -88,7 +96,14 @@ class FilaAjuste extends StatelessWidget { ), const SizedBox(width: 6), ], - const Icon(Icons.chevron_right_rounded), + // 10.9 (Tier 4 visual fidelity): the prototype's chevron is 19px + // at 40% opacity (t4 lines 515-539), not Material's 24px + // full-opacity default. + Icon( + Icons.chevron_right_rounded, + size: 19, + color: const Color(0xFFF2F7FA).withValues(alpha: 0.4), + ), ], ), onTap: onTap, diff --git a/test/pantallas/ajustes/widgets/fila_ajuste_test.dart b/test/pantallas/ajustes/widgets/fila_ajuste_test.dart index 2fdfde3..ccc31cd 100644 --- a/test/pantallas/ajustes/widgets/fila_ajuste_test.dart +++ b/test/pantallas/ajustes/widgets/fila_ajuste_test.dart @@ -8,6 +8,24 @@ import 'package:pluriwave/tema/pluriwave_theme.dart'; /// lines 512-539, 625 — "Voz clara", "Alta", "3 guardados", "Alfabético", /// "7 · 84 MB", "Español", "Hoy, 08:12", "200 MB"). `FilaAjuste` used to /// accept only `icon`/`titulo`/`onTap` — no value slot at all. +/// Pre-existing project constraint (see `pantalla_ajustes_test.dart`): +/// `PluriGlassSurface` paints a background over `ListTile`'s ink layer, +/// which Flutter flags as a warning-level assertion, not a correctness bug. +/// Only needed by the `GrupoAjustes` test below — the bare `FilaAjuste` +/// tests above never wrap a `ListTile` inside that surface. +void _suppressListTileInkAssertion() { + final original = FlutterError.onError; + FlutterError.onError = (details) { + if (details.exceptionAsString().contains( + 'ListTile background color or ink splashes may be invisible', + )) { + return; + } + original?.call(details); + }; + addTearDown(() => FlutterError.onError = original); +} + void main() { Widget host(Widget child) { return MaterialApp( @@ -49,4 +67,59 @@ void main() { expect(find.text('Info'), findsOneWidget); expect(find.byIcon(Icons.chevron_right_rounded), findsOneWidget); }); + + testWidgets( + 'visual fidelity (audit 10.6/10.8/10.9): leading icon is 21px, the ' + 'title is 14px, and the chevron is 19px at 40% opacity (t4 lines ' + '514-515)', + (tester) async { + await tester.pumpWidget( + host( + FilaAjuste( + icon: Icons.equalizer_rounded, + titulo: 'Ecualizador base', + onTap: () {}, + ), + ), + ); + + final icon = tester.widget(find.byIcon(Icons.equalizer_rounded)); + expect(icon.size, 21); + + final titulo = tester.widget(find.text('Ecualizador base')); + expect(titulo.style?.fontSize, 14); + + final chevron = tester.widget( + find.byIcon(Icons.chevron_right_rounded), + ); + expect(chevron.size, 19); + expect(chevron.color, const Color(0xFFF2F7FA).withValues(alpha: 0.4)); + }, + ); + + testWidgets( + 'visual fidelity (audit S10): GrupoAjustes insets its row divider by ' + '47px, not full-bleed (t4 line 516)', + (tester) async { + _suppressListTileInkAssertion(); + await tester.pumpWidget( + host( + GrupoAjustes( + titulo: 'AUDIO', + filas: [ + FilaAjuste( + icon: Icons.equalizer_rounded, + titulo: 'Uno', + onTap: () {}, + ), + FilaAjuste(icon: Icons.hd_rounded, titulo: 'Dos', onTap: () {}), + ], + ), + ), + ); + + final divider = tester.widget(find.byType(Divider)); + expect(divider.indent, 47); + }, + ); }