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.
265 lines
8.4 KiB
Dart
265 lines
8.4 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import '../modelos/preset_ecualizador.dart';
|
|
|
|
class ConfiguracionEcualizador {
|
|
const ConfiguracionEcualizador({
|
|
required this.principal,
|
|
required this.porEmisora,
|
|
this.activo = true,
|
|
this.eqMultiDeviceEnabled = false,
|
|
this.presetsDispositivo = const {},
|
|
this.presetsMatriz = const {},
|
|
this.nombresDispositivos = const {},
|
|
});
|
|
|
|
final PresetEcualizador principal;
|
|
final Map<String, PresetEcualizador> porEmisora;
|
|
final bool activo;
|
|
|
|
/// Feature toggle: when false all multi-device logic is bypassed.
|
|
final bool eqMultiDeviceEnabled;
|
|
|
|
/// Per-device presets: deviceId → PresetEcualizador.
|
|
final Map<String, PresetEcualizador> presetsDispositivo;
|
|
|
|
/// Matrix presets: "stationUuid:deviceId" → PresetEcualizador.
|
|
final Map<String, PresetEcualizador> presetsMatriz;
|
|
|
|
/// Custom display names for devices: deviceId → custom name.
|
|
final Map<String, String> nombresDispositivos;
|
|
}
|
|
|
|
class ServicioEcualizador {
|
|
ServicioEcualizador({SharedPreferences? prefs}) : _prefs = prefs;
|
|
|
|
static const _keyPresetPrincipal = 'eq_preset_principal_v1';
|
|
static const _keyPresetsPorEmisora = 'eq_presets_por_emisora_v1';
|
|
static const _keyActivo = 'eq_activo_v1';
|
|
static const _keyMultiDeviceEnabled = 'eq_multi_device_enabled_v1';
|
|
static const _keyPresetsPorDispositivo = 'eq_preset_por_dispositivo_v1';
|
|
static const _keyPresetsMatriz = 'eq_presets_matriz_v1';
|
|
static const _keyNombresDispositivos = 'eq_nombres_dispositivos_v1';
|
|
|
|
final SharedPreferences? _prefs;
|
|
|
|
/// Injected startup instance (S3-R4); getInstance() is only a fallback.
|
|
Future<SharedPreferences> _resolverPrefs() async =>
|
|
_prefs ?? SharedPreferences.getInstance();
|
|
|
|
Future<ConfiguracionEcualizador> cargar() async {
|
|
final prefs = await _resolverPrefs();
|
|
final principal = _leerPresetPrincipal(prefs);
|
|
final porEmisora = _leerPresetsPorEmisora(prefs);
|
|
final presetsDispositivo = _leerMapa(prefs, _keyPresetsPorDispositivo);
|
|
final presetsMatriz = _leerMapa(prefs, _keyPresetsMatriz);
|
|
final nombresDispositivos = _leerMapaStrings(prefs, _keyNombresDispositivos);
|
|
return ConfiguracionEcualizador(
|
|
principal: principal,
|
|
porEmisora: porEmisora,
|
|
activo: prefs.getBool(_keyActivo) ?? true,
|
|
eqMultiDeviceEnabled: prefs.getBool(_keyMultiDeviceEnabled) ?? false,
|
|
presetsDispositivo: presetsDispositivo,
|
|
presetsMatriz: presetsMatriz,
|
|
nombresDispositivos: nombresDispositivos,
|
|
);
|
|
}
|
|
|
|
Future<void> guardarPrincipal(PresetEcualizador preset) async {
|
|
final prefs = await _resolverPrefs();
|
|
await prefs.setString(_keyPresetPrincipal, jsonEncode(preset.toJson()));
|
|
}
|
|
|
|
Future<void> guardarPorEmisora(String uuid, PresetEcualizador preset) async {
|
|
final prefs = await _resolverPrefs();
|
|
final mapa = _leerPresetsPorEmisora(prefs);
|
|
mapa[uuid] = preset;
|
|
await _guardarPresetsPorEmisora(prefs, mapa);
|
|
}
|
|
|
|
Future<void> guardarActivo(bool activo) async {
|
|
final prefs = await _resolverPrefs();
|
|
await prefs.setBool(_keyActivo, activo);
|
|
}
|
|
|
|
Future<void> eliminarPorEmisora(String uuid) async {
|
|
final prefs = await _resolverPrefs();
|
|
final mapa = _leerPresetsPorEmisora(prefs);
|
|
mapa.remove(uuid);
|
|
await _guardarPresetsPorEmisora(prefs, mapa);
|
|
}
|
|
|
|
Future<void> guardarConfiguracion(ConfiguracionEcualizador config) async {
|
|
final prefs = await _resolverPrefs();
|
|
await prefs.setString(
|
|
_keyPresetPrincipal,
|
|
jsonEncode(config.principal.toJson()),
|
|
);
|
|
await _guardarPresetsPorEmisora(prefs, config.porEmisora);
|
|
await prefs.setBool(_keyActivo, config.activo);
|
|
await prefs.setBool(_keyMultiDeviceEnabled, config.eqMultiDeviceEnabled);
|
|
await _guardarMapa(
|
|
prefs,
|
|
_keyPresetsPorDispositivo,
|
|
config.presetsDispositivo,
|
|
);
|
|
await _guardarMapa(prefs, _keyPresetsMatriz, config.presetsMatriz);
|
|
await _guardarMapaStrings(
|
|
prefs,
|
|
_keyNombresDispositivos,
|
|
config.nombresDispositivos,
|
|
);
|
|
}
|
|
|
|
/// Persists the multi-device feature toggle.
|
|
Future<void> guardarToggleMultiDispositivo(bool habilitado) async {
|
|
final prefs = await _resolverPrefs();
|
|
await prefs.setBool(_keyMultiDeviceEnabled, habilitado);
|
|
}
|
|
|
|
/// Saves a per-device preset.
|
|
Future<void> guardarPresetDispositivo(
|
|
String deviceId,
|
|
PresetEcualizador preset,
|
|
) async {
|
|
final prefs = await _resolverPrefs();
|
|
final mapa = _leerMapa(prefs, _keyPresetsPorDispositivo);
|
|
mapa[deviceId] = preset;
|
|
await _guardarMapa(prefs, _keyPresetsPorDispositivo, mapa);
|
|
}
|
|
|
|
/// Saves a matrix (stationUuid:deviceId) preset entry.
|
|
Future<void> guardarPresetMatriz(
|
|
String clave,
|
|
PresetEcualizador preset,
|
|
) async {
|
|
final prefs = await _resolverPrefs();
|
|
final mapa = _leerMapa(prefs, _keyPresetsMatriz);
|
|
mapa[clave] = preset;
|
|
await _guardarMapa(prefs, _keyPresetsMatriz, mapa);
|
|
}
|
|
|
|
/// Removes a per-device preset entry.
|
|
Future<void> eliminarPresetDispositivo(String deviceId) async {
|
|
final prefs = await _resolverPrefs();
|
|
final mapa = _leerMapa(prefs, _keyPresetsPorDispositivo);
|
|
mapa.remove(deviceId);
|
|
await _guardarMapa(prefs, _keyPresetsPorDispositivo, mapa);
|
|
}
|
|
|
|
/// Removes a matrix preset entry.
|
|
Future<void> eliminarPresetMatriz(String clave) async {
|
|
final prefs = await _resolverPrefs();
|
|
final mapa = _leerMapa(prefs, _keyPresetsMatriz);
|
|
mapa.remove(clave);
|
|
await _guardarMapa(prefs, _keyPresetsMatriz, mapa);
|
|
}
|
|
|
|
/// Returns the persisted device custom names map.
|
|
Future<Map<String, String>> cargarNombresDispositivos() async {
|
|
final prefs = await _resolverPrefs();
|
|
return _leerMapaStrings(prefs, _keyNombresDispositivos);
|
|
}
|
|
|
|
/// Persists the device custom names map.
|
|
Future<void> guardarNombresDispositivos(Map<String, String> nombres) async {
|
|
final prefs = await _resolverPrefs();
|
|
await _guardarMapaStrings(prefs, _keyNombresDispositivos, nombres);
|
|
}
|
|
|
|
/// Reads a `Map<String, PresetEcualizador>` from a SharedPreferences JSON key.
|
|
Map<String, PresetEcualizador> _leerMapa(
|
|
SharedPreferences prefs,
|
|
String key,
|
|
) {
|
|
final raw = prefs.getString(key);
|
|
if (raw == null || raw.isEmpty) return {};
|
|
try {
|
|
final data = Map<String, dynamic>.from(jsonDecode(raw) as Map);
|
|
return data.map(
|
|
(k, v) => MapEntry(
|
|
k,
|
|
PresetEcualizador.desdeJson(Map<String, dynamic>.from(v as Map)),
|
|
),
|
|
);
|
|
} catch (_) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
Future<void> _guardarMapa(
|
|
SharedPreferences prefs,
|
|
String key,
|
|
Map<String, PresetEcualizador> mapa,
|
|
) async {
|
|
final serializado = mapa.map((k, v) => MapEntry(k, v.toJson()));
|
|
await prefs.setString(key, jsonEncode(serializado));
|
|
}
|
|
|
|
/// Reads a `Map<String, String>` from a SharedPreferences JSON key.
|
|
Map<String, String> _leerMapaStrings(SharedPreferences prefs, String key) {
|
|
final raw = prefs.getString(key);
|
|
if (raw == null || raw.isEmpty) return {};
|
|
try {
|
|
final data = Map<String, dynamic>.from(jsonDecode(raw) as Map);
|
|
return data.map((k, v) => MapEntry(k, v as String));
|
|
} catch (_) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
Future<void> _guardarMapaStrings(
|
|
SharedPreferences prefs,
|
|
String key,
|
|
Map<String, String> mapa,
|
|
) async {
|
|
await prefs.setString(key, jsonEncode(mapa));
|
|
}
|
|
|
|
PresetEcualizador _leerPresetPrincipal(SharedPreferences prefs) {
|
|
final raw = prefs.getString(_keyPresetPrincipal);
|
|
if (raw == null || raw.isEmpty) {
|
|
return PresetEcualizador.flat;
|
|
}
|
|
try {
|
|
return PresetEcualizador.desdeJson(
|
|
Map<String, dynamic>.from(jsonDecode(raw) as Map),
|
|
);
|
|
} catch (_) {
|
|
return PresetEcualizador.flat;
|
|
}
|
|
}
|
|
|
|
Map<String, PresetEcualizador> _leerPresetsPorEmisora(
|
|
SharedPreferences prefs,
|
|
) {
|
|
final raw = prefs.getString(_keyPresetsPorEmisora);
|
|
if (raw == null || raw.isEmpty) {
|
|
return {};
|
|
}
|
|
try {
|
|
final data = Map<String, dynamic>.from(jsonDecode(raw) as Map);
|
|
return data.map(
|
|
(uuid, preset) => MapEntry(
|
|
uuid,
|
|
PresetEcualizador.desdeJson(Map<String, dynamic>.from(preset as Map)),
|
|
),
|
|
);
|
|
} catch (_) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
Future<void> _guardarPresetsPorEmisora(
|
|
SharedPreferences prefs,
|
|
Map<String, PresetEcualizador> mapa,
|
|
) async {
|
|
final serializado = mapa.map(
|
|
(uuid, preset) => MapEntry(uuid, preset.toJson()),
|
|
);
|
|
await prefs.setString(_keyPresetsPorEmisora, jsonEncode(serializado));
|
|
}
|
|
}
|