Add stateInWhileSubscribed extension (#3456)

This commit is contained in:
Phil Oliver 2025-10-13 16:04:29 -04:00 committed by GitHub
parent 5c745bdd90
commit 3a232fc33f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 96 additions and 199 deletions

View file

@ -52,6 +52,7 @@ import org.meshtastic.core.datastore.model.RecentAddress
import org.meshtastic.core.model.util.anonymize
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import timber.log.Timber
import javax.inject.Inject
@ -168,33 +169,21 @@ constructor(
val mockDevice = DeviceListEntry.Mock("Demo Mode")
val bleDevicesForUi: StateFlow<List<DeviceListEntry>> =
bleDevicesFlow.stateIn(viewModelScope, SharingStarted.WhileSubscribed(SHARING_STARTED_TIMEOUT_MS), emptyList())
bleDevicesFlow.stateInWhileSubscribed(initialValue = emptyList())
/** UI StateFlow for discovered TCP devices. */
val discoveredTcpDevicesForUi: StateFlow<List<DeviceListEntry>> =
processedDiscoveredTcpDevicesFlow.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(SHARING_STARTED_TIMEOUT_MS),
listOf(),
)
processedDiscoveredTcpDevicesFlow.stateInWhileSubscribed(initialValue = listOf())
/** UI StateFlow for recently connected TCP devices that are not currently discovered. */
val recentTcpDevicesForUi: StateFlow<List<DeviceListEntry>> =
filteredRecentTcpDevicesFlow.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(SHARING_STARTED_TIMEOUT_MS),
listOf(),
)
filteredRecentTcpDevicesFlow.stateInWhileSubscribed(initialValue = listOf())
val usbDevicesForUi: StateFlow<List<DeviceListEntry>> =
combine(usbDevicesFlow, showMockInterface) { usb, showMock ->
usb + if (showMock) listOf(mockDevice) else emptyList()
}
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(SHARING_STARTED_TIMEOUT_MS),
if (showMockInterface.value) listOf(mockDevice) else emptyList(),
)
.stateInWhileSubscribed(initialValue = if (showMockInterface.value) listOf(mockDevice) else emptyList())
init {
serviceRepository.statusMessage.onEach { errorText.value = it }.launchIn(viewModelScope)
@ -217,11 +206,7 @@ constructor(
val selectedNotNullFlow: StateFlow<String> =
selectedAddressFlow
.map { it ?: NO_DEVICE_SELECTED }
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(SHARING_STARTED_TIMEOUT_MS),
selectedAddressFlow.value ?: NO_DEVICE_SELECTED,
)
.stateInWhileSubscribed(initialValue = selectedAddressFlow.value ?: NO_DEVICE_SELECTED)
val scanResult = MutableLiveData<MutableMap<String, DeviceListEntry>>(mutableMapOf())
@ -385,4 +370,3 @@ constructor(
}
const val NO_DEVICE_SELECTED = "n"
private const val SHARING_STARTED_TIMEOUT_MS = 5000L

View file

@ -42,7 +42,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.meshtastic.core.analytics.platform.PlatformAnalytics
import org.meshtastic.core.data.repository.FirmwareReleaseRepository
@ -58,6 +57,7 @@ import org.meshtastic.core.service.MeshServiceNotifications
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.component.toSharedContact
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import org.meshtastic.proto.AdminProtos
import org.meshtastic.proto.AppOnlyProtos
import org.meshtastic.proto.MeshProtos
@ -171,10 +171,7 @@ constructor(
get() = serviceRepository.meshService
val unreadMessageCount =
packetRepository
.getUnreadCountTotal()
.map { it.coerceAtLeast(0) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000L), 0)
packetRepository.getUnreadCountTotal().map { it.coerceAtLeast(0) }.stateInWhileSubscribed(initialValue = 0)
// hardware info about our local device (can be null)
val myNodeInfo: StateFlow<MyNodeEntity?>

View file

@ -18,20 +18,18 @@
package com.geeksville.mesh.ui.connections
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.stateIn
import org.meshtastic.core.data.repository.NodeRepository
import org.meshtastic.core.data.repository.RadioConfigRepository
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.prefs.ui.UiPrefs
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import org.meshtastic.proto.LocalOnlyProtos.LocalConfig
import javax.inject.Inject
@ -46,11 +44,7 @@ constructor(
private val uiPrefs: UiPrefs,
) : ViewModel() {
val localConfig: StateFlow<LocalConfig> =
radioConfigRepository.localConfigFlow.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000L),
LocalConfig.getDefaultInstance(),
)
radioConfigRepository.localConfigFlow.stateInWhileSubscribed(initialValue = LocalConfig.getDefaultInstance())
val connectionState = serviceRepository.connectionState

View file

@ -24,9 +24,7 @@ import com.geeksville.mesh.model.Contact
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.meshtastic.core.data.repository.NodeRepository
import org.meshtastic.core.data.repository.PacketRepository
@ -37,6 +35,7 @@ import org.meshtastic.core.model.util.getChannel
import org.meshtastic.core.model.util.getShortDate
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.strings.R
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import org.meshtastic.proto.channelSet
import javax.inject.Inject
import kotlin.collections.map
@ -55,12 +54,7 @@ constructor(
val connectionState = serviceRepository.connectionState
val channels =
radioConfigRepository.channelSetFlow.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
channelSet {},
)
val channels = radioConfigRepository.channelSetFlow.stateInWhileSubscribed(initialValue = channelSet {})
val contactList =
combine(
@ -117,11 +111,7 @@ constructor(
)
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList(),
)
.stateInWhileSubscribed(initialValue = emptyList())
fun getNode(userId: String?) = nodeRepository.getNode(userId ?: DataPacket.ID_BROADCAST)

View file

@ -23,9 +23,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.meshtastic.core.analytics.DataPair
import org.meshtastic.core.analytics.platform.PlatformAnalytics
@ -33,6 +31,7 @@ import org.meshtastic.core.data.repository.RadioConfigRepository
import org.meshtastic.core.model.util.toChannelSet
import org.meshtastic.core.proto.getChannelList
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
import org.meshtastic.proto.AppOnlyProtos
import org.meshtastic.proto.ChannelProtos
import org.meshtastic.proto.ConfigProtos.Config
@ -55,18 +54,9 @@ constructor(
val connectionState = serviceRepository.connectionState
val localConfig =
radioConfigRepository.localConfigFlow.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
LocalConfig.getDefaultInstance(),
)
radioConfigRepository.localConfigFlow.stateInWhileSubscribed(initialValue = LocalConfig.getDefaultInstance())
val channels =
radioConfigRepository.channelSetFlow.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
channelSet {},
)
val channels = radioConfigRepository.channelSetFlow.stateInWhileSubscribed(initialValue = channelSet {})
// managed mode disables all access to configuration
val isManaged: Boolean