fix(devices): cache platform device names, dedupe placeholder ids, purge collided EQ entries
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:
@@ -64,6 +64,7 @@ void main() {
|
||||
Future<EstadoRadio> crearEstado({
|
||||
bool eqMultiDeviceEnabled = false,
|
||||
Map<String, PresetEcualizador> presetsDispositivo = const {},
|
||||
FakeServicioDispositivoAudio? dispositivoAudio,
|
||||
}) async {
|
||||
final estado = EstadoRadio(
|
||||
audio: FakeServicioAudio(),
|
||||
@@ -76,6 +77,7 @@ void main() {
|
||||
servicioGrabacion: _FakeGrabacion(),
|
||||
resolverArchivoCustom: _archivoCustomVacio,
|
||||
iniciarAutomaticamente: false,
|
||||
dispositivoAudio: dispositivoAudio,
|
||||
);
|
||||
await estado.ecualizador.cargarPersistido();
|
||||
return estado;
|
||||
@@ -99,6 +101,7 @@ void main() {
|
||||
Map<String, PresetEcualizador>? presetsDispositivo,
|
||||
Map<String, String>? nombresDispositivos,
|
||||
String? activeDeviceId,
|
||||
String nombrePlataforma = 'BT Speaker',
|
||||
}) async {
|
||||
final fakeDispositivo = activeDeviceId != null
|
||||
? (FakeServicioDispositivoAudio()
|
||||
@@ -106,7 +109,7 @@ void main() {
|
||||
DispositivoAudio(
|
||||
id: activeDeviceId,
|
||||
tipo: TipoDispositivo.bluetoothA2dp,
|
||||
nombre: 'BT Speaker',
|
||||
nombre: nombrePlataforma,
|
||||
),
|
||||
))
|
||||
: null;
|
||||
@@ -380,6 +383,134 @@ void main() {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ── bt-device-identity Phase 4: display fix + permission trigger ─────────
|
||||
|
||||
group('_SeccionEcualizadorAvanzado — bt-device-identity Phase 4', () {
|
||||
// 4.1 — new behavior: the cached platform name (not '') now feeds
|
||||
// nombreVisible, so a device with no custom rename shows its real name.
|
||||
testWidgets('4.1 platform name displays with no custom rename', (
|
||||
tester,
|
||||
) async {
|
||||
setLargeSurface(tester);
|
||||
_suppressListTileInkAssertion();
|
||||
const deviceId = 'bt_a2dp:AA:BB:CC:DD:EE:FF';
|
||||
final estado = await crearEstadoConNombres(
|
||||
presetsDispositivo: {deviceId: PresetEcualizador.rock},
|
||||
activeDeviceId: deviceId,
|
||||
nombrePlataforma: 'AirPods Pro',
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(buildAjustes(estado));
|
||||
await pumpStable(tester);
|
||||
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Known audio devices'),
|
||||
300,
|
||||
scrollable: find.byType(Scrollable).first,
|
||||
);
|
||||
await pumpStable(tester);
|
||||
|
||||
expect(find.text('AirPods Pro'), findsOneWidget);
|
||||
expect(find.text(deviceId), findsNothing);
|
||||
});
|
||||
|
||||
// 4.4 — triangulation companion: custom rename still wins even though
|
||||
// the row now also has a cached platform name available.
|
||||
testWidgets('4.4 custom rename overrides platform name', (tester) async {
|
||||
setLargeSurface(tester);
|
||||
_suppressListTileInkAssertion();
|
||||
const deviceId = 'bt_a2dp:AA:BB:CC:DD:EE:FF';
|
||||
final estado = await crearEstadoConNombres(
|
||||
presetsDispositivo: {deviceId: PresetEcualizador.rock},
|
||||
activeDeviceId: deviceId,
|
||||
nombrePlataforma: 'AirPods Pro',
|
||||
nombresDispositivos: {deviceId: 'My Headphones'},
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(buildAjustes(estado));
|
||||
await pumpStable(tester);
|
||||
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Known audio devices'),
|
||||
300,
|
||||
scrollable: find.byType(Scrollable).first,
|
||||
);
|
||||
await pumpStable(tester);
|
||||
|
||||
expect(find.text('My Headphones'), findsOneWidget);
|
||||
expect(find.text('AirPods Pro'), findsNothing);
|
||||
});
|
||||
|
||||
// 4.5 — approval test (regression-lock): a device never seen on the
|
||||
// stream has no cached platform name, so legacy raw-id fallback holds.
|
||||
testWidgets('4.5 no platform name yet falls back to raw id', (
|
||||
tester,
|
||||
) async {
|
||||
setLargeSurface(tester);
|
||||
_suppressListTileInkAssertion();
|
||||
const deviceId = 'bt_a2dp:AA:BB:CC:DD:EE:FF';
|
||||
final estado = await crearEstadoConNombres(
|
||||
presetsDispositivo: {deviceId: PresetEcualizador.rock},
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(buildAjustes(estado));
|
||||
await pumpStable(tester);
|
||||
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Known audio devices'),
|
||||
300,
|
||||
scrollable: find.byType(Scrollable).first,
|
||||
);
|
||||
await pumpStable(tester);
|
||||
|
||||
expect(find.text(deviceId), findsOneWidget);
|
||||
});
|
||||
|
||||
// 4.6 — permission trigger point: turning the toggle ON requests
|
||||
// BLUETOOTH_CONNECT; turning it back OFF must not re-fire the request.
|
||||
testWidgets('4.6 permission call fires on device-management open', (
|
||||
tester,
|
||||
) async {
|
||||
setLargeSurface(tester);
|
||||
_suppressListTileInkAssertion();
|
||||
final fakeDispositivo = FakeServicioDispositivoAudio();
|
||||
final estado = await crearEstado(
|
||||
eqMultiDeviceEnabled: false,
|
||||
dispositivoAudio: fakeDispositivo,
|
||||
);
|
||||
addTearDown(estado.dispose);
|
||||
|
||||
await tester.pumpWidget(buildAjustes(estado));
|
||||
await pumpStable(tester);
|
||||
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Advanced Equalization Options'),
|
||||
300,
|
||||
scrollable: find.byType(Scrollable).first,
|
||||
);
|
||||
await pumpStable(tester);
|
||||
|
||||
expect(fakeDispositivo.solicitarPermisoBluetoothCalls, equals(0));
|
||||
|
||||
// Toggle ON: permission requested exactly once.
|
||||
await tester.tap(find.byType(Switch).last);
|
||||
await pumpStable(tester);
|
||||
|
||||
expect(estado.ecualizador.eqMultiDeviceEnabled, isTrue);
|
||||
expect(fakeDispositivo.solicitarPermisoBluetoothCalls, equals(1));
|
||||
|
||||
// Toggle OFF again: no further permission request.
|
||||
await tester.tap(find.byType(Switch).last);
|
||||
await pumpStable(tester);
|
||||
|
||||
expect(estado.ecualizador.eqMultiDeviceEnabled, isFalse);
|
||||
expect(fakeDispositivo.solicitarPermisoBluetoothCalls, equals(1));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ── Infrastructure ──────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user