Jetpack Compose nested theming preview

5.3k Views Asked by At

Let's consider the following @Composable functions:

@Composable
fun WelcomeScreen() {
    ...
    ButtonTheme {
        Button(...) {...}
    }
}

@Composable
@Preview
fun MockWelcome() {
    AppTheme {
        WelcomeScreen { }
    }
}

@Composable
@Preview
fun MockDarkWelcome() {
    AppTheme(darkTheme = true) {
        WelcomeScreen { }
    }
}

And theme (note: AppTheme follows the same logic):

@Composable
fun ButtonTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    MaterialTheme(
        ...
        colors = if (darkTheme) darkButtonColorPalette else lightButtonColorPalette,
    )
}

The preview window will show both WelcomeScreen versions correctly but the dark version will not show the button in the dark theme.
Running the app everything is OK, this it's only a preview "problem".

So, my question is: is this intended behaviour, a bug, or a misconfiguration?

Full code here: https://github.com/GuilhE/JetpackChallenge

1

There are 1 best solutions below

0
On

If you join together the previews and screen together you effectively have something like this:

AppTheme(darkTheme = true) {
    ButtonTheme {
        Button(...) {...}
    }
}

So the ButtonTheme will always be used no matter what theme you use in preview - the preview theme is overridden always.

To make the previews work as you want you'd need to abstract ButtonTheme outside of WelcomeScreen so something like this:

@Composable
fun MyApp() {
    ...
    MyTheme {
        WelcomeScreen()
    }
}

@Composable
fun WelcomeScreen() {
    ...
    Button(...) {...}
}

@Composable
@Preview
fun MockWelcome() {
    AppTheme {
        WelcomeScreen { }
    }
}

@Composable
@Preview
fun MockDarkWelcome() {
    AppTheme(darkTheme = true) {
        WelcomeScreen { }
    }
}