From a6f292f7373f148ebfa4c691702a460a26073961 Mon Sep 17 00:00:00 2001 From: darken Date: Mon, 13 Apr 2026 15:52:55 +0200 Subject: [PATCH] Render device settings before BT profile state arrives --- .../ui/devicesettings/DeviceSettingsViewModel.kt | 5 ++++- .../DeviceSettingsViewModelTest.kt | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModel.kt b/app/src/main/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModel.kt index 0511c161..08dc3533 100644 --- a/app/src/main/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModel.kt +++ b/app/src/main/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModel.kt @@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.isActive +import kotlinx.coroutines.flow.onStart import java.time.Instant import javax.inject.Inject @@ -80,7 +81,9 @@ class DeviceSettingsViewModel @Inject constructor( deviceForProfile(profileId), upgradeRepo.upgradeInfo, isForceConnecting, - bluetoothManager.connectedDevices, + // The Bluetooth HEADSET profile lookup can be slow to produce its first value. + // Seed this branch so the screen can render immediately after navigation. + bluetoothManager.connectedDevices.onStart { emit(emptyList()) }, ) { _, device, upgrade, forcing, connectedDevices -> val connectedAddresses = connectedDevices.map { it.address }.toSet() State( diff --git a/app/src/test/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModelTest.kt b/app/src/test/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModelTest.kt index 2df3ce66..48551393 100644 --- a/app/src/test/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModelTest.kt +++ b/app/src/test/java/eu/darken/capod/main/ui/devicesettings/DeviceSettingsViewModelTest.kt @@ -21,13 +21,16 @@ import io.mockk.verify import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain +import kotlinx.coroutines.withTimeout import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -298,4 +301,17 @@ class DeviceSettingsViewModelTest : BaseTest() { vm.state.first().isClassicallyConnected shouldBe false } + + @Test + fun `state emits even when connected devices flow has not emitted yet`() = runTest(testDispatcher) { + every { bluetoothManager.connectedDevices } returns flow { awaitCancellation() } + + val vm = createViewModel() + vm.initialize(testAddress) + + val state = withTimeout(1_000) { vm.state.first() } + + state.device?.address shouldBe testAddress + state.isClassicallyConnected shouldBe false + } }