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.
7.2 KiB
Spec: EQ Device Auto-Switch UX
Delta for multi-device-eq
MODIFIED Requirements
Requirement: Startup device initialization
When eqMultiDeviceEnabled is true, the system MUST query the current audio device via obtenerDispositivoActual() immediately after _configurarSuscripcionDispositivo() runs inside cargarPersistido(). The result MUST seed _dispositivoActualId, bootstrap a device preset if this is the first time the device is seen, and trigger _resolverPresetActivo() so the correct preset is applied before the first playback event.
(Previously: _dispositivoActualId was null at startup; preset resolution required a reconnect event.)
Scenario: correct preset applied at startup — device known
- GIVEN
eqMultiDeviceEnabledistrue - AND a preset for the current device ID already exists in
presetsDispositivo - WHEN the app starts and
cargarPersistido()completes - THEN
_dispositivoActualIdMUST be set to the current device ID - AND the device-resolved preset MUST be applied without any user action
Scenario: first-seen device bootstrapped at startup
- GIVEN
eqMultiDeviceEnabledistrue - AND the current device has no existing entry in
presetsDispositivo - WHEN
cargarPersistido()runs - THEN the device MUST be bootstrapped with a copy of the currently resolved preset
- AND
_dispositivoActualIdMUST be set to that device ID
Scenario: obtenerDispositivoActual() fails gracefully
- GIVEN
eqMultiDeviceEnabledistrue - AND the platform channel call throws or returns null
- WHEN
cargarPersistido()runs - THEN
_dispositivoActualIdMUST fall back to"builtin_speaker" - AND no exception MUST propagate to callers
Scenario: toggle off — no device query at startup
- GIVEN
eqMultiDeviceEnabledisfalse - WHEN the app starts
- THEN
obtenerDispositivoActual()MUST NOT be called - AND EQ behavior MUST be identical to the pre-feature baseline
New Capability: eq-device-rename
Purpose
Persistent custom names for audio devices, a connection status indicator per device row, and an edit modal combining rename input with embedded EQ editing. All gated by eqMultiDeviceEnabled.
Requirements
Requirement: Device name persistence
The system MUST store a Map<String, String> of deviceId → customName under the SharedPreferences key eq_nombres_dispositivos_v1. EstadoEcualizador MUST expose renombrarDispositivo(id, nombre) to write an entry and obtenerNombreDispositivo(id) to read one. Both operations MUST be reflected in ServicioEcualizador.
Scenario: rename persists across restarts
- GIVEN the user renames device
"bt_a2dp:AA:BB"to"Living Room BT" - WHEN the app is killed and relaunched
- THEN
obtenerNombreDispositivo("bt_a2dp:AA:BB")MUST return"Living Room BT"
Scenario: rename is immediately readable
- GIVEN no custom name exists for a device
- WHEN
renombrarDispositivo("bt_a2dp:AA:BB", "Office Speaker")is called - THEN
obtenerNombreDispositivo("bt_a2dp:AA:BB")MUST immediately return"Office Speaker"
Scenario: empty name is not persisted
- GIVEN a device already has the custom name
"My Headset" - WHEN
renombrarDispositivo(id, "")is called - THEN the existing name MUST be preserved (empty names MUST NOT overwrite)
Scenario: feature toggle off — no name storage
- GIVEN
eqMultiDeviceEnabledisfalse - WHEN any rename API is called
- THEN the operation MUST be a no-op and MUST NOT write to SharedPreferences
Requirement: Display name fallback chain
When displaying a device name anywhere in the UI, the system MUST resolve it using the following priority order, stopping at the first non-null, non-empty value:
- Custom name from
eq_nombres_dispositivos_v1 - Platform name (
DispositivoAudio.nombre) - Raw device ID
Scenario: custom name wins over platform name
- GIVEN device has custom name
"Studio Monitors"and platform name"USB Audio" - WHEN the device row is rendered
- THEN
"Studio Monitors"MUST be displayed
Scenario: platform name used when no custom name
- GIVEN no custom name exists for device with platform name
"Sony WH-1000XM5" - WHEN the device row is rendered
- THEN
"Sony WH-1000XM5"MUST be displayed
Scenario: device ID used as last resort
- GIVEN no custom name and platform name is null or empty
- WHEN the device row is rendered
- THEN the raw device ID MUST be displayed (never an empty or null label)
Requirement: Connection status indicator
The Settings device list MUST display a visible connection indicator on each device row. The indicator MUST be green when the device ID matches EstadoEcualizador.dispositivoActualId, and absent (or neutral) otherwise.
Scenario: active device shows green indicator
- GIVEN device
"bt_a2dp:AA:BB"is the current active device - WHEN the device list is rendered in Settings
- THEN that device row MUST show a green indicator
- AND no other row MUST show a green indicator simultaneously
Scenario: indicator updates after device change
- GIVEN device
"builtin_speaker"was active and showing green - WHEN a BT device connects and becomes active
- THEN the green indicator MUST move to the BT device row
- AND the built-in speaker row MUST no longer show it
Scenario: no indicator when toggle is off
- GIVEN
eqMultiDeviceEnabledisfalse - WHEN the Settings screen is viewed
- THEN no connection indicator MUST appear (device list section is hidden)
Requirement: Device edit modal
Tapping a device row in Settings MUST open a bottom sheet containing a rename TextField pre-filled with the device's resolved display name, and an embedded EcualizadorWidget scoped to that device's preset. The modal MUST use showDragHandle: true and isScrollControlled: true.
Scenario: modal opens on device row tap
- GIVEN the device list is visible in Settings
- WHEN the user taps a device row
- THEN a bottom sheet MUST appear
- AND it MUST contain a TextField pre-filled with the current display name (resolved via fallback chain)
- AND it MUST contain an
EcualizadorWidgetshowing that device's preset
Scenario: rename confirmed in modal persists
- GIVEN the edit modal is open for device
"bt_a2dp:AA:BB" - WHEN the user edits the name field to
"Bedroom Speaker"and confirms - THEN
renombrarDispositivo("bt_a2dp:AA:BB", "Bedroom Speaker")MUST be called - AND the device row MUST reflect the new name after the modal closes
Scenario: EQ changes in modal apply to device preset
- GIVEN the edit modal is open for device
"bt_a2dp:AA:BB" - WHEN the user adjusts a band in the embedded
EcualizadorWidget - THEN the change MUST be saved to
presetsDispositivo["bt_a2dp:AA:BB"] - AND the active EQ MUST update immediately if that device is currently active
Scenario: modal dismiss without save leaves state unchanged
- GIVEN the edit modal is open and no changes have been confirmed
- WHEN the user dismisses the sheet by dragging down
- THEN the device name and preset MUST remain unchanged
Scenario: modal is scrollable to prevent EQ widget clipping
- GIVEN the bottom sheet is open on a small screen
- WHEN the user scrolls within the sheet
- THEN the full
EcualizadorWidgetMUST be reachable without clipping