To get started, you'll learn how to customize the chat features you build with Stream's Compose Chat SDK.
Specifically, you'll work with Stream's Compose ChatTheme component to define these features so that your app truly looks and feels the way you want it to.
You can find all the code in this article on GitHub.
Note: This article assumes you are familiar with Stream UI Components. If you're unfamiliar with Stream Jetpack Compose UI Components, check out the Jetpack Compose Chat Tutorial
Understanding the ChatTheme Component
The is the default wrapper for all Stream Compose components.
By default, it has properties that can style the entirety of any Stream Chat application. Some of these properties include (but are not limited to): colors, shapes, and typography.
With ChatTheme
, it's possible to apply a different set of colors, shapes, and typography to your entire chat app.
12345678910@Composable public fun ChatTheme( isInDarkMode: Boolean = isSystemInDarkTheme(), colors: StreamColors = if (isInDarkMode) StreamColors.defaultDarkColors() else StreamColors.defaultColors(), dimens: StreamDimens = StreamDimens.defaultDimens(), typography: StreamTypography = StreamTypography.defaultTypography(), shapes: StreamShapes = StreamShapes.defaultShapes(), // ... content: @Composable () -> Unit, )
To customize the ChatTheme
component, you need to provide your own colors, shapes, and typography to override ChatTheme
's default implementation.
Don't worry! You'll learn how you can add your own custom implementations to all the styling properties, starting with colors.
Adding Custom Colors
To add colors from your own design style, you need to use the StreamColors
class. This contains all colors in the Stream color palette.
First, you need an object to define your own colors:
123456789object CustomColors { val Primary = Color(0xFF69ABFD) val PrimaryDark = Color(0xFF478CE9) val PrimaryLight = Color(0xFFD0E8FD) val OverLay = Color(0xA0A2C8FF) val Accent = Color(0xFFA20DFF) val TextHigh = Color(0xFF1A1A1A) val TextLow = Color(0xFF2E2E2E) }
In the code above, you define the custom colors that you'll use for the components inside your app.
With your colors defined, you need to specify which custom colors you want to swap with the components in StreamColors
. This is what it looks like:
12345678910111213141516171819val CustomLightStreamColors @Composable get() = StreamColors.defaultColors().copy( textHighEmphasis = CustomColors.TextHigh, textLowEmphasis = CustomColors.TextLow, disabled = CustomColors.PrimaryDark, borders = CustomColors.Primary, inputBackground = CustomColors.PrimaryLight, appBackground = CustomColors.PrimaryLight, barsBackground = CustomColors.Primary, linkBackground = CustomColors.PrimaryLight, overlay = CustomColors.OverLay, overlayDark = CustomColors.PrimaryDark, primaryAccent = CustomColors.Accent, highlight = CustomColors.PrimaryDark, ownMessagesBackground = CustomColors.PrimaryDark, otherMessagesBackground = CustomColors.PrimaryDark, deletedMessagesBackgroundColor = CustomColors.PrimaryDark )
In the code above, you provide your custom colors for the various properties defined in the StreamColors
class. This will apply to your whole app. You can always change these values.
Additionally, you can re-use the default colors by using Stream.defaultColors()
. This returns an instance that contains the Stream color palette.
Note: You can always use the default set of colors, shapes, typography (and more) from Stream, and simply
copy
that object to adjust a few values inside it. This way, you don't have to provide all values yourself, just the ones you want to change!
Adding Custom Shapes
Shapes let you define the appearance of your components in your app. To customize the shapes, you use the StreamShapes
class, which contains the shapes for different components.
123456789val CustomStreamShapes = StreamShapes( avatar = RoundedCornerShape(40), myMessageBubble = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp, bottomStart = 20.dp), otherMessageBubble = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp, bottomEnd = 20.dp), inputField = RoundedCornerShape(24.dp), attachment = RoundedCornerShape(16.dp), imageThumbnail = RoundedCornerShape(10.dp), bottomSheet = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp), )
Using the StreamShapes
class, you can define the shapes for attachments, bottom sheets, input fields, avatars, images, thumbnails, and message bubbles.
The last bit on customization is the typography which you'll learn about next.
Adding Custom Typography
Typography allows you to add fonts to your app. The StreamTypography
class lets you define custom typography.
First, you need to add any custom fonts you want to use in the fonts folder. For this example, you can use the free Source Code Pro font.
Then, create a FontFamily
for your newly-added fonts:
1234val SourceCodePro = FontFamily( Font(R.font.sourcecodepro_regular), Font(R.font.sourcecodepro_bold, FontWeight.Bold) )
This allows you to use the SourceCodePro
font in your custom definitions.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869val StreamCustomTypography = StreamTypography( title1 = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Normal, fontSize = 18.sp ), title3 = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Normal, fontSize = 16.sp ), title3Bold = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Bold, fontSize = 16.sp ), body = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Normal, fontSize = 14.sp ), bodyItalic = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Normal, fontStyle = FontStyle.Italic, fontSize = 14.sp ), bodyBold = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Bold, fontSize = 14.sp ), footnote = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Normal, fontSize = 12.sp ), footnoteItalic = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Normal, fontStyle = FontStyle.Italic, fontSize = 12.sp ), footnoteBold = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Bold, fontSize = 12.sp ), captionBold = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Bold, fontSize = 12.sp ), tabBar = TextStyle( fontFamily = SourceCodePro, fontWeight = FontWeight.Normal, fontSize = 12.sp ) )
Here, you define all the text style properties that will be used across all the text style components in your chat app.
With the StreamTypography
class, if you only want to change the font family and not the values for other components, you can do so like this:
1StreamTypography.defaultTypography(SourceCodePro)
This only changes the font family. Other properties, like font size and weight, will remain the same as the default Stream UI Component values.
Now that you have all these custom components defined, it's time you apply them to ChatTheme
.
Joining the Pieces Together
Defining custom StreamTypography
, StreamShapes
, and StreamColors
won't apply these changes to your app. You also need to provide them to ChatTheme
.
To apply your customized components, wrap your UI components with ChatTheme
:
12345678910111213ChatTheme( shapes = CustomStreamShapes, colors = if (isSystemInDarkTheme()) StreamColors.defaultDarkColors() else CustomLightStreamColors, typography = StreamCustomTypography ) { ChannelsScreen( title = stringResource(id = R.string.app_name), onItemClick = { channel -> startActivity(MessagesActivity.getIntent(this, channel.cid)) }, onBackPressed = { finish() } ) }
Here's a breakdown of what the code above does:
- You use the
shapes
property to provide your custom shapes. - You use
colors
to provide your custom colors. (You also need to provide colors for dark mode. The above example uses Stream's default dark theme color palette, but you can choose to provide your own colors as well.) - You use
typography
to provide your custom typography.
Finally, you must add your customizations to every ChatTheme
instance across your app for your changes to apply. If you fail to apply your customizations to a ChatTheme
instance, it will use the default Stream theming instead.
Having applied these customizations to ChannelsScreen
and MessageScreen
, your app will now look like this:
What changed:
- You can see that the colors of components across the whole app have changed to be blue, as per the colors defined in the
CustomLightStreamColors
. - The corners on the input field, image thumbnails, and messages bubbles are slightly more rounded.
- The avatars have changed from a circle to a square.
- And of course, the font for all text components is now Source Code Pro.
Conclusion
In this article, you learned how to add your own custom theming to Stream Compose UI components and how easy it is to provide your own custom values to the different properties. This makes it easy for you to provide your own design system alongside Stream's UI Components.
You can find the full sample project with examples in this tutorial on GitHub.
To learn more about the Compose components and how to use them, take a look at the Compose SDK documentation.
The Compose SDK is still in beta. In case you have any feedback on using the SDK, reach the team on Twitter and on GitHub, or show us what customizations you're building!
And as always, happy coding!