fix(devices): cache platform device names, dedupe placeholder ids, purge collided EQ entries
Build & Deploy PluriWave / Análisis de código (push) Successful in 36s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 1m47s

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).
This commit is contained in:
2026-07-11 00:25:00 +02:00
parent 224763bca3
commit b17c582572
11 changed files with 711 additions and 7 deletions
+58
View File
@@ -43,6 +43,13 @@ class ServicioEcualizador {
static const _keyPresetsMatriz = 'eq_presets_matriz_v1';
static const _keyNombresDispositivos = 'eq_nombres_dispositivos_v1';
/// bt-device-identity ADR-5: guard flag for the one-time placeholder purge.
static const _keyPlaceholderPurgaHecha = 'eq_placeholder_purge_done_v1';
/// bt-device-identity ADR-3: the exact OS placeholder MAC, in the
/// `bt_a2dp:`-prefixed id shape used across all device-keyed SP maps.
static const _placeholderMacLiteral = 'bt_a2dp:02:00:00:00:00:00';
final SharedPreferences? _prefs;
/// Injected startup instance (S3-R4); getInstance() is only a fallback.
@@ -50,6 +57,7 @@ class ServicioEcualizador {
_prefs ?? SharedPreferences.getInstance();
Future<ConfiguracionEcualizador> cargar() async {
await migrarClavesPlaceholder();
final prefs = await _resolverPrefs();
final principal = _leerPresetPrincipal(prefs);
final porEmisora = _leerPresetsPorEmisora(prefs);
@@ -67,6 +75,56 @@ class ServicioEcualizador {
);
}
/// One-time guarded migration (bt-device-identity ADR-5): purges entries
/// keyed by the exact OS placeholder MAC ([_placeholderMacLiteral]) from
/// all three device-keyed SP maps. Idempotent — short-circuits via
/// [_keyPlaceholderPurgaHecha] after the first successful run. Every other
/// entry (including near-miss keys) is preserved byte-for-byte.
Future<void> migrarClavesPlaceholder() async {
final prefs = await _resolverPrefs();
if (prefs.getBool(_keyPlaceholderPurgaHecha) ?? false) return;
final presetsPorDispositivo = _leerMapa(prefs, _keyPresetsPorDispositivo);
if (presetsPorDispositivo.remove(_placeholderMacLiteral) != null) {
await _guardarMapa(
prefs,
_keyPresetsPorDispositivo,
presetsPorDispositivo,
);
}
// Matrix keys are "stationUuid:deviceId"; split on the FIRST colon only
// (station UUIDs are RFC4122 and contain no colons — multi-device-eq
// ADR-3), since deviceId itself may contain colons (e.g. a MAC-based id).
final presetsMatriz = _leerMapa(prefs, _keyPresetsMatriz);
final clavesMatrizAPurgar = presetsMatriz.keys.where((clave) {
final separador = clave.indexOf(':');
if (separador == -1) return false;
final deviceIdSegmento = clave.substring(separador + 1);
return deviceIdSegmento == _placeholderMacLiteral;
}).toList();
if (clavesMatrizAPurgar.isNotEmpty) {
for (final clave in clavesMatrizAPurgar) {
presetsMatriz.remove(clave);
}
await _guardarMapa(prefs, _keyPresetsMatriz, presetsMatriz);
}
final nombresDispositivos = _leerMapaStrings(
prefs,
_keyNombresDispositivos,
);
if (nombresDispositivos.remove(_placeholderMacLiteral) != null) {
await _guardarMapaStrings(
prefs,
_keyNombresDispositivos,
nombresDispositivos,
);
}
await prefs.setBool(_keyPlaceholderPurgaHecha, true);
}
Future<void> guardarPrincipal(PresetEcualizador preset) async {
final prefs = await _resolverPrefs();
await prefs.setString(_keyPresetPrincipal, jsonEncode(preset.toJson()));