From ed3f34e57994276c7d7ed0b08289b7cc69a76fb7 Mon Sep 17 00:00:00 2001 From: Steven Elliott Date: Tue, 3 Feb 2026 12:38:55 -0500 Subject: [PATCH 1/2] Sync dark theme preference to UiModeManager for splash screen On cold start, the splash screen theme is determined by the application's UiModeManager night mode setting, not by the in-app Compose theme. Without this change, a user who selects "Dark" in the app's settings will still see a light splash screen on the next launch, causing a jarring visual flash. This adds a lifecycle-aware collector that maps the user's DarkThemeConfig preference to UiModeManager.setApplicationNightMode(), ensuring the splash screen matches the chosen theme. Guarded behind API 31+ (Android S) since setApplicationNightMode was introduced there. --- .../samples/apps/nowinandroid/MainActivity.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt index ecc23d80e0..cdb52385c2 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt @@ -16,6 +16,8 @@ package com.google.samples.apps.nowinandroid +import android.app.UiModeManager +import android.os.Build import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.SystemBarStyle @@ -34,12 +36,14 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.metrics.performance.JankStats import androidx.tracing.trace import com.google.samples.apps.nowinandroid.MainActivityUiState.Loading +import com.google.samples.apps.nowinandroid.MainActivityUiState.Success import com.google.samples.apps.nowinandroid.core.analytics.AnalyticsHelper import com.google.samples.apps.nowinandroid.core.analytics.LocalAnalyticsHelper import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme +import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig import com.google.samples.apps.nowinandroid.core.ui.LocalTimeZone import com.google.samples.apps.nowinandroid.ui.NiaApp import com.google.samples.apps.nowinandroid.ui.rememberNiaAppState @@ -48,6 +52,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import javax.inject.Inject @@ -127,6 +132,28 @@ class MainActivity : ComponentActivity() { } } + // Sync the user's dark theme preference to the system-level UiModeManager so the + // splash screen uses the correct theme on the next cold start. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState + .mapNotNull { (it as? Success)?.userData?.darkThemeConfig } + .distinctUntilChanged() + .collect { darkThemeConfig -> + val uiModeManager = getSystemService(UiModeManager::class.java) + uiModeManager.setApplicationNightMode( + when (darkThemeConfig) { + DarkThemeConfig.FOLLOW_SYSTEM -> UiModeManager.MODE_NIGHT_AUTO + DarkThemeConfig.LIGHT -> UiModeManager.MODE_NIGHT_NO + DarkThemeConfig.DARK -> UiModeManager.MODE_NIGHT_YES + }, + ) + } + } + } + } + // Keep the splash screen on-screen until the UI state is loaded. This condition is // evaluated each time the app needs to be redrawn so it should be fast to avoid blocking // the UI. From 8b7b4f1a0b674b38d0e92a78db96e395202fd5de Mon Sep 17 00:00:00 2001 From: Steven Elliott Date: Tue, 3 Feb 2026 13:43:13 -0500 Subject: [PATCH 2/2] Hoist UiModeManager lookup out of collect block Move getSystemService call outside the flow collector so the system service is resolved once rather than on every emission. --- .../kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt index cdb52385c2..0e74c54dc9 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt @@ -135,13 +135,13 @@ class MainActivity : ComponentActivity() { // Sync the user's dark theme preference to the system-level UiModeManager so the // splash screen uses the correct theme on the next cold start. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val uiModeManager = getSystemService(UiModeManager::class.java) lifecycleScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState .mapNotNull { (it as? Success)?.userData?.darkThemeConfig } .distinctUntilChanged() .collect { darkThemeConfig -> - val uiModeManager = getSystemService(UiModeManager::class.java) uiModeManager.setApplicationNightMode( when (darkThemeConfig) { DarkThemeConfig.FOLLOW_SYSTEM -> UiModeManager.MODE_NIGHT_AUTO