TarjetaEmisora had the only good fallback for a station with no artwork -- a deterministic pick from 4 bundled illustrations with a gradient/glyph last resort. FilaEmisoraPlana's flat rows, the Escuchar hero, the "Tus emisoras" grid cell, the mini player and the full player each had their own, separate, flat primaryContainer square instead. Extract the good fallback into PluriStationArtFallback and use it from every one of those call sites. The selection formula (asset order, codeUnits-sum modulo) is preserved exactly, since navegacion_auto.dart mirrors the same formula independently for Android Auto's own drawable rotation.
174 lines
5.5 KiB
Dart
174 lines
5.5 KiB
Dart
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/tema/pluriwave_tokens.dart';
|
|
import 'package:pluriwave/widgets/fila_emisora_plana.dart';
|
|
import 'package:pluriwave/widgets/pluri_station_art_fallback.dart';
|
|
import 'package:pluriwave/widgets/tarjeta_emisora.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import '../helpers/fakes.dart';
|
|
import '../helpers/fakes_alarmas.dart';
|
|
|
|
EstadoRadio _estado() => EstadoRadio(
|
|
audio: FakeServicioAudio(),
|
|
favoritos: FakeServicioFavoritos(),
|
|
radio: FakeServicioRadio(),
|
|
servicioEcualizador: FakeServicioEcualizador(),
|
|
servicioGrabacion: FakeServicioGrabacionRadioInactiva(),
|
|
iniciarAutomaticamente: false,
|
|
);
|
|
|
|
Widget _host(EstadoRadio estado, Widget child) {
|
|
return ChangeNotifierProvider<EstadoRadio>.value(
|
|
value: estado,
|
|
child: MaterialApp(
|
|
locale: const Locale('en'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: Scaffold(body: child),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Item 23 / audit 4.3 + 6.5 (t4:226-232, 302-306): the shared flat row
|
|
/// backing Favoritos and search results.
|
|
void main() {
|
|
testWidgets(
|
|
'renders a flat, background-less row -- no TarjetaEmisora underneath',
|
|
(tester) async {
|
|
final estado = _estado();
|
|
addTearDown(estado.dispose);
|
|
final emisora = emisoraDemo(uuid: 'a', nombre: 'Station A');
|
|
|
|
await tester.pumpWidget(
|
|
_host(estado, FilaEmisoraPlana(emisora: emisora, meta: 'Rock - Spain')),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.text('Station A'), findsOneWidget);
|
|
expect(find.text('Rock - Spain'), findsOneWidget);
|
|
expect(
|
|
find.byType(TarjetaEmisora),
|
|
findsNothing,
|
|
reason: 'a flat row does not reuse the full glass card',
|
|
);
|
|
},
|
|
);
|
|
|
|
testWidgets('the thumbnail is 48x48 with a 12 radius (t4:226, t4:302)', (
|
|
tester,
|
|
) async {
|
|
final estado = _estado();
|
|
addTearDown(estado.dispose);
|
|
final emisora = emisoraDemo(uuid: 'a', nombre: 'Station A');
|
|
|
|
await tester.pumpWidget(
|
|
_host(estado, FilaEmisoraPlana(emisora: emisora, meta: '')),
|
|
);
|
|
await tester.pump();
|
|
|
|
final arte = find.byKey(const ValueKey('fila-emisora-plana-arte'));
|
|
expect(tester.getSize(arte), const Size(48, 48));
|
|
final clip = tester.widget<ClipRRect>(arte);
|
|
expect(
|
|
(clip.borderRadius as BorderRadius).topLeft,
|
|
const Radius.circular(12),
|
|
);
|
|
});
|
|
|
|
testWidgets(
|
|
'issue 6 (feedback-pruebas): a station with no favicon shows the shared '
|
|
'PluriStationArtFallback, not a flat coloured square',
|
|
(tester) async {
|
|
final estado = _estado();
|
|
addTearDown(estado.dispose);
|
|
final emisora = emisoraDemo(uuid: 'sin-arte', nombre: 'Sin Arte');
|
|
|
|
await tester.pumpWidget(
|
|
_host(estado, FilaEmisoraPlana(emisora: emisora, meta: '')),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(
|
|
find.descendant(
|
|
of: find.byKey(const ValueKey('fila-emisora-plana-arte')),
|
|
matching: find.byType(PluriStationArtFallback),
|
|
),
|
|
findsOneWidget,
|
|
reason:
|
|
'issue 6: the flat row must reach the shared fallback, not its '
|
|
'own flat primaryContainer square',
|
|
);
|
|
},
|
|
);
|
|
|
|
testWidgets('omits the meta line entirely when empty (no stray gap)', (
|
|
tester,
|
|
) async {
|
|
final estado = _estado();
|
|
addTearDown(estado.dispose);
|
|
final emisora = emisoraDemo(uuid: 'a', nombre: 'Station A');
|
|
|
|
await tester.pumpWidget(
|
|
_host(estado, FilaEmisoraPlana(emisora: emisora, meta: '')),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.text('Station A'), findsOneWidget);
|
|
// Only the title Text should exist in the info column -- no empty
|
|
// second Text node.
|
|
expect(find.text(''), findsNothing);
|
|
});
|
|
|
|
testWidgets('BotonReproducirCircular is 44x44, brand-teal-tinted background, '
|
|
'22px play_arrow icon (t4:230, t4:305)', (tester) async {
|
|
var tapped = false;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: BotonReproducirCircular(onPressed: () => tapped = true),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
|
|
final boton = find.byKey(const ValueKey('boton-reproducir-circular'));
|
|
final material = tester.widget<Material>(boton);
|
|
expect(material.color, PluriWaveTokens.brand.withValues(alpha: 0.14));
|
|
expect(material.shape, const CircleBorder());
|
|
|
|
final icon = tester.widget<Icon>(find.byIcon(Icons.play_arrow_rounded));
|
|
expect(icon.size, 22);
|
|
expect(icon.color, PluriWaveTokens.brand);
|
|
|
|
await tester.tap(find.byIcon(Icons.play_arrow_rounded));
|
|
expect(tapped, isTrue);
|
|
});
|
|
|
|
testWidgets(
|
|
'BotonFavoritoEmisora toggles favourite status and shows a snackbar '
|
|
'(t4:304)',
|
|
(tester) async {
|
|
final estado = _estado();
|
|
addTearDown(estado.dispose);
|
|
final emisora = emisoraDemo(uuid: 'a', nombre: 'Station A');
|
|
|
|
await tester.pumpWidget(
|
|
_host(estado, BotonFavoritoEmisora(emisora: emisora)),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.byIcon(Icons.favorite_outline_rounded), findsOneWidget);
|
|
|
|
await tester.tap(find.byIcon(Icons.favorite_outline_rounded));
|
|
await tester.pump();
|
|
await tester.pump();
|
|
|
|
expect(find.byIcon(Icons.favorite_rounded), findsOneWidget);
|
|
expect(await estado.esFavorito('a'), isTrue);
|
|
},
|
|
);
|
|
}
|