From 2b688fa3d57f9fc60d083db80533bfea37ee7402 Mon Sep 17 00:00:00 2001 From: Al Kent Date: Thu, 18 Apr 2024 14:27:24 -0500 Subject: [PATCH] adding plugin extension stub --- gradle/libs.versions.toml | 1 - paparazzi-annotations/build.gradle | 4 + .../api/paparazzi-gradle-plugin.api | 3 + .../cash/paparazzi/gradle/PaparazziPlugin.kt | 9 ++ paparazzi/api/paparazzi.api | 38 ----- .../app/cash/paparazzi/preview/Snapshot.kt | 104 -------------- .../java/app/cash/paparazzi/preview/Utils.kt | 133 ------------------ 7 files changed, 16 insertions(+), 276 deletions(-) delete mode 100644 paparazzi/src/main/java/app/cash/paparazzi/preview/Snapshot.kt delete mode 100644 paparazzi/src/main/java/app/cash/paparazzi/preview/Utils.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4fd264211c..38269b8cd9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,6 @@ bytebuddy-agent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "by bytebuddy-core = { module = "net.bytebuddy:byte-buddy", version.ref = "bytebuddy" } compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" } -composeUi-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose" } composeUi-material = { module = "androidx.compose.material:material", version.ref = "compose" } composeUi-uiTooling = { module = "androidx.compose.ui:ui-tooling" } diff --git a/paparazzi-annotations/build.gradle b/paparazzi-annotations/build.gradle index 30ffd833c6..d5acfb4b71 100644 --- a/paparazzi-annotations/build.gradle +++ b/paparazzi-annotations/build.gradle @@ -1,3 +1,7 @@ apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.plugin.compose' apply plugin: 'com.vanniktech.maven.publish' + +dependencies { + implementation libs.compose.runtime +} diff --git a/paparazzi-gradle-plugin/api/paparazzi-gradle-plugin.api b/paparazzi-gradle-plugin/api/paparazzi-gradle-plugin.api index 7596e218ac..5a49a902ee 100644 --- a/paparazzi-gradle-plugin/api/paparazzi-gradle-plugin.api +++ b/paparazzi-gradle-plugin/api/paparazzi-gradle-plugin.api @@ -1,3 +1,6 @@ +public abstract interface class app/cash/paparazzi/gradle/PaparazziExtension { +} + public final class app/cash/paparazzi/gradle/PaparazziPlugin : org/gradle/api/Plugin { public fun (Lorg/gradle/api/provider/ProviderFactory;)V public synthetic fun apply (Ljava/lang/Object;)V diff --git a/paparazzi-gradle-plugin/src/main/java/app/cash/paparazzi/gradle/PaparazziPlugin.kt b/paparazzi-gradle-plugin/src/main/java/app/cash/paparazzi/gradle/PaparazziPlugin.kt index 37a4708480..9175bd51bf 100644 --- a/paparazzi-gradle-plugin/src/main/java/app/cash/paparazzi/gradle/PaparazziPlugin.kt +++ b/paparazzi-gradle-plugin/src/main/java/app/cash/paparazzi/gradle/PaparazziPlugin.kt @@ -46,11 +46,17 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget import java.util.Locale import javax.inject.Inject +public interface PaparazziExtension + @Suppress("unused") public class PaparazziPlugin @Inject constructor( private val providerFactory: ProviderFactory ) : Plugin { + + private lateinit var config: PaparazziExtension override fun apply(project: Project) { + config = project.createDslConfig() + val supportedPlugins = listOf("com.android.application", "com.android.library", "com.android.dynamic-feature") project.afterEvaluate { check(supportedPlugins.any { project.plugins.hasPlugin(it) }) { @@ -258,6 +264,8 @@ public class PaparazziPlugin @Inject constructor( } } + private fun Project.createDslConfig() = extensions.create(EXTENSION_NAME, PaparazziExtension::class.java) + private fun Project.setupLayoutlibRuntimeDependency(): FileCollection { val operatingSystem = OperatingSystem.current() val nativeLibraryArtifactId = when { @@ -322,3 +330,4 @@ public class PaparazziPlugin @Inject constructor( } private const val DEFAULT_COMPILE_SDK_VERSION = 34 +private const val EXTENSION_NAME = "paparazzi" diff --git a/paparazzi/api/paparazzi.api b/paparazzi/api/paparazzi.api index b451ff9db0..01a6bf3947 100644 --- a/paparazzi/api/paparazzi.api +++ b/paparazzi/api/paparazzi.api @@ -235,41 +235,3 @@ public final class app/cash/paparazzi/accessibility/AccessibilityRenderExtension public fun renderView (Landroid/view/View;)Landroid/view/View; } -public final class app/cash/paparazzi/preview/ComposableSingletons$SnapshotKt { - public static final field INSTANCE Lapp/cash/paparazzi/preview/ComposableSingletons$SnapshotKt; - public static field lambda-1 Lkotlin/jvm/functions/Function3; - public fun ()V - public final fun getLambda-1$paparazzi ()Lkotlin/jvm/functions/Function3; -} - -public final class app/cash/paparazzi/preview/ComposableSingletons$UtilsKt { - public static final field INSTANCE Lapp/cash/paparazzi/preview/ComposableSingletons$UtilsKt; - public static field lambda-1 Lkotlin/jvm/functions/Function3; - public static field lambda-2 Lkotlin/jvm/functions/Function3; - public fun ()V - public final fun getLambda-1$paparazzi ()Lkotlin/jvm/functions/Function3; - public final fun getLambda-2$paparazzi ()Lkotlin/jvm/functions/Function3; -} - -public final class app/cash/paparazzi/preview/DefaultLocaleRule : org/junit/rules/TestRule { - public static final field $stable I - public fun (Ljava/lang/String;)V - public fun apply (Lorg/junit/runners/model/Statement;Lorg/junit/runner/Description;)Lorg/junit/runners/model/Statement; - public final fun getLocale ()Ljava/lang/String; -} - -public class app/cash/paparazzi/preview/PaparazziValuesProvider : com/google/testing/junit/testparameterinjector/TestParameter$TestParameterValuesProvider { - public static final field $stable I - public fun (Ljava/util/List;)V - public fun provideValues ()Ljava/util/List; -} - -public final class app/cash/paparazzi/preview/SnapshotKt { - public static final fun deviceConfig (Lapp/cash/paparazzi/annotations/PaparazziPreviewData;Lapp/cash/paparazzi/DeviceConfig;)Lapp/cash/paparazzi/DeviceConfig; - public static synthetic fun deviceConfig$default (Lapp/cash/paparazzi/annotations/PaparazziPreviewData;Lapp/cash/paparazzi/DeviceConfig;ILjava/lang/Object;)Lapp/cash/paparazzi/DeviceConfig; - public static final fun flatten (Ljava/util/List;)Ljava/util/List; - public static final fun locale (Lapp/cash/paparazzi/annotations/PaparazziPreviewData;)Ljava/lang/String; - public static final fun snapshot (Lapp/cash/paparazzi/Paparazzi;Lapp/cash/paparazzi/annotations/PaparazziPreviewData;Ljava/lang/String;ZLkotlin/jvm/functions/Function3;)V - public static synthetic fun snapshot$default (Lapp/cash/paparazzi/Paparazzi;Lapp/cash/paparazzi/annotations/PaparazziPreviewData;Ljava/lang/String;ZLkotlin/jvm/functions/Function3;ILjava/lang/Object;)V -} - diff --git a/paparazzi/src/main/java/app/cash/paparazzi/preview/Snapshot.kt b/paparazzi/src/main/java/app/cash/paparazzi/preview/Snapshot.kt deleted file mode 100644 index 8c06dcece6..0000000000 --- a/paparazzi/src/main/java/app/cash/paparazzi/preview/Snapshot.kt +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright Square, Inc. -package app.cash.paparazzi.preview - -import androidx.compose.runtime.Composable -import app.cash.paparazzi.DeviceConfig -import app.cash.paparazzi.Paparazzi -import app.cash.paparazzi.annotations.PaparazziPreviewData -import com.google.testing.junit.testparameterinjector.TestParameter.TestParameterValuesProvider -import org.junit.rules.TestRule -import org.junit.runner.Description -import org.junit.runners.model.Statement -import java.util.Locale - -/** - * Take a snapshot of the given [previewData]. - */ -public fun Paparazzi.snapshot( - previewData: PaparazziPreviewData, - name: String? = null, - localInspectionMode: Boolean = true, - wrapper: @Composable (@Composable () -> Unit) -> Unit = { it() } -) { - when (previewData) { - is PaparazziPreviewData.Default -> snapshotDefault(previewData, name, localInspectionMode, wrapper) - is PaparazziPreviewData.Provider<*> -> snapshotProvider(previewData, name, localInspectionMode, wrapper) - is PaparazziPreviewData.Empty -> Unit - is PaparazziPreviewData.Error -> throw Exception(previewData.message) - } -} - -/** - * Generate a Paparazzi DeviceConfig for the given preview - * using the given [default] DeviceConfig. - * - * default: The IDE renders a preview with a higher resolution than - * the default device set by Paparazzi (which is currently Nexus 5). Defaulting to - * a larger device brings the previews and snapshots closer in parity. - */ -public fun PaparazziPreviewData.deviceConfig( - default: DeviceConfig = DeviceConfig.PIXEL_5 -): DeviceConfig = when (this) { - is PaparazziPreviewData.Default -> preview.deviceConfig(default) - is PaparazziPreviewData.Provider<*> -> preview.deviceConfig(default) - else -> default -} - -/** - * Returns a locale for the given preview, or null if error or empty. - */ -public fun PaparazziPreviewData.locale(): String? = when (this) { - is PaparazziPreviewData.Default -> preview.locale - is PaparazziPreviewData.Provider<*> -> preview.locale - else -> null -} - -/** - * Convert a list of generated [PaparazziPreviewData] - * to a flat list of [PaparazziPreviewData]s. - */ -public fun List.flatten(): List = flatMap { - when (it) { - is PaparazziPreviewData.Provider<*> -> List(it.previewParameter.values.count()) { i -> - it.withPreviewParameterIndex(i) - } - else -> listOf(it) - } -} - -/** - * A `@TestParameter` values provider for the given [annotations]. - * - * Example usage: - * ``` - * private class ValuesProvider : PaparazziValuesProvider(paparazziAnnotations) - * ``` - */ -public open class PaparazziValuesProvider( - private val annotations: List -) : TestParameterValuesProvider { - override fun provideValues(): List = annotations.flatten() -} - -/** - * Enforce a particular default locale for a test. Resets back to default on completion. - */ -public class DefaultLocaleRule(public val locale: String?) : TestRule { - override fun apply( - base: Statement, - description: Description - ): Statement { - return object : Statement() { - override fun evaluate() { - val default = Locale.getDefault() - - try { - locale?.let { Locale.setDefault(Locale.forLanguageTag(it)) } - base.evaluate() - } finally { - Locale.setDefault(default) - } - } - } - } -} diff --git a/paparazzi/src/main/java/app/cash/paparazzi/preview/Utils.kt b/paparazzi/src/main/java/app/cash/paparazzi/preview/Utils.kt deleted file mode 100644 index b70b87e662..0000000000 --- a/paparazzi/src/main/java/app/cash/paparazzi/preview/Utils.kt +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright Square, Inc. -package app.cash.paparazzi.preview - -import android.content.res.Configuration -import android.util.DisplayMetrics -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalInspectionMode -import app.cash.paparazzi.DeviceConfig -import app.cash.paparazzi.Paparazzi -import app.cash.paparazzi.annotations.PaparazziPreviewData -import app.cash.paparazzi.annotations.PreviewData -import com.android.resources.NightMode -import com.android.resources.UiMode -import java.util.Locale -import kotlin.math.roundToInt - -internal fun String.deviceConfig() = when (this) { - "id:Nexus 7" -> DeviceConfig.NEXUS_7 - "id:Nexus 7 2013" -> DeviceConfig.NEXUS_7_2012 - "id:Nexus 5" -> DeviceConfig.NEXUS_5 - "id:Nexus 6" -> DeviceConfig.NEXUS_7 - "id:Nexus 9" -> DeviceConfig.NEXUS_10 - "name:Nexus 10" -> DeviceConfig.NEXUS_10 - "id:Nexus 5X" -> DeviceConfig.NEXUS_5 - "id:Nexus 6P" -> DeviceConfig.NEXUS_7 - "id:pixel_c" -> DeviceConfig.PIXEL_C - "id:pixel" -> DeviceConfig.PIXEL - "id:pixel_xl" -> DeviceConfig.PIXEL_XL - "id:pixel_2" -> DeviceConfig.PIXEL_2 - "id:pixel_2_xl" -> DeviceConfig.PIXEL_2_XL - "id:pixel_3" -> DeviceConfig.PIXEL_3 - "id:pixel_3_xl" -> DeviceConfig.PIXEL_3_XL - "id:pixel_3a" -> DeviceConfig.PIXEL_3A - "id:pixel_3a_xl" -> DeviceConfig.PIXEL_3A_XL - "id:pixel_4" -> DeviceConfig.PIXEL_4 - "id:pixel_4_xl" -> DeviceConfig.PIXEL_4_XL - "id:pixel_5" -> DeviceConfig.PIXEL_5 - "id:pixel_6" -> DeviceConfig.PIXEL_6 - "id:pixel_6_pro" -> DeviceConfig.PIXEL_6_PRO - "id:wearos_small_round" -> DeviceConfig.WEAR_OS_SMALL_ROUND - "id:wearos_square" -> DeviceConfig.WEAR_OS_SQUARE - else -> null -} - -internal fun Int.uiMode() = when (this and Configuration.UI_MODE_TYPE_MASK) { - Configuration.UI_MODE_TYPE_NORMAL -> UiMode.NORMAL - Configuration.UI_MODE_TYPE_CAR -> UiMode.CAR - Configuration.UI_MODE_TYPE_DESK -> UiMode.DESK - Configuration.UI_MODE_TYPE_APPLIANCE -> UiMode.APPLIANCE - Configuration.UI_MODE_TYPE_WATCH -> UiMode.WATCH - Configuration.UI_MODE_TYPE_VR_HEADSET -> UiMode.VR_HEADSET - else -> null -} - -internal fun Int.nightMode() = when (this and Configuration.UI_MODE_NIGHT_MASK) { - Configuration.UI_MODE_NIGHT_NO -> NightMode.NOTNIGHT - Configuration.UI_MODE_NIGHT_YES -> NightMode.NIGHT - else -> null -} - -internal fun String.localeQualifierString() = - Locale.forLanguageTag(this).run { - "$language-r$country" - } - -internal fun PreviewData?.deviceConfig(defaultDeviceConfig: DeviceConfig) = - (this?.device?.deviceConfig() ?: defaultDeviceConfig).let { config -> - config.copy( - screenWidth = this?.widthDp?.toPx(config.density.dpiValue) ?: config.screenWidth, - screenHeight = this?.heightDp?.toPx(config.density.dpiValue) ?: config.screenHeight, - fontScale = this?.fontScale ?: config.fontScale, - uiMode = this?.uiMode?.uiMode() ?: config.uiMode, - nightMode = this?.uiMode?.nightMode() ?: config.nightMode, - locale = this?.locale?.localeQualifierString() ?: config.locale - ) - } - -private fun Int.toPx(dpi: Int) = - (this * (dpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).roundToInt() - -internal fun Paparazzi.snapshotDefault( - previewData: PaparazziPreviewData.Default, - name: String?, - localInspectionMode: Boolean, - wrapper: @Composable (@Composable () -> Unit) -> Unit = { it() } -) { - snapshot(name) { - PreviewWrapper(previewData.preview.backgroundColor, localInspectionMode) { - wrapper { previewData.composable() } - } - } -} - -internal fun Paparazzi.snapshotProvider( - previewData: PaparazziPreviewData.Provider, - name: String?, - localInspectionMode: Boolean, - wrapper: @Composable (@Composable () -> Unit) -> Unit = { it() } -) { - val paramValue = previewData.previewParameter.values - .elementAt(previewData.previewParameter.index) - - snapshot(name) { - PreviewWrapper(previewData.preview.backgroundColor, localInspectionMode) { - wrapper { previewData.composable(paramValue) } - } - } -} - -@Composable -private fun PreviewWrapper( - backgroundColor: String?, - localInspectionMode: Boolean, - content: @Composable BoxScope.() -> Unit -) { - CompositionLocalProvider(LocalInspectionMode provides localInspectionMode) { - Box( - modifier = Modifier - .then( - backgroundColor?.toLong(16) - ?.let { Modifier.background(Color(it)) } - ?: Modifier - ), - content = content - ) - } -}