Skip to content

Commit 41f0f56

Browse files
committed
Fix WaveformSlider thumb and progress fill misalignment
1 parent 75cafde commit 41f0f56

1 file changed

Lines changed: 87 additions & 88 deletions

File tree

  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/audio

stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/audio/WaveformSlider.kt

Lines changed: 87 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,16 @@ import androidx.compose.foundation.background
2121
import androidx.compose.foundation.border
2222
import androidx.compose.foundation.layout.Box
2323
import androidx.compose.foundation.layout.BoxScope
24+
import androidx.compose.foundation.layout.BoxWithConstraints
2425
import androidx.compose.foundation.layout.fillMaxSize
2526
import androidx.compose.foundation.layout.fillMaxWidth
2627
import androidx.compose.foundation.layout.height
2728
import androidx.compose.foundation.layout.offset
2829
import androidx.compose.foundation.layout.size
29-
import androidx.compose.foundation.layout.width
3030
import androidx.compose.foundation.progressSemantics
3131
import androidx.compose.foundation.shape.CircleShape
3232
import androidx.compose.runtime.Composable
3333
import androidx.compose.runtime.getValue
34-
import androidx.compose.runtime.mutableFloatStateOf
3534
import androidx.compose.runtime.mutableStateOf
3635
import androidx.compose.runtime.remember
3736
import androidx.compose.runtime.rememberUpdatedState
@@ -41,9 +40,7 @@ import androidx.compose.ui.Modifier
4140
import androidx.compose.ui.geometry.CornerRadius
4241
import androidx.compose.ui.geometry.Offset
4342
import androidx.compose.ui.geometry.Size
44-
import androidx.compose.ui.graphics.Color
4543
import androidx.compose.ui.graphics.graphicsLayer
46-
import androidx.compose.ui.layout.onSizeChanged
4744
import androidx.compose.ui.platform.LocalDensity
4845
import androidx.compose.ui.platform.LocalLayoutDirection
4946
import androidx.compose.ui.tooling.preview.Preview
@@ -60,7 +57,6 @@ import kotlin.random.Random
6057
*
6158
* @param modifier Modifier for styling.
6259
* @param waveformData The waveform data to display.
63-
* @param style The style for the waveform slider.
6460
* @param visibleBarLimit The number of bars to display at once.
6561
* @param adjustBarWidthToLimit Whether to adjust the bar width to fit the visible bar limit.
6662
* @param progress The current progress of the waveform.
@@ -84,43 +80,45 @@ public fun StaticWaveformSlider(
8480
) {
8581
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
8682
val currentProgress by rememberUpdatedState(progress)
87-
var widthPx by remember { mutableFloatStateOf(0f) }
88-
Box(
83+
BoxWithConstraints(
8984
modifier = modifier
9085
.fillMaxSize()
91-
.progressSemantics(value = progress)
92-
.onSizeChanged { size ->
93-
widthPx = size.width.toFloat()
94-
}
95-
.dragPointerInput(
96-
enabled = isThumbVisible,
97-
onDragStart = {
98-
onDragStart(it.toHorizontalProgress(widthPx, isRtl))
99-
},
100-
onDrag = {
101-
onDrag(it.toHorizontalProgress(widthPx, isRtl))
102-
},
103-
onDragStop = {
104-
onDragStop(it?.toHorizontalProgress(widthPx, isRtl) ?: currentProgress)
105-
},
106-
),
86+
.progressSemantics(value = progress),
10787
) {
108-
// Draw the waveform
109-
WaveformTrack(
110-
modifier = Modifier.fillMaxSize(),
111-
waveformData = waveformData,
112-
visibleBarLimit = visibleBarLimit,
113-
adjustBarWidthToLimit = adjustBarWidthToLimit,
114-
progress = progress,
115-
)
116-
117-
// Draw the thumb
118-
if (isThumbVisible) {
119-
WaveformHandle(
120-
isPlaying = isPlaying,
88+
val widthPx = constraints.maxWidth.toFloat()
89+
Box(
90+
modifier = Modifier
91+
.fillMaxSize()
92+
.dragPointerInput(
93+
enabled = isThumbVisible,
94+
onDragStart = {
95+
onDragStart(it.toHorizontalProgress(widthPx, isRtl))
96+
},
97+
onDrag = {
98+
onDrag(it.toHorizontalProgress(widthPx, isRtl))
99+
},
100+
onDragStop = {
101+
onDragStop(it?.toHorizontalProgress(widthPx, isRtl) ?: currentProgress)
102+
},
103+
),
104+
) {
105+
// Draw the waveform
106+
WaveformTrack(
107+
modifier = Modifier.fillMaxSize(),
108+
waveformData = waveformData,
109+
visibleBarLimit = visibleBarLimit,
110+
adjustBarWidthToLimit = adjustBarWidthToLimit,
121111
progress = progress,
122-
parentWidthPx = widthPx,
123112
)
113+
114+
// Draw the thumb
115+
if (isThumbVisible) {
116+
WaveformHandle(
117+
isPlaying = isPlaying,
118+
progress = progress,
119+
parentWidthPx = widthPx,
120+
)
121+
}
124122
}
125123
}
126124
}
@@ -175,25 +173,24 @@ internal fun WaveformTrack(
175173

176174
val totalBars = when (adjustBarWidthToLimit) {
177175
true -> visibleBarLimit
178-
else -> when (waveformData.size > visibleBarLimit) {
179-
true -> visibleBarLimit
180-
else -> waveformData.size
181-
}
176+
else -> minOf(waveformData.size, visibleBarLimit)
182177
}
183178
val visibleBars = minOf(visibleBarLimit, waveformData.size)
184179
var barCornerRadius by remember(totalBars) { mutableStateOf(CornerRadius.Zero) }
185180
Canvas(
186181
modifier = modifier.graphicsLayer { scaleX = if (isRtl) -1f else 1f },
187182
) {
183+
if (totalBars <= 0) return@Canvas
184+
188185
val canvasW = size.width
189186
val canvasH = size.height
190187
val spaceWidth = canvasW * BarSpacingRatio
191188
val barsWidth = canvasW - spaceWidth
192189
val totalSpaces = totalBars - 1
193190
val barWidth = barsWidth / totalBars
194-
val barSpacing = spaceWidth / totalSpaces
191+
val barSpacing = if (totalSpaces > 0) spaceWidth / totalSpaces else 0f
195192

196-
val thresholdX = canvasW * finalProgress * visibleBars / visibleBarLimit
193+
val thresholdX = canvasW * finalProgress * visibleBars / totalBars
197194
val halfHeight = canvasH / 2
198195
if (barCornerRadius.x != barWidth || barCornerRadius.y != barWidth) {
199196
barCornerRadius = CornerRadius(barWidth, barWidth)
@@ -227,60 +224,62 @@ internal fun WaveformTrack(
227224
}
228225
}
229226

230-
@Preview(showBackground = true)
227+
@Preview(showBackground = true, widthDp = 250)
231228
@Composable
232-
internal fun WaveformSeekBarPreview() {
233-
val rand = Random(50)
234-
val waveform = List(50) { rand.nextFloat() }
229+
private fun StaticWaveformSliderAtStartPreview() {
230+
ChatPreviewTheme { StaticWaveformSliderSample(progress = 0f, isPlaying = true) }
231+
}
235232

236-
ChatPreviewTheme {
237-
Box(
238-
modifier = Modifier
239-
.width(250.dp)
240-
.height(60.dp)
241-
.background(Color.Cyan),
242-
contentAlignment = Alignment.Center,
243-
) {
244-
StaticWaveformSlider(
245-
modifier = Modifier
246-
.fillMaxWidth()
247-
.height(36.dp),
248-
waveformData = waveform,
249-
progress = 0.0f,
250-
isPlaying = true,
251-
)
252-
}
253-
}
233+
@Preview(showBackground = true, widthDp = 250)
234+
@Composable
235+
private fun StaticWaveformSliderMidwayPreview() {
236+
ChatPreviewTheme { StaticWaveformSliderSample(progress = 0.5f, isPlaying = true) }
237+
}
238+
239+
@Preview(showBackground = true, widthDp = 250)
240+
@Composable
241+
private fun StaticWaveformSliderPausedPreview() {
242+
ChatPreviewTheme { StaticWaveformSliderSample(progress = 0.3f, isPlaying = false) }
254243
}
255244

256-
@Preview(showBackground = true)
245+
@Preview(showBackground = true, widthDp = 250)
257246
@Composable
258-
internal fun WaveformTrackPreview() {
259-
val waveform = mutableListOf<Float>()
260-
val barCount = 100
261-
for (i in 0 until barCount) {
262-
waveform.add((i + 1) / barCount.toFloat())
247+
private fun StaticWaveformSliderWithoutThumbPreview() {
248+
ChatPreviewTheme { StaticWaveformSliderSample(progress = 0.7f, isPlaying = true, isThumbVisible = false) }
249+
}
250+
251+
@Composable
252+
private fun StaticWaveformSliderSample(progress: Float, isPlaying: Boolean, isThumbVisible: Boolean = true) {
253+
val previewWaveform = remember {
254+
val rand = Random(50)
255+
List(50) { rand.nextFloat() }
263256
}
264257

258+
StaticWaveformSlider(
259+
modifier = Modifier
260+
.fillMaxWidth()
261+
.height(36.dp),
262+
waveformData = previewWaveform,
263+
progress = progress,
264+
isPlaying = isPlaying,
265+
isThumbVisible = isThumbVisible,
266+
)
267+
}
268+
269+
@Preview(showBackground = true, widthDp = 250)
270+
@Composable
271+
private fun FullWaveformTrackPreview() {
265272
ChatPreviewTheme {
266-
Box(
273+
val waveform = List(100) { (it + 1) / 100f }
274+
WaveformTrack(
267275
modifier = Modifier
268-
.width(250.dp)
269-
.height(80.dp)
270-
.background(Color.Black),
271-
contentAlignment = Alignment.Center,
272-
) {
273-
WaveformTrack(
274-
modifier = Modifier
275-
.background(Color.Red)
276-
.fillMaxWidth()
277-
.height(60.dp),
278-
waveformData = waveform,
279-
progress = 0f,
280-
adjustBarWidthToLimit = true,
281-
visibleBarLimit = 100,
282-
)
283-
}
276+
.fillMaxWidth()
277+
.height(60.dp),
278+
waveformData = waveform,
279+
progress = 1f,
280+
adjustBarWidthToLimit = true,
281+
visibleBarLimit = 100,
282+
)
284283
}
285284
}
286285

0 commit comments

Comments
 (0)