Skip to content

Commit 2c64c99

Browse files
committed
feat: media progress bar
1 parent 95beca5 commit 2c64c99

1 file changed

Lines changed: 63 additions & 2 deletions

File tree

app/src/main/java/com/sameerasw/airsync/presentation/ui/components/FloatingMediaPlayer.kt

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.compose.material3.ButtonGroup
3434
import androidx.compose.material3.Card
3535
import androidx.compose.material3.CardDefaults
3636
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
37+
import androidx.compose.material3.LinearWavyProgressIndicator
3738
import androidx.compose.material3.FilledIconButton
3839
import androidx.compose.material3.FilledTonalIconButton
3940
import androidx.compose.material3.Icon
@@ -59,6 +60,7 @@ import androidx.compose.animation.core.exponentialDecay
5960
import androidx.compose.animation.core.spring
6061
import androidx.compose.animation.core.tween
6162
import androidx.compose.foundation.ExperimentalFoundationApi
63+
import androidx.compose.foundation.basicMarquee
6264
import androidx.compose.foundation.gestures.AnchoredDraggableState
6365
import androidx.compose.foundation.gestures.DraggableAnchors
6466
import 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(
350405
fun 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

Comments
 (0)