feat(android): slim NowPlaying scrubber — 4dp track + tight slider
android / Build + lint + test (push) Failing after 1m44s
android / Build + lint + test (push) Failing after 1m44s
The M3 Slider default track is 16dp tall and the Slider itself expands to the 48dp interactive-component minimum, so the 14dp thumb we'd already shrunk to a flat circle was still sitting in the middle of a fat horizontal pill with lots of empty space above and below. Operator framing: "puffy, not a tool." Two changes: - Custom 4dp rounded track replaces SliderDefaults.Track. The thumb (14dp) now reads as visibly taller than the bar — the classic "handle on a string" cue that says "tool, draggable." Also drops M3's stop-indicator dot which the web scrubber doesn't have. - Clamp the Slider's vertical footprint to 20dp via Modifier. height. 14dp thumb + 3dp clearance each side, vs the default ~17dp empty above and below. Touch area stays usable since the drag axis is horizontal — pulling left/right anywhere on the thin bar feels natural, and Slider's gesture detector still responds to a tap anywhere along its row. Keeps an Android flavor (slightly thicker than the web's 2-3px hairline; rounded caps; accent fill) without reading as bulky.
This commit is contained in:
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
@@ -85,6 +86,9 @@ private const val COVER_MAX_WIDTH_DP = 320
|
|||||||
private const val TRANSPORT_ICON_DP = 36
|
private const val TRANSPORT_ICON_DP = 36
|
||||||
private const val PLAY_PAUSE_ICON_DP = 56
|
private const val PLAY_PAUSE_ICON_DP = 56
|
||||||
private const val POP_GRACE_MS = 500L
|
private const val POP_GRACE_MS = 500L
|
||||||
|
private val SCRUB_TRACK_HEIGHT_DP = 4.dp
|
||||||
|
private val SCRUB_TRACK_CORNER_DP = 2.dp
|
||||||
|
private val SCRUB_SLIDER_HEIGHT_DP = 20.dp
|
||||||
|
|
||||||
// Vertical drag-down threshold (in pixels) past which the gesture
|
// Vertical drag-down threshold (in pixels) past which the gesture
|
||||||
// pops the player. Matches Flutter's 80px threshold in spirit;
|
// pops the player. Matches Flutter's 80px threshold in spirit;
|
||||||
@@ -472,7 +476,12 @@ private fun ScrubberRow(positionMs: Long, durationMs: Long, onSeek: (Long) -> Un
|
|||||||
onValueChange = { newFraction ->
|
onValueChange = { newFraction ->
|
||||||
if (durationMs > 0) onSeek((newFraction * durationMs).toLong())
|
if (durationMs > 0) onSeek((newFraction * durationMs).toLong())
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
// Clamp the Slider's vertical footprint so the M3-default
|
||||||
|
// 48dp interactive-component padding doesn't leave the thumb
|
||||||
|
// floating in empty space above and below the track. 20dp =
|
||||||
|
// 14dp thumb + 3dp clearance each side; touch area is still
|
||||||
|
// wide enough since the drag axis is horizontal.
|
||||||
|
modifier = Modifier.fillMaxWidth().height(SCRUB_SLIDER_HEIGHT_DP),
|
||||||
colors = sliderColors,
|
colors = sliderColors,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
// Plain filled circle to match the web client's `<input
|
// Plain filled circle to match the web client's `<input
|
||||||
@@ -488,6 +497,29 @@ private fun ScrubberRow(positionMs: Long, durationMs: Long, onSeek: (Long) -> Un
|
|||||||
.background(accent),
|
.background(accent),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
// Custom 4dp rounded track. M3's default Track is 16dp tall
|
||||||
|
// and reads as a heavy pill rather than a measurement line;
|
||||||
|
// making the thumb visibly taller than the track (14dp thumb
|
||||||
|
// on a 4dp bar) restores the "handle on a string" cue your
|
||||||
|
// eye reads as "tool, draggable." Also drops M3's stop
|
||||||
|
// indicator dot, which the web scrubber doesn't have.
|
||||||
|
track = { _ ->
|
||||||
|
Box(modifier = Modifier.fillMaxWidth().height(SCRUB_TRACK_HEIGHT_DP)) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.matchParentSize()
|
||||||
|
.clip(RoundedCornerShape(SCRUB_TRACK_CORNER_DP))
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(fraction)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.clip(RoundedCornerShape(SCRUB_TRACK_CORNER_DP))
|
||||||
|
.background(accent),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|||||||
Reference in New Issue
Block a user