Apply user dark mode preference to splashscreen

pull/1718/head
Andrea Severi 10 months ago
parent 55dbe61c65
commit 5afa9defd7
No known key found for this signature in database
GPG Key ID: BF5DFA9B836FBEC3

@ -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)

@ -41,6 +41,7 @@
<activity
android:name=".MainActivity"
android:configChanges="uiMode"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

@ -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() {
}
}
private data class ThemeInfo(
/**
* Returns `true` if the Android theme should be used, as a function of the [uiState].
* Returns `true` if dark theme should be used.
*/
@Composable
private fun shouldUseAndroidTheme(
uiState: MainActivityUiState,
): Boolean = when (uiState) {
Loading -> false
is Success -> when (uiState.userData.themeBrand) {
ThemeBrand.DEFAULT -> false
ThemeBrand.ANDROID -> true
}
}
val isThemeDark: Boolean,
/**
* Returns `true` if theme should follow the system settings.
*/
val shouldFollowSystem: Boolean,
/**
* Returns `true` if the dynamic color is disabled, as a function of the [uiState].
* 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
}
)
}
}

Loading…
Cancel
Save