make the mini player progress bar unrounded and tie expansion to the drag

This commit is contained in:
austinried
2026-10-04 00:29:54 +00:00
parent 5907ebcb5c
commit ad1bb1fc8e
2 changed files with 61 additions and 19 deletions
+49 -13
View File
@@ -3,6 +3,7 @@ package com.subtracks.ui
import android.net.Uri
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@@ -19,10 +20,14 @@ import androidx.compose.foundation.layout.navigationBars
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
@@ -49,6 +54,7 @@ import com.subtracks.ui.theme.rememberArtworkColors
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.koin.compose.koinInject
import org.koin.compose.viewmodel.koinViewModel
@@ -100,8 +106,12 @@ private fun MainNavigation() {
val navController = rememberNavController()
val playbackController = koinInject<PlaybackController>()
val playback by playbackController.state.collectAsStateWithLifecycle()
var showingNowPlaying by rememberSaveable { mutableStateOf(false) }
var showingQueue by rememberSaveable { mutableStateOf(false) }
var draggingExpand by remember { mutableStateOf(false) }
var dragFraction by remember { mutableFloatStateOf(0f) }
val expandProgress = remember { Animatable(0f) }
val scope = rememberCoroutineScope()
val nowPlayingProgress = if (draggingExpand) dragFraction else expandProgress.value
LaunchedEffect(Unit) { playbackController.connect() }
val playerVisible = playback.item != null
@@ -221,23 +231,47 @@ private fun MainNavigation() {
state = playback,
coverArt = miniArt,
artwork = rememberArtworkColors(miniArt),
onExpand = { showingNowPlaying = true },
onExpand = {
draggingExpand = false
scope.launch { expandProgress.animateTo(1f) }
},
onPlayPause = playbackController::togglePlayPause,
onNext = playbackController::next,
onExpandProgress = {
draggingExpand = true
dragFraction = it
},
onExpandCommit = {
draggingExpand = false
scope.launch {
expandProgress.snapTo(dragFraction)
expandProgress.animateTo(1f)
}
},
onExpandCancel = {
draggingExpand = false
scope.launch {
expandProgress.snapTo(dragFraction)
expandProgress.animateTo(0f)
}
},
)
}
}
AnimatedVisibility(
visible = showingNowPlaying,
enter = slideInVertically(initialOffsetY = { it }) + fadeIn(tween(NOW_PLAYING_DURATION_MS)),
exit = slideOutVertically(targetOffsetY = { it }) + fadeOut(tween(NOW_PLAYING_DURATION_MS)),
) {
NowPlayingRoute(
onBack = { showingNowPlaying = false },
onQueue = { showingQueue = true },
modifier = Modifier.fillMaxSize(),
)
if (nowPlayingProgress > 0f) {
Box(
modifier =
Modifier
.fillMaxSize()
.graphicsLayer { translationY = (1f - nowPlayingProgress) * size.height },
) {
NowPlayingRoute(
onBack = { scope.launch { expandProgress.animateTo(0f) } },
onQueue = { showingQueue = true },
modifier = Modifier.fillMaxSize(),
)
}
}
AnimatedVisibility(
@@ -253,5 +287,7 @@ private fun MainNavigation() {
}
BackHandler(enabled = showingQueue) { showingQueue = false }
BackHandler(enabled = showingNowPlaying && !showingQueue) { showingNowPlaying = false }
BackHandler(enabled = nowPlayingProgress > 0f && !showingQueue) {
scope.launch { expandProgress.animateTo(0f) }
}
}
@@ -34,6 +34,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
@@ -43,7 +44,7 @@ import com.subtracks.ui.components.CoverArt
import com.subtracks.ui.theme.ArtworkColors
import com.subtracks.ui.theme.ArtworkTheme
private val EXPAND_DRAG = 48.dp
private val EXPAND_DRAG = 240.dp
@Composable
fun MiniPlayer(
@@ -53,6 +54,9 @@ fun MiniPlayer(
onExpand: () -> Unit,
onPlayPause: () -> Unit,
onNext: () -> Unit,
onExpandProgress: (Float) -> Unit = {},
onExpandCommit: () -> Unit = {},
onExpandCancel: () -> Unit = {},
modifier: Modifier = Modifier,
) {
val item = state.item ?: return
@@ -75,11 +79,12 @@ fun MiniPlayer(
state =
rememberDraggableState { delta ->
dragUpPx = (dragUpPx - delta).coerceAtLeast(0f)
if (dragUpPx >= expandThresholdPx) {
dragUpPx = 0f
onExpand()
}
onExpandProgress((dragUpPx / expandThresholdPx).coerceIn(0f, 1f))
},
onDragStopped = {
if (dragUpPx >= expandThresholdPx / 2f) onExpandCommit() else onExpandCancel()
dragUpPx = 0f
},
).clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
@@ -89,9 +94,10 @@ fun MiniPlayer(
Column {
LinearProgressIndicator(
progress = { progress },
modifier = Modifier.fillMaxWidth().height(2.dp),
modifier = Modifier.fillMaxWidth().height(4.dp),
color = MaterialTheme.colorScheme.primary,
trackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.24f),
strokeCap = StrokeCap.Butt,
gapSize = 0.dp,
drawStopIndicator = {},
)