refactor(state): extract export/import service and equalizer state from EstadoRadio
- 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
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../modelos/preset_ecualizador.dart';
|
||||
import '../servicios/servicio_audio.dart';
|
||||
import '../servicios/servicio_ecualizador.dart';
|
||||
|
||||
/// Equalizer state extracted from `EstadoRadio` (S4-R1).
|
||||
///
|
||||
/// Owns the main preset, the per-station preset map, the current (applied)
|
||||
/// preset and the enabled flag, plus their persistence through
|
||||
/// [ServicioEcualizador] and their application through [ServicioAudio].
|
||||
/// Notifies ONLY its own listeners — EQ changes must not rebuild
|
||||
/// `EstadoRadio` consumers (S4-R1-A, S4-R5).
|
||||
class EstadoEcualizador extends ChangeNotifier {
|
||||
EstadoEcualizador({
|
||||
required this.audio,
|
||||
ServicioEcualizador? servicio,
|
||||
String? Function()? emisoraActualUuid,
|
||||
}) : servicio = servicio ?? ServicioEcualizador(),
|
||||
_emisoraActualUuid = emisoraActualUuid ?? (() => null);
|
||||
|
||||
final ServicioAudio audio;
|
||||
final ServicioEcualizador servicio;
|
||||
|
||||
/// Callback into the owner (EstadoRadio) for the currently playing station;
|
||||
/// keeps this notifier free of any station-list coupling.
|
||||
final String? Function() _emisoraActualUuid;
|
||||
|
||||
final Map<String, PresetEcualizador> _presetsEmisoraMap = {};
|
||||
PresetEcualizador _presetPrincipal = PresetEcualizador.flat;
|
||||
PresetEcualizador _presetActual = PresetEcualizador.flat;
|
||||
bool _activo = true;
|
||||
|
||||
PresetEcualizador get presetActual => _presetActual;
|
||||
PresetEcualizador get presetPrincipal => _presetPrincipal;
|
||||
bool get activo => _activo;
|
||||
bool get disponible => audio.ecualizadorDisponible;
|
||||
Map<String, PresetEcualizador> get presetsPorEmisora =>
|
||||
Map.unmodifiable(_presetsEmisoraMap);
|
||||
|
||||
bool get emisoraActualTienePresetPropio {
|
||||
final uuid = _emisoraActualUuid();
|
||||
if (uuid == null) return false;
|
||||
return tienePresetPorEmisora(uuid);
|
||||
}
|
||||
|
||||
bool tienePresetPorEmisora(String uuid) =>
|
||||
_presetsEmisoraMap.containsKey(uuid);
|
||||
|
||||
PresetEcualizador? presetPorEmisora(String uuid) => _presetsEmisoraMap[uuid];
|
||||
|
||||
PresetEcualizador presetParaEmisora(String uuid) =>
|
||||
_presetsEmisoraMap[uuid] ?? _presetPrincipal;
|
||||
|
||||
/// Loads the persisted EQ configuration and applies it to the audio engine.
|
||||
Future<void> cargarPersistido() async {
|
||||
try {
|
||||
final config = await servicio.cargar();
|
||||
_presetPrincipal = config.principal;
|
||||
_presetActual = config.principal;
|
||||
_activo = config.activo;
|
||||
_presetsEmisoraMap
|
||||
..clear()
|
||||
..addAll(config.porEmisora);
|
||||
await audio.setEcualizadorActivo(_activo);
|
||||
await audio.aplicarPreset(_presetPrincipal);
|
||||
} catch (_) {
|
||||
_presetPrincipal = PresetEcualizador.flat;
|
||||
_presetActual = PresetEcualizador.flat;
|
||||
_activo = true;
|
||||
_presetsEmisoraMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies [preset] to the audio engine and tracks it as current
|
||||
/// WITHOUT persisting it (used when switching stations).
|
||||
Future<void> aplicarPresetActivo(PresetEcualizador preset) async {
|
||||
_presetActual = preset;
|
||||
await audio.aplicarPreset(preset);
|
||||
}
|
||||
|
||||
Future<void> cambiarPresetPrincipal(
|
||||
PresetEcualizador preset, {
|
||||
bool notificar = true,
|
||||
}) async {
|
||||
_presetPrincipal = preset;
|
||||
await servicio.guardarPrincipal(preset);
|
||||
|
||||
final uuid = _emisoraActualUuid();
|
||||
final puedeAplicarAhora =
|
||||
uuid == null || !_presetsEmisoraMap.containsKey(uuid);
|
||||
if (puedeAplicarAhora) {
|
||||
await aplicarPresetActivo(preset);
|
||||
}
|
||||
|
||||
if (notificar) notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> guardarPresetPorEmisora(
|
||||
String uuid,
|
||||
PresetEcualizador preset, {
|
||||
bool notificar = true,
|
||||
}) async {
|
||||
_presetsEmisoraMap[uuid] = preset;
|
||||
await servicio.guardarPorEmisora(uuid, preset);
|
||||
if (_emisoraActualUuid() == uuid) {
|
||||
await aplicarPresetActivo(preset);
|
||||
}
|
||||
if (notificar) notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> habilitarPresetPorEmisora(
|
||||
String uuid, {
|
||||
PresetEcualizador? base,
|
||||
bool notificar = true,
|
||||
}) async {
|
||||
final presetBase = base ?? _presetsEmisoraMap[uuid] ?? _presetPrincipal;
|
||||
await guardarPresetPorEmisora(uuid, presetBase, notificar: notificar);
|
||||
}
|
||||
|
||||
Future<void> deshabilitarPresetPorEmisora(
|
||||
String uuid, {
|
||||
bool notificar = true,
|
||||
}) async {
|
||||
_presetsEmisoraMap.remove(uuid);
|
||||
await servicio.eliminarPorEmisora(uuid);
|
||||
if (_emisoraActualUuid() == uuid) {
|
||||
await aplicarPresetActivo(_presetPrincipal);
|
||||
}
|
||||
if (notificar) notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> cambiarModoEmisoraActual({required bool usarPropio}) async {
|
||||
final uuid = _emisoraActualUuid();
|
||||
if (uuid == null) return;
|
||||
if (usarPropio) {
|
||||
await habilitarPresetPorEmisora(uuid);
|
||||
} else {
|
||||
await deshabilitarPresetPorEmisora(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cambiarActivo(bool activo) async {
|
||||
_activo = activo;
|
||||
await servicio.guardarActivo(activo);
|
||||
await audio.setEcualizadorActivo(activo);
|
||||
if (activo) {
|
||||
await audio.aplicarPreset(_presetActual);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> cambiarPreset(
|
||||
PresetEcualizador preset, {
|
||||
bool guardarPorEmisora = true,
|
||||
}) async {
|
||||
final uuid = _emisoraActualUuid();
|
||||
final usarPresetPropio =
|
||||
guardarPorEmisora &&
|
||||
uuid != null &&
|
||||
_presetsEmisoraMap.containsKey(uuid);
|
||||
|
||||
if (usarPresetPropio) {
|
||||
await guardarPresetPorEmisora(uuid, preset);
|
||||
return;
|
||||
}
|
||||
await cambiarPresetPrincipal(preset);
|
||||
}
|
||||
|
||||
Future<void> cambiarBanda(int index, double db) async {
|
||||
final bandas = List<double>.from(_presetActual.bandas);
|
||||
if (index < 0 || index >= bandas.length) return;
|
||||
|
||||
bandas[index] = db;
|
||||
final modificado = PresetEcualizador(
|
||||
nombre: 'Personalizado',
|
||||
bandas: bandas,
|
||||
);
|
||||
await cambiarPreset(modificado);
|
||||
}
|
||||
|
||||
/// Replaces the whole EQ configuration (backup import path): persists it,
|
||||
/// re-applies the preset effective for the current station and notifies.
|
||||
Future<void> importarConfiguracion({
|
||||
required PresetEcualizador principal,
|
||||
required Map<String, PresetEcualizador> porEmisora,
|
||||
}) async {
|
||||
_presetPrincipal = principal;
|
||||
_presetsEmisoraMap
|
||||
..clear()
|
||||
..addAll(porEmisora);
|
||||
|
||||
await servicio.guardarConfiguracion(
|
||||
ConfiguracionEcualizador(
|
||||
principal: _presetPrincipal,
|
||||
porEmisora: _presetsEmisoraMap,
|
||||
activo: _activo,
|
||||
),
|
||||
);
|
||||
|
||||
final uuid = _emisoraActualUuid();
|
||||
await aplicarPresetActivo(
|
||||
uuid == null ? _presetPrincipal : presetParaEmisora(uuid),
|
||||
);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user