Compose Theme: How to change light and dark mode dynamically with SharedFlow
In this article I want to propose a method to change from light mode to dark mode and vice versa using SharedFlow.
Part I: Animated colors switching from light to dark mode
Flow and SharedFlow
First let’s look at what a Flow is, let’s read the documentation:
In coroutines, a flow is a type that can emit multiple values sequentially, as opposed to suspend functions that return only a single value. For example, you can use a flow to receive live updates from a database.
Flows are built on top of coroutines and can provide multiple values. A flow is conceptually a stream of data that can be computed asynchronously. The emitted values must be of the same type. For example, a
Flow<Int>is a flow that emits integer values.
What about SharedFlow ? It is a Flow API that enable flows to optimally emit state updates and emit values to multiple consumers.
As an example, you could use a
SharedFlowto send ticks to the rest of the app so that all the content refreshes periodically at the same time.
Implementation
SharedFlow and Theme
First, we create our SharedFlowwhich we will use to notify the selected mode change:
Where Theme is an Enum with the theme modes.
Use cases
Now, following Android architecture with Hilt, we define in the domain model two use cases to emit and read the SharedFlow
With GetThemeUpdateUseCase we ask the Flow<Theme> value and with PublishThemeUpdateUseCase we emit the Theme value.
ViewModels
In the ViewModels we use the use cases above, in one of them we emit the Theme value selected from a DropdownMenu
Selecting the light or the dark mode we call publishThemeUpdateUseCase with the relative theme selected.
In the other ViewModel we collect the Theme value and update a State variable to observe the change in the Compose screen.
Update Theme
Finally, in the MainActivity we observe the theme state value to update the MaterialTheme , passing the value to our ComposeFuctionsTheme
In the following repository, you can find the completed runnable implementation, also we used DataStore to save the value locally:
You can find a branch with the implementation of Material 3.
Thank you, I hope you enjoyed reading it.
