From d195518dfb4fdf1575d93773efbf281750abfed3 Mon Sep 17 00:00:00 2001 From: Honey Date: Wed, 12 Aug 2026 00:40:38 +0200 Subject: [PATCH] =?UTF-8?q?fix(android=20settings):=20remove=20open=20dela?= =?UTF-8?q?y=20=E2=80=94=20seed=20theme=20instead=20of=20a=20loading=20gat?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous flicker fix gated the whole settings form behind a 'loaded' spinner, which read as a small lag when opening Settings (it waited for DataStore's first emit even though it's already warm). Instead, expose the applied theme id (NsColors.themeId, set in applyNsTheme) and seed the ViewModel's initial state with it, so the theme picker no longer jumps from the default — no gate, no spinner, no delay. Remaining text fields fill within a frame from the warm DataStore. Co-Authored-By: Claude Opus 4.8 --- .../kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt | 9 --------- .../src/main/kotlin/com/novasonic/app/ui/theme/Color.kt | 2 ++ .../com/novasonic/app/viewmodel/SettingsViewModel.kt | 6 +++--- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt b/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt index ebe444d..ff1babf 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt @@ -67,15 +67,6 @@ fun SettingsScreen(onOpenStats: () -> Unit = {}) { ) } - // Wait for the persisted settings before drawing the form — otherwise the default state - // (e.g. theme = Dark Ocean) flashes for a frame and then jumps to the real values. - if (!state.loaded) { - Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator(color = NsAccent) - } - return - } - Column( verticalArrangement = Arrangement.spacedBy(12.dp), modifier = Modifier diff --git a/android/app/src/main/kotlin/com/novasonic/app/ui/theme/Color.kt b/android/app/src/main/kotlin/com/novasonic/app/ui/theme/Color.kt index e48dd27..8c5c624 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/ui/theme/Color.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/ui/theme/Color.kt @@ -7,6 +7,7 @@ import androidx.compose.ui.graphics.Color // ── Dynamic theme state — Compose tracks reads automatically ───────────────── object NsColors { + var themeId by mutableStateOf("dark-ocean") // currently applied theme id (readable) var accent by mutableStateOf(Color(0xFF4F8EF7)) var accentDim by mutableStateOf(Color(0xFF2A6CD6)) var bg by mutableStateOf(Color(0xFF070D14)) @@ -88,6 +89,7 @@ val NS_THEMES = listOf( fun applyNsTheme(themeId: String) { val t = NS_THEMES.find { it.id == themeId } ?: NS_THEMES.first() + NsColors.themeId = t.id NsColors.accent = t.accent NsColors.accentDim = t.accentDim NsColors.bg = t.bg diff --git a/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt b/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt index d0df2a8..71fb74c 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import com.novasonic.app.api.AbsClient import com.novasonic.app.app import com.novasonic.app.data.PrefsStore +import com.novasonic.app.ui.theme.NsColors import io.ktor.client.HttpClient import io.ktor.client.engine.android.Android import io.ktor.client.plugins.HttpTimeout @@ -35,7 +36,6 @@ data class SettingsUiState( val absUrl: String = "", val absApiKey: String = "", val absChapterTrackMode: Boolean = false, - val loaded: Boolean = false, val isSaving: Boolean = false, val savedOk: Boolean = false, val error: String? = null, @@ -48,7 +48,8 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) { private val repo = app.app.repository - private val _state = MutableStateFlow(SettingsUiState()) + // Seed the theme with the already-applied one so the picker doesn't jump before DataStore emits. + private val _state = MutableStateFlow(SettingsUiState(theme = NsColors.themeId)) val state: StateFlow = _state init { @@ -67,7 +68,6 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) { absUrl = s.absUrl, absApiKey = s.absApiKey, absChapterTrackMode = s.absChapterTrackMode, - loaded = true, ) } }