- MainActivity: onListen re-emits the current active device and registers
the audio device callback idempotently, so recreated activities resync
instead of freezing the active-device id on a disconnected device.
- servicio_dispositivo_audio: resubscribir() re-opens the event channel;
estado_ecualizador exposes refrescarDispositivoActual() with an
in-flight guard, invoked on app resume and when opening advanced EQ
options, clearing stale green-dot device selections.
- navegacion_auto/servicio_audio: new 'Personalizado' browse tree in
Android Auto (5 band folders, 13 gain steps each) applied live via
setBanda; preset and gain taps persist at device level when
multi-device EQ is active and respect station/matrix overrides,
with apply-before-persist ordering and children-changed notifications.
- l10n: regenerate stale generated localizations; add rxdart as direct
dependency for the subscribeToChildren override.
The advanced EQ device list kept the green-dot selection on the last
connected Bluetooth device after it disconnected, instead of falling
back to the default preset.
- MainActivity.kt: onAudioDevicesRemoved recomputed the active output
device via AudioManager.getDevices(), which can still momentarily
report the just-removed sink (observed on Bluetooth A2DP). Removed
device ids are now excluded explicitly instead of trusting
getDevices() to already be current.
- estado_ecualizador.dart: cambiarMultiDeviceEnabled() re-seeds
dispositivoActualId from a fresh query when the toggle turns back
on, matching cargarPersistido(), so a stale id from before the
toggle flip can't leave the dot pinned to a disconnected device.
Dart half of bt-device-identity. EstadoEcualizador now caches each
device's platform-reported name in memory so the settings screen
shows the device's own Bluetooth name instead of its raw id when no
custom rename exists, and skips auto-creating preset entries for the
composite-placeholder sentinel. Enabling multi-device EQ triggers the
Bluetooth permission request through the new channel contract. A
flag-guarded one-time migration purges only entries keyed by the
exact literal placeholder id from the three per-device preference
maps, since those collided entries cannot be attributed to a device.
Work unit 2/2 of bt-device-identity (Dart state + migration).
_onDispositivoCambiado() bootstrapped a device-level preset entry for
every never-seen device id, including the built-in speaker. That
persistent level-3 entry masked later global-preset edits (level 3
beats level 4 on every resolution), so disconnecting a BT device or
cold-starting without one could leave the EQ stuck on an outdated
copy instead of the current global preset.
The base speaker is now excluded from the first-seen bootstrap:
disconnect and cold start always resolve through the live hierarchy.
BT/wired/USB devices keep their bootstrap behavior unchanged.
Fix multi-device EQ auto-switching by calling obtenerDispositivoActual()
during cargarPersistido() to seed the initial device ID. Add device
management modal with rename support, EQ preset editing, and connection
status indicator. Translate device UI keys to all 13 locales.
Introduce multi-device EQ support allowing each audio output device
(built-in speaker, wired, USB, individual Bluetooth by MAC) to have
its own equalizer preset, combined with existing per-station presets
for a full station×device matrix.
- Add DispositivoAudio model and ServicioDispositivoAudio interface
- Add Android platform channel (AudioDeviceCallback) for device detection
- Add iOS AudioDevicesPlugin (AVAudioSession route tracking)
- Extend ServicioEcualizador with device and matrix persistence keys
- Implement 4-level resolution: matrix > station > device > global
- Add advanced EQ settings section with feature toggle (off by default)
- Extend export/import to v3 with backward compatibility
- 184 tests passing, zero analyzer issues
- New ServicioExportImport owns the v2 backup envelope, pretty JSON encode and graceful decode; byte-compatible with existing exports, locked by a round-trip test
- pantalla_ajustes delegates backup serialization to the service (inline jsonDecode/jsonEncode removed)
- New EstadoEcualizador ChangeNotifier owns all EQ state and persistence (principal/current/per-station presets, active flag), exposed via its own provider so EQ changes no longer rebuild EstadoRadio consumers
- EstadoRadio slims down ~210 lines and keeps 15 delegating compat members marked TODO(S4b) for the next slice to remove
- Player EQ toggle rewired to the new provider to avoid going stale
- 4 new tests (103 total green), flutter analyze clean