perf: optimize screen load times with progressive un-gating and SWR caching (#1192)
This commit is contained in:
55 files changed
+2494
-401
No files matched your search
@@ -88,6 +88,7 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.m57.hermescontrol.R
|
||||
import com.m57.hermescontrol.data.local.AuthManager
|
||||
import com.m57.hermescontrol.data.model.EnvVarConfig
|
||||
import com.m57.hermescontrol.theme.LocalHermesStatusColors
|
||||
import com.m57.hermescontrol.ui.common.EmptyState
|
||||
@@ -114,6 +115,7 @@ fun KeysScreen(
|
||||
viewModel: KeysViewModel = viewModel { KeysViewModel() },
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
val dataScope by AuthManager.dataScopeFlow.collectAsStateWithLifecycle()
|
||||
var query by remember { mutableStateOf("") }
|
||||
var selectedCategory by remember { mutableStateOf(FILTER_ALL) }
|
||||
|
||||
@@ -150,7 +152,8 @@ fun KeysScreen(
|
||||
|
||||
val hasAnyVars = state.categories.any { it.vars.isNotEmpty() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
LaunchedEffect(dataScope) {
|
||||
viewModel.clearScopeOwnedState()
|
||||
viewModel.loadKeys()
|
||||
}
|
||||
|
||||
@@ -211,7 +214,7 @@ fun KeysScreen(
|
||||
title = { Text(stringResource(R.string.screen_keys)) },
|
||||
navigationIcon = onOpenDrawer?.let { NavIcon.Menu(it) },
|
||||
isRefreshing = state.isLoading,
|
||||
onRefresh = { viewModel.loadKeys() },
|
||||
onRefresh = { viewModel.loadKeys(forceRefresh = true) },
|
||||
actions = {
|
||||
IconButton(onClick = { viewModel.openAddDialog() }) {
|
||||
Icon(
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.m57.hermescontrol.ui.keys
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.m57.hermescontrol.data.local.SwrCache
|
||||
import com.m57.hermescontrol.data.model.EnvVarConfig
|
||||
import com.m57.hermescontrol.data.model.EnvVarDeleteRequest
|
||||
import com.m57.hermescontrol.data.model.EnvVarRevealRequest
|
||||
@@ -11,6 +12,7 @@ import com.m57.hermescontrol.data.remote.NetworkResult
|
||||
import com.m57.hermescontrol.data.remote.safeApiCall
|
||||
import com.m57.hermescontrol.ui.common.ToastHost
|
||||
import com.m57.hermescontrol.ui.common.safeLaunchLoad
|
||||
import com.m57.hermescontrol.ui.common.safeLaunchSwrLoad
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -55,6 +57,19 @@ class KeysViewModel :
|
||||
private val _uiState = MutableStateFlow(KeysUiState())
|
||||
val uiState: StateFlow<KeysUiState> = _uiState.asStateFlow()
|
||||
|
||||
private val keysCache = SwrCache<String, Map<String, EnvVarConfig>>()
|
||||
|
||||
fun clearScopeOwnedState() {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
categories = emptyList(),
|
||||
revealedValues = emptyMap(),
|
||||
errorMessage = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildCategoryList(
|
||||
envVars: Map<String, EnvVarConfig>,
|
||||
expandedCategories: Set<String> =
|
||||
@@ -89,8 +104,21 @@ class KeysViewModel :
|
||||
}
|
||||
}
|
||||
|
||||
fun loadKeys() {
|
||||
safeLaunchLoad(
|
||||
fun loadKeys(forceRefresh: Boolean = false) {
|
||||
safeLaunchSwrLoad(
|
||||
cache = keysCache,
|
||||
forceRefresh = forceRefresh,
|
||||
onCacheHit = { envVars ->
|
||||
val currentCategories = _uiState.value.categories
|
||||
val expandedCategories = currentCategories.map { it.name to it.expanded }.toMap()
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
categories = buildCategoryList(envVars, expandedCategories.keys),
|
||||
errorMessage = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
apiCall = { safeApiCall { ApiClient.hermesApi.getEnvVars() } },
|
||||
onStart = { _uiState.update { it.copy(isLoading = true, errorMessage = null) } },
|
||||
onSuccess = { data ->
|
||||
@@ -178,7 +206,7 @@ class KeysViewModel :
|
||||
toastMessage = "Key added successfully",
|
||||
)
|
||||
}
|
||||
loadKeys()
|
||||
loadKeys(forceRefresh = true)
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
@@ -223,7 +251,7 @@ class KeysViewModel :
|
||||
toastMessage = "Key deleted successfully",
|
||||
)
|
||||
}
|
||||
loadKeys()
|
||||
loadKeys(forceRefresh = true)
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
@@ -281,7 +309,7 @@ class KeysViewModel :
|
||||
when (result) {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update { it.copy(keysChanged = true, toastMessage = "Key updated successfully") }
|
||||
loadKeys()
|
||||
loadKeys(forceRefresh = true)
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
|
||||
Reference in new issue
Block a user