feat(android): swipe-up-to-expand gesture on MiniPlayer (#34)
Ports player_bar.dart's onVerticalDragEnd — an upward flick anywhere on the bar expands into NowPlaying, alongside the existing tap-to-expand. A vertical draggable claims only vertical-dominant drags, so the inline seek slider keeps its horizontal scrub gesture. The 200 px/s Flutter threshold is expressed in dp and density-converted so the flick feels the same across screen densities. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,9 @@ import androidx.compose.animation.Crossfade
|
|||||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.draggable
|
||||||
|
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@@ -27,6 +30,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
@@ -52,6 +56,11 @@ private const val MINI_BAR_TONAL_ELEVATION_DP = 4
|
|||||||
private const val COVER_SIZE_DP = 48
|
private const val COVER_SIZE_DP = 48
|
||||||
private const val SCRUBBER_ROW_HEIGHT_DP = 4
|
private const val SCRUBBER_ROW_HEIGHT_DP = 4
|
||||||
|
|
||||||
|
// Upward flick speed (dp/s) that expands the bar into NowPlaying.
|
||||||
|
// Mirrors player_bar.dart's 200 px/s threshold; expressed in dp and
|
||||||
|
// converted via density so the gesture feels the same across screens.
|
||||||
|
private const val SWIPE_UP_VELOCITY_DP = 200
|
||||||
|
|
||||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
@OptIn(ExperimentalSharedTransitionApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun MiniCover(coverUrl: String, contentDescription: String) {
|
private fun MiniCover(coverUrl: String, contentDescription: String) {
|
||||||
@@ -126,10 +135,22 @@ fun MiniPlayer(
|
|||||||
val isLiked by trackActionsViewModel.isLikedFlow(track.id)
|
val isLiked by trackActionsViewModel.isLikedFlow(track.id)
|
||||||
.collectAsStateWithLifecycle(initialValue = false)
|
.collectAsStateWithLifecycle(initialValue = false)
|
||||||
|
|
||||||
|
// Swipe up anywhere on the bar to expand into the full player —
|
||||||
|
// mirrors player_bar.dart. We only act on a clear upward flick
|
||||||
|
// (negative velocity past the threshold) so a slow tap-with-jitter
|
||||||
|
// doesn't accidentally open the screen. The horizontal seek slider
|
||||||
|
// keeps its own gestures; a vertical draggable only claims
|
||||||
|
// vertical-dominant drags.
|
||||||
|
val flickThresholdPx = with(LocalDensity.current) { SWIPE_UP_VELOCITY_DP.dp.toPx() }
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(MINI_BAR_HEIGHT_DP.dp),
|
.height(MINI_BAR_HEIGHT_DP.dp)
|
||||||
|
.draggable(
|
||||||
|
orientation = Orientation.Vertical,
|
||||||
|
state = rememberDraggableState { },
|
||||||
|
onDragStopped = { velocity -> if (velocity < -flickThresholdPx) onExpandClick() },
|
||||||
|
),
|
||||||
color = MaterialTheme.colorScheme.surface,
|
color = MaterialTheme.colorScheme.surface,
|
||||||
tonalElevation = MINI_BAR_TONAL_ELEVATION_DP.dp,
|
tonalElevation = MINI_BAR_TONAL_ELEVATION_DP.dp,
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user