new: display current playback position and implement cross-platform position tracking
This commit is contained in:
@@ -97,6 +97,11 @@ fun PlayerScreen(
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "${uiState.positionMs} ms",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
|
||||
Button(
|
||||
modifier = Modifier.size(60.dp),
|
||||
contentPadding = PaddingValues(0.dp),
|
||||
@@ -132,7 +137,7 @@ private fun PlayerScreenPlayingPreview() {
|
||||
GwenedegTheme {
|
||||
PlayerScreen(
|
||||
recordTitle = "Demat",
|
||||
uiState = PlayerUiState(playbackState = PlaybackState.PLAYING),
|
||||
uiState = PlayerUiState(playbackState = PlaybackState.PLAYING, positionMs = 1234),
|
||||
onMainPlayActionButtonClicked = {},
|
||||
onBackClicked = {},
|
||||
)
|
||||
@@ -145,7 +150,7 @@ private fun PlayerScreenPausedPreview() {
|
||||
GwenedegTheme {
|
||||
PlayerScreen(
|
||||
recordTitle = "Demat",
|
||||
uiState = PlayerUiState(playbackState = PlaybackState.PAUSED),
|
||||
uiState = PlayerUiState(playbackState = PlaybackState.PAUSED, positionMs = 1234),
|
||||
onMainPlayActionButtonClicked = {},
|
||||
onBackClicked = {},
|
||||
)
|
||||
@@ -158,7 +163,7 @@ private fun PlayerScreenEndedPreview() {
|
||||
GwenedegTheme {
|
||||
PlayerScreen(
|
||||
recordTitle = "Demat",
|
||||
uiState = PlayerUiState(playbackState = PlaybackState.ENDED),
|
||||
uiState = PlayerUiState(playbackState = PlaybackState.ENDED, positionMs = 1234),
|
||||
onMainPlayActionButtonClicked = {},
|
||||
onBackClicked = {},
|
||||
)
|
||||
|
||||
@@ -4,4 +4,5 @@ import fr.ajaury.gwenedeg.player.PlaybackState
|
||||
|
||||
data class PlayerUiState(
|
||||
val playbackState: PlaybackState = PlaybackState.IDLE,
|
||||
val positionMs: Long = 0L,
|
||||
)
|
||||
|
||||
+40
-7
@@ -7,11 +7,17 @@ import fr.ajaury.gwenedeg.player.AudioPlayer
|
||||
import fr.ajaury.gwenedeg.player.AudioSessionManager
|
||||
import fr.ajaury.gwenedeg.player.PlaybackState
|
||||
import gwenedeg.shared.generated.resources.Res
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class PlayerViewModel(
|
||||
@@ -21,13 +27,36 @@ class PlayerViewModel(
|
||||
) : ViewModel() {
|
||||
private var filePath: String? = null
|
||||
|
||||
val uiState: StateFlow<PlayerUiState> = audioPlayer.playbackState
|
||||
.map { PlayerUiState(playbackState = it) }
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5.seconds),
|
||||
initialValue = PlayerUiState(),
|
||||
private val playbackState = audioPlayer.playbackState
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private val currentPosition = playbackState
|
||||
.flatMapLatest { state ->
|
||||
if (state == PlaybackState.PLAYING) {
|
||||
flow {
|
||||
while (true) {
|
||||
emit(audioPlayer.currentPosition())
|
||||
delay(POSITION_POLL_INTERVAL)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flowOf(audioPlayer.currentPosition())
|
||||
}
|
||||
}
|
||||
|
||||
val uiState: StateFlow<PlayerUiState> = combine(
|
||||
playbackState,
|
||||
currentPosition,
|
||||
) { playbackState, currentPositionMs ->
|
||||
PlayerUiState(
|
||||
playbackState = playbackState,
|
||||
positionMs = currentPositionMs.inWholeMilliseconds,
|
||||
)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5.seconds),
|
||||
initialValue = PlayerUiState(),
|
||||
)
|
||||
|
||||
init {
|
||||
audioSessionManager.activate()
|
||||
@@ -60,4 +89,8 @@ class PlayerViewModel(
|
||||
audioSessionManager.deactivate()
|
||||
audioPlayer.release()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val POSITION_POLL_INTERVAL = 200.milliseconds
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user