@@ -34,6 +34,7 @@ import androidx.compose.material3.ButtonGroup
3434import androidx.compose.material3.Card
3535import androidx.compose.material3.CardDefaults
3636import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
37+ import androidx.compose.material3.LinearWavyProgressIndicator
3738import androidx.compose.material3.FilledIconButton
3839import androidx.compose.material3.FilledTonalIconButton
3940import androidx.compose.material3.Icon
@@ -59,6 +60,7 @@ import androidx.compose.animation.core.exponentialDecay
5960import androidx.compose.animation.core.spring
6061import androidx.compose.animation.core.tween
6162import androidx.compose.foundation.ExperimentalFoundationApi
63+ import androidx.compose.foundation.basicMarquee
6264import androidx.compose.foundation.gestures.AnchoredDraggableState
6365import androidx.compose.foundation.gestures.DraggableAnchors
6466import androidx.compose.foundation.gestures.Orientation
@@ -101,6 +103,21 @@ fun FloatingMediaPlayer(
101103 val scope = rememberCoroutineScope()
102104 val haptics = LocalHapticFeedback .current
103105
106+ var currentElapsedTimeMs by remember(musicInfo) { mutableStateOf(musicInfo?.elapsedTime ? : 0L ) }
107+
108+ LaunchedEffect (musicInfo?.isPlaying, musicInfo?.elapsedTime) {
109+ if (musicInfo?.isPlaying == true ) {
110+ var lastTime = System .currentTimeMillis()
111+ while (true ) {
112+ kotlinx.coroutines.delay(500 )
113+ val now = System .currentTimeMillis()
114+ val delta = (now - lastTime) * ((musicInfo.playbackRate).toFloat())
115+ currentElapsedTimeMs + = delta.toLong()
116+ lastTime = now
117+ }
118+ }
119+ }
120+
104121 val collapsedHeight = 72 .dp
105122 val expandedHeight = 280 .dp
106123
@@ -199,15 +216,15 @@ fun FloatingMediaPlayer(
199216 style = MaterialTheme .typography.titleMedium,
200217 fontWeight = FontWeight .Bold ,
201218 maxLines = 1 ,
202- overflow = TextOverflow . Ellipsis ,
219+ modifier = Modifier .basicMarquee() ,
203220 color = MaterialTheme .colorScheme.onSurface
204221 )
205222 Text (
206223 text = musicInfo?.artist?.takeIf { it.isNotEmpty() } ? : " from your Mac" ,
207224 style = MaterialTheme .typography.bodySmall,
208225 color = MaterialTheme .colorScheme.onSurfaceVariant,
209226 maxLines = 1 ,
210- overflow = TextOverflow . Ellipsis
227+ modifier = Modifier .basicMarquee(),
211228 )
212229 }
213230
@@ -273,6 +290,44 @@ fun FloatingMediaPlayer(
273290 Spacer (modifier = Modifier .size(48 .dp)) // To balance the chevron
274291 }
275292
293+ if (musicInfo != null && musicInfo.duration > 0 ) {
294+ Column (
295+ modifier = Modifier .fillMaxWidth(),
296+ verticalArrangement = Arrangement .spacedBy(4 .dp)
297+ ) {
298+ val durationSeconds = musicInfo.duration / 1000L
299+ val elapsedSeconds = (currentElapsedTimeMs / 1000L ).coerceIn(0L , durationSeconds)
300+ val elapsedFraction = (currentElapsedTimeMs.toFloat() / musicInfo.duration.toFloat()).coerceIn(0f , 1f )
301+
302+ LinearWavyProgressIndicator (
303+ progress = { elapsedFraction },
304+ modifier = Modifier
305+ .fillMaxWidth()
306+ .height(10 .dp),
307+ color = MaterialTheme .colorScheme.primary,
308+ trackColor = MaterialTheme .colorScheme.primaryContainer,
309+ wavelength = 20 .dp,
310+ amplitude = { if (musicInfo.isPlaying) 1.0f else 0f }
311+ )
312+
313+ Row (
314+ modifier = Modifier .fillMaxWidth(),
315+ horizontalArrangement = Arrangement .SpaceBetween
316+ ) {
317+ Text (
318+ text = formatTime(elapsedSeconds),
319+ style = MaterialTheme .typography.bodySmall,
320+ color = MaterialTheme .colorScheme.onSurfaceVariant
321+ )
322+ Text (
323+ text = formatTime(durationSeconds),
324+ style = MaterialTheme .typography.bodySmall,
325+ color = MaterialTheme .colorScheme.onSurfaceVariant
326+ )
327+ }
328+ }
329+ }
330+
276331 // Media Controls
277332 Row (
278333 modifier = Modifier .fillMaxWidth(),
@@ -350,3 +405,9 @@ fun FloatingMediaPlayer(
350405fun lerp (start : Float , stop : Float , fraction : Float ): Float {
351406 return (1 - fraction) * start + fraction * stop
352407}
408+
409+ private fun formatTime (seconds : Long ): String {
410+ val mins = seconds / 60
411+ val secs = seconds % 60
412+ return " $mins :${if (secs < 10 ) " 0" else " " }$secs "
413+ }
0 commit comments