I would like to create an isDarkTheme
variable whose default value is that of the device's system. Then I would like to create a setter that can be used anywhere in the app. I've written this code which isn't correct:
class ThemeViewModel : ViewModel() {
private val _isDarkTheme = MutableStateFlow(isSystemInDarkTheme())
val isDarkTheme: StateFlow<Boolean> = _isDarkTheme.asStateFlow()
fun toggleTheme() {
_isDarkTheme.value = !_isDarkTheme.value
}
}
isSystemInDarkTheme()
is a composable function, so you cannot call it from your view model.
Instead change your view model to not only allow the states light (false
) and dark (true
), but also the state undefined (null
):
class ThemeViewModel : ViewModel() {
private val _isDarkTheme: MutableStateFlow<Boolean?> = MutableStateFlow(null)
val isDarkTheme: StateFlow<Boolean?> = _isDarkTheme.asStateFlow()
fun setTheme(isDarkTheme: Boolean) {
_isDarkTheme.value = isDarkTheme
}
}
I replaced toggleTheme
with setTheme
to make the null handling a bit easier.
Now you can use the view model in your composable like this:
val isDarkTheme =
viewModel.isDarkTheme.collectAsStateWithLifecycle().value ?: isSystemInDarkTheme()
MyAppTheme(isDarkTheme) {
Button(onClick = { viewModel.setTheme(!isDarkTheme) }) { Text("toggle theme") }
}
Here you can use isSystemInDarkTheme()
as a fallback should the view model's state be in the undefined state.