Readable accent text app-wide; Android queue drag math under test #144
@@ -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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user