Skip to content

Commit a0f22da

Browse files
committed
Extract parsing logic from tree rendering logic
1 parent 764f991 commit a0f22da

File tree

5 files changed

+130
-133
lines changed

5 files changed

+130
-133
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import androidx.compose.ui.geometry.Offset
1717
import com.squareup.workflow1.traceviewer.model.Node
1818
import com.squareup.workflow1.traceviewer.model.NodeUpdate
1919
import com.squareup.workflow1.traceviewer.ui.FrameSelectTab
20-
import com.squareup.workflow1.traceviewer.ui.RenderTrace
20+
import com.squareup.workflow1.traceviewer.util.RenderTrace
2121
import com.squareup.workflow1.traceviewer.ui.RightInfoPanel
2222
import com.squareup.workflow1.traceviewer.ui.TraceModeToggleSwitch
2323
import com.squareup.workflow1.traceviewer.util.SandboxBackground

workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/ui/WorkflowTree.kt

Lines changed: 1 addition & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ import androidx.compose.foundation.layout.padding
1111
import androidx.compose.material.Text
1212
import androidx.compose.runtime.Composable
1313
import androidx.compose.runtime.LaunchedEffect
14-
import androidx.compose.runtime.getValue
15-
import androidx.compose.runtime.mutableStateListOf
16-
import androidx.compose.runtime.mutableStateMapOf
17-
import androidx.compose.runtime.mutableStateOf
18-
import androidx.compose.runtime.remember
19-
import androidx.compose.runtime.setValue
2014
import androidx.compose.ui.Alignment
2115
import androidx.compose.ui.ExperimentalComposeUiApi
2216
import androidx.compose.ui.Modifier
@@ -26,122 +20,7 @@ import androidx.compose.ui.input.pointer.isPrimaryPressed
2620
import androidx.compose.ui.input.pointer.isSecondaryPressed
2721
import androidx.compose.ui.input.pointer.onPointerEvent
2822
import androidx.compose.ui.unit.dp
29-
import com.squareup.moshi.JsonAdapter
30-
import com.squareup.workflow1.traceviewer.TraceMode
3123
import com.squareup.workflow1.traceviewer.model.Node
32-
import com.squareup.workflow1.traceviewer.util.ParseResult
33-
import com.squareup.workflow1.traceviewer.util.createMoshiAdapter
34-
import com.squareup.workflow1.traceviewer.util.parseFileTrace
35-
import com.squareup.workflow1.traceviewer.util.parseLiveTrace
36-
import kotlinx.coroutines.Dispatchers
37-
import kotlinx.coroutines.launch
38-
import kotlinx.coroutines.withContext
39-
import java.net.SocketException
40-
41-
/**
42-
* Access point for drawing the main content of the app. It will load the trace for given files and
43-
* tabs. This will also all errors related to errors parsing a given trace JSON file.
44-
*
45-
* This handles either File or Live trace modes, and will parse equally
46-
*/
47-
@Composable
48-
internal fun RenderTrace(
49-
traceSource: TraceMode,
50-
frameInd: Int,
51-
onFileParse: (List<Node>) -> Unit,
52-
onNodeSelect: (Node, Node?) -> Unit,
53-
onNewFrame: () -> Unit,
54-
modifier: Modifier = Modifier
55-
) {
56-
var isLoading by remember(traceSource) { mutableStateOf(true) }
57-
var error by remember(traceSource) { mutableStateOf<Throwable?>(null) }
58-
val frames = remember { mutableStateListOf<Node>() }
59-
val fullTree = remember { mutableStateListOf<Node>() }
60-
val affectedNodes = remember { mutableStateListOf<Set<Node>>() }
61-
62-
// Updates current state with the new data from trace source.
63-
fun addToStates(frame: List<Node>, tree: List<Node>, affected: List<Set<Node>>) {
64-
frames.addAll(frame)
65-
fullTree.addAll(tree)
66-
affectedNodes.addAll(affected)
67-
isLoading = false
68-
onFileParse(frame)
69-
}
70-
71-
// Handles the result of parsing a trace, either from file or live. Live mode includes callback
72-
// for when a new frame is received.
73-
fun handleParseResult(
74-
parseResult: ParseResult,
75-
onNewFrame: (() -> Unit)? = null
76-
) {
77-
when (parseResult) {
78-
is ParseResult.Failure -> {
79-
error = parseResult.error
80-
}
81-
is ParseResult.Success -> {
82-
addToStates(
83-
frame = parseResult.trace,
84-
tree = parseResult.trees,
85-
affected = parseResult.affectedNodes
86-
)
87-
onNewFrame?.invoke()
88-
}
89-
}
90-
}
91-
92-
LaunchedEffect(traceSource) {
93-
when (traceSource) {
94-
is TraceMode.File -> {
95-
checkNotNull(traceSource.file){
96-
"TraceMode.File should have a non-null file to parse."
97-
}
98-
val parseResult = parseFileTrace(traceSource.file)
99-
handleParseResult(parseResult)
100-
}
101-
102-
is TraceMode.Live -> {
103-
val socket = traceSource.socket
104-
launch {
105-
try {
106-
socket.pollSocket()
107-
} catch (e: SocketException) {
108-
error = SocketException("Socket has already been closed or is not available: ${e.message}")
109-
return@launch
110-
}
111-
}
112-
if (error != null) {
113-
return@LaunchedEffect
114-
}
115-
val adapter: JsonAdapter<List<Node>> = createMoshiAdapter<Node>()
116-
117-
withContext(Dispatchers.Default) {
118-
// Since channel implements ChannelIterator, we can for-loop through on the receiver end.
119-
for (renderPass in socket.renderPassChannel) {
120-
val currentTree = fullTree.lastOrNull()
121-
val parseResult = parseLiveTrace(renderPass, adapter, currentTree)
122-
handleParseResult(parseResult, onNewFrame)
123-
}
124-
}
125-
}
126-
}
127-
}
128-
129-
if (error != null) {
130-
Text("Error parsing: ${error?.message}")
131-
return
132-
}
133-
134-
if (!isLoading) {
135-
val previousFrame = if (frameInd > 0) fullTree[frameInd - 1] else null
136-
DrawTree(
137-
node = fullTree[frameInd],
138-
previousNode = previousFrame,
139-
affectedNodes = affectedNodes[frameInd],
140-
expandedNodes = remember(frameInd) { mutableStateMapOf() },
141-
onNodeSelect = onNodeSelect,
142-
)
143-
}
144-
}
14524

14625
/**
14726
* Since the workflow nodes present a tree structure, we utilize a recursive function to draw the tree
@@ -151,7 +30,7 @@ internal fun RenderTrace(
15130
* closed from user clicks.
15231
*/
15332
@Composable
154-
private fun DrawTree(
33+
internal fun DrawTree(
15534
node: Node,
15635
previousNode: Node?,
15736
affectedNodes: Set<Node>,

workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/util/JsonParser.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ internal suspend fun parseFileTrace(
5656
* Parses a single render pass from a live trace stream.
5757
* Similar to parseFileTrace but handles one render pass at a time.
5858
*
59-
* @return ParseResult containing the new frame, merged tree, and current render pass nodes.
59+
* @return [ParseResult] containing the new frame, merged tree, and current render pass nodes.
6060
*/
6161
internal fun parseLiveTrace(
6262
renderPass: String,

workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/util/SocketClient.kt

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
package com.squareup.workflow1.traceviewer.util
22

3-
import kotlinx.coroutines.CoroutineScope
43
import kotlinx.coroutines.Dispatchers
5-
import kotlinx.coroutines.Job
64
import kotlinx.coroutines.channels.Channel
7-
import kotlinx.coroutines.launch
85
import kotlinx.coroutines.withContext
9-
import kotlinx.coroutines.delay
10-
import kotlinx.coroutines.yield
11-
126
import java.net.Socket
137
import java.net.SocketException
148

@@ -33,7 +27,7 @@ internal class SocketClient {
3327
* `localabstract:` to connect to it.
3428
*/
3529
fun open() {
36-
if (initialized){
30+
if (initialized) {
3731
return
3832
}
3933
initialized = true
@@ -44,7 +38,7 @@ internal class SocketClient {
4438
// The adb forward command will output the port number it picks to connect.
4539
process.waitFor()
4640
val port = process.inputStream.bufferedReader().readText()
47-
.trim().toInt()
41+
.trim().toInt()
4842

4943
socket = Socket("localhost", port)
5044
}
@@ -71,7 +65,6 @@ internal class SocketClient {
7165
while (true) {
7266
val input = reader.readLine()
7367
renderPassChannel.trySend(input)
74-
println(input)
7568
}
7669
} catch (e: SocketException) {
7770
e.printStackTrace()
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.squareup.workflow1.traceviewer.util
2+
3+
import androidx.compose.material.Text
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.LaunchedEffect
6+
import androidx.compose.runtime.getValue
7+
import androidx.compose.runtime.mutableStateListOf
8+
import androidx.compose.runtime.mutableStateMapOf
9+
import androidx.compose.runtime.mutableStateOf
10+
import androidx.compose.runtime.remember
11+
import androidx.compose.runtime.setValue
12+
import androidx.compose.ui.Modifier
13+
import com.squareup.moshi.JsonAdapter
14+
import com.squareup.workflow1.traceviewer.TraceMode
15+
import com.squareup.workflow1.traceviewer.model.Node
16+
import com.squareup.workflow1.traceviewer.ui.DrawTree
17+
import kotlinx.coroutines.Dispatchers
18+
import kotlinx.coroutines.launch
19+
import kotlinx.coroutines.withContext
20+
import java.net.SocketException
21+
22+
/**
23+
* Handles parsing the trace's after JsonParser has turned all render passes into frames. Also calls
24+
* the UI composables to render the full trace.
25+
*
26+
* This handles either File or Live trace modes, and will parse equally
27+
*/
28+
@Composable
29+
internal fun RenderTrace(
30+
traceSource: TraceMode,
31+
frameInd: Int,
32+
onFileParse: (List<Node>) -> Unit,
33+
onNodeSelect: (Node, Node?) -> Unit,
34+
onNewFrame: () -> Unit,
35+
modifier: Modifier = Modifier
36+
) {
37+
var isLoading by remember(traceSource) { mutableStateOf(true) }
38+
var error by remember(traceSource) { mutableStateOf<Throwable?>(null) }
39+
val frames = remember { mutableStateListOf<Node>() }
40+
val fullTree = remember { mutableStateListOf<Node>() }
41+
val affectedNodes = remember { mutableStateListOf<Set<Node>>() }
42+
43+
// Updates current state with the new data from trace source.
44+
fun addToStates(frame: List<Node>, tree: List<Node>, affected: List<Set<Node>>) {
45+
frames.addAll(frame)
46+
fullTree.addAll(tree)
47+
affectedNodes.addAll(affected)
48+
isLoading = false
49+
onFileParse(frame)
50+
}
51+
52+
// Handles the result of parsing a trace, either from file or live. Live mode includes callback
53+
// for when a new frame is received.
54+
fun handleParseResult(
55+
parseResult: ParseResult,
56+
onNewFrame: (() -> Unit)? = null
57+
) {
58+
when (parseResult) {
59+
is ParseResult.Failure -> {
60+
error = parseResult.error
61+
}
62+
is ParseResult.Success -> {
63+
addToStates(
64+
frame = parseResult.trace,
65+
tree = parseResult.trees,
66+
affected = parseResult.affectedNodes
67+
)
68+
onNewFrame?.invoke()
69+
}
70+
}
71+
}
72+
73+
LaunchedEffect(traceSource) {
74+
when (traceSource) {
75+
is TraceMode.File -> {
76+
checkNotNull(traceSource.file) {
77+
"TraceMode.File should have a non-null file to parse."
78+
}
79+
val parseResult = parseFileTrace(traceSource.file)
80+
handleParseResult(parseResult)
81+
}
82+
83+
is TraceMode.Live -> {
84+
val socket = traceSource.socket
85+
launch {
86+
try {
87+
socket.pollSocket()
88+
} catch (e: SocketException) {
89+
error = SocketException("Socket has already been closed or is not available: ${e.message}")
90+
return@launch
91+
}
92+
}
93+
if (error != null) {
94+
return@LaunchedEffect
95+
}
96+
val adapter: JsonAdapter<List<Node>> = createMoshiAdapter<Node>()
97+
98+
withContext(Dispatchers.Default) {
99+
// Since channel implements ChannelIterator, we can for-loop through on the receiver end.
100+
for (renderPass in socket.renderPassChannel) {
101+
val currentTree = fullTree.lastOrNull()
102+
val parseResult = parseLiveTrace(renderPass, adapter, currentTree)
103+
handleParseResult(parseResult, onNewFrame)
104+
}
105+
}
106+
}
107+
}
108+
}
109+
110+
if (error != null) {
111+
Text("Error parsing: ${error?.message}")
112+
return
113+
}
114+
115+
if (!isLoading) {
116+
val previousFrame = if (frameInd > 0) fullTree[frameInd - 1] else null
117+
DrawTree(
118+
node = fullTree[frameInd],
119+
previousNode = previousFrame,
120+
affectedNodes = affectedNodes[frameInd],
121+
expandedNodes = remember(frameInd) { mutableStateMapOf() },
122+
onNodeSelect = onNodeSelect,
123+
)
124+
}
125+
}

0 commit comments

Comments
 (0)