Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make stacked preview annotations generate showkaseMetadata components for each annotation #259

Merged
merged 15 commits into from Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -173,6 +173,7 @@ to understand the behavior when you don't pass any properties.
**Note:** Make sure that you add this annotation to only those functions that meet the following criteria:
- Functions that don't have any parameters
- If it does have a parameter, it has to be annotated with `@PreviewParameter` that is provided a `PreviewParameterProvider` implementation.
- Stacked `@Preview` and `ShowkaseComposable` annotations are only supported with KSP at the moment. This is because of this [issue](https://youtrack.jetbrains.com/issue/KT-49682).

This is identical to how `@Preview` works in Compose as well so Showkase just adheres to the same rules.

Expand Down
@@ -1,5 +1,7 @@
package com.airbnb.android.showkasesample

import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
Expand All @@ -9,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.airbnb.android.showkase.annotation.ShowkaseComposable

Expand Down Expand Up @@ -44,3 +47,24 @@ fun BasicChipYellowPreview() {
modifier = Modifier.background(color = Color.Yellow)
)
}

@Preview(name = "Basic Chip Blue Light", group = "Chips", uiMode = UI_MODE_NIGHT_NO)
@Preview(name = "Basic Chip Blue Dark", group = "Chips", uiMode = UI_MODE_NIGHT_YES)
@Composable
fun BasicChipBluePreview() {
BasicChip(
text = "Chip Component",
modifier = Modifier.background(color = Color.Blue)
)
}


@ShowkaseComposable(name = "Basic Chip Grey Light", group = "Chips")
vinaygaba marked this conversation as resolved.
Show resolved Hide resolved
@ShowkaseComposable(name = "Basic Chip Grey Dark", group = "Chips")
@Composable
fun BasicChipGreyPreview() {
BasicChip(
text = "Chip Component",
modifier = Modifier.background(color = Color.Gray)
)
}
Expand Up @@ -57,6 +57,7 @@ package com.airbnb.android.showkase.annotation
@MustBeDocumented
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.FUNCTION)
@Repeatable
@Suppress("LongParameterList")
annotation class ShowkaseComposable(
val name: String = "",
Expand Down
Expand Up @@ -71,8 +71,10 @@ abstract class BaseProcessorTest {
}
}

protected fun compileInputsAndVerifyOutputs() {
compileInputs { mode, compilation, result ->
protected fun compileInputsAndVerifyOutputs(
modes:List<Mode> = listOf(Mode.KSP, Mode.KAPT)
) {
compileInputs(modes = modes) { mode, compilation, result ->
result.assertGeneratedSources(mode, compilation)
}
}
Expand Down
Expand Up @@ -508,5 +508,17 @@ class ShowkaseProcessorTest : BaseProcessorTest() {
fun `composable function with multiple preview functions compiles`() {
compileInputsAndVerifyOutputs()
}

@Test
fun `composable function with multiple preview annotations stacked generates output`() {
// This functionality is only supported with KSP for now.
compileInputsAndVerifyOutputs(modes = listOf(Mode.KSP))
vinaygaba marked this conversation as resolved.
Show resolved Hide resolved
}

@Test
fun `composable function with multiple showkasecomposable annotations stacked generates output`() {
// This functionality is only supported with KSP for now.
compileInputsAndVerifyOutputs(modes = listOf(Mode.KSP))
}
}

Expand Up @@ -19,4 +19,19 @@ public class ShowkaseMetadata_com_airbnb_android_showkase_processor_testing {
)
public fun group2name2(): Unit {
}

@ShowkaseCodegenMetadata(
showkaseName = "name1",
showkaseGroup = "group1",
packageName = "com.airbnb.android.showkase_processor_testing",
packageSimpleName = "showkase_processor_testing",
showkaseElementName = "TestComposable1",
insideObject = false,
insideWrapperClass = false,
showkaseKDoc = "",
showkaseMetadataType = "COMPONENT",
isDefaultStyle = false,
)
public fun group1name1(): Unit {
}
}
@@ -0,0 +1,21 @@
package com.airbnb.android.showkase_processor_testing

import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.runtime.Composable
import androidx.compose.ui.semantics.SemanticsProperties.Text
import androidx.compose.ui.tooling.preview.Preview

@Preview(
name = "small font",
group = "font scales",
fontScale = 0.5f
)
@Preview(
name = "large font",
group = "font scales",
fontScale = 1.5f
)
@Composable
public fun ComposablePreviewFont() {

}
@@ -0,0 +1,37 @@
// This is an auto-generated file. Please do not edit/modify this file.
package com.airbnb.android.showkase

import com.airbnb.android.showkase.`annotation`.ShowkaseCodegenMetadata
import kotlin.Unit

public class ShowkaseMetadata_com_airbnb_android_showkase_processor_testing {
@ShowkaseCodegenMetadata(
showkaseName = "small font",
showkaseGroup = "font scales",
packageName = "com.airbnb.android.showkase_processor_testing",
packageSimpleName = "showkase_processor_testing",
showkaseElementName = "ComposablePreviewFont",
insideObject = false,
insideWrapperClass = false,
showkaseKDoc = "",
showkaseMetadataType = "COMPONENT",
isDefaultStyle = false,
)
public fun fontscalessmallfont(): Unit {
}

@ShowkaseCodegenMetadata(
showkaseName = "large font",
showkaseGroup = "font scales",
packageName = "com.airbnb.android.showkase_processor_testing",
packageSimpleName = "showkase_processor_testing",
showkaseElementName = "ComposablePreviewFont",
insideObject = false,
insideWrapperClass = false,
showkaseKDoc = "",
showkaseMetadataType = "COMPONENT",
isDefaultStyle = false,
)
public fun fontscaleslargefont1(): Unit {
}
}
@@ -0,0 +1,24 @@
package com.airbnb.android.showkase_processor_testing

import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.runtime.Composable
import androidx.compose.ui.semantics.SemanticsProperties.Text
import androidx.compose.ui.tooling.preview.Preview
import com.airbnb.android.showkase.annotation.ShowkaseComposable

@ShowkaseComposable(
name = "small font",
group = "font scales",
widthDp = 250,
heightDp = 250,
)
@ShowkaseComposable(
name = "large font",
group = "font scales",
widthDp = 200,
heightDp = 200,
)
@Composable
public fun StackedShowkaseComposables() {

}
@@ -0,0 +1,41 @@
// This is an auto-generated file. Please do not edit/modify this file.
package com.airbnb.android.showkase

import com.airbnb.android.showkase.`annotation`.ShowkaseCodegenMetadata
import kotlin.Unit

public class ShowkaseMetadata_com_airbnb_android_showkase_processor_testing {
@ShowkaseCodegenMetadata(
showkaseName = "small font",
showkaseGroup = "font scales",
packageName = "com.airbnb.android.showkase_processor_testing",
packageSimpleName = "showkase_processor_testing",
showkaseElementName = "StackedShowkaseComposables",
insideObject = false,
insideWrapperClass = false,
showkaseKDoc = "",
showkaseMetadataType = "COMPONENT",
isDefaultStyle = false,
showkaseWidthDp = 250,
showkaseHeightDp = 250,
)
public fun fontscalessmallfont(): Unit {
}

@ShowkaseCodegenMetadata(
showkaseName = "large font",
showkaseGroup = "font scales",
packageName = "com.airbnb.android.showkase_processor_testing",
packageSimpleName = "showkase_processor_testing",
showkaseElementName = "StackedShowkaseComposables",
insideObject = false,
insideWrapperClass = false,
showkaseKDoc = "",
showkaseMetadataType = "COMPONENT",
isDefaultStyle = false,
showkaseWidthDp = 200,
showkaseHeightDp = 200,
)
public fun fontscaleslargefont1(): Unit {
}
}
Expand Up @@ -29,7 +29,7 @@ public class TestShowkaseRootCodegen : ShowkaseProvider {
componentName = "name",
componentKDoc = "",
componentKey =
"""com.airbnb.android.showkase_processor_testing_com.airbnb.android.showkase_processor_testing.WrapperClass_group_name_null_$index""",
"""com.airbnb.android.showkase_processor_testing_com.airbnb.android.showkase_processor_testing.WrapperClass_group_name_0_null_$index""",
isDefaultStyle = false,
component = @Composable {
WrapperClass.TestComposable(text = previewParam)
Expand Down
Expand Up @@ -29,7 +29,7 @@ public class TestShowkaseRootCodegen : ShowkaseProvider {
componentName = "name",
componentKDoc = "",
componentKey =
"""com.airbnb.android.showkase_processor_testing_my_very_long_name_com.airbnb.android.showkase_processor_testing_my_very_long_name.WrapperClass_group_name_null_$index""",
"""com.airbnb.android.showkase_processor_testing_my_very_long_name_com.airbnb.android.showkase_processor_testing_my_very_long_name.WrapperClass_group_name_0_null_$index""",
isDefaultStyle = false,
component = @Composable {
WrapperClass.TestComposable(text = previewParam)
Expand Down
Expand Up @@ -22,7 +22,8 @@ public class TestShowkaseRootCodegen : ShowkaseProvider {
group = "group",
componentName = "name",
componentKDoc = "",
componentKey = """com.airbnb.android.showkase_processor_testing_null_group_name_null""",
componentKey =
"""com.airbnb.android.showkase_processor_testing_null_group_name_0_null""",
isDefaultStyle = false,
component = @Composable { TestComposable() })
)
Expand Down
Expand Up @@ -23,7 +23,7 @@ public class TestShowkaseRootCodegen : ShowkaseProvider {
componentName = "TestComposable",
componentKDoc = "",
componentKey =
"""com.airbnb.android.showkase_processor_testing_null_DefaultGroup_TestComposable_null""",
"""com.airbnb.android.showkase_processor_testing_null_DefaultGroup_TestComposable_0_null""",
isDefaultStyle = false,
component = @Composable { TestComposable() })
).apply {
Expand All @@ -38,7 +38,7 @@ public class TestShowkaseRootCodegen : ShowkaseProvider {
componentName = "TestComposable2",
componentKDoc = "",
componentKey =
"""com.airbnb.android.showkase_processor_testing_null_DefaultGroup_TestComposable2_null_$index""",
"""com.airbnb.android.showkase_processor_testing_null_DefaultGroup_TestComposable2_0_null_$index""",
isDefaultStyle = false,
component = @Composable { TestComposable2(text = previewParam) }
)
Expand Down
Expand Up @@ -23,7 +23,7 @@ public class TestShowkaseRootCodegen : ShowkaseProvider {
componentName = "TestComposable",
componentKDoc = "",
componentKey =
"""com.airbnb.android.showkase_processor_testing_null_DefaultGroup_TestComposable_null""",
"""com.airbnb.android.showkase_processor_testing_null_DefaultGroup_TestComposable_0_null""",
isDefaultStyle = false,
component = @Composable { TestComposable() })
)
Expand Down
Expand Up @@ -83,6 +83,8 @@ class ShowkaseProcessor @JvmOverloads constructor(
): Set<ShowkaseMetadata.Component> {
return roundEnvironment.getElementsAnnotatedWith(ShowkaseComposable::class)
.mapNotNull { element ->
if (showkaseValidator.checkElementIsAnnotationClass(element)) return@mapNotNull null

showkaseValidator.validateComponentElement(
element,
ShowkaseComposable::class.java.simpleName
Expand All @@ -91,14 +93,14 @@ class ShowkaseProcessor @JvmOverloads constructor(
element = element,
showkaseValidator = showkaseValidator,
)
}.toSet()
}.flatten().mapNotNull { it }.toSet()
}


private fun processPreviewAnnotation(roundEnvironment: XRoundEnv): Set<ShowkaseMetadata.Component> {
vinaygaba marked this conversation as resolved.
Show resolved Hide resolved
return roundEnvironment.getElementsAnnotatedWith(PREVIEW_CLASS_NAME)
.mapNotNull { element ->
if (showkaseValidator.checkElementIsMultiPreview(element)) return@mapNotNull null
if (showkaseValidator.checkElementIsAnnotationClass(element)) return@mapNotNull null
showkaseValidator.validateComponentElement(
element,
PREVIEW_SIMPLE_NAME
Expand All @@ -109,7 +111,7 @@ class ShowkaseProcessor @JvmOverloads constructor(
showkaseValidator = showkaseValidator
)

}.toSet()
}.flatten().mapNotNull { it }.toSet()
}

private fun writeMetadataFile(uniqueComposablesMetadata: Set<ShowkaseMetadata>) {
Expand All @@ -126,12 +128,21 @@ class ShowkaseProcessor @JvmOverloads constructor(
// only distict method's are passed onto the next round. We do this by deduping on
// the combination of packageName, the wrapper class when available(otherwise it
// will be null) & the methodName.
"${it.packageName}_${it.enclosingClassName}_${it.elementName}"
if (it.componentIndex != null) {
"${it.packageName}_${it.enclosingClassName}_${it.elementName}_${it.componentIndex}"
} else {

"${it.packageName}_${it.enclosingClassName}_${it.elementName}"
}
}
.distinctBy {
// We also ensure that the component groupName and the component name are unique so
// that they don't show up twice in the browser app.
"${it.showkaseName}_${it.showkaseGroup}_${it.showkaseStyleName}"
// that they don't show up twice in the browser app.
if (it.componentIndex != null) {
"${it.showkaseName}_${it.showkaseGroup}_${it.showkaseStyleName}_${it.componentIndex}"
} else {
"${it.showkaseName}_${it.showkaseGroup}_${it.showkaseStyleName}"
}
}
.sortedBy {
"${it.packageName}_${it.enclosingClassName}_${it.elementName}"
Expand Down
Expand Up @@ -75,8 +75,8 @@ internal class ShowkaseValidator {
}
}

// This should check if it is an annotation that's annotated with @Preview annotation
internal fun checkElementIsMultiPreview(element: XElement): Boolean {
// This should check if it is an annotation that's annotated with @Preview or @ShowkaseComposable annotation
internal fun checkElementIsAnnotationClass(element: XElement): Boolean {
return element.isTypeElement() && element.isAnnotationClass()
}

Expand Down