Files
Javier Bautista Fernández d579a0e107 feat: Implement startup retry mechanism for custom stations and equalizer persistence
- 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.
2026-04-27 17:34:04 +02:00

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.