You'll learn all about Material You and how you can dynamically import colors from the Material 3 Compose library into our versatile Chat Compose SDK, giving your app a more polished and personalized feel for your users.
To show you just how powerful the API is, you'll also learn how to use the Material Theme Builder so that you can create your own Material Design 3 themes.
What Is Material You?
Earlier this year, Google announced Material You, a new direction for Material Design that focuses on personalization and flexibility.
A major element of Material You is its dynamic color system, which is a color extraction algorithm that enables you to build a color scheme based on a user's wallpaper. On Android 12, both the system UI and individual applications can use color schemes based on the dynamic color system to provide an individualized and expressive experience.
In late October, the new guidelines, components, and APIs were finally released to enable developers to start building with Material Design 3.
The guidelines walk you through how to implement dynamic color and explore new personalization features of Material Design 3. If you're interested in dynamic colors, check out the links below:
-
New dynamic color guidelines: Describes how the dynamic color system works in detail, from generating tonal palettes to how color is applied to each component.
-
Guidance on customizing for brand expression: Describes how you can use the new color system to automatically adapt your app’s branding colors to your user’s color preferences.
The Compose Material 3 Library
If you're building apps with Jetpack Compose, you can access APIs and components for Material 3 using the aptly-named Compose Material 3 library.
This library contains updated components, typography, color, elevation APIs, and more. In this post, we'll only focus on the new ColorScheme class and dynamic colors.
However, you can take a look at the Material Theming in Compose page or the accompanying video from Android Dev Summit for more details on what’s included in the new Material API and how to use it.
To get started, you must include the library as a dependency in your project. As of now, the latest version is 1.0.0-alpha02:
1implementation "androidx.compose.material3:material3:1.0.0-alpha02"
You're now ready to start coding! Since the dynamic colors are only provided by the system on Android 12 and above, you need to check your device's SDK version.
You can use the dynamicLightColorScheme and dynamicDarkColorScheme methods to get a ColorScheme instance.
1234if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val lightColors: ColorScheme = dynamicLightColorScheme(context) val darkColors: ColorScheme = dynamicDarkColorScheme(context) }
This object includes all the colors described on the user-generated color page of the M3 documentation:
123456789101112@Stable class ColorScheme( primary: Color, onPrimary: Color, primaryContainer: Color, onPrimaryContainer: Color, inversePrimary: Color, secondary: Color, onSecondary: Color, secondaryContainer: Color, onSecondaryContainer: Color, ...,
If you're using the androidx.compose.material3.MaterialTheme
in your app, you can pass in a ColorScheme
directly, and the colors in it will be applied to all material3
components:
12345MaterialTheme(colorScheme = lightColors) { Button(...) { Text(...) } }
Be sure to import components such as
Button
orText
from theandroidx.compose.material3
package, and not fromandroidx.compose.material
!
However, you can also use the values in ColorScheme
directly in your Jetpack Compose code, which is what you'll do in the next section as you apply them to the Stream Chat SDK.
Theming With Material You Colors
In our Compose Chat SDK, theming is done by using the ChatTheme component. This accepts a StreamColor parameter, and all Chat UI Components use these colors in their implementation.
By default, we ship a set of light and dark colors which are applied automatically based on the system settings for dark mode.
123456789101112131415@Composable public fun ChatTheme( isInDarkMode: Boolean = isSystemInDarkTheme(), colors: StreamColors = if (isInDarkMode) StreamColors.defaultDarkColors() else StreamColors.defaultColors(), ... content: @Composable () -> Unit, ) { CompositionLocalProvider( LocalColors provides colors, ... ) { content() } }
Check out Customizing the Compose Chat SDK With ChatTheme to learn how you can customize Compose UI components to your requirements.
The Material 3 library exposes a ColorScheme
object. To apply those colors to the Chat Components, we need to somehow bridge the values in that object to a StreamColor
.
Here's an example of how you could do that:
123456789101112131415161718192021private fun adapt(scheme: ColorScheme) = StreamColors( textHighEmphasis = scheme.onPrimaryContainer, textLowEmphasis = scheme.onSecondaryContainer, disabled = scheme.inversePrimary, borders = scheme.outline, inputBackground = scheme.surfaceVariant, appBackground = scheme.background, barsBackground = scheme.secondaryContainer, linkBackground = scheme.primaryContainer, overlay = scheme.surface.copy(alpha = 0.5f), overlayDark = scheme.inverseSurface.copy(alpha = 0.5f), primaryAccent = scheme.primary, errorAccent = scheme.error, infoAccent = scheme.secondary, highlight = scheme.inversePrimary, ownMessagesBackground = scheme.secondaryContainer, otherMessagesBackground = scheme.tertiaryContainer, deletedMessagesBackground = scheme.onError, threadSeparatorGradientStart = scheme.background, threadSeparatorGradientEnd = scheme.surfaceVariant, )
This is just a quick example solution based on trial-and-error experimentation. Feel free to tinker around with the code to make the mapping even better!
To take light and dark mode into account, as well as the availability of dynamic colors on the device, you'd also want to perform the following steps:
123456789101112131415161718@Composable fun createStreamColors(): StreamColors { val isInDarkMode = isSystemInDarkTheme() return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Use dynamic colors if available val scheme = when { isInDarkMode -> dynamicDarkColorScheme(LocalContext.current) else -> dynamicLightColorScheme(LocalContext.current) } return adapt(scheme) } else { // Fall back to the default colors otherwise when { isInDarkMode -> StreamColors.defaultDarkColors() else -> StreamColors.defaultColors() } } }
Note: The function above is a
@Composable
function, which allows it to accessisSystemInDarkTheme()
dynamically, as well as theLocalContext
.
As the final step, you need to pass the colors created here to the ChatTheme
that wraps your Chat Components to apply the customizations:
12345678setContent { ChatTheme(colors = createStreamColors()) { MessagesScreen( channelId = channelId, onBackPressed = this::finish ) } }
If you run your app on an Android 12 device now, you'll see various color schemes based on the colors that the system extracts from your current wallpaper!
You can also toggle between light and dark mode, and the colors will update automatically:
You can check out the implementation above in action by grabbing the code from the GitHub repository for this tutorial and running it on your own device.
Theming With Material Theme Builder
The Material Design team introduced Material Theme Builder, which helps you visualize Material You's dynamic color and create a custom Material Design 3 theme.
The Material Theme Builder on the Web lets you build dynamic color schemes on the web client.
One of the noticeable features of the Material Theme Builder is that you can export your custom themes as native codes such as Android Views (XML) and Jetpack Compose (includes Theme, Color, and Type). As you can see below, Jetpack Compose codes based on a custom theme were generated on the website.
1234567891011121314151617181920212223242526272829val md_theme_light_primary = Color(0xFF6750A4) val md_theme_light_onPrimary = Color(0xFFFFFFFF) val md_theme_light_primaryContainer = Color(0xFFEADDFF) val md_theme_light_onPrimaryContainer = Color(0xFF21005D) ... val md_theme_dark_primary = Color(0xFFD0BCFF) val md_theme_dark_onPrimary = Color(0xFF381E72) val md_theme_dark_primaryContainer = Color(0xFF4F378B) val md_theme_dark_onPrimaryContainer = Color(0xFFEADDFF) ... private val LightThemeColors = lightColorScheme( primary = md_theme_light_primary, onPrimary = md_theme_light_onPrimary, primaryContainer = md_theme_light_primaryContainer, onPrimaryContainer = md_theme_light_onPrimaryContainer, secondary = md_theme_light_secondary, ..., private val DarkThemeColors = darkColorScheme( primary = md_theme_dark_primary, onPrimary = md_theme_dark_onPrimary, primaryContainer = md_theme_dark_primaryContainer, onPrimaryContainer = md_theme_dark_onPrimaryContainer, secondary = md_theme_dark_secondary, ...,
The end result with the generated theme will look like this:
Wrapping Up
In this tutorial, you saw how easy it is to pull colors from the Material 3 Compose library and use them in our Chat SDK for Compose. Feel free to keep iterating on the adaptation code to achieve even nicer results!
To learn more about the Compose Chat SDK, try the Compose Chat Tutorial or check out the Compose Chat documentation that covers all the available components, how to use them, and what customization options are available.
As always, keep coding!