diff --git a/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt b/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt index 6ca5d895a..d45fa0dbe 100644 --- a/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt @@ -47,7 +47,10 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn import javax.inject.Inject @HiltViewModel @@ -158,7 +161,15 @@ class BTScanModel @Inject constructor( val selectedBluetooth: Boolean get() = selectedAddress?.getOrNull(0) == 'x' // / Use the string for the NopInterface - val selectedNotNull: String get() = selectedAddress ?: NO_DEVICE_SELECTED + val selectedAddressFlow: StateFlow = radioInterfaceService.currentDeviceAddressFlow + + val selectedNotNullFlow: StateFlow = selectedAddressFlow + .map { it ?: NO_DEVICE_SELECTED } + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(SHARING_STARTED_TIMEOUT_MS), + selectedAddressFlow.value ?: NO_DEVICE_SELECTED + ) val scanResult = MutableLiveData>(mutableMapOf()) @@ -282,3 +293,4 @@ class BTScanModel @Inject constructor( } const val NO_DEVICE_SELECTED = "n" +private const val SHARING_STARTED_TIMEOUT_MS = 5000L diff --git a/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt index 13a720c63..a7b585b8b 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt @@ -41,6 +41,7 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -74,6 +75,10 @@ class RadioInterfaceService @Inject constructor( private val _receivedData = MutableSharedFlow() val receivedData: SharedFlow = _receivedData + // Thread-safe StateFlow for tracking device address changes + private val _currentDeviceAddressFlow = MutableStateFlow(prefs.getString(DEVADDR_KEY, null)) + val currentDeviceAddressFlow: StateFlow = _currentDeviceAddressFlow.asStateFlow() + private val logSends = false private val logReceives = false private lateinit var sentPacketsLog: BinaryLogFile // inited in onCreate @@ -301,6 +306,7 @@ class RadioInterfaceService @Inject constructor( putString(DEVADDR_KEY, address) } } + _currentDeviceAddressFlow.value = address // Force the service to reconnect startInterface() diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt index 484a8401c..4b0b3831b 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt @@ -141,7 +141,7 @@ fun ConnectionsScreen( val context = LocalContext.current val app = (context.applicationContext as GeeksvilleApplication) val info by uiViewModel.myNodeInfo.collectAsState() - val selectedDevice = scanModel.selectedNotNull + val selectedDevice by scanModel.selectedNotNullFlow.collectAsStateWithLifecycle() val bluetoothEnabled by bluetoothViewModel.enabled.observeAsState() val regionUnset = currentRegion == ConfigProtos.Config.LoRaConfig.RegionCode.UNSET && connectionState == MeshService.ConnectionState.CONNECTED