@@ -11,12 +11,6 @@ import androidx.compose.foundation.layout.padding
1111import androidx.compose.material.Text
1212import androidx.compose.runtime.Composable
1313import 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
2014import androidx.compose.ui.Alignment
2115import androidx.compose.ui.ExperimentalComposeUiApi
2216import androidx.compose.ui.Modifier
@@ -26,122 +20,7 @@ import androidx.compose.ui.input.pointer.isPrimaryPressed
2620import androidx.compose.ui.input.pointer.isSecondaryPressed
2721import androidx.compose.ui.input.pointer.onPointerEvent
2822import androidx.compose.ui.unit.dp
29- import com.squareup.moshi.JsonAdapter
30- import com.squareup.workflow1.traceviewer.TraceMode
3123import 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 >,
0 commit comments