Skip to content

Commit 6d2d31b

Browse files
committed
Group unaffected and affected children separately
1 parent 6dddf94 commit 6d2d31b

File tree

1 file changed

+82
-21
lines changed
  • workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/ui

1 file changed

+82
-21
lines changed

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

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import androidx.compose.foundation.layout.Box
77
import androidx.compose.foundation.layout.Column
88
import androidx.compose.foundation.layout.Row
99
import androidx.compose.foundation.layout.fillMaxSize
10+
import androidx.compose.foundation.layout.fillMaxWidth
1011
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.shape.RoundedCornerShape
1113
import androidx.compose.material.Text
1214
import androidx.compose.runtime.Composable
1315
import androidx.compose.runtime.LaunchedEffect
@@ -26,6 +28,7 @@ import androidx.compose.ui.input.pointer.isPrimaryPressed
2628
import androidx.compose.ui.input.pointer.isSecondaryPressed
2729
import androidx.compose.ui.input.pointer.onPointerEvent
2830
import androidx.compose.ui.unit.dp
31+
import androidx.compose.ui.unit.sp
2932
import com.squareup.moshi.JsonAdapter
3033
import com.squareup.workflow1.traceviewer.TraceMode
3134
import com.squareup.workflow1.traceviewer.model.Node
@@ -140,6 +143,7 @@ internal fun RenderTrace(
140143
* A mutable map is used to persist the expansion state of the nodes, allowing them to be open and
141144
* closed from user clicks.
142145
*/
146+
@OptIn(ExperimentalComposeUiApi::class)
143147
@Composable
144148
private fun DrawTree(
145149
node: Node,
@@ -151,17 +155,20 @@ private fun DrawTree(
151155
) {
152156
Column(
153157
modifier
154-
.padding(5.dp)
155-
.border(1.dp, Color.Black)
158+
.padding(6.dp)
159+
.border(3.dp, Color.Black)
156160
.fillMaxSize(),
157161
horizontalAlignment = Alignment.CenterHorizontally,
158162
) {
163+
val groupKey = "${node.id}-unaffected"
159164
val isAffected = affectedNodes.contains(node)
160165
// By default, nodes that relevant to this specific frame are expanded. All others are closed.
161166
LaunchedEffect(expandedNodes) {
162167
expandedNodes[node.id] = isAffected
168+
expandedNodes[groupKey] = false
163169
}
164170
val isExpanded = expandedNodes[node.id] == true
171+
val unaffectedChildrenExpanded = expandedNodes[groupKey] == true
165172

166173
DrawNode(
167174
node = node,
@@ -174,26 +181,80 @@ private fun DrawTree(
174181

175182
// Draws the node's children recursively.
176183
if (isExpanded) {
177-
Row(
178-
horizontalArrangement = Arrangement.Center,
179-
verticalAlignment = Alignment.Top
180-
) {
181-
/*
182-
We pair up the current node's children with previous frame's children.
183-
In the edge case that the current frame has additional children compared to the previous
184-
frame, we replace with null and will check before next recursive call.
185-
*/
186-
node.children.forEach { (id, childNode) ->
187-
val prevFrameChildNode = previousFrameNode?.children?.get(id)
188-
DrawTree(
189-
node = childNode,
190-
previousFrameNode = prevFrameChildNode,
191-
affectedNodes = affectedNodes,
192-
expandedNodes = expandedNodes,
193-
onNodeSelect = onNodeSelect
194-
)
184+
// Draw the affected children, and only draw the unaffected children it is clicked annd expanded.
185+
val (affectedChildren, unaffectedChildren) = node.children.values
186+
.partition { affectedNodes.contains(it) }
187+
188+
189+
if (unaffectedChildren.isNotEmpty()) {
190+
Box (
191+
modifier = Modifier
192+
.onPointerEvent(PointerEventType.Press) {
193+
if (it.buttons.isSecondaryPressed) {
194+
// The open/close state for this group is always set when this node is first composed.
195+
expandedNodes[groupKey] = !expandedNodes[groupKey]!!
196+
}
197+
}
198+
) {
199+
if (!unaffectedChildrenExpanded) {
200+
Column(
201+
modifier = Modifier
202+
.background(Color.LightGray.copy(alpha = 0.3f), shape = RoundedCornerShape(4.dp))
203+
.border(1.dp, Color.Gray)
204+
.padding(8.dp),
205+
horizontalAlignment = Alignment.CenterHorizontally
206+
) {
207+
Text(text = "${node.name}'s", color = Color.DarkGray)
208+
Text(text = "${unaffectedChildren.size} unaffected children", color = Color.DarkGray, fontSize = 12.sp)
209+
}
210+
} else {
211+
DrawChildren(
212+
children = unaffectedChildren,
213+
previousFrameNode = previousFrameNode,
214+
affectedNodes = affectedNodes,
215+
expandedNodes = expandedNodes,
216+
onNodeSelect = onNodeSelect
217+
)
218+
}
195219
}
196220
}
221+
222+
if (affectedChildren.isNotEmpty()) {
223+
DrawChildren(
224+
children = affectedChildren,
225+
previousFrameNode = previousFrameNode,
226+
affectedNodes = affectedNodes,
227+
expandedNodes = expandedNodes,
228+
onNodeSelect = onNodeSelect
229+
)
230+
}
231+
}
232+
}
233+
}
234+
235+
@Composable
236+
private fun DrawChildren(
237+
children: List<Node>,
238+
previousFrameNode: Node?,
239+
affectedNodes: Set<Node>,
240+
expandedNodes: MutableMap<String, Boolean>,
241+
onNodeSelect: (NodeUpdate) -> Unit,
242+
) {
243+
Row(
244+
modifier = Modifier
245+
.fillMaxWidth()
246+
.padding(8.dp),
247+
horizontalArrangement = Arrangement.SpaceEvenly,
248+
verticalAlignment = Alignment.Top
249+
) {
250+
children.forEach { childNode ->
251+
DrawTree(
252+
node = childNode,
253+
previousFrameNode = previousFrameNode?.children?.get(childNode.id),
254+
affectedNodes = affectedNodes,
255+
expandedNodes = expandedNodes,
256+
onNodeSelect = onNodeSelect
257+
)
197258
}
198259
}
199260
}
@@ -227,7 +288,7 @@ private fun DrawNode(
227288
onExpandToggle(node)
228289
}
229290
}
230-
.padding(10.dp)
291+
.padding(16.dp)
231292
) {
232293
Column(horizontalAlignment = Alignment.CenterHorizontally) {
233294
Row(

0 commit comments

Comments
 (0)