From 5afa9defd734c50578ff0690c1a871648ac723a7 Mon Sep 17 00:00:00 2001 From: Andrea Severi Date: Mon, 9 Dec 2024 13:43:49 +0100 Subject: [PATCH] Apply user dark mode preference to splashscreen --- app/build.gradle.kts | 1 + app/src/main/AndroidManifest.xml | 1 + .../samples/apps/nowinandroid/MainActivity.kt | 116 ++++++++++++------ 3 files changed, 79 insertions(+), 39 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5434df8c2..3102b4510 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -89,6 +89,7 @@ dependencies { implementation(projects.sync.work) implementation(libs.androidx.activity.compose) + implementation(libs.androidx.appcompat) implementation(libs.androidx.compose.material3.adaptive) implementation(libs.androidx.compose.material3.adaptive.layout) implementation(libs.androidx.compose.material3.adaptive.navigation) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5b22f9865..af3534342 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -41,6 +41,7 @@ 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 599bd0b35..dc2eef3f1 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,12 +16,16 @@ package com.google.samples.apps.nowinandroid +import android.app.UiModeManager +import android.content.Context +import android.os.Build import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatDelegate import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -108,23 +112,24 @@ class MainActivity : ComponentActivity() { enableEdgeToEdge() setContent { - val darkTheme = shouldUseDarkTheme(uiState) + val themeInfo = themeInfo(uiState) // Update the edge to edge configuration to match the theme // This is the same parameters as the default enableEdgeToEdge call, but we manually // resolve whether or not to show dark theme using uiState, since it can be different // than the configuration's dark theme value based on the user preference. - DisposableEffect(darkTheme) { + DisposableEffect(themeInfo.isThemeDark, themeInfo.shouldFollowSystem) { enableEdgeToEdge( statusBarStyle = SystemBarStyle.auto( android.graphics.Color.TRANSPARENT, android.graphics.Color.TRANSPARENT, - ) { darkTheme }, + ) { themeInfo.isThemeDark }, navigationBarStyle = SystemBarStyle.auto( lightScrim, darkScrim, - ) { darkTheme }, + ) { themeInfo.isThemeDark }, ) + setAppTheme(getSystemService(Context.UI_MODE_SERVICE) as UiModeManager, themeInfo) onDispose {} } @@ -141,9 +146,9 @@ class MainActivity : ComponentActivity() { LocalTimeZone provides currentTimeZone, ) { NiaTheme( - darkTheme = darkTheme, - androidTheme = shouldUseAndroidTheme(uiState), - disableDynamicTheming = shouldDisableDynamicTheming(uiState), + darkTheme = themeInfo.isThemeDark, + androidTheme = themeInfo.shouldUseAndroidTheme, + disableDynamicTheming = themeInfo.shouldDisableDynamicTheming, ) { NiaApp(appState) } @@ -162,44 +167,77 @@ class MainActivity : ComponentActivity() { } } -/** - * Returns `true` if the Android theme should be used, as a function of the [uiState]. - */ -@Composable -private fun shouldUseAndroidTheme( - uiState: MainActivityUiState, -): Boolean = when (uiState) { - Loading -> false - is Success -> when (uiState.userData.themeBrand) { - ThemeBrand.DEFAULT -> false - ThemeBrand.ANDROID -> true - } -} +private data class ThemeInfo( + /** + * Returns `true` if dark theme should be used. + */ + val isThemeDark: Boolean, -/** - * Returns `true` if the dynamic color is disabled, as a function of the [uiState]. - */ + /** + * Returns `true` if theme should follow the system settings. + */ + val shouldFollowSystem: Boolean, + + /** + * Returns `true` if the dynamic color is disabled. + */ + val shouldDisableDynamicTheming: Boolean, + + /** + * Returns `true` if the Android theme should be used. + */ + val shouldUseAndroidTheme: Boolean, +) @Composable -private fun shouldDisableDynamicTheming( - uiState: MainActivityUiState, -): Boolean = when (uiState) { - Loading -> false - is Success -> !uiState.userData.useDynamicColor +private fun themeInfo(uiState: MainActivityUiState): ThemeInfo { + return when (uiState) { + Loading -> ThemeInfo( + isThemeDark = isSystemInDarkTheme(), + shouldFollowSystem = false, + shouldDisableDynamicTheming = false, + shouldUseAndroidTheme = false + ) + + is Success -> { + val isThemeDark = uiState.userData.darkThemeConfig == DarkThemeConfig.DARK + val shouldFollowSystem = uiState.userData.darkThemeConfig == DarkThemeConfig.FOLLOW_SYSTEM + ThemeInfo( + isThemeDark = isThemeDark || (shouldFollowSystem && isSystemInDarkTheme()), + shouldFollowSystem = shouldFollowSystem, + shouldDisableDynamicTheming = !uiState.userData.useDynamicColor, + shouldUseAndroidTheme = uiState.userData.themeBrand == ThemeBrand.ANDROID + ) + } + } } /** - * Returns `true` if dark theme should be used, as a function of the [uiState] and the - * current system context. + * Sets app theme to reflect user choice. */ -@Composable -private fun shouldUseDarkTheme( - uiState: MainActivityUiState, -): Boolean = when (uiState) { - Loading -> isSystemInDarkTheme() - is Success -> when (uiState.userData.darkThemeConfig) { - DarkThemeConfig.FOLLOW_SYSTEM -> isSystemInDarkTheme() - DarkThemeConfig.LIGHT -> false - DarkThemeConfig.DARK -> true +private fun setAppTheme( + uiModeManager: UiModeManager, + themeInfo: ThemeInfo +) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + uiModeManager.setApplicationNightMode( + if (themeInfo.shouldFollowSystem) { + UiModeManager.MODE_NIGHT_AUTO + } else if (themeInfo.isThemeDark) { + UiModeManager.MODE_NIGHT_YES + } else { + UiModeManager.MODE_NIGHT_NO + } + ) + } else { + AppCompatDelegate.setDefaultNightMode( + if (themeInfo.shouldFollowSystem) { + AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + } else if (themeInfo.isThemeDark) { + AppCompatDelegate.MODE_NIGHT_YES + } else { + AppCompatDelegate.MODE_NIGHT_NO + } + ) } }