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

6.9 KiB
Raw Permalink Blame History

Tasks: Multi-Device Equalizer

Review Workload Forecast

Field Value
Estimated changed lines 700950
400-line budget risk High
Chained PRs recommended Yes
Suggested split PR 1: Model + Service + Platform channel → PR 2: State layer + persistence → PR 3: UI + export-import
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 Platform bridge + Dart service + model + fakes PR 1 Base: feature/multi-device-eq; no behavioral changes yet
2 State layer 4-level resolution + persistence + toggle PR 2 Base: PR 1 branch; depends on Unit 1
3 Settings UI + export/import v3 PR 3 Base: PR 2 branch; depends on Unit 2

Phase 1: Foundation — Model and Service Interface (PR 1 scope)

  • 1.1 RED: write test/modelos/dispositivo_audio_test.dart — assert TipoDispositivo enum values and DispositivoAudio equality
  • 1.2 GREEN: create lib/modelos/dispositivo_audio.dartTipoDispositivo enum + DispositivoAudio value class with ==/hashCode
  • 1.3 RED: write test/servicios/servicio_dispositivo_audio_test.dart — assert abstract contract + fake stream behavior
  • 1.4 GREEN: create lib/servicios/servicio_dispositivo_audio.dart — abstract class with dispositivoActual, onDispositivoCambiado, obtenerDispositivoActual(), dispose()
  • 1.5 GREEN: add FakeServicioDispositivoAudio to test/helpers/fakes.dartStreamController-backed fake; emitDispositivo(DispositivoAudio) helper
  • 1.6 REFACTOR: ensure fake satisfies all scenarios from spec audio-device-detection / Fakeable service interface

Phase 2: Platform Channel — Android (PR 1 scope)

  • 2.1 RED: write test/servicios/servicio_dispositivo_audio_real_test.dart — stub MethodChannel, assert obtenerDispositivoActual() maps {id,type,name} to DispositivoAudio
  • 2.2 GREEN: implement ServicioDispositivoAudioReal in lib/servicios/servicio_dispositivo_audio.dart — MethodChannel getActiveDevice + EventChannel stream; map type int → TipoDispositivo
  • 2.3 GREEN: add pluriwave/audio_devices EventChannel + MethodChannel in android/app/src/main/kotlin/.../MainActivity.ktAudioDeviceCallback on API ≥ 23; stable key derivation (bt_a2dp:<MAC>, wired_headset, builtin_speaker, usb_headset:<address>)
  • 2.4 REFACTOR: verify BT MAC key matches spec scenario BT MAC key is stable across restarts

Phase 3: Platform Channel — iOS (PR 1 scope)

  • 3.1 GREEN: create ios/Runner/AudioDevicesPlugin.swiftAVAudioSession.routeChangeNotification → EventChannel; derive portType+uid key; fallback to portType+portName per spec iOS uid fallback
  • 3.2 GREEN: register AudioDevicesPlugin in ios/Runner/AppDelegate.swift
  • 3.3 RED: write unit test asserting toggle-disabled path returns empty stream (uses fake, not real channel)

Phase 4: EQ Service — Persistence Layer (PR 2 scope)

  • 4.1 RED: extend test/servicios/servicio_ecualizador_test.dart — assert new SP key CRUD: guardarPresetDispositivo, obtenerPresetDispositivo, guardarPresetMatriz, obtenerPresetMatriz, obtenerToggleMultiDispositivo
  • 4.2 GREEN: modify lib/servicios/servicio_ecualizador.dart — add SP keys eq_multi_device_enabled_v1, eq_preset_por_dispositivo_v1, eq_presets_matriz_v1; add typed read/write methods for device and matrix maps
  • 4.3 GREEN: extend ConfiguracionEcualizador (in servicio_ecualizador.dart) — add presetsDispositivo, presetsMatriz, eqMultiDeviceEnabled fields; update fromJson/toJson
  • 4.4 REFACTOR: validate storage size stays under 50 KB for 250 matrix entries per spec scenario

Phase 5: State Layer — 4-Level Resolution (PR 2 scope)

  • 5.1 RED: write failing tests in test/estado/estado_ecualizador_test.dart — 4-level resolution scenarios: matrix wins, falls back to station, falls back to device, falls back to global
  • 5.2 GREEN: modify lib/estado/estado_ecualizador.dart — inject ServicioDispositivoAudio; add presetsDispositivo, presetsMatriz, _dispositivoActual, eqMultiDeviceEnabled; implement _resolverPreset() with 4-level hierarchy
  • 5.3 RED: write failing tests — device stream subscription: FakeServicioDispositivoAudio emits device → assert _resolverPreset() re-runs and notifyListeners() fires
  • 5.4 GREEN: subscribe to ServicioDispositivoAudio.onDispositivoCambiado in EstadoEcualizador.init() when toggle is enabled; call aplicarPresetActivo() on event
  • 5.5 RED: write failing tests — first-seen device copies current resolved preset; subsequent reconnect does not overwrite
  • 5.6 GREEN: implement first-device initialization: if presetsDispositivo[deviceId] is null, set it to current resolved preset and persist
  • 5.7 RED: write failing tests — toggle-off path uses only 2-level resolution (station → global); no device subscription established
  • 5.8 GREEN: guard all device logic behind eqMultiDeviceEnabled check in EstadoEcualizador
  • 5.9 REFACTOR: ensure _recrearPlayer() / aplicarPresetActivo() path applies device-resolved preset, not stale _presetActual, per ADR-5

Phase 6: Export/Import v3 (PR 3 scope)

  • 6.1 RED: extend test/servicios/servicio_export_import_test.dart — v3 export includes schemaVersion: 3, presetsPorDispositivo, presetsMatriz; v3 round-trip preserves device presets; v2 import succeeds with empty device maps
  • 6.2 GREEN: modify lib/servicios/servicio_export_import.dart — bump schemaVersion to 3; serialize/deserialize presetsDispositivo and presetsMatriz; handle missing fields from v1/v2 imports as empty maps
  • 6.3 REFACTOR: confirm v4-future guard (unknown schemaVersion values do not crash)

Phase 7: Settings UI (PR 3 scope)

  • 7.1 RED: write widget test test/pantallas/pantalla_ajustes_test.dart — toggle off: _SeccionEcualizadorAvanzado absent; toggle on with devices: device list visible
  • 7.2 GREEN: add _SeccionEcualizadorAvanzado widget in lib/pantallas/pantalla_ajustes.dartSwitchListTile for eqMultiDeviceEnabled; ListView of known devices and their preset names, shown only when toggle is on and devices detected
  • 7.3 REFACTOR: confirm widget is hidden (not just invisible) when toggle is off per spec scenario

Phase 8: Integration Verification

  • 8.1 Run flutter test — all new and modified tests must pass
  • 8.2 Run flutter analyze — zero new warnings or errors
  • 8.3 Run dart format . — no unformatted files
  • 8.4 Manual smoke: toggle off → verify zero EQ behavior change vs. current release
  • 8.5 Manual smoke: toggle on, connect BT device → verify EQ swap within 500ms