I am working on a Kotlin Multiplatform App with Compose Multiplatform for targets android, iOS and Desktop (MacOS, Linux and Windows with jvm). In my App.kt, I am setting the color scheme on the app based on the system theme, using light and dark color schemes as corresponds. Both Android and iOS are working as expected. However, in Windows and MacOS (I'm assuming Linux as well, but I've not been able to test it) it is working for the system theme the device had on the app start, but it doesn't change if the system config changes, meaning that the app has to be restarted in order to react to this change. How can I handle that? I have added some jvmArgs to adapt to the system theme, but it is only changing the top bar of the window of the app, not the scheme of the app itself.
compose.desktop {
...
application {
...
nativeDistributions {
...
jvmArgs("-Dapple.awt.application.appearance=system")
}
}
}
@Composable
fun App() {
val isDarkTheme = isSystemInDarkTheme()
MaterialTheme(
colorScheme = if(isDarkTheme) darkColorScheme() else lightColorScheme(),
typography = sampleTypography(),
) {
AppContent()
}
}
It's a known issue. Until it's fixed, you would have to use a library to detect theme changes on the desktop.
Personally I use jSystemThemeDetector, here's what the wrapper looks like.
You can have it as actual
for desktop and keep using system variant for other platforms.
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import com.jthemedetecor.OsThemeDetector
import java.util.function.Consumer
@Composable
fun isSystemInDarkTheme(): Boolean {
val isSystemInDarkTheme = isSystemInDarkTheme().let { currentValue ->
remember(currentValue) { mutableStateOf(currentValue) }
}
DisposableEffect(isSystemInDarkTheme) {
val listener = Consumer<Boolean> {
isSystemInDarkTheme.value = it
}
val detector = OsThemeDetector.getDetector()
detector.registerListener(listener)
onDispose {
detector.removeListener(listener)
}
}
return isSystemInDarkTheme.value
}