fix(eq): resync EstadoEcualizador with car/notification-initiated changes
A toggle from the Android Auto notification or a preset picked from the car's EQ folder mutated PluriWaveAudioHandler state directly, leaving EstadoEcualizador (and therefore the phone UI) unaware and never persisting the change, so it was lost on the next app restart. Forward the handler's ecualizadorActivo flag through ServicioAudio and, mirroring EstadoRadio's existing playFromMediaId resync, diff it plus presetActual against the cached values on every estadoStream tick, adopting and persisting a divergence via ServicioEcualizador.
This commit is contained in:
@@ -37,7 +37,9 @@ class EstadoEcualizador extends ChangeNotifier {
|
||||
_presetsPersonalizadosService =
|
||||
presetsPersonalizadosService ?? ServicioPresetsPersonalizados(),
|
||||
_dispositivoAudio = dispositivoAudio,
|
||||
_emisoraActualUuid = emisoraActualUuid ?? (() => null);
|
||||
_emisoraActualUuid = emisoraActualUuid ?? (() => null) {
|
||||
_escucharCambiosEqDesdeHandler();
|
||||
}
|
||||
|
||||
final ServicioAudio audio;
|
||||
final ServicioEcualizador servicio;
|
||||
@@ -84,6 +86,20 @@ class EstadoEcualizador extends ChangeNotifier {
|
||||
StreamSubscription<DispositivoAudio>? _deviceSub;
|
||||
Future<void>? _refrescoEnCurso;
|
||||
|
||||
/// Catches a car/notification-initiated EQ change that bypasses this
|
||||
/// class entirely (eq-sync-superficies): `accionEqToggle` calls
|
||||
/// `PluriWaveAudioHandler.setEcualizadorActivo` directly, and
|
||||
/// `seleccionarPresetEqPorMediaId` calls `aplicarPreset` directly — both
|
||||
/// mutate ONLY the handler's own `_ecualizadorActivo`/`_presetActual`
|
||||
/// fields, never [audio]'s owner ([EstadoEcualizador]). Mirrors the exact
|
||||
/// shape `EstadoRadio._escucharErroresReproduccion` already uses for the
|
||||
/// equivalent `playFromMediaId` gap: on every [ServicioAudio.estadoStream]
|
||||
/// tick (which the handler already re-emits on any EQ change via
|
||||
/// `_actualizarControlesEq()`, regardless of who triggered it), compare
|
||||
/// the handler's current EQ state against our cached copy and adopt it on
|
||||
/// divergence.
|
||||
StreamSubscription<EstadoReproduccion>? _suscripcionEstadoAudioEq;
|
||||
|
||||
PresetEcualizador get presetActual => _presetActual;
|
||||
PresetEcualizador get presetPrincipal => _presetPrincipal;
|
||||
bool get activo => _activo;
|
||||
@@ -337,6 +353,58 @@ class EstadoEcualizador extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Subscribes to [ServicioAudio.estadoStream] to catch a
|
||||
/// car/notification-initiated EQ change (see [_suscripcionEstadoAudioEq]
|
||||
/// doc for the full rationale).
|
||||
void _escucharCambiosEqDesdeHandler() {
|
||||
_suscripcionEstadoAudioEq = audio.estadoStream.listen((_) {
|
||||
unawaited(_resincronizarConHandler());
|
||||
});
|
||||
}
|
||||
|
||||
/// Compares the handler's live EQ state ([ServicioAudio.ecualizadorActivo],
|
||||
/// [ServicioAudio.presetActual]) against our cached [_activo]/
|
||||
/// [_presetActual] and adopts the handler's value on divergence.
|
||||
///
|
||||
/// Deliberately never calls back into [audio] here (no
|
||||
/// `setEcualizadorActivo`/`aplicarPreset`): doing so would re-trigger the
|
||||
/// handler's own `_actualizarControlesEq()` re-push, which would tick
|
||||
/// [ServicioAudio.estadoStream] again and re-enter this method forever.
|
||||
/// Only a local field write, [servicio] persistence and [notifyListeners]
|
||||
/// happen here, so a divergence is resolved in a single pass.
|
||||
///
|
||||
/// Wrapped in try/catch like every other handler-facing read in this
|
||||
/// class (e.g. [_sembrarDispositivoActual]): a test double or an
|
||||
/// unexpected platform state that makes [audio]'s EQ getters unavailable
|
||||
/// must never crash the stream subscription — it just skips this tick.
|
||||
Future<void> _resincronizarConHandler() async {
|
||||
try {
|
||||
final activoHandler = audio.ecualizadorActivo;
|
||||
final presetHandler = audio.presetActual;
|
||||
|
||||
final activoDiverge = activoHandler != _activo;
|
||||
final presetDiverge = presetHandler != _presetActual;
|
||||
if (!activoDiverge && !presetDiverge) return;
|
||||
|
||||
if (activoDiverge) {
|
||||
_activo = activoHandler;
|
||||
// Closes the persistence gap: `PluriWaveAudioHandler` never
|
||||
// persists anything itself (it must stay headless-constructible,
|
||||
// with zero SharedPreferences/Provider access) — [servicio] is the
|
||||
// only owner of EQ persistence, so a car/notification toggle must
|
||||
// be saved HERE or it is lost on the next process restart.
|
||||
await servicio.guardarActivo(activoHandler);
|
||||
}
|
||||
if (presetDiverge) {
|
||||
_presetActual = presetHandler;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
} catch (_) {
|
||||
// See doc above — never let a resync failure crash the app.
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies [preset] to the audio engine and tracks it as current
|
||||
/// WITHOUT persisting it (used when switching stations).
|
||||
Future<void> aplicarPresetActivo(PresetEcualizador preset) async {
|
||||
@@ -673,6 +741,7 @@ class EstadoEcualizador extends ChangeNotifier {
|
||||
@override
|
||||
void dispose() {
|
||||
_deviceSub?.cancel();
|
||||
_suscripcionEstadoAudioEq?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,6 +582,13 @@ class ServicioAudio {
|
||||
bool get ecualizadorDisponible => _handler.ecualizadorDisponible;
|
||||
PresetEcualizador get presetActual => _handler.presetActual;
|
||||
|
||||
/// Forwards the handler's own on/off flag (eq-sync-superficies): a
|
||||
/// car/notification toggle (`accionEqToggle`) mutates
|
||||
/// `PluriWaveAudioHandler._ecualizadorActivo` directly, bypassing
|
||||
/// [setEcualizadorActivo] entirely. [EstadoEcualizador] polls this getter
|
||||
/// on every [estadoStream] tick to detect and resync that divergence.
|
||||
bool get ecualizadorActivo => _handler.ecualizadorActivo;
|
||||
|
||||
Future<void> aplicarPreset(PresetEcualizador preset) =>
|
||||
_handler.aplicarPreset(preset);
|
||||
Future<void> setEcualizadorActivo(bool activo) =>
|
||||
|
||||
Reference in New Issue
Block a user