Skip to content

Commit 418abf1

Browse files
committed
New frame selector format
1 parent 4f9f92b commit 418abf1

File tree

3 files changed

+156
-85
lines changed

3 files changed

+156
-85
lines changed

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

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

3+
import androidx.compose.foundation.layout.Arrangement
34
import androidx.compose.foundation.layout.Box
45
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.padding
57
import androidx.compose.runtime.Composable
68
import androidx.compose.runtime.LaunchedEffect
79
import androidx.compose.runtime.getValue
@@ -18,12 +20,13 @@ import androidx.compose.ui.Modifier
1820
import androidx.compose.ui.geometry.Offset
1921
import androidx.compose.ui.layout.onGloballyPositioned
2022
import androidx.compose.ui.unit.IntSize
23+
import androidx.compose.ui.unit.dp
2124
import com.squareup.workflow1.traceviewer.model.Node
2225
import com.squareup.workflow1.traceviewer.model.NodeUpdate
2326
import com.squareup.workflow1.traceviewer.ui.RightInfoPanel
2427
import com.squareup.workflow1.traceviewer.ui.control.DisplayDevices
2528
import com.squareup.workflow1.traceviewer.ui.control.FileDump
26-
import com.squareup.workflow1.traceviewer.ui.control.FrameSelectTab
29+
import com.squareup.workflow1.traceviewer.ui.control.FrameNavigator
2730
import com.squareup.workflow1.traceviewer.ui.control.SearchBox
2831
import com.squareup.workflow1.traceviewer.ui.control.TraceModeToggleSwitch
2932
import com.squareup.workflow1.traceviewer.ui.control.UploadFile
@@ -97,15 +100,13 @@ internal fun App(
97100
}
98101

99102
Column(
100-
modifier = Modifier.align(Alignment.TopCenter)
103+
modifier = Modifier
104+
.align(Alignment.TopCenter)
105+
.padding(top = 8.dp),
106+
verticalArrangement = Arrangement.spacedBy(8.dp),
107+
horizontalAlignment = Alignment.CenterHorizontally
101108
) {
102109
if (active) {
103-
FrameSelectTab(
104-
size = frameSize,
105-
currentIndex = frameIndex,
106-
onIndexChange = { frameIndex = it },
107-
)
108-
109110
// Since we can jump from frame to frame, we fill in the map during each recomposition
110111
if (nodeLocations.getOrNull(frameInd) == null) {
111112
// frameSize has not been updated yet, so on the first frame, frameSize = nodeLocations.size = 0,
@@ -124,7 +125,12 @@ internal fun App(
124125
val newY = sandboxState.offset.y - nodeLocations[frameInd][node]!!.y + appWindowSize.height / 2
125126
sandboxState.offset = Offset(x = newX, y = newY)
126127
},
127-
modifier = Modifier.align(Alignment.CenterHorizontally)
128+
)
129+
130+
FrameNavigator(
131+
totalFrames = frameSize,
132+
currentIndex = frameIndex,
133+
onIndexChange = { frameIndex = it },
128134
)
129135
}
130136
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.squareup.workflow1.traceviewer.ui.control
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.layout.Arrangement
6+
import androidx.compose.foundation.layout.Box
7+
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.heightIn
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.layout.width
12+
import androidx.compose.foundation.shape.RoundedCornerShape
13+
import androidx.compose.material.DropdownMenu
14+
import androidx.compose.material.DropdownMenuItem
15+
import androidx.compose.material.Icon
16+
import androidx.compose.material.IconButton
17+
import androidx.compose.material.Surface
18+
import androidx.compose.material.Text
19+
import androidx.compose.material.icons.Icons
20+
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
21+
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
22+
import androidx.compose.material.icons.filled.ArrowDropDown
23+
import androidx.compose.runtime.Composable
24+
import androidx.compose.runtime.getValue
25+
import androidx.compose.runtime.mutableStateOf
26+
import androidx.compose.runtime.remember
27+
import androidx.compose.runtime.setValue
28+
import androidx.compose.ui.Alignment
29+
import androidx.compose.ui.Modifier
30+
import androidx.compose.ui.draw.clip
31+
import androidx.compose.ui.graphics.Color
32+
import androidx.compose.ui.text.font.FontWeight
33+
import androidx.compose.ui.unit.dp
34+
import androidx.compose.ui.unit.sp
35+
36+
/**
37+
* A frame navigator that shows the current frame number with dropdown selection
38+
* and left/right navigation arrows.
39+
*/
40+
@Composable
41+
internal fun FrameNavigator(
42+
totalFrames: Int,
43+
currentIndex: Int,
44+
onIndexChange: (Int) -> Unit,
45+
modifier: Modifier = Modifier
46+
) {
47+
var dropdownExpanded by remember { mutableStateOf(false) }
48+
49+
Surface(
50+
modifier = modifier,
51+
color = Color.White,
52+
elevation = 2.dp,
53+
shape = RoundedCornerShape(8.dp)
54+
) {
55+
Row(
56+
modifier = Modifier
57+
.padding(horizontal = 8.dp, vertical = 4.dp),
58+
verticalAlignment = Alignment.CenterVertically,
59+
horizontalArrangement = Arrangement.spacedBy(4.dp)
60+
) {
61+
// Previous frame button
62+
IconButton(
63+
onClick = {
64+
if (currentIndex > 0) {
65+
onIndexChange(currentIndex - 1)
66+
}
67+
},
68+
enabled = currentIndex > 0
69+
) {
70+
Icon(
71+
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowLeft,
72+
contentDescription = "Previous frame",
73+
tint = if (currentIndex > 0) Color.Black else Color.LightGray
74+
)
75+
}
76+
77+
Box {
78+
Row(
79+
modifier = Modifier
80+
.clip(RoundedCornerShape(4.dp))
81+
.clickable { dropdownExpanded = true }
82+
.padding(horizontal = 12.dp, vertical = 8.dp),
83+
verticalAlignment = Alignment.CenterVertically,
84+
horizontalArrangement = Arrangement.spacedBy(4.dp)
85+
) {
86+
Text(
87+
text = "Frame ${currentIndex + 1}",
88+
fontSize = 14.sp,
89+
fontWeight = FontWeight.Medium,
90+
color = Color.Black
91+
)
92+
Icon(
93+
imageVector = Icons.Default.ArrowDropDown,
94+
contentDescription = "Select frame",
95+
tint = Color.Black
96+
)
97+
}
98+
99+
DropdownMenu(
100+
expanded = dropdownExpanded,
101+
onDismissRequest = { dropdownExpanded = false },
102+
modifier = Modifier
103+
.background(Color.White)
104+
.width(150.dp)
105+
.heightIn(max = 350.dp)
106+
) {
107+
(0 until totalFrames).forEach { index ->
108+
DropdownMenuItem(
109+
onClick = {
110+
onIndexChange(index)
111+
dropdownExpanded = false
112+
},
113+
modifier = Modifier.fillMaxWidth()
114+
) {
115+
Text(
116+
text = "Frame ${index + 1}",
117+
color = if (index == currentIndex) Color.Black else Color.LightGray,
118+
fontWeight = if (index == currentIndex) FontWeight.Bold else FontWeight.Normal
119+
)
120+
}
121+
}
122+
}
123+
}
124+
125+
IconButton(
126+
onClick = {
127+
if (currentIndex < totalFrames - 1) {
128+
onIndexChange(currentIndex + 1)
129+
}
130+
},
131+
enabled = currentIndex < totalFrames - 1
132+
) {
133+
Icon(
134+
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
135+
contentDescription = "Next frame",
136+
tint = if (currentIndex < totalFrames - 1) Color.Black else Color.LightGray
137+
)
138+
}
139+
}
140+
}
141+
}

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

Lines changed: 0 additions & 76 deletions
This file was deleted.

0 commit comments

Comments
 (0)