Files
FreeTLab bccc5c48b8
Build & Deploy PluriWave / Análisis de código (push) Successful in 38s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m30s
docs(openspec): add SDD artifact trail for recent alarm and EQ changes
Persist the exploration, proposal, spec, design, tasks, and
verify/archive reports produced during the multi-device EQ,
alarm-countdown, and notification-visual-polish SDD cycles.
2026-07-04 12:42:11 +02:00

7.3 KiB
Raw Permalink Blame History

Tasks: EQ Device Auto-Switch UX

Review Workload Forecast

Field Value
Estimated changed lines 380520
400-line budget risk High
Chained PRs recommended Yes
Suggested split PR 1 (service + state) → PR 2 (UI + l10n) → PR 3 (widget tests)
Delivery strategy ask-on-risk
Chain strategy pending

Decision needed before apply: Yes Chained PRs recommended: Yes Chain strategy: pending 400-line budget risk: High

Suggested Work Units

Unit Goal Likely PR Notes
1 Bug fix + rename persistence layer (service + state) PR 1 base = main; ~150 lines; no UI dependency
2 Settings UI rewrite + edit modal + l10n PR 2 base = PR 1; ~220 lines; depends on Unit 1 APIs
3 Widget tests for modal + integration tests PR 3 base = PR 2; ~120 lines; closes test coverage gap

Phase 1: Foundation — Service Layer (PR 1 slice)

Strict TDD: RED first, then GREEN, then REFACTOR for each task group.

  • 1.1 RED — Write failing unit tests in test/servicios/servicio_ecualizador_test.dart for cargarNombresDispositivos() returning empty map when SP key absent
  • 1.2 RED — Add failing test: guardarNombresDispositivos({id: name}) writes JSON to eq_nombres_dispositivos_v1 SP key
  • 1.3 RED — Add failing test: round-trip save → load returns same map
  • 1.4 GREEN — Add _keyNombresDispositivos = 'eq_nombres_dispositivos_v1' to lib/servicios/servicio_ecualizador.dart
  • 1.5 GREEN — Implement cargarNombresDispositivos() and guardarNombresDispositivos() in ServicioEcualizador (reuse existing _leerMapa/_guardarMapa JSON pattern adapted for Map<String, String>)
  • 1.6 GREEN — Add nombresDispositivos field to ConfiguracionEcualizador data class; include in cargar() and wire into ServicioEcualizador.cargar() call
  • 1.7 REFACTOR — Ensure no duplicate SP read calls; confirm cargar() returns nombresDispositivos in a single pass; update any copyWith if present

Phase 2: Core — State Layer Bug Fix + Rename API (PR 1 slice)

  • 2.1 RED — Write failing unit tests in test/estado/estado_ecualizador_test.dart: after cargarPersistido() with eqMultiDeviceEnabled=true and fake device service returning 'bt_a2dp:AA:BB', assert dispositivoActualId == 'bt_a2dp:AA:BB' (spec scenario: correct preset at startup)
  • 2.2 RED — Add failing test: first-seen device is bootstrapped with copy of resolved preset after cargarPersistido() (spec scenario: first-seen device bootstrapped at startup)
  • 2.3 RED — Add failing test: obtenerDispositivoActual() throws → dispositivoActualId falls back to 'builtin_speaker' (spec scenario: graceful failure)
  • 2.4 RED — Add failing test: eqMultiDeviceEnabled=falseobtenerDispositivoActual() never called (spec scenario: toggle off)
  • 2.5 GREEN — In lib/estado/estado_ecualizador.dart, inside cargarPersistido(), after _configurarSuscripcionDispositivo(), add try/catch await obtenerDispositivoActual() call that seeds _dispositivoActualId then calls _onDispositivoCambiado() to trigger bootstrap + preset resolution
  • 2.6 RED — Add failing tests for rename API: renombrarDispositivo(id, nombre) writes to _nombresDispositivos, calls notifyListeners(); empty string is no-op (spec scenarios: rename persists, empty name not persisted)
  • 2.7 RED — Add failing test: obtenerNombreDispositivo(id) returns stored name or empty string
  • 2.8 RED — Add failing tests for nombreVisible(deviceId, platformName) fallback chain: custom > platform > id (all three spec scenarios)
  • 2.9 GREEN — Add _nombresDispositivos map field; implement renombrarDispositivo(), obtenerNombreDispositivo(), nombreVisible(), and get nombresDispositivos getter in lib/estado/estado_ecualizador.dart; wire to service persist on rename
  • 2.10 REFACTOR — Extract fallback chain to a single helper, ensure _nombresDispositivos is loaded from ConfiguracionEcualizador.nombresDispositivos in cargarPersistido()

Phase 3: Integration — Settings UI Rewrite (PR 2 slice)

  • 3.1 RED — Write failing widget test in test/pantallas/pantalla_ajustes_test.dart: connection dot is present on active device row, absent on inactive rows (spec scenario: active device shows green indicator)
  • 3.2 RED — Add failing widget test: tapping a device row opens a bottom sheet with a TextField pre-filled with resolved display name and an EcualizadorWidget (spec scenario: modal opens on device row tap)
  • 3.3 RED — Add failing widget test: EcualizadorWidget in modal is reachable by scrolling on small viewport (spec scenario: modal is scrollable)
  • 3.4 GREEN — Rewrite _SeccionEcualizadorAvanzado device rows in lib/pantallas/pantalla_ajustes.dart: add green dot Icon gated on entry.key == eq.dispositivoActualId; display name via eq.nombreVisible(id, device.nombre); add onTap handler
  • 3.5 GREEN — Implement _DialogoEdicionDispositivo StatefulWidget in lib/pantallas/pantalla_ajustes.dart: showModalBottomSheet with showDragHandle: true, isScrollControlled: true, TextField pre-filled with display name, embedded EcualizadorWidget, confirm/dismiss logic calling eq.renombrarDispositivo(id, name)
  • 3.6 RED — Add failing widget test: renaming in modal and confirming calls renombrarDispositivo; device row reflects new name after close (spec scenario: rename confirmed in modal persists)
  • 3.7 RED — Add failing widget test: dismissing modal without confirming leaves name unchanged (spec scenario: modal dismiss without save)
  • 3.8 GREEN — Wire dismiss-without-save path (no renombrarDispositivo call on drag-dismiss)
  • 3.9 REFACTOR — Extract modal into its own file if pantalla_ajustes.dart exceeds 400 lines; ensure fallback chain is called from EstadoEcualizador, not inlined in UI

Phase 4: Localisation (PR 2 slice)

  • 4.1 Add ~5 new ARB keys to lib/l10n/app_en.arb: eqDeviceEditTitle, eqDeviceNameLabel, eqDeviceNameHint, eqDeviceNameConfirm, eqDeviceConnected
  • 4.2 Translate all 5 keys in the 12 remaining locale files (app_es.arb, app_pt.arb, app_fr.arb, app_de.arb, app_it.arb, app_ja.arb, app_ko.arb, app_zh.arb, app_ru.arb, app_ar.arb, app_hi.arb, app_tr.arb)
  • 4.3 Run flutter gen-l10n and verify no ARB parse errors; confirm generated .g.dart includes all new keys
  • 4.4 Replace any hardcoded strings in _SeccionEcualizadorAvanzado and _DialogoEdicionDispositivo with l10n references

Phase 5: Cleanup + Verification (PR 3 slice)

  • 5.1 Run full test suite; confirm all RED tasks from Phases 13 are GREEN
  • 5.2 Verify spec scenario coverage: cross-check each scenario in openspec/changes/eq-device-autoswitch-ux/spec.md against a corresponding test (add any gap tests)
  • 5.3 Run flutter analyze; resolve any new lint warnings introduced by this change
  • 5.4 Remove any TODO/FIXME comments introduced during GREEN phase
  • 5.5 Confirm nombresDispositivos omission from export schema v4 is documented in design open questions (no code change needed — already deferred per proposal)