package com.suno.android.common_ui.extensions import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.media3.common.MediaItem import androidx.media3.common.Player import androidx.media3.common.Timeline import kotlinx.coroutines.android.awaitFrame import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds @Composable fun Player.collectCurrentPositionAsState( pollRate: Duration? = null, // if null, poll every frame ): State { val currentPositionState = remember(this) { mutableStateOf(Duration.ZERO) } LaunchedEffect(pollRate) { while (isActive) { currentPositionState.value = currentPosition.milliseconds if (pollRate != null) { delay(pollRate) } else { awaitFrame() } } } return currentPositionState } @Composable fun Player.collectDurationAsState(): State { val durationState = remember(this) { mutableStateOf( this.duration.takeIf { it >= 0 }?.milliseconds ?: Duration.ZERO, ) } DisposableEffect(this) { val listener = object : Player.Listener { override fun onTimelineChanged( timeline: Timeline, reason: Int, ) { super.onTimelineChanged(timeline, reason) durationState.value = duration.milliseconds } } addListener(listener) onDispose { removeListener(listener) } } return durationState } @Composable fun Player.collectIsCurrentMediaItemSeekableAsState(): State { val canSeekState = remember(this) { mutableStateOf(this.isCurrentMediaItemSeekable) } DisposableEffect(this) { val listener = object : Player.Listener { override fun onPlaybackStateChanged( playbackState: Int, ) { super.onPlaybackStateChanged(playbackState) canSeekState.value = isCurrentMediaItemSeekable } override fun onMediaItemTransition( mediaItem: MediaItem?, reason: Int, ) { super.onMediaItemTransition(mediaItem, reason) canSeekState.value = isCurrentMediaItemSeekable } } addListener(listener) onDispose { removeListener(listener) } } return canSeekState }