Reputation: 2175
With the new color contrast feature in android 15, I have now defined a new color palette for low, medium and high color contrast for both light and dark scheme. How can I apply this dynamically based on what the user has set on his phone ?
Currently, my Theme.kt is like this:
@Composable
fun MesTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> darkScheme
else -> lightScheme
}
// Update the system bar colors
rememberSystemUiController().setSystemBarsColor(
color = colorScheme.background
)
MaterialTheme(
colorScheme = colorScheme,
typography = MesTypography,
shapes = MesShapes,
content = content
)
}
It is only using the light and dark scheme. I need to be able to apply both the medium and high contrast schemes as well.
Upvotes: 0
Views: 201
Reputation: 26801
As mentioned, you can use the UiModeManager#getContrast
method introduced in Android 14 (Upside Down Cake) to query the contrast value. Its return value is as described:
[Returns] The color contrast, float in [-1, 1] where
0
corresponds to the default contrast-1
corresponds to the minimum contrast1
corresponds to the maximum contrastValue is between
-1.0f
and1.0f
inclusive
An example can be found in the Reply Compose sample. Shown below are the relevant portions:
fun isContrastAvailable(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
}
@Composable
fun selectSchemeForContrast(isDark: Boolean): ColorScheme {
val context = LocalContext.current
var colorScheme = if (isDark) darkScheme else lightScheme
val isPreview = LocalInspectionMode.current
// TODO(b/336693596): UIModeManager is not yet supported in preview
if (!isPreview && isContrastAvailable()) {
val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
val contrastLevel = uiModeManager.contrast
colorScheme = when (contrastLevel) {
in 0.0f..0.33f -> if (isDark)
darkScheme else lightScheme
in 0.34f..0.66f -> if (isDark)
mediumContrastDarkColorScheme else mediumContrastLightColorScheme
in 0.67f..1.0f -> if (isDark)
highContrastDarkColorScheme else highContrastLightColorScheme
else -> if (isDark) darkScheme else lightScheme
}
return colorScheme
} else return colorScheme
}
@Composable
fun ContrastAwareReplyTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = false,
content: @Composable() () -> Unit
) {
val replyColorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
else -> selectSchemeForContrast(darkTheme)
}
// ...
MaterialTheme(
colorScheme = replyColorScheme,
typography = replyTypography,
shapes = shapes,
content = content
)
}
Upvotes: 1