feat: Implement iOS support and unify Compose Multiplatform infrastructure (#4876)

This commit is contained in:
James Rich 2026-03-21 18:19:13 -05:00 committed by GitHub
parent f04924ded5
commit d136b162a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
170 changed files with 2208 additions and 2432 deletions

View file

@ -33,6 +33,8 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.koin.core.annotation.Named
import org.koin.core.annotation.Single
import org.meshtastic.core.ble.BluetoothRepository
@ -100,7 +102,7 @@ class SharedRadioInterfaceService(
private var radioIf: RadioTransport? = null
private var isStarted = false
@Volatile private var listenersInitialized = false
private val listenersInitialized = kotlinx.atomicfu.atomic(false)
private var heartbeatJob: kotlinx.coroutines.Job? = null
private var lastHeartbeatMillis = 0L
@ -108,42 +110,46 @@ class SharedRadioInterfaceService(
private const val HEARTBEAT_INTERVAL_MILLIS = 30 * 1000L
}
private val initLock = Mutex()
private fun initStateListeners() {
if (listenersInitialized) return
synchronized(this) {
if (listenersInitialized) return
listenersInitialized = true
if (listenersInitialized.value) return
processLifecycle.coroutineScope.launch {
initLock.withLock {
if (listenersInitialized.value) return@withLock
listenersInitialized.value = true
radioPrefs.devAddr
.onEach { addr ->
if (_currentDeviceAddressFlow.value != addr) {
_currentDeviceAddressFlow.value = addr
startInterface()
radioPrefs.devAddr
.onEach { addr ->
if (_currentDeviceAddressFlow.value != addr) {
_currentDeviceAddressFlow.value = addr
startInterface()
}
}
}
.launchIn(processLifecycle.coroutineScope)
.launchIn(processLifecycle.coroutineScope)
bluetoothRepository.state
.onEach { state ->
if (state.enabled) {
startInterface()
} else if (getBondedDeviceAddress()?.startsWith(InterfaceId.BLUETOOTH.id) == true) {
stopInterface()
bluetoothRepository.state
.onEach { state ->
if (state.enabled) {
startInterface()
} else if (getBondedDeviceAddress()?.startsWith(InterfaceId.BLUETOOTH.id) == true) {
stopInterface()
}
}
}
.catch { Logger.e(it) { "bluetoothRepository.state flow crashed!" } }
.launchIn(processLifecycle.coroutineScope)
.catch { Logger.e(it) { "bluetoothRepository.state flow crashed!" } }
.launchIn(processLifecycle.coroutineScope)
networkRepository.networkAvailable
.onEach { state ->
if (state) {
startInterface()
} else if (getBondedDeviceAddress()?.startsWith(InterfaceId.TCP.id) == true) {
stopInterface()
networkRepository.networkAvailable
.onEach { state ->
if (state) {
startInterface()
} else if (getBondedDeviceAddress()?.startsWith(InterfaceId.TCP.id) == true) {
stopInterface()
}
}
}
.catch { Logger.e(it) { "networkRepository.networkAvailable flow crashed!" } }
.launchIn(processLifecycle.coroutineScope)
.catch { Logger.e(it) { "networkRepository.networkAvailable flow crashed!" } }
.launchIn(processLifecycle.coroutineScope)
}
}
}