From 0c264d166fd8a7df31d62ac193790ec2738886f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Sastre=20Fl=C3=B3rez?= Date: Thu, 21 Mar 2024 16:27:17 +0100 Subject: [PATCH 1/3] migrate to M3 --- lazycolumnscreen/build.gradle | 3 +- .../lazycolumnscreen/CoffeeDrinksFragment.kt | 1 - .../lazycolumnscreen/CoffeeDrinksScreen.kt | 79 +++++++++++++--- .../testing/lazycolumnscreen/Divider.kt | 4 +- .../testing/lazycolumnscreen/ListItem.kt | 14 +-- .../testing/lazycolumnscreen/Theme.kt | 94 +++++++++++++------ 6 files changed, 141 insertions(+), 54 deletions(-) diff --git a/lazycolumnscreen/build.gradle b/lazycolumnscreen/build.gradle index ca42c248..a80b0547 100644 --- a/lazycolumnscreen/build.gradle +++ b/lazycolumnscreen/build.gradle @@ -55,11 +55,12 @@ dependencies { implementation "androidx.compose.runtime:runtime" implementation "androidx.compose.ui:ui" implementation "androidx.compose.foundation:foundation-layout" - implementation "androidx.compose.material:material" + implementation "androidx.compose.material3:material3" implementation "androidx.compose.material:material-icons-extended" implementation "androidx.compose.foundation:foundation" implementation "androidx.compose.animation:animation" implementation "androidx.compose.ui:ui-tooling" + implementation "androidx.compose.ui:ui-tooling-preview" implementation "androidx.compose.runtime:runtime-livedata" implementation "androidx.navigation:navigation-compose:2.7.7" diff --git a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksFragment.kt b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksFragment.kt index b4ce3ee4..4f31f875 100644 --- a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksFragment.kt +++ b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksFragment.kt @@ -7,7 +7,6 @@ import android.view.ViewGroup import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity import androidx.fragment.app.viewModels class CoffeeDrinksFragment : Fragment() { diff --git a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksScreen.kt b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksScreen.kt index 7e3e3d23..28896c87 100644 --- a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksScreen.kt +++ b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/CoffeeDrinksScreen.kt @@ -1,20 +1,24 @@ package com.example.road.to.effective.snapshot.testing.lazycolumnscreen import android.annotation.SuppressLint +import android.content.res.Configuration import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.SnackbarDuration -import androidx.compose.material.SnackbarHost -import androidx.compose.material.SnackbarHostState -import androidx.compose.material.SnackbarResult -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.material.TopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarColors import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -23,6 +27,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewDynamicColors +import androidx.compose.ui.tooling.preview.Wallpapers @SuppressLint("UnusedMaterialScaffoldPaddingParameter") @Composable @@ -35,7 +42,7 @@ fun ShowSuccessCoffeeDrinksScreen( Scaffold( snackbarHost = { SnackbarHost(snackbarHostState) }, - ) { + ) { padding -> if (showSnackbar) { ActionNotSupportedSnackbar( @@ -45,6 +52,7 @@ fun ShowSuccessCoffeeDrinksScreen( } CoffeeDrinksScreenUI( + modifier = Modifier.padding(padding), coffeeDrinksState = coffeeDrinksState, coffeeShopName = coffeeShopName, onCoffeeDrinkItemClick = { showSnackbar = true } @@ -54,11 +62,14 @@ fun ShowSuccessCoffeeDrinksScreen( @Composable fun CoffeeDrinksScreenUI( + modifier: Modifier = Modifier, coffeeDrinksState: CoffeeDrinksState, coffeeShopName: String, onCoffeeDrinkItemClick: () -> Unit, ) { - Surface { + Surface( + modifier = modifier + ) { Column { CoffeeDrinkAppBar(coffeeShopName) CoffeeDrinkList( @@ -69,6 +80,40 @@ fun CoffeeDrinksScreenUI( } } +@Preview( + name = "with_dynamic_colors", + apiLevel = 30, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Preview( + name = "no_dynamic_colors", + apiLevel = 30, + uiMode = Configuration.UI_MODE_NIGHT_NO +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.BLUE_DOMINATED_EXAMPLE +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.RED_DOMINATED_EXAMPLE +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.GREEN_DOMINATED_EXAMPLE +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.YELLOW_DOMINATED_EXAMPLE +) +@Composable +fun PreviewCoffeeDrinkAppBar() { + AppTheme { + CoffeeDrinkAppBar() + } +} + +@OptIn(ExperimentalMaterial3Api::class) @Composable fun CoffeeDrinkAppBar( coffeeShopName: String = "", @@ -77,12 +122,16 @@ fun CoffeeDrinkAppBar( title = { Text( text = stringResource(R.string.coffee_drinks_title).addLocation(coffeeShopName), - style = MaterialTheme.typography.h6.copy( - color = MaterialTheme.colors.onPrimary - ) + style = MaterialTheme.typography.titleLarge ) }, - backgroundColor = MaterialTheme.colors.primary + colors = TopAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + scrolledContainerColor = MaterialTheme.colorScheme.primary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + actionIconContentColor = MaterialTheme.colorScheme.onPrimary + ) ) } diff --git a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Divider.kt b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Divider.kt index cb2a5801..6a85ab61 100644 --- a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Divider.kt +++ b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Divider.kt @@ -3,7 +3,7 @@ package com.example.road.to.effective.snapshot.testing.lazycolumnscreen import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding -import androidx.compose.material.Divider +import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -13,7 +13,7 @@ import androidx.compose.ui.graphics.Color fun AppDivider( padding: PaddingValues = PaddingValues() ) { - Divider( + HorizontalDivider( modifier = Modifier .padding(padding) .alpha(0.12f), diff --git a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/ListItem.kt b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/ListItem.kt index 12e9a8c2..9cd99b2f 100644 --- a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/ListItem.kt +++ b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/ListItem.kt @@ -11,9 +11,9 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface -import androidx.compose.material.Text +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -46,7 +46,7 @@ fun CoffeeDrinkList( fun CoffeeDrinkListItem( coffeeDrink: CoffeeDrinkItem ) { - Row(Modifier.background(color = MaterialTheme.colors.background)) { + Row(Modifier.background(color = MaterialTheme.colorScheme.background)) { CoffeeDrinkLogo(id = coffeeDrink.imageUrl) Box( modifier = Modifier.weight(1f) @@ -82,7 +82,7 @@ private fun CoffeeDrinkTitle(title: String) { text = title, modifier = Modifier.padding(top = 8.dp, end = 8.dp), style = TextStyle(fontSize = 24.sp), - color = MaterialTheme.colors.onSurface, + color = MaterialTheme.colorScheme.onSurface, maxLines = 1 ) } @@ -96,7 +96,7 @@ private fun CoffeeDrinkIngredient(ingredients: String) { .alpha(0.54f), maxLines = 1, overflow = TextOverflow.Ellipsis, - style = MaterialTheme.typography.body1, - color = MaterialTheme.colors.onSurface + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface ) } diff --git a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt index dd075609..eb6259f0 100644 --- a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt +++ b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt @@ -1,39 +1,74 @@ package com.example.road.to.effective.snapshot.testing.lazycolumnscreen +import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material.MaterialTheme -import androidx.compose.material.darkColors -import androidx.compose.material.lightColors +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext -val lightThemeColors = lightColors( +val lightThemeColors = lightColorScheme( primary = Color(0xFF855446), - primaryVariant = Color(0xFF9C684B), - secondary = Color(0xFF03DAC5), - secondaryVariant = Color(0xFF0AC9F0), - background = Color.White, - surface = Color.White, + secondary = Color(0xFF9C684B), + tertiary = Color(0xFF03DAC5), error = Color(0xFFB00020), + background = Color.White, + + primaryContainer = Color(0xFFFFDBD1), + secondaryContainer = Color(0xFFFFDBCA), + tertiaryContainer = Color(0xFF4FFBE5), + errorContainer = Color(0xFFFFDAD6), + surface = Color(0xFFf8FDFF), + + onPrimaryContainer = Color(0xFF3B0900), + onSecondaryContainer = Color(0xFF331200), + onTertiaryContainer = Color(0xFF00201C), + onErrorContainer = Color(0xFF410002), + onSurface = Color(0xFF001F25), + onPrimary = Color.White, onSecondary = Color.White, - onBackground = Color.Black, - onSurface = Color.Black, - onError = Color.White + onTertiary = Color.White, + onError = Color.White, + onBackground = Color(0xFF001F25), + + outline = Color(0xFF85736E), + surfaceVariant = Color(0xFFF5DED8), + onSurfaceVariant = Color(0xFF53433F) ) -val darkThemeColors = darkColors( - primary = Color(0xFF1F1F1F), - primaryVariant = Color(0xFF3E2723), - secondary = Color(0xFF03DAC5), - background = Color(0xFF121212), - surface = Color.Black, - error = Color(0xFFCF6679), - onPrimary = Color.White, - onSecondary = Color.White, - onBackground = Color.White, - onSurface = Color.White, - onError = Color.Black +val darkThemeColors = darkColorScheme( + primary = Color(0xFFFFB5A0), + secondary = Color(0xFFFFB68E), + tertiary = Color(0xFF17DEC9), + error = Color(0xFFFFB4AB), + background = Color(0xFF001F25), + + onPrimary = Color(0xFF5E1702), + onSecondary = Color(0xFF542200), + onTertiary = Color(0xFF003731), + onError = Color(0xFF690005), + onBackground = Color(0xFFA6EEFF), + + primaryContainer = Color(0xFF7C2D15), + secondaryContainer = Color(0xFF773300), + tertiaryContainer = Color(0xFF005048), + errorContainer = Color(0xFF93000A), + surface = Color(0xFF001F25), + + onPrimaryContainer = Color(0xFFFFDBD1), + onSecondaryContainer = Color(0xFFFFDBCA), + onTertiaryContainer = Color(0xFF4FFBE5), + onErrorContainer = Color(0xFFFFDAD6), + onSurface = Color(0xFFA6EEFF), + + outline = Color(0xFF5E1702), + surfaceVariant = Color(0xFF53433F), + onSurfaceVariant = Color(0xFFD8C2BC), ) @SuppressWarnings @@ -41,14 +76,17 @@ val darkThemeColors = darkColors( fun AppTheme( content: @Composable () -> Unit ) { - val colors = if (isSystemInDarkTheme()) { - darkThemeColors + val inDarkMode: Boolean = isSystemInDarkTheme() + + val colors = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val context = LocalContext.current + if (inDarkMode) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) } else { - lightThemeColors + if (inDarkMode) darkThemeColors else lightThemeColors } MaterialTheme( - colors = colors, + colorScheme = colors, content = content ) } From 8a3490f4d048add8f1a2c2f42bdfb487ebb44bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Sastre=20Fl=C3=B3rez?= Date: Wed, 18 Sep 2024 09:25:10 +0200 Subject: [PATCH 2/3] Add Compose-Preview Screenshots for Wallpapers --- .../PreviewsForScreenshotTests.kt | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/lazycolumnscreen-previews/compose-screenshot/src/screenshotTest/java/snapshot/testing/lazycolumn_previews/compose_screenshot/PreviewsForScreenshotTests.kt b/lazycolumnscreen-previews/compose-screenshot/src/screenshotTest/java/snapshot/testing/lazycolumn_previews/compose_screenshot/PreviewsForScreenshotTests.kt index 6142553b..af8739a5 100644 --- a/lazycolumnscreen-previews/compose-screenshot/src/screenshotTest/java/snapshot/testing/lazycolumn_previews/compose_screenshot/PreviewsForScreenshotTests.kt +++ b/lazycolumnscreen-previews/compose-screenshot/src/screenshotTest/java/snapshot/testing/lazycolumn_previews/compose_screenshot/PreviewsForScreenshotTests.kt @@ -1,24 +1,30 @@ package snapshot.testing.lazycolumn_previews.compose_screenshot +import android.content.res.Configuration import android.os.Build import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewFontScale import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.Wallpapers import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.AppTheme +import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.CoffeeDrinkAppBar import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.CoffeeDrinkItem import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.CoffeeDrinkList import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.R /** + * Screenshot tests are generated from these Previews. + * A general tolerance value is defined in the gradle plugin + * * Record: ./gradlew :lazycolumnscreen-previews:compose-screenshot:updateDebugScreenshotTest * Verify: ./gradlew :lazycolumnscreen-previews:compose-screenshot:validateDebugScreenshotTest * * Keep in mind that currently, Compose Preview screenshot testing tool only supports previews * in the "screenshotTest" source, so previews in the "main" source are ignored */ -class PreviewsForScreenshotTests { +class CoffeeDrinkItemPreviews { private val coffeeDrink = CoffeeDrinkItem( id = 1L, @@ -66,7 +72,7 @@ class PreviewsForScreenshotTests { } } - @Preview(apiLevel = 31) + @Preview(apiLevel = 33) @Composable fun CoffeeDrinkListApiLevelPreview() { AppTheme { @@ -75,4 +81,62 @@ class PreviewsForScreenshotTests { ) } } +} + +class AppBarWallpaperPreviews { + // Dynamic Colors are applied from API 31+ + @Preview( + apiLevel = 30, + uiMode = Configuration.UI_MODE_NIGHT_YES + ) + @Preview( + apiLevel = 30, + uiMode = Configuration.UI_MODE_NIGHT_NO + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.BLUE_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.BLUE_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.RED_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.RED_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.GREEN_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.GREEN_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.YELLOW_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO + ) + @Preview( + apiLevel = 33, + wallpaper = Wallpapers.YELLOW_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES + ) + @Composable + fun PreviewCoffeeDrinkAppBar() { + AppTheme { + CoffeeDrinkAppBar() + } + } } \ No newline at end of file From daed318196754faa986e5822ef535b9443c6541b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Sastre=20Fl=C3=B3rez?= Date: Wed, 18 Sep 2024 09:26:48 +0200 Subject: [PATCH 3/3] Add Roborazzi tests for Wallpapers --- .../roborazzi/build.gradle | 5 +- .../roborazzi/PreviewsForScreenshotTests.kt | 62 ++++++++++++++++++- .../roborazzi/RoborazziComposePreviewTests.kt | 52 +++++++++++++--- .../roborazzi/utils/RenderPreview.kt | 35 +++++++++++ .../testing/lazycolumnscreen/Theme.kt | 17 ++++- 5 files changed, 160 insertions(+), 11 deletions(-) create mode 100644 lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/utils/RenderPreview.kt diff --git a/lazycolumnscreen-previews/roborazzi/build.gradle b/lazycolumnscreen-previews/roborazzi/build.gradle index c796c934..d48ec0c7 100644 --- a/lazycolumnscreen-previews/roborazzi/build.gradle +++ b/lazycolumnscreen-previews/roborazzi/build.gradle @@ -65,7 +65,7 @@ dependencies { implementation platform('androidx.compose:compose-bom:2024.05.00') implementation "androidx.compose.runtime:runtime" implementation "androidx.compose.foundation:foundation-layout" - implementation "androidx.compose.material:material" + implementation "androidx.compose.material3:material3" implementation "androidx.compose.material:material-icons-extended" implementation "androidx.compose.foundation:foundation" implementation "androidx.compose.animation:animation" @@ -81,4 +81,7 @@ dependencies { testImplementation 'io.github.takahirom.roborazzi:roborazzi-compose:1.26.0' testImplementation 'com.github.sergio-sastre.ComposablePreviewScanner:android:0.3.0' + + // To support Dynamic Colors in Roborazzi tests + testImplementation("com.materialkolor:material-kolor:1.7.0") } \ No newline at end of file diff --git a/lazycolumnscreen-previews/roborazzi/src/main/java/snapshot/testing/lazycolumn_previews/roborazzi/PreviewsForScreenshotTests.kt b/lazycolumnscreen-previews/roborazzi/src/main/java/snapshot/testing/lazycolumn_previews/roborazzi/PreviewsForScreenshotTests.kt index 99165eb5..7502961c 100644 --- a/lazycolumnscreen-previews/roborazzi/src/main/java/snapshot/testing/lazycolumn_previews/roborazzi/PreviewsForScreenshotTests.kt +++ b/lazycolumnscreen-previews/roborazzi/src/main/java/snapshot/testing/lazycolumn_previews/roborazzi/PreviewsForScreenshotTests.kt @@ -1,12 +1,15 @@ package snapshot.testing.lazycolumn_previews.roborazzi +import android.content.res.Configuration import android.os.Build import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewFontScale import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.Wallpapers import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.AppTheme +import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.CoffeeDrinkAppBar import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.CoffeeDrinkItem import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.CoffeeDrinkList import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.R @@ -39,7 +42,6 @@ fun CoffeeDrinkListWithParametersPreview( } } - @PreviewFontScale @PreviewLightDark @Composable @@ -61,7 +63,7 @@ fun CoffeeDrinkListPseudoLocalePreview() { } } -@Preview(apiLevel = 31) +@Preview(apiLevel = 33) @Composable fun CoffeeDrinkListApiLevelPreview() { AppTheme { @@ -80,4 +82,60 @@ fun CoffeeDrinkListAccessibilityPreview() { coffeeDrink = coffeeDrink ) } +} + +// Dynamic Colors are applied from API 31+ +@Preview( + apiLevel = 30, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Preview( + apiLevel = 30, + uiMode = Configuration.UI_MODE_NIGHT_NO +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.BLUE_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.BLUE_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.RED_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.RED_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.GREEN_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.GREEN_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.YELLOW_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_NO +) +@Preview( + apiLevel = 33, + wallpaper = Wallpapers.YELLOW_DOMINATED_EXAMPLE, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Composable +fun PreviewCoffeeDrinkAppBar() { + AppTheme { + CoffeeDrinkAppBar() + } } \ No newline at end of file diff --git a/lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/RoborazziComposePreviewTests.kt b/lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/RoborazziComposePreviewTests.kt index dbb14438..da3b9b24 100644 --- a/lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/RoborazziComposePreviewTests.kt +++ b/lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/RoborazziComposePreviewTests.kt @@ -11,6 +11,7 @@ import sergio.sastre.composable.preview.scanner.android.AndroidComposablePreview import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo import sergio.sastre.composable.preview.scanner.android.screenshotid.AndroidPreviewScreenshotIdBuilder import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview +import snapshot.testing.lazycolumn_previews.roborazzi.utils.RenderPreview import snapshot.testing.lazycolumn_previews.roborazzi.utils.RobolectricPreviewInfosApplier import snapshot.testing.lazycolumn_previews.roborazzi.utils.RoborazziConfig import snapshot.testing.lazycolumn_previews.roborazzi.utils.RoborazziOptionsMapper @@ -40,7 +41,9 @@ class RoborazziApiLevelUnder28ComposePreviewTests( .scanPackageTrees("snapshot.testing.lazycolumn_previews.roborazzi") .includeAnnotationInfoForAllOf(RoborazziConfig::class.java) // Native graphics do not work fine on API < 28, and default value is -1 - .filterPreviews { previewParams -> previewParams.apiLevel < 28 } + .filterPreviews { + preview -> preview.apiLevel < 28 || preview.apiLevel == 34 + } .getPreviews() } @@ -59,13 +62,13 @@ class RoborazziApiLevelUnder28ComposePreviewTests( filePath = filePath(AndroidPreviewScreenshotIdBuilder(preview).build()), roborazziOptions = RoborazziOptionsMapper.createFor(preview) ) { - preview() + RenderPreview(preview) } } } @RunWith(ParameterizedRobolectricTestRunner::class) -class RoborazziApiLevel31ComposePreviewTests( +class RoborazziApiLevelUnder30ComposePreviewTests( private val preview: ComposablePreview, ) { @@ -74,7 +77,42 @@ class RoborazziApiLevel31ComposePreviewTests( AndroidComposablePreviewScanner() .scanPackageTrees("snapshot.testing.lazycolumn_previews.roborazzi") .includeAnnotationInfoForAllOf(RoborazziConfig::class.java) - .filterPreviews { previewParams -> previewParams.apiLevel == 31 } + // Native graphics do not work fine on API < 28, and default value is -1 + .filterPreviews { preview -> preview.apiLevel == 30 } + .getPreviews() + } + + @JvmStatic + @ParameterizedRobolectricTestRunner.Parameters + fun values(): List> = cachedPreviews + } + + @GraphicsMode(NATIVE) + @Config(sdk = [30]) // same as filtered previews + @Test + fun snapshot() { + RobolectricPreviewInfosApplier.applyFor(preview) + + captureRoboImage( + filePath = filePath(AndroidPreviewScreenshotIdBuilder(preview).build()), + roborazziOptions = RoborazziOptionsMapper.createFor(preview) + ) { + RenderPreview(preview) + } + } +} + +@RunWith(ParameterizedRobolectricTestRunner::class) +class RoborazziApiLevel33ComposePreviewTests( + private val preview: ComposablePreview, +) { + + companion object { + private val cachedPreviews: List> by lazy { + AndroidComposablePreviewScanner() + .scanPackageTrees("snapshot.testing.lazycolumn_previews.roborazzi") + .includeAnnotationInfoForAllOf(RoborazziConfig::class.java) + .filterPreviews { preview -> preview.apiLevel == 33 } .getPreviews() } @@ -84,7 +122,7 @@ class RoborazziApiLevel31ComposePreviewTests( } @GraphicsMode(NATIVE) - @Config(sdk = [31]) // same as filtered previews + @Config(sdk = [33]) // same as filtered previews @Test fun snapshot() { RobolectricPreviewInfosApplier.applyFor(preview) @@ -93,7 +131,7 @@ class RoborazziApiLevel31ComposePreviewTests( filePath = filePath(AndroidPreviewScreenshotIdBuilder(preview).build()), roborazziOptions = RoborazziOptionsMapper.createFor(preview) ) { - preview() + RenderPreview(preview) } } -} \ No newline at end of file +} diff --git a/lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/utils/RenderPreview.kt b/lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/utils/RenderPreview.kt new file mode 100644 index 00000000..6cda8059 --- /dev/null +++ b/lazycolumnscreen-previews/roborazzi/src/test/java/snapshot/testing/lazycolumn_previews/roborazzi/utils/RenderPreview.kt @@ -0,0 +1,35 @@ +package snapshot.testing.lazycolumn_previews.roborazzi.utils + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Wallpapers +import com.example.road.to.effective.snapshot.testing.lazycolumnscreen.LocalAppTheme +import com.materialkolor.DynamicMaterialTheme +import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo +import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview + +@Composable +fun RenderPreview( + previewComposable: ComposablePreview +) { + val seedColor = + when (previewComposable.previewInfo.wallpaper) { + Wallpapers.RED_DOMINATED_EXAMPLE -> Color.Red + Wallpapers.GREEN_DOMINATED_EXAMPLE -> Color.Green + Wallpapers.YELLOW_DOMINATED_EXAMPLE -> Color.Yellow + Wallpapers.BLUE_DOMINATED_EXAMPLE -> Color.Blue + Wallpapers.NONE -> null + else -> null + } + + when (seedColor == null) { + true -> previewComposable() + false -> + CompositionLocalProvider( + LocalAppTheme provides { content -> DynamicMaterialTheme(seedColor) { content() } } + ) { + previewComposable() + } + } +} \ No newline at end of file diff --git a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt index eb6259f0..4ac42fcb 100644 --- a/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt +++ b/lazycolumnscreen/src/main/java/com/example/road/to/effective/snapshot/testing/lazycolumnscreen/Theme.kt @@ -8,6 +8,7 @@ import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @@ -71,9 +72,13 @@ val darkThemeColors = darkColorScheme( onSurfaceVariant = Color(0xFFD8C2BC), ) +val LocalAppTheme = staticCompositionLocalOf<(@Composable (content: @Composable () -> Unit) -> Unit)> { + { content -> DefaultAppTheme(content) } // Default to your real `AppTheme` +} + @SuppressWarnings @Composable -fun AppTheme( +private fun DefaultAppTheme( content: @Composable () -> Unit ) { val inDarkMode: Boolean = isSystemInDarkTheme() @@ -90,3 +95,13 @@ fun AppTheme( content = content ) } + +@SuppressWarnings +@Composable +fun AppTheme( + content: @Composable () -> Unit +) { + val appTheme = LocalAppTheme.current + // Apply the theme (either the default `AppTheme` or an overridden one in tests) + appTheme(content) +}