fix(escuchar): show the station meta line in the hero

Audit 1.6 (t4 line 62): the Escuchar hero never rendered "genre ·
country · bitrate kbps" between the station name and the visualizer.
Built from fields Emisora already carries (tags/pais/bitrate) — no
new fields, no service calls — omitting gracefully whatever a station
lacks.
This commit is contained in:
2026-07-29 23:34:07 +02:00
parent 9840205a83
commit e1505d7aaa
2 changed files with 104 additions and 0 deletions
+30
View File
@@ -267,6 +267,22 @@ class _EscucharHero extends StatelessWidget {
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
if (_metaEscuchar(emisora) case final meta?) ...[
const SizedBox(height: 4),
Text(
meta,
key: const ValueKey('escuchar-hero-meta'),
style: TextStyle(
fontSize: 12.5,
fontWeight: FontWeight.w600,
color: theme.colorScheme.onSurface.withValues(
alpha: 0.62,
),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
const SizedBox(height: 8),
VisualizadorAudio(
estadoStream: estado.estadoStream,
@@ -536,3 +552,17 @@ class _FilaTransporteEscuchar extends StatelessWidget {
: l10n.durationMinutesSeconds(d.inMinutes, s);
}
}
/// Audit 1.6 (t4 line 62): "género · país · kbps" built ONLY from fields
/// [Emisora] already carries (`tags`/`pais`/`bitrate`) — no new fields, no
/// service calls. Whatever a station lacks is omitted gracefully; this
/// never renders a stray leading/trailing/doubled " · ".
String? _metaEscuchar(Emisora emisora) {
final partes = <String>[
if (emisora.generos.isNotEmpty) emisora.generos.first,
if (emisora.pais != null && emisora.pais!.isNotEmpty) emisora.pais!,
if (emisora.bitrate != null && emisora.bitrate! > 0)
'${emisora.bitrate} kbps',
];
return partes.isEmpty ? null : partes.join(' · ');
}
+74
View File
@@ -8,6 +8,7 @@ import 'package:pluriwave/estado/estado_grabacion.dart';
import 'package:pluriwave/estado/estado_navegacion.dart';
import 'package:pluriwave/estado/estado_radio.dart';
import 'package:pluriwave/l10n/gen/app_localizations.dart';
import 'package:pluriwave/modelos/emisora.dart';
import 'package:pluriwave/pantallas/pantalla_inicio.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -164,6 +165,79 @@ void main() {
reason: 'prototype t4 line 56 sizes the Escuchar hero artwork at 132',
);
});
testWidgets('visual fidelity (audit 1.6): the hero shows "genre · country · '
'bitrate kbps" built from the station model, nothing invented', (
tester,
) async {
_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);
const completa = Emisora(
uuid: 'meta-1',
nombre: 'Radio Horizonte',
url: 'https://stream.demo/radio',
tags: 'Noticias',
pais: 'España',
bitrate: 128,
);
await favoritos.agregar(completa);
await estado.cargarFavoritos();
// The hero only renders when a station is active.
await tester.runAsync(() => estado.reproducir(completa));
await tester.pumpWidget(
_conProviders(estado, _testApp(const PantallaInicio())),
);
await _pumpBounded(tester);
expect(
find.text('Noticias · España · 128 kbps'),
findsOneWidget,
reason: 'prototype t4 line 62: "Noticias · España · 128 kbps"',
);
});
testWidgets(
'visual fidelity (audit 1.6): a station missing every meta field omits '
'the line gracefully, no stray separators',
(tester) async {
_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 desnuda = emisoraDemo(uuid: 'meta-2', nombre: 'Radio Desnuda');
await favoritos.agregar(desnuda);
await estado.cargarFavoritos();
await tester.runAsync(() => estado.reproducir(desnuda));
await tester.pumpWidget(
_conProviders(estado, _testApp(const PantallaInicio())),
);
await _pumpBounded(tester);
expect(find.byKey(const ValueKey('escuchar-hero-meta')), findsNothing);
},
);
}
/// Mirrors the app.dart wiring: EstadoRadio owns the domain notifiers and