Restyle the Ecualizador settings screen to the new visual language while keeping the equalizer at 5 bands (spike-resolved, Engram id 2498 - band count is device-reported via just_audio's AndroidEqualizer, not app-chosen; the approved mockup's 7 sliders would silently no-op on typical hardware). - Restyle EcualizadorWidget in place: strip its internal title + preset chip row (the pushed screen's header now carries the title), add a habilitado parameter that greys/disables every slider when EQ is off. Widen PresetsEcualizadorWidget additively (personalizados param) so custom presets can join the chip row without a second implementation. - Add servicio_presets_personalizados.dart (new file, own SharedPreferences key eq_custom_presets_v1) for custom EQ preset persistence - kept out of servicio_ecualizador.dart, which has an empty-git-diff success criterion for this change. preset_ecualizador.dart is unchanged: a custom preset is just a PresetEcualizador with a user-supplied name. - Extend EstadoEcualizador with presetsPersonalizados, guardarPresetPersonalizado (validates non-empty name), eliminarPresetPersonalizado. The load is a new explicit cargarPresetsPersonalizados(), deliberately NOT folded into cargarPersistido(): that method is exercised ~30 times by estado_ecualizador_test.dart (protected, must stay unmodified) via Fakes only, with no SharedPreferences awareness in that file. - Build out the Ecualizador screen body: base-vs-per-station explainer banner, a "Salida activa" row surfaced on the main screen (previously Advanced-only), an "Emisoras con ajuste propio" drill-down sourced from the existing presetsPorEmisora map, and a "Guardar como preset" action. New coverage lives in new files rather than touching the three protected EQ test files: ecualizador_widget_test.dart (component-level, did not exist before this commit), servicio_presets_personalizados_test.dart, and estado_ecualizador_presets_personalizados_test.dart. servicio_ecualizador.dart, servicio_audio.dart and the three protected EQ test files keep an empty git diff. Full suite: 713/713 green (2 skipped, unchanged), up from 682. size:exception - realized 1,954 changed lines (25 files, plus this docs update) against the 400-550 forecast: lib/ + ARB alone is ~650 lines, near the top of the forecast band by itself since this WU also had to build out a screen body WU3a only stubbed; the rest is 4 test files (675 lines) and 11 new ARB keys regenerating 13 lib/l10n/gen files (~546 lines) - the same pattern every prior work unit in this branch has hit. Not splittable: WU14 reuses this unit's editor component by exact runtime type and cannot begin until this lands as a whole.
96 lines
3.2 KiB
Dart
96 lines
3.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:pluriwave/l10n/gen/app_localizations.dart';
|
|
import 'package:pluriwave/modelos/preset_ecualizador.dart';
|
|
import 'package:pluriwave/widgets/ecualizador_widget.dart';
|
|
|
|
/// WU13 task 13.1 — first-class regression guard (design ADR-5, spec
|
|
/// `eq-custom-presets` "Five-Band Equalizer"): the equalizer widget must
|
|
/// always render exactly 5 vertical sliders. Band count is device-reported
|
|
/// via `just_audio`'s `AndroidEqualizer` (spike, Engram id 2498), not
|
|
/// app-chosen — any future change rendering 7 sliders is rejected on sight.
|
|
///
|
|
/// **Correction found at apply time**: `tasks.md`'s WU13 Verify command
|
|
/// names this file as if it already existed ("Modified tests:
|
|
/// ecualizador_widget_test.dart"). No such file existed before this commit
|
|
/// (`ecualizador_widget.dart` had zero test coverage) — created new instead.
|
|
void main() {
|
|
Widget buildWidget({
|
|
PresetEcualizador? preset,
|
|
bool habilitado = true,
|
|
void Function(PresetEcualizador)? onCambio,
|
|
}) {
|
|
return MaterialApp(
|
|
locale: const Locale('en'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: Scaffold(
|
|
body: EcualizadorWidget(
|
|
preset: preset ?? PresetEcualizador.flat,
|
|
habilitado: habilitado,
|
|
onCambio: onCambio ?? (_) {},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
testWidgets('renders exactly 5 vertical sliders, one per band', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(buildWidget());
|
|
|
|
expect(find.byType(Slider), findsNWidgets(5));
|
|
});
|
|
|
|
testWidgets('renders exactly 5 sliders regardless of the preset selected', (
|
|
tester,
|
|
) async {
|
|
// Regression guard restated: a future change proposing 7 sliders (the
|
|
// rejected mockup band count) must fail this test regardless of which
|
|
// fixed preset is active.
|
|
await tester.pumpWidget(buildWidget(preset: PresetEcualizador.jazz));
|
|
|
|
expect(find.byType(Slider), findsNWidgets(5));
|
|
});
|
|
|
|
testWidgets('dragging a slider reports the updated band back via onCambio', (
|
|
tester,
|
|
) async {
|
|
PresetEcualizador? reportado;
|
|
await tester.pumpWidget(buildWidget(onCambio: (p) => reportado = p));
|
|
|
|
final slider = tester.widget<Slider>(find.byType(Slider).first);
|
|
slider.onChanged?.call(6.0);
|
|
await tester.pump();
|
|
|
|
expect(reportado, isNotNull);
|
|
expect(reportado!.bandas.length, 5);
|
|
expect(reportado!.bandas.first, 6.0);
|
|
});
|
|
|
|
testWidgets(
|
|
'habilitado: false disables every slider (greyed, non-interactive)',
|
|
(tester) async {
|
|
await tester.pumpWidget(buildWidget(habilitado: false));
|
|
|
|
final sliders = tester.widgetList<Slider>(find.byType(Slider));
|
|
expect(sliders, hasLength(5));
|
|
for (final slider in sliders) {
|
|
expect(slider.onChanged, isNull);
|
|
}
|
|
},
|
|
);
|
|
|
|
testWidgets('habilitado: true (default) keeps every slider interactive', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(buildWidget());
|
|
|
|
final sliders = tester.widgetList<Slider>(find.byType(Slider));
|
|
expect(sliders, hasLength(5));
|
|
for (final slider in sliders) {
|
|
expect(slider.onChanged, isNotNull);
|
|
}
|
|
});
|
|
}
|