Readable accent text app-wide; Android queue drag math under test #144

Merged
bvandeusen merged 2 commits from dev into main 2026-10-08 06:29:48 -04:00
3 changed files with 111 additions and 3 deletions
Showing only changes of commit 43c369f082 - Show all commits
@@ -0,0 +1,32 @@
package com.fabledsword.minstrel.player.ui
import kotlin.math.roundToInt
/**
* Drag offset to row delta, rounded to the nearest row boundary. The Android
* half of web's `offsetToDelta` (web/src/lib/components/queue-row-math.ts):
* the two clients are meant to agree, and QueueDragMathTest mirrors web's
* cases so both are held to it (#2436).
*
* Ties round toward positive infinity, as JS `Math.round` does: half a row
* down moves one row, half a row up stays put. A row not yet measured
* (height 0) moves nothing.
*/
internal fun queueDragDelta(offsetPx: Float, rowHeightPx: Int): Int =
if (rowHeightPx > 0) (offsetPx / rowHeightPx).roundToInt() else 0
/**
* The queue index a row dragged from [index] lands on, clamped to the queue.
* A drag past either end stops at the first or last row.
*/
internal fun queueDragTarget(
index: Int,
offsetPx: Float,
rowHeightPx: Int,
queueSize: Int,
): Int {
// coerceIn throws on an empty range; a row can't be dragged in an empty
// queue, but the composable's keys can briefly outlive the list.
if (queueSize <= 0) return index
return (index + queueDragDelta(offsetPx, rowHeightPx)).coerceIn(0, queueSize - 1)
}
@@ -48,7 +48,6 @@ import com.fabledsword.minstrel.shared.formatDuration
import com.fabledsword.minstrel.shared.widgets.LikeButton
import com.fabledsword.minstrel.shared.widgets.ServerImage
import com.fabledsword.minstrel.theme.LocalActionColors
import kotlin.math.roundToInt
/*
* A single queue row, split out of QueueScreen.kt when swipe-to-remove (#2435)
@@ -278,8 +277,7 @@ private fun Modifier.queueReorderDrag(
onOffsetChange(offset)
},
onDragEnd = {
val delta = if (rowHeightPx > 0) (offset / rowHeightPx).roundToInt() else 0
val target = (index + delta).coerceIn(0, queueSize - 1)
val target = queueDragTarget(index, offset, rowHeightPx, queueSize)
if (target != index) onMove(index, target)
offset = 0f
onOffsetChange(0f)
@@ -0,0 +1,78 @@
package com.fabledsword.minstrel.player.ui
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
/**
* The queue drag math (#2436). The delta cases mirror web's
* queue-row-math.test.ts one for one, so a change to either client's
* rounding shows up as a disagreement here rather than as a drop that lands
* one row off on one platform only.
*/
class QueueDragMathTest {
@Test
fun `zero offset moves nothing`() {
assertEquals(0, queueDragDelta(0f, 64))
}
@Test
fun `a full row down moves one`() {
assertEquals(1, queueDragDelta(64f, 64))
}
@Test
fun `just under half a row rounds down`() {
assertEquals(0, queueDragDelta(31f, 64))
}
@Test
fun `half a row or more rounds up`() {
assertEquals(1, queueDragDelta(32f, 64))
}
@Test
fun `drag up is symmetric, with ties toward positive infinity as in JS`() {
assertEquals(-1, queueDragDelta(-64f, 64))
assertEquals(0, queueDragDelta(-32f, 64))
}
@Test
fun `several rows`() {
assertEquals(3, queueDragDelta(192f, 64))
assertEquals(-2, queueDragDelta(-128f, 64))
}
@Test
fun `a row not yet measured moves nothing`() {
assertEquals(0, queueDragDelta(100f, 0))
assertEquals(0, queueDragDelta(100f, -1))
}
@Test
fun `the measured row height is what counts`() {
assertEquals(1, queueDragDelta(56f, 56))
assertEquals(1, queueDragDelta(28f, 56))
}
@Test
fun `a drag past either end stops at the first or last row`() {
assertEquals(0, queueDragTarget(index = 1, offsetPx = -640f, rowHeightPx = 64, queueSize = 5))
assertEquals(4, queueDragTarget(index = 3, offsetPx = 640f, rowHeightPx = 64, queueSize = 5))
}
@Test
fun `a sub-half-row drag lands where it started`() {
assertEquals(2, queueDragTarget(index = 2, offsetPx = 20f, rowHeightPx = 64, queueSize = 5))
}
@Test
fun `before the row is measured a drag lands where it started`() {
assertEquals(2, queueDragTarget(index = 2, offsetPx = 300f, rowHeightPx = 0, queueSize = 5))
}
@Test
fun `an empty queue does not throw`() {
assertEquals(0, queueDragTarget(index = 0, offsetPx = 64f, rowHeightPx = 64, queueSize = 0))
}
}