Skip to content

Commit 5237290

Browse files
Introduce SlotTableInspector API for Compose.
1 parent 29d788d commit 5237290

10 files changed

Lines changed: 761 additions & 63 deletions

File tree

sample-compose/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ tasks.withType<KotlinCompile> {
5555

5656
dependencies {
5757
implementation(project(":radiography"))
58+
implementation(project(":slot-table-inspector"))
5859
implementation(Dependencies.AppCompat)
5960
implementation(Dependencies.Compose(sampleComposeVersion).Activity())
6061
implementation(Dependencies.Compose(sampleComposeVersion).Material)

sample-compose/src/main/java/com/squareup/radiography/sample/compose/ComposeSampleApp.kt

Lines changed: 101 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.compose.foundation.rememberScrollState
2020
import androidx.compose.foundation.verticalScroll
2121
import androidx.compose.material.Checkbox
2222
import androidx.compose.material.MaterialTheme
23+
import androidx.compose.material.Surface
2324
import androidx.compose.material.Text
2425
import androidx.compose.material.TextButton
2526
import androidx.compose.material.TextField
@@ -31,15 +32,19 @@ import androidx.compose.runtime.mutableStateOf
3132
import androidx.compose.runtime.remember
3233
import androidx.compose.runtime.setValue
3334
import androidx.compose.ui.Alignment
35+
import androidx.compose.ui.ExperimentalComposeUiApi
3436
import androidx.compose.ui.Modifier
3537
import androidx.compose.ui.platform.LocalContext
3638
import androidx.compose.ui.platform.testTag
3739
import androidx.compose.ui.text.font.FontFamily
3840
import androidx.compose.ui.text.input.PasswordVisualTransformation
41+
import androidx.compose.ui.text.style.TextAlign
3942
import androidx.compose.ui.tooling.preview.Preview
4043
import androidx.compose.ui.unit.dp
4144
import androidx.compose.ui.unit.sp
4245
import androidx.compose.ui.viewinterop.AndroidView
46+
import androidx.compose.ui.window.Dialog
47+
import androidx.compose.ui.window.DialogProperties
4348
import radiography.ExperimentalRadiographyComposeApi
4449
import radiography.Radiography
4550
import radiography.ScanScopes.FocusedWindowScope
@@ -50,6 +55,9 @@ import radiography.ViewStateRenderers.DefaultsNoPii
5055
import radiography.ViewStateRenderers.ViewRenderer
5156
import radiography.ViewStateRenderers.androidViewStateRendererFor
5257
import radiography.ViewStateRenderers.textViewRenderer
58+
import radiography.compose.slottable.SlotTableInspectable
59+
import radiography.compose.slottable.SlotTableInspector
60+
import radiography.compose.slottable.SlotTableInspectorState
5361

5462
internal const val TEXT_FIELD_TEST_TAG = "text-field"
5563
internal const val LIVE_HIERARCHY_TEST_TAG = "live-hierarchy"
@@ -59,84 +67,115 @@ internal const val LIVE_HIERARCHY_TEST_TAG = "live-hierarchy"
5967
ComposeSampleApp()
6068
}
6169

62-
@OptIn(ExperimentalRadiographyComposeApi::class, ExperimentalAnimationApi::class)
70+
@OptIn(
71+
ExperimentalRadiographyComposeApi::class,
72+
ExperimentalAnimationApi::class,
73+
ExperimentalComposeUiApi::class,
74+
)
6375
@Composable fun ComposeSampleApp() {
6476
val context = LocalContext.current
6577
val liveHierarchy = remember { mutableStateOf<String?>(null) }
78+
val slotTableInspectorState = remember { SlotTableInspectorState() }
79+
var showSlotTableInspector by remember { mutableStateOf(false) }
6680

6781
var username by remember { mutableStateOf("") }
6882
var password by remember { mutableStateOf("") }
6983
var rememberMe by remember { mutableStateOf(false) }
7084

71-
MaterialTheme {
72-
Column(
73-
modifier = Modifier.padding(16.dp),
74-
horizontalAlignment = Alignment.CenterHorizontally,
75-
verticalArrangement = Arrangement.spacedBy(16.dp)
76-
) {
77-
RadiographyLogo(Modifier.height(128.dp))
85+
SlotTableInspectable(slotTableInspectorState) {
86+
MaterialTheme {
87+
Column(
88+
modifier = Modifier.padding(16.dp),
89+
horizontalAlignment = Alignment.CenterHorizontally,
90+
verticalArrangement = Arrangement.spacedBy(16.dp)
91+
) {
92+
RadiographyLogo(Modifier.height(128.dp))
7893

79-
TextField(
80-
value = username,
81-
onValueChange = { username = it },
82-
label = { Text("Username") },
83-
colors = TextFieldDefaults.outlinedTextFieldColors(),
84-
modifier = Modifier.testTag(TEXT_FIELD_TEST_TAG)
85-
)
86-
TextField(
87-
value = password,
88-
onValueChange = { password = it },
89-
label = { Text("Password") },
90-
colors = TextFieldDefaults.outlinedTextFieldColors(),
91-
visualTransformation = PasswordVisualTransformation()
92-
)
93-
Row(verticalAlignment = Alignment.CenterVertically) {
94-
Checkbox(checked = rememberMe, onCheckedChange = { rememberMe = it })
95-
Spacer(Modifier.width(8.dp))
96-
Text("Remember me")
97-
}
98-
99-
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
100-
TextButton(onClick = {}) {
101-
Text("SIGN IN")
94+
TextField(
95+
value = username,
96+
onValueChange = { username = it },
97+
label = { Text("Username") },
98+
colors = TextFieldDefaults.outlinedTextFieldColors(),
99+
modifier = Modifier.testTag(TEXT_FIELD_TEST_TAG)
100+
)
101+
TextField(
102+
value = password,
103+
onValueChange = { password = it },
104+
label = { Text("Password") },
105+
colors = TextFieldDefaults.outlinedTextFieldColors(),
106+
visualTransformation = PasswordVisualTransformation()
107+
)
108+
Row(verticalAlignment = Alignment.CenterVertically) {
109+
Checkbox(checked = rememberMe, onCheckedChange = { rememberMe = it })
110+
Spacer(Modifier.width(8.dp))
111+
Text("Remember me")
102112
}
103-
TextButton(onClick = {}) {
104-
Text("FORGOT PASSWORD")
113+
114+
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
115+
TextButton(onClick = {}) {
116+
Text("SIGN IN")
117+
}
118+
TextButton(onClick = {}) {
119+
Text("FORGOT PASSWORD")
120+
}
105121
}
106-
}
107122

108-
// Include a classic Android view in the composition.
109-
AndroidView(::TextView) {
110-
@SuppressLint("SetTextI18n")
111-
it.text = "By signing in, you agree to our Terms and Conditions."
112-
}
123+
// Include a classic Android view in the composition.
124+
AndroidView(::TextView) {
125+
@SuppressLint("SetTextI18n")
126+
it.text = "By signing in, you agree to our Terms and Conditions."
127+
}
113128

114-
liveHierarchy.value?.let {
115-
Row(
116-
modifier = Modifier
117-
.horizontalScroll(rememberScrollState())
118-
.weight(1f)
119-
) {
120-
Column(Modifier.verticalScroll(rememberScrollState())) {
121-
Text(
122-
liveHierarchy.value.orEmpty(),
123-
fontFamily = FontFamily.Monospace,
124-
fontSize = 6.sp,
125-
modifier = Modifier.testTag(LIVE_HIERARCHY_TEST_TAG)
126-
)
129+
liveHierarchy.value?.let {
130+
Row(
131+
modifier = Modifier
132+
.horizontalScroll(rememberScrollState())
133+
.weight(1f)
134+
) {
135+
Column(Modifier.verticalScroll(rememberScrollState())) {
136+
Text(
137+
liveHierarchy.value.orEmpty(),
138+
fontFamily = FontFamily.Monospace,
139+
fontSize = 6.sp,
140+
modifier = Modifier.testTag(LIVE_HIERARCHY_TEST_TAG)
141+
)
142+
}
143+
}
144+
}
145+
Row {
146+
TextButton(
147+
modifier = Modifier.weight(1f),
148+
onClick = { showSelectionDialog(context) }
149+
) {
150+
Text("SHOW STRING RENDERING DIALOG", textAlign = TextAlign.Center)
151+
}
152+
TextButton(
153+
modifier = Modifier.weight(1f),
154+
onClick = {
155+
slotTableInspectorState.captureSlotTables()
156+
showSlotTableInspector = true
157+
}) {
158+
Text("SHOW SLOT TABLE INSPECTOR", textAlign = TextAlign.Center)
127159
}
128160
}
129-
}
130-
TextButton(onClick = { showSelectionDialog(context) }) {
131-
Text("SHOW STRING RENDERING DIALOG")
132-
}
133161

134-
SideEffect {
135-
liveHierarchy.value = Radiography.scan(
136-
viewStateRenderers = DefaultsIncludingPii,
137-
// Don't trigger infinite recursion.
138-
viewFilter = skipComposeTestTagsFilter(LIVE_HIERARCHY_TEST_TAG)
139-
)
162+
SideEffect {
163+
liveHierarchy.value = Radiography.scan(
164+
viewStateRenderers = DefaultsIncludingPii,
165+
// Don't trigger infinite recursion.
166+
viewFilter = skipComposeTestTagsFilter(LIVE_HIERARCHY_TEST_TAG)
167+
)
168+
}
169+
if (showSlotTableInspector) {
170+
Dialog(
171+
onDismissRequest = { showSlotTableInspector = false },
172+
properties = DialogProperties(usePlatformDefaultWidth = false)
173+
) {
174+
Surface {
175+
SlotTableInspector(slotTableInspectorState)
176+
}
177+
}
178+
}
140179
}
141180
}
142181
}

settings.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ include(
2020
":compose-unsupported-tests",
2121
":radiography",
2222
":sample",
23-
":sample-compose"
23+
":sample-compose",
24+
":slot-table-inspector",
2425
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public final class radiography/compose/slottable/SlotTableInspectorKt {
2+
public static final fun SlotTableInspectable (Lradiography/compose/slottable/SlotTableInspectorState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
3+
public static final fun SlotTableInspector (Lradiography/compose/slottable/SlotTableInspectorState;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;II)V
4+
}
5+
6+
public final class radiography/compose/slottable/SlotTableInspectorState {
7+
public static final field $stable I
8+
public fun <init> ()V
9+
public final fun captureSlotTables ()V
10+
}
11+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2+
3+
plugins {
4+
id("com.android.library")
5+
kotlin("android")
6+
id("com.vanniktech.maven.publish")
7+
}
8+
9+
android {
10+
compileSdk = 30
11+
12+
compileOptions {
13+
sourceCompatibility = JavaVersion.VERSION_1_8
14+
targetCompatibility = JavaVersion.VERSION_1_8
15+
}
16+
17+
defaultConfig {
18+
// Compose minSdk is also 21.
19+
minSdk = 21
20+
targetSdk = 30
21+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
22+
}
23+
24+
buildFeatures {
25+
buildConfig = false
26+
compose = true
27+
}
28+
29+
composeOptions {
30+
kotlinCompilerExtensionVersion = Versions.Compose
31+
}
32+
33+
testOptions {
34+
execution = "ANDROIDX_TEST_ORCHESTRATOR"
35+
}
36+
}
37+
38+
tasks.withType<KotlinCompile> {
39+
kotlinOptions {
40+
freeCompilerArgs += listOfNotNull(
41+
"-Xopt-in=kotlin.RequiresOptIn",
42+
43+
// Require explicit public modifiers and types.
44+
// TODO this should be moved to a top-level `kotlin { explicitApi() }` once that's working
45+
// for android projects, see https://youtrack.jetbrains.com/issue/KT-37652.
46+
"-Xexplicit-api=strict".takeUnless {
47+
// Tests aren't part of the public API, don't turn explicit API mode on for them.
48+
name.contains("test", ignoreCase = true)
49+
}
50+
)
51+
}
52+
}
53+
54+
dependencies {
55+
implementation(Dependencies.Compose().Material)
56+
// implementation(Dependencies.Compose().ToolingData)
57+
implementation(Dependencies.Compose().Tooling)
58+
59+
testImplementation(Dependencies.JUnit)
60+
testImplementation(Dependencies.Mockito)
61+
testImplementation(Dependencies.Robolectric)
62+
testImplementation(Dependencies.Truth)
63+
64+
androidTestImplementation(Dependencies.Compose().Testing)
65+
androidTestImplementation(Dependencies.InstrumentationTests.Core)
66+
androidTestImplementation(Dependencies.InstrumentationTests.Espresso)
67+
androidTestImplementation(Dependencies.InstrumentationTests.Rules)
68+
androidTestImplementation(Dependencies.InstrumentationTests.Runner)
69+
androidTestImplementation(Dependencies.Truth)
70+
androidTestUtil(Dependencies.InstrumentationTests.Orchestrator)
71+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
POM_ARTIFACT_ID=slot-table-inspector
2+
POM_NAME=Radiography slot table inspector
3+
POM_PACKAGING=aar
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.squareup.radiography.compose.slottable.test">
3+
4+
<!--
5+
Workaround required for running tests on API 30 devices.
6+
See https://github.com/android/android-test/issues/743.
7+
Version 1.3.1 of the AndroidX Test libraries remove the need for this workaround.
8+
-->
9+
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
10+
11+
<application>
12+
<activity android:name="androidx.activity.ComponentActivity" />
13+
</application>
14+
</manifest>
15+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<manifest package="com.squareup.radiography.compose.slottable"/>

0 commit comments

Comments
 (0)