- Added state management for startup retry and custom station handling in `EstadoRadio`. - Created tasks for implementing strict TDD with RED tests for HTTP failure retries and EQ persistence. - Developed verification report to ensure compliance with TDD practices. - Introduced fake services for testing, including `FakeServicioAudio`, `FakeServicioFavoritos`, and `FakeServicioRadio`. - Implemented widget tests for `PantallaInicio` and `PantallaFavoritos` to validate UI behavior with custom stations. - Enhanced `ServicioRadio` to support host rotation and retry logic for API calls. - Established a new configuration file to enforce project constraints and testing rules.
4.8 KiB
4.8 KiB
Design: Startup retry, custom stations, and equalizer persistence
Technical Approach
Keep the existing Provider/ChangeNotifier architecture. Add test seams first, then implement: radio retry in ServicioRadio, main-list composition in EstadoRadio, and EQ persistence in a dedicated ServicioEcualizador using SharedPreferences. Persisted Provider EQ state must not depend on Android equalizer availability.
Architecture Decisions
| Decision | Choice | Alternatives | Rationale |
|---|---|---|---|
| API retry owner | ServicioRadio._get() owns bounded retry and host rotation |
Retry only in EstadoRadio |
Centralizes network resilience for startup and search; avoids duplicated policy. |
| Custom stations home UX | Add EstadoRadio.emisorasInicio/similar combining custom + popular when no genre filter |
Separate home section | Minimal UI change and reuses TarjetaEmisora favorite behavior; separate section can come later. |
| EQ storage | New ServicioEcualizador with SharedPreferences JSON |
SQLite migration in favorites DB | Main EQ is app-level, not favorite-row data; SharedPreferences is already available and simpler. |
| Station EQ fallback | Map<uuid, PresetEcualizador>; absent key means "use main" |
Store explicit mode enum per station | Absence is compact and maps naturally to disabling own EQ. |
| Current station source | Fix ServicioAudio/handler to assign/clear emisoraActual |
Track only in EstadoRadio |
Existing mini player and player screen already read audio.emisoraActual; fix the actual source. |
Data Flow
Startup:
PluriWaveApp -> EstadoRadio._init()
-> ServicioEcualizador.cargar() -> preset principal + mapa por emisora
-> ServicioRadio.obtenerPopulares/Tendencias() -> retry/rotate host
-> ServicioFavoritos + emisoras_custom.json
Playback:
UI -> EstadoRadio.reproducir(emisora)
-> ServicioAudio.reproducir(emisora) sets current station
-> EstadoRadio selects EQ: presetsPorEmisora[uuid] ?? presetPrincipal
-> ServicioAudio.aplicarPreset(selected)
EQ update:
Settings/player EQ controls -> EstadoRadio
-> update main EQ OR station EQ
-> ServicioEcualizador.guardar(...)
-> ServicioAudio applies if available
File Changes
| File | Action | Description |
|---|---|---|
lib/servicios/servicio_ecualizador.dart |
Create | Load/save main EQ and station EQ map from SharedPreferences. |
lib/servicios/servicio_radio.dart |
Modify | Add injectable client/config, retry count, backoff, and host rotation. |
lib/estado/estado_radio.dart |
Modify | Inject services, load EQ during init, expose combined main listing, apply fallback EQ policy. |
lib/servicios/servicio_audio.dart |
Modify | Assign/clear emisoraActual; keep default behavior backward-compatible. |
lib/pantallas/pantalla_inicio.dart |
Modify | Use combined main listing when no genre filter. |
lib/pantallas/pantalla_ajustes.dart |
Modify | Distinguish main EQ from favorite-station own EQ controls. |
lib/modelos/preset_ecualizador.dart |
Modify | Add equality/copy helpers if tests need deterministic comparisons. |
test/servicios/servicio_radio_test.dart |
Create | Retry/host rotation tests. |
test/estado/estado_radio_test.dart |
Create | EQ persistence, custom listing, and station EQ policy tests. |
test/pantallas/pantalla_inicio_test.dart |
Create | Widget coverage for custom station rendering/favorite action. |
Interfaces / Contracts
Suggested public surface:
class ServicioEcualizador {
Future<ConfiguracionEcualizador> cargar();
Future<void> guardarPrincipal(PresetEcualizador preset);
Future<void> guardarPorEmisora(String uuid, PresetEcualizador preset);
Future<void> eliminarPorEmisora(String uuid);
}
ConfiguracionEcualizador contains PresetEcualizador principal and Map<String, PresetEcualizador> porEmisora.
Testing Strategy
| Layer | What to Test | Approach |
|---|---|---|
| Unit | ServicioRadio retries and rotates hosts |
Fake http.Client, zero delay. |
| Unit | EQ load/save and fallback selection | SharedPreferences mock values + fake audio service. |
| Unit | Custom station added appears in combined listing | Inject fake custom storage or initial state. |
| Widget | Home renders custom station and favorite tap persists | Pump PantallaInicio with test EstadoRadio. |
| Regression | Current station updates for mini player/station EQ | Fake audio handler/service assertions. |
Migration / Rollout
No destructive migration. On first run without EQ keys, use PresetEcualizador.flat as main EQ and empty per-station map. Existing export/import keys can be read opportunistically but app-local persistence should use the new service.
Open Questions
- None blocking. The first implementation can place station EQ controls in Settings for the currently playing favorite; a richer per-favorite management screen can be deferred.