package mx.trackermap.TrackerMap.controllers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import mx.trackermap.TrackerMap.client.apis.DevicesApi import mx.trackermap.TrackerMap.client.apis.PositionsApi import mx.trackermap.TrackerMap.client.models.Position import mx.trackermap.TrackerMap.client.models.UnitInformation import mx.trackermap.TrackerMap.utils.Coroutines import kotlin.time.Duration.Companion.seconds import kotlin.time.ExperimentalTime @DelicateCoroutinesApi @ExperimentalTime class UnitsController( private val devicesApi: DevicesApi, private val positionsApi: PositionsApi ) { private companion object { const val UPDATE_TIME = 20 } val displayedUnitsFlow = MutableStateFlow>(emptyList()) private val unitsFlow = MutableStateFlow>(emptyList()) private val queryFlow = MutableStateFlow("") init { GlobalScope.launch { fetchUnits(this) } GlobalScope.launch { setupFlows() } } private suspend fun fetchUnits(scope: CoroutineScope) { Coroutines.tickerFlow(UPDATE_TIME.seconds) .map { print("Fetching new positions...\n") positionsApi.positionsGet() } .distinctUntilChanged { old, new -> old.contentEquals(new) } .onEach { positions -> print("Position(s) changed! Reloading data...\n") val devices = devicesApi.devicesGet() val positionsMap: MutableMap = mutableMapOf() positions.forEach { position -> position.deviceId?.let { positionsMap[it] = position } } val units = devices.map { UnitInformation(it, positionsMap[it.id]) } unitsFlow.value = units } .catch { print("Could not retrieve positions\n") } .launchIn(scope) } fun search(query: String) { queryFlow.value = query } suspend fun getUnit(deviceId: Int): UnitInformation { val device = devicesApi.devicesGet(id = deviceId).first() val position = positionsApi.positionsGet(id = device.positionId).first() return UnitInformation(device, position) } private suspend fun setupFlows() { unitsFlow.combine(queryFlow) { units, query -> units.filter { unit -> unit.device.name.contains(query, true) || unit.device.contact?.contains(query, true) == true || unit.position?.address?.contains(query, true) == true } }.collect { units -> this.displayedUnitsFlow.value = units } } }