Skip to content

Commit b9e854e

Browse files
authored
Merge pull request #1417 from square/japplin/workflow-visualizer-title
Refactor Workflow Trace Viewer to have multi window support
2 parents eab82ae + 80ea45f commit b9e854e

File tree

12 files changed

+315
-175
lines changed

12 files changed

+315
-175
lines changed

gradle/libs.versions.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ squareup-retrofit = "2.9.0"
9292
squareup-seismic = "1.0.3"
9393
squareup-workflow = "1.0.0"
9494

95+
skiko = "0.9.4"
96+
telephoto = "0.16.0"
9597
timber = "5.0.1"
9698
truth = "1.4.4"
9799
turbine = "1.0.0"
@@ -203,7 +205,7 @@ google-ksp = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin
203205
hamcrest = "org.hamcrest:hamcrest-core:2.2"
204206

205207
java-diff-utils = { module = "io.github.java-diff-utils:java-diff-utils", version.ref = "java-diff-utils" }
206-
208+
telephoto = { module = "me.saket.telephoto:zoomable", version.ref = "telephoto" }
207209
jetbrains-annotations = "org.jetbrains:annotations:24.0.1"
208210

209211
junit = { module = "junit:junit", version.ref = "jUnit" }
@@ -251,6 +253,8 @@ robolectric-annotations = { module = "org.robolectric:annotations", version.ref
251253
rxjava2-rxandroid = { module = "io.reactivex.rxjava2:rxandroid", version.ref = "rxjava2-android" }
252254
rxjava2-rxjava = { module = "io.reactivex.rxjava2:rxjava", version.ref = "rxjava2-core" }
253255

256+
skiko = { module = "org.jetbrains.skiko:skiko-awt-runtime-macos-arm64", version.ref = "skiko" }
257+
254258
squareup-curtains = { module = "com.squareup.curtains:curtains", version.ref = "squareup-curtains" }
255259

256260
squareup-cycler = { module = "com.squareup.cycler:cycler", version.ref = "squareup-cycler" }

workflow-trace-viewer/api/workflow-trace-viewer.api

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,45 @@
11
public final class com/squareup/workflow1/traceviewer/ComposableSingletons$MainKt {
22
public static final field INSTANCE Lcom/squareup/workflow1/traceviewer/ComposableSingletons$MainKt;
33
public fun <init> ()V
4-
public final fun getLambda$468449326$wf1_workflow_trace_viewer ()Lkotlin/jvm/functions/Function3;
4+
public final fun getLambda$-793818668$wf1_workflow_trace_viewer ()Lkotlin/jvm/functions/Function3;
55
}
66

77
public final class com/squareup/workflow1/traceviewer/MainKt {
88
public static final fun main ()V
99
public static synthetic fun main ([Ljava/lang/String;)V
1010
}
1111

12+
public abstract interface class com/squareup/workflow1/traceviewer/TraceWindow {
13+
}
14+
15+
public final class com/squareup/workflow1/traceviewer/TraceWindow$DeviceWindow : com/squareup/workflow1/traceviewer/TraceWindow {
16+
public static final field $stable I
17+
public fun <init> (Ljava/lang/String;)V
18+
public final fun component1 ()Ljava/lang/String;
19+
public final fun copy (Ljava/lang/String;)Lcom/squareup/workflow1/traceviewer/TraceWindow$DeviceWindow;
20+
public static synthetic fun copy$default (Lcom/squareup/workflow1/traceviewer/TraceWindow$DeviceWindow;Ljava/lang/String;ILjava/lang/Object;)Lcom/squareup/workflow1/traceviewer/TraceWindow$DeviceWindow;
21+
public fun equals (Ljava/lang/Object;)Z
22+
public final fun getDevice ()Ljava/lang/String;
23+
public fun hashCode ()I
24+
public fun toString ()Ljava/lang/String;
25+
}
26+
27+
public final class com/squareup/workflow1/traceviewer/TraceWindow$FileWindow : com/squareup/workflow1/traceviewer/TraceWindow {
28+
public static final field $stable I
29+
public fun <init> (Lio/github/vinceglb/filekit/PlatformFile;)V
30+
public final fun component1 ()Lio/github/vinceglb/filekit/PlatformFile;
31+
public final fun copy (Lio/github/vinceglb/filekit/PlatformFile;)Lcom/squareup/workflow1/traceviewer/TraceWindow$FileWindow;
32+
public static synthetic fun copy$default (Lcom/squareup/workflow1/traceviewer/TraceWindow$FileWindow;Lio/github/vinceglb/filekit/PlatformFile;ILjava/lang/Object;)Lcom/squareup/workflow1/traceviewer/TraceWindow$FileWindow;
33+
public fun equals (Ljava/lang/Object;)Z
34+
public final fun getFile ()Lio/github/vinceglb/filekit/PlatformFile;
35+
public fun hashCode ()I
36+
public fun toString ()Ljava/lang/String;
37+
}
38+
1239
public final class com/squareup/workflow1/traceviewer/ui/ComposableSingletons$WorkflowInfoPanelKt {
1340
public static final field INSTANCE Lcom/squareup/workflow1/traceviewer/ui/ComposableSingletons$WorkflowInfoPanelKt;
1441
public fun <init> ()V
15-
public final fun getLambda$-1653175968$wf1_workflow_trace_viewer ()Lkotlin/jvm/functions/Function3;
42+
public final fun getLambda$-1925612255$wf1_workflow_trace_viewer ()Lkotlin/jvm/functions/Function3;
1643
}
1744

1845
public final class com/squareup/workflow1/traceviewer/ui/control/ComposableSingletons$SearchBoxKt {
@@ -28,3 +55,11 @@ public final class com/squareup/workflow1/traceviewer/ui/control/ComposableSingl
2855
public final fun getLambda$-1248702605$wf1_workflow_trace_viewer ()Lkotlin/jvm/functions/Function3;
2956
}
3057

58+
public final class com/squareup/workflow1/traceviewer/ui/control/DisplayDevicesKt {
59+
public static final fun getAdb ()Ljava/lang/String;
60+
}
61+
62+
public final class com/squareup/workflow1/traceviewer/util/parser/TraceParserKt {
63+
public static final fun Error (Ljava/lang/String;Landroidx/compose/runtime/Composer;I)V
64+
}
65+

workflow-trace-viewer/build.gradle.kts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
2+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
3+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
24

35
plugins {
46
id("kotlin-multiplatform")
@@ -27,6 +29,8 @@ kotlin {
2729
implementation(libs.squareup.moshi.kotlin)
2830
implementation(libs.filekit.dialogs.compose)
2931
implementation(libs.java.diff.utils)
32+
implementation(libs.telephoto)
33+
implementation(libs.skiko)
3034
}
3135
}
3236
jvmTest {
@@ -50,15 +54,25 @@ compose {
5054
includeAllModules = true
5155
targetFormats(TargetFormat.Dmg)
5256
packageName = "Workflow Trace Viewer"
53-
packageVersion = "1.0.0"
57+
packageVersion = (property("VERSION_NAME") as String).substringBefore("-SNAPSHOT")
5458
macOS {
5559
bundleID = "com.squareup.workflow1.traceviewer"
5660
}
5761
}
62+
63+
buildTypes.release.proguard {
64+
isEnabled.set(false)
65+
}
5866
}
5967
}
6068
}
6169

6270
tasks.named<Test>("jvmTest") {
6371
useJUnitPlatform()
6472
}
73+
74+
tasks.withType<KotlinCompile>().configureEach {
75+
compilerOptions {
76+
jvmTarget.set(JvmTarget.JVM_11)
77+
}
78+
}

workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/App.kt renamed to workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/FileTraceViewer.kt

Lines changed: 17 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package com.squareup.workflow1.traceviewer
22

33
import androidx.compose.foundation.layout.Arrangement
44
import androidx.compose.foundation.layout.Box
5-
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Row
66
import androidx.compose.foundation.layout.padding
77
import androidx.compose.runtime.Composable
88
import androidx.compose.runtime.LaunchedEffect
99
import androidx.compose.runtime.getValue
10-
import androidx.compose.runtime.mutableFloatStateOf
10+
import androidx.compose.runtime.key
1111
import androidx.compose.runtime.mutableIntStateOf
1212
import androidx.compose.runtime.mutableStateListOf
1313
import androidx.compose.runtime.mutableStateMapOf
@@ -25,12 +25,9 @@ import androidx.compose.ui.unit.dp
2525
import com.squareup.workflow1.traceviewer.model.Node
2626
import com.squareup.workflow1.traceviewer.model.NodeUpdate
2727
import com.squareup.workflow1.traceviewer.ui.RightInfoPanel
28-
import com.squareup.workflow1.traceviewer.ui.control.DisplayDevices
2928
import com.squareup.workflow1.traceviewer.ui.control.FileDump
3029
import com.squareup.workflow1.traceviewer.ui.control.FrameNavigator
3130
import com.squareup.workflow1.traceviewer.ui.control.SearchBox
32-
import com.squareup.workflow1.traceviewer.ui.control.TraceModeToggleSwitch
33-
import com.squareup.workflow1.traceviewer.ui.control.UploadFile
3431
import com.squareup.workflow1.traceviewer.util.SandboxBackground
3532
import com.squareup.workflow1.traceviewer.util.parser.RenderTrace
3633
import io.github.vinceglb.filekit.PlatformFile
@@ -39,21 +36,20 @@ import io.github.vinceglb.filekit.PlatformFile
3936
* Main composable that provides the different layers of UI.
4037
*/
4138
@Composable
42-
internal fun App(
43-
modifier: Modifier = Modifier
39+
internal fun TraceViewerWindow(
40+
modifier: Modifier = Modifier,
41+
traceMode: TraceMode,
4442
) {
4543
var appWindowSize by remember { mutableStateOf(IntSize(0, 0)) }
4644
var selectedNode by remember { mutableStateOf<NodeUpdate?>(null) }
4745
var frameSize by remember { mutableIntStateOf(0) }
4846
var rawRenderPass by remember { mutableStateOf("") }
49-
var frameIndex by remember { mutableIntStateOf(0) }
47+
var frameIndex by remember { mutableIntStateOf(if (traceMode is TraceMode.Live) -1 else 0) }
5048
val sandboxState = remember { SandboxState() }
5149
val nodeLocations = remember { mutableStateListOf<SnapshotStateMap<Node, Offset>>() }
5250

5351
// Default to File mode, and can be toggled to be in Live mode.
5452
var active by remember { mutableStateOf(false) }
55-
var traceMode by remember { mutableStateOf<TraceMode>(TraceMode.File(null)) }
56-
var selectedTraceFile by remember { mutableStateOf<PlatformFile?>(null) }
5753
// frameIndex is set to -1 when app is in Live Mode, so we increment it by one to avoid off-by-one errors
5854
val frameInd = if (traceMode is TraceMode.Live) frameIndex + 1 else frameIndex
5955

@@ -68,15 +64,6 @@ internal fun App(
6864
appWindowSize = it
6965
}
7066
) {
71-
fun resetStates() {
72-
selectedTraceFile = null
73-
selectedNode = null
74-
frameIndex = 0
75-
frameSize = 0
76-
rawRenderPass = ""
77-
active = false
78-
nodeLocations.clear()
79-
}
8067

8168
// Main content
8269
SandboxBackground(
@@ -101,12 +88,12 @@ internal fun App(
10188
}
10289
}
10390

104-
Column(
91+
Row(
10592
modifier = Modifier
10693
.align(Alignment.TopCenter)
10794
.padding(top = 8.dp),
108-
verticalArrangement = Arrangement.spacedBy(8.dp),
109-
horizontalAlignment = Alignment.CenterHorizontally
95+
horizontalArrangement = Arrangement.spacedBy(8.dp),
96+
verticalAlignment = Alignment.Top,
11097
) {
11198
if (active) {
11299
// Frames that appear in composition may not happen sequentially, so when the current frame
@@ -124,7 +111,6 @@ internal fun App(
124111
SearchBox(
125112
nodes = frameNodeLocations.keys.toList(),
126113
onSearch = { name ->
127-
sandboxState.scale = 1f
128114
val node = frameNodeLocations.keys.first { it.name == name }
129115
val newX = (sandboxState.offset.x - frameNodeLocations.getValue(node).x
130116
+ appWindowSize.width / 2)
@@ -141,63 +127,23 @@ internal fun App(
141127
)
142128
}
143129
}
144-
145-
TraceModeToggleSwitch(
146-
onToggle = {
147-
resetStates()
148-
traceMode = if (traceMode is TraceMode.Live) {
149-
frameIndex = 0
150-
TraceMode.File(null)
151-
} else {
152-
/*
153-
We set the frame to -1 here since we always increment it during Live mode as the list of
154-
frames get populated, so we avoid off by one when indexing into the frames.
155-
*/
156-
frameIndex = -1
157-
TraceMode.Live()
158-
}
159-
},
160-
traceMode = traceMode,
161-
modifier = Modifier.align(Alignment.BottomCenter)
162-
)
163-
164-
// The states are reset when a new file is selected.
165-
if (traceMode is TraceMode.File) {
166-
UploadFile(
167-
resetOnFileSelect = {
168-
resetStates()
169-
selectedTraceFile = it
170-
traceMode = TraceMode.File(it)
171-
},
172-
modifier = Modifier.align(Alignment.BottomStart)
173-
)
174-
}
175-
176-
if (traceMode is TraceMode.Live && (traceMode as TraceMode.Live).device == null) {
177-
DisplayDevices(
178-
onDeviceSelect = { selectedDevice ->
179-
traceMode = TraceMode.Live(selectedDevice)
180-
},
181-
devices = listDevices(),
182-
modifier = Modifier.align(Alignment.Center)
183-
)
184-
130+
if (traceMode is TraceMode.Live) {
185131
FileDump(
186132
trace = rawRenderPass,
187-
modifier = Modifier.align(Alignment.BottomStart)
133+
modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp)
134+
)
135+
}
136+
key(selectedNode) {
137+
RightInfoPanel(
138+
selectedNode = selectedNode,
139+
modifier = Modifier.align(Alignment.TopEnd)
188140
)
189141
}
190-
191-
RightInfoPanel(
192-
selectedNode = selectedNode,
193-
modifier = Modifier.align(Alignment.TopEnd)
194-
)
195142
}
196143
}
197144

198145
internal class SandboxState {
199146
var offset by mutableStateOf(Offset.Zero)
200-
var scale by mutableFloatStateOf(1f)
201147

202148
fun reset() {
203149
offset = Offset.Zero
@@ -218,13 +164,3 @@ internal sealed interface TraceMode {
218164
}
219165
}
220166
}
221-
222-
/**
223-
* Allows users to select from multiple devices that are currently running.
224-
*/
225-
private fun listDevices(): List<String> {
226-
val process = ProcessBuilder("adb", "devices", "-l").start()
227-
process.waitFor()
228-
// We drop the header "List of devices attached"
229-
return process.inputStream.bufferedReader().readLines().drop(1).dropLast(1)
230-
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.squareup.workflow1.traceviewer
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxSize
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.material.MaterialTheme
9+
import androidx.compose.material.Text
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.getValue
12+
import androidx.compose.runtime.produceState
13+
import androidx.compose.ui.Alignment
14+
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.text.font.FontWeight
16+
import androidx.compose.ui.unit.dp
17+
import androidx.compose.ui.unit.sp
18+
import com.squareup.workflow1.traceviewer.ui.control.DisplayDevices
19+
import com.squareup.workflow1.traceviewer.ui.control.UploadFile
20+
import io.github.vinceglb.filekit.PlatformFile
21+
import kotlinx.coroutines.delay
22+
23+
/**
24+
* Main window composable that shows both file upload and device selection options.
25+
*/
26+
@Composable
27+
internal fun LandingWindow(
28+
modifier: Modifier = Modifier,
29+
onFileSelected: (PlatformFile) -> Unit,
30+
onDeviceSelected: (String) -> Unit
31+
) {
32+
Box(modifier = modifier.fillMaxSize()) {
33+
Column(
34+
modifier = Modifier
35+
.fillMaxSize()
36+
.padding(32.dp),
37+
horizontalAlignment = Alignment.CenterHorizontally,
38+
verticalArrangement = Arrangement.Center
39+
) {
40+
Text(
41+
text = "Workflow Trace Viewer",
42+
fontSize = 24.sp,
43+
fontWeight = FontWeight.Bold,
44+
modifier = Modifier.padding(bottom = 48.dp)
45+
)
46+
47+
// File selection section
48+
UploadFile(
49+
resetOnFileSelect = { file ->
50+
file?.let { onFileSelected(it) }
51+
}
52+
)
53+
54+
Text(
55+
text = "— OR —",
56+
fontSize = 14.sp,
57+
color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
58+
modifier = Modifier.padding(bottom = 24.dp)
59+
)
60+
61+
// Device selection section
62+
Text(
63+
text = "Connect to Device",
64+
fontSize = 18.sp,
65+
fontWeight = FontWeight.Medium,
66+
modifier = Modifier.padding(bottom = 24.dp)
67+
)
68+
69+
DisplayDevices(
70+
onDeviceSelect = onDeviceSelected,
71+
)
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)