mirror of
https://github.com/home-assistant/android
synced 2024-10-15 12:32:54 +00:00
Only subscribe to supported entities on Wear OS home screen (#3103)
* Only subscribe to favorite entities on Wear OS homescreen * Switch to subscribing to all supported domains * Update entity states when app is resumed and entities are loaded to keep things in sync * Only update domains when needed * Update all registeries when we resume * Move UI update to view model * Review comment * Clear values before updates * Process review comments
This commit is contained in:
parent
8563efef5f
commit
d5714d85e4
|
@ -15,6 +15,7 @@ import io.homeassistant.companion.android.onboarding.OnboardingActivity
|
|||
import io.homeassistant.companion.android.onboarding.integration.MobileAppIntegrationActivity
|
||||
import io.homeassistant.companion.android.sensors.SensorReceiver
|
||||
import io.homeassistant.companion.android.sensors.SensorWorker
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -26,6 +27,8 @@ class HomeActivity : ComponentActivity(), HomeView {
|
|||
|
||||
private val mainViewModel by viewModels<MainViewModel>()
|
||||
|
||||
private var entityUpdateJob: Job? = null
|
||||
|
||||
companion object {
|
||||
private const val TAG = "HomeActivity"
|
||||
|
||||
|
@ -48,7 +51,12 @@ class HomeActivity : ComponentActivity(), HomeView {
|
|||
|
||||
lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
launch { mainViewModel.entityUpdates() }
|
||||
launch {
|
||||
mainViewModel.supportedEntities.collect {
|
||||
if (entityUpdateJob?.isActive == true) entityUpdateJob?.cancel()
|
||||
entityUpdateJob = launch { mainViewModel.entityUpdates() }
|
||||
}
|
||||
}
|
||||
launch { mainViewModel.areaUpdates() }
|
||||
launch { mainViewModel.deviceUpdates() }
|
||||
launch { mainViewModel.entityRegistryUpdates() }
|
||||
|
@ -61,6 +69,11 @@ class HomeActivity : ComponentActivity(), HomeView {
|
|||
SensorWorker.start(this)
|
||||
|
||||
mainViewModel.initAllSensors()
|
||||
|
||||
lifecycleScope.launch {
|
||||
if (mainViewModel.loadingState.value == MainViewModel.LoadingState.READY)
|
||||
mainViewModel.updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
|
|
@ -28,7 +28,7 @@ interface HomePresenter {
|
|||
fun getWebSocketState(): WebSocketState?
|
||||
|
||||
suspend fun getEntities(): List<Entity<*>>?
|
||||
suspend fun getEntityUpdates(): Flow<Entity<*>>?
|
||||
suspend fun getEntityUpdates(entityIds: List<String>): Flow<Entity<*>>?
|
||||
|
||||
suspend fun getAreaRegistry(): List<AreaRegistryResponse>?
|
||||
suspend fun getDeviceRegistry(): List<DeviceRegistryResponse>?
|
||||
|
|
|
@ -77,8 +77,8 @@ class HomePresenterImpl @Inject constructor(
|
|||
return integrationUseCase.getEntities()
|
||||
}
|
||||
|
||||
override suspend fun getEntityUpdates(): Flow<Entity<*>>? {
|
||||
return integrationUseCase.getEntityUpdates()
|
||||
override suspend fun getEntityUpdates(entityIds: List<String>): Flow<Entity<*>>? {
|
||||
return integrationUseCase.getEntityUpdates(entityIds)
|
||||
}
|
||||
|
||||
override suspend fun onEntityClicked(entityId: String, state: String) {
|
||||
|
|
|
@ -26,9 +26,13 @@ import io.homeassistant.companion.android.database.wear.FavoritesDao
|
|||
import io.homeassistant.companion.android.database.wear.getAllFlow
|
||||
import io.homeassistant.companion.android.sensors.SensorReceiver
|
||||
import io.homeassistant.companion.android.util.RegistriesDataHandler
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
|
@ -63,6 +67,9 @@ class MainViewModel @Inject constructor(
|
|||
var entities = mutableStateMapOf<String, Entity<*>>()
|
||||
private set
|
||||
|
||||
private val _supportedEntities = MutableStateFlow(emptyList<String>())
|
||||
val supportedEntities = _supportedEntities.asStateFlow()
|
||||
|
||||
/**
|
||||
* IDs of favorites in the Favorites database.
|
||||
*/
|
||||
|
@ -133,27 +140,7 @@ class MainViewModel @Inject constructor(
|
|||
try {
|
||||
// Load initial state
|
||||
loadingState.value = LoadingState.LOADING
|
||||
val getAreaRegistry = async { homePresenter.getAreaRegistry() }
|
||||
val getDeviceRegistry = async { homePresenter.getDeviceRegistry() }
|
||||
val getEntityRegistry = async { homePresenter.getEntityRegistry() }
|
||||
val getEntities = async { homePresenter.getEntities() }
|
||||
|
||||
areaRegistry = getAreaRegistry.await()?.also {
|
||||
areas.addAll(it)
|
||||
}
|
||||
deviceRegistry = getDeviceRegistry.await()
|
||||
entityRegistry = getEntityRegistry.await()
|
||||
|
||||
getEntities.await()?.forEach {
|
||||
if (supportedDomains().contains(it.domain)) {
|
||||
entities[it.entityId] = it
|
||||
// add to cache if part of favorites
|
||||
if (favoriteEntityIds.value.contains(it.entityId)) {
|
||||
addCachedFavorite(it.entityId)
|
||||
}
|
||||
}
|
||||
}
|
||||
updateEntityDomains()
|
||||
updateUI()
|
||||
|
||||
// Finished initial load, update state
|
||||
val webSocketState = homePresenter.getWebSocketState()
|
||||
|
@ -173,14 +160,44 @@ class MainViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateEntityStates(entity: Entity<*>) {
|
||||
if (supportedDomains().contains(entity.domain)) {
|
||||
entities[entity.entityId] = entity
|
||||
// add to cache if part of favorites
|
||||
if (favoriteEntityIds.value.contains(entity.entityId)) {
|
||||
addCachedFavorite(entity.entityId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateUI() = withContext(Dispatchers.IO) {
|
||||
val getAreaRegistry = async { homePresenter.getAreaRegistry() }
|
||||
val getDeviceRegistry = async { homePresenter.getDeviceRegistry() }
|
||||
val getEntityRegistry = async { homePresenter.getEntityRegistry() }
|
||||
val getEntities = async { homePresenter.getEntities() }
|
||||
|
||||
areaRegistry = getAreaRegistry.await()?.also {
|
||||
areas.clear()
|
||||
areas.addAll(it)
|
||||
}
|
||||
deviceRegistry = getDeviceRegistry.await()
|
||||
entityRegistry = getEntityRegistry.await()
|
||||
|
||||
_supportedEntities.value = getSupportedEntities()
|
||||
|
||||
getEntities.await()?.also {
|
||||
entities.clear()
|
||||
it.forEach { state -> updateEntityStates(state) }
|
||||
}
|
||||
updateEntityDomains()
|
||||
}
|
||||
|
||||
suspend fun entityUpdates() {
|
||||
if (!homePresenter.isConnected())
|
||||
return
|
||||
homePresenter.getEntityUpdates()?.collect {
|
||||
if (supportedDomains().contains(it.domain)) {
|
||||
entities[it.entityId] = it
|
||||
updateEntityDomains()
|
||||
}
|
||||
homePresenter.getEntityUpdates(supportedEntities.value)?.collect {
|
||||
updateEntityStates(it)
|
||||
updateEntityDomains()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,11 +228,18 @@ class MainViewModel @Inject constructor(
|
|||
return
|
||||
homePresenter.getEntityRegistryUpdates()?.collect {
|
||||
entityRegistry = homePresenter.getEntityRegistry()
|
||||
_supportedEntities.value = getSupportedEntities()
|
||||
updateEntityDomains()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEntityDomains() {
|
||||
private fun getSupportedEntities(): List<String> =
|
||||
entityRegistry
|
||||
.orEmpty()
|
||||
.map { it.entityId }
|
||||
.filter { it.split(".")[0] in supportedDomains() }
|
||||
|
||||
private fun updateEntityDomains() {
|
||||
val entitiesList = entities.values.toList().sortedBy { it.entityId }
|
||||
val areasList = areaRegistry.orEmpty().sortedBy { it.name }
|
||||
val domainsList = entitiesList.map { it.domain }.distinct()
|
||||
|
|
|
@ -151,14 +151,14 @@ private fun PreviewEntityUI() {
|
|||
onEntityClicked = { _, _ -> },
|
||||
isHapticEnabled = true,
|
||||
isToastEnabled = false,
|
||||
onEntityLongPressed = { _ -> }
|
||||
onEntityLongPressed = { }
|
||||
)
|
||||
EntityUi(
|
||||
entity = previewEntity3,
|
||||
onEntityClicked = { _, _ -> },
|
||||
isHapticEnabled = false,
|
||||
isToastEnabled = true,
|
||||
onEntityLongPressed = { _ -> }
|
||||
onEntityLongPressed = { }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue