refactor: simplify player state
This commit is contained in:
@@ -48,6 +48,9 @@ kotlin {
|
|||||||
implementation(libs.vorbisspi)
|
implementation(libs.vorbisspi)
|
||||||
}
|
}
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
|
// Models (exposed through AudioPlayer's public API)
|
||||||
|
// api(projects.core.model)
|
||||||
|
|
||||||
// Coroutines
|
// Coroutines
|
||||||
implementation(libs.kotlinx.coroutinesCore)
|
implementation(libs.kotlinx.coroutinesCore)
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ package fr.ajaury.gwenedeg.core.model
|
|||||||
data class Record(
|
data class Record(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val index: Int,
|
val index: Int,
|
||||||
val title: String,
|
val title: Phrase,
|
||||||
val titleTranslation: String? = null,
|
|
||||||
val audioResourcePath: String,
|
val audioResourcePath: String,
|
||||||
val subtitleResourcePath: String,
|
val subtitleResourcePath: String,
|
||||||
val translationSubtitleResourcePath: String? = null,
|
val translationSubtitleResourcePath: String? = null,
|
||||||
|
|||||||
+32
-14
@@ -1,11 +1,13 @@
|
|||||||
package fr.ajaury.gwenedeg.player.data
|
package fr.ajaury.gwenedeg.player.data
|
||||||
|
|
||||||
import fr.ajaury.gwenedeg.core.logging.domain.Logger
|
import fr.ajaury.gwenedeg.core.logging.domain.Logger
|
||||||
|
import fr.ajaury.gwenedeg.core.model.Phrase
|
||||||
import fr.ajaury.gwenedeg.core.model.Record
|
import fr.ajaury.gwenedeg.core.model.Record
|
||||||
import fr.ajaury.gwenedeg.player.domain.AudioPlayer
|
import fr.ajaury.gwenedeg.player.domain.AudioPlayer
|
||||||
import fr.ajaury.gwenedeg.player.domain.PlaybackRepository
|
import fr.ajaury.gwenedeg.player.domain.PlaybackRepository
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackTiming
|
import fr.ajaury.gwenedeg.player.model.PlaybackTiming
|
||||||
|
import fr.ajaury.gwenedeg.player.model.PlayerState
|
||||||
import fr.ajaury.gwenedeg.resourcereader.data.domain.ResourceReader
|
import fr.ajaury.gwenedeg.resourcereader.data.domain.ResourceReader
|
||||||
import fr.ajaury.gwenedeg.subtitle.domain.GetCurrentSubtitleIndexUseCase
|
import fr.ajaury.gwenedeg.subtitle.domain.GetCurrentSubtitleIndexUseCase
|
||||||
import fr.ajaury.gwenedeg.subtitle.domain.SubtitleRepository
|
import fr.ajaury.gwenedeg.subtitle.domain.SubtitleRepository
|
||||||
@@ -16,7 +18,6 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
@@ -33,15 +34,15 @@ internal class PlaybackRepositoryImpl(
|
|||||||
private val getCurrentSubtitleIndex: GetCurrentSubtitleIndexUseCase,
|
private val getCurrentSubtitleIndex: GetCurrentSubtitleIndexUseCase,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
) : PlaybackRepository {
|
) : PlaybackRepository {
|
||||||
private val subtitleState = MutableStateFlow(Subtitle(emptyList()))
|
private val recordTitle = MutableStateFlow(Phrase(transcription = ""))
|
||||||
override val subtitle: StateFlow<Subtitle> = subtitleState.asStateFlow()
|
private val subtitle = MutableStateFlow(Subtitle(emptyList()))
|
||||||
|
|
||||||
override val playbackState: StateFlow<PlaybackState> = audioPlayer.playbackState
|
private val playbackState: StateFlow<PlaybackState> = audioPlayer.playbackState
|
||||||
|
|
||||||
override val duration: Duration get() = audioPlayer.duration
|
private val duration: Duration get() = audioPlayer.duration
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
override val currentPosition: Flow<Duration> = playbackState.flatMapLatest { state ->
|
private val currentPosition: Flow<Duration> = playbackState.flatMapLatest { state ->
|
||||||
if (state == PlaybackState.PLAYING) {
|
if (state == PlaybackState.PLAYING) {
|
||||||
flow {
|
flow {
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -54,15 +55,15 @@ internal class PlaybackRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val playbackTiming = currentPosition.map { currentPosition ->
|
private val playbackTiming = currentPosition.map { currentPosition ->
|
||||||
PlaybackTiming(
|
PlaybackTiming(
|
||||||
positionMs = currentPosition.inWholeMilliseconds,
|
positionMs = currentPosition.inWholeMilliseconds,
|
||||||
durationMs = duration.inWholeMilliseconds,
|
durationMs = duration.inWholeMilliseconds,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val currentSubtitleIndex: Flow<Int?> = combine(
|
private val currentSubtitleIndex: Flow<Int?> = combine(
|
||||||
subtitleState,
|
subtitle,
|
||||||
currentPosition,
|
currentPosition,
|
||||||
) { subtitle, position ->
|
) { subtitle, position ->
|
||||||
getCurrentSubtitleIndex(
|
getCurrentSubtitleIndex(
|
||||||
@@ -71,9 +72,26 @@ internal class PlaybackRepositoryImpl(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val playerState: Flow<PlayerState> = combine(
|
||||||
|
playbackState,
|
||||||
|
subtitle,
|
||||||
|
playbackTiming,
|
||||||
|
currentSubtitleIndex,
|
||||||
|
recordTitle,
|
||||||
|
) { playbackState, subtitle, playbackTiming, currentSubtitleIndex, recordTitle ->
|
||||||
|
PlayerState(
|
||||||
|
playbackState = playbackState,
|
||||||
|
playbackTiming = playbackTiming,
|
||||||
|
subtitleLines = subtitle.lines,
|
||||||
|
currentSubtitleIndex = currentSubtitleIndex,
|
||||||
|
recordTitle = recordTitle,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun load(record: Record) {
|
override suspend fun load(record: Record) {
|
||||||
playAudio(filePath = record.audioResourcePath)
|
playAudio(filePath = record.audioResourcePath)
|
||||||
subtitleState.value = loadSubtitle(record = record)
|
subtitle.value = loadSubtitle(record = record)
|
||||||
|
recordTitle.value = record.title
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playAudio(filePath: String) {
|
private fun playAudio(filePath: String) {
|
||||||
@@ -120,12 +138,12 @@ internal class PlaybackRepositoryImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun seekToSentence(sentenceIndex: Int) {
|
override fun seekToSentence(sentenceIndex: Int) {
|
||||||
val matchingSubtitleLine = subtitleState.value.lines.getOrNull(sentenceIndex) ?: return
|
val matchingSubtitleLine = subtitle.value.lines.getOrNull(sentenceIndex) ?: return
|
||||||
audioPlayer.seekTo(matchingSubtitleLine.startTime)
|
audioPlayer.seekTo(matchingSubtitleLine.startTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun goToPreviousSentence() {
|
override fun goToPreviousSentence() {
|
||||||
val lines = subtitleState.value.lines
|
val lines = subtitle.value.lines
|
||||||
val currentIndex = currentSentenceIndex() ?: return
|
val currentIndex = currentSentenceIndex() ?: return
|
||||||
val currentLine = lines.getOrNull(currentIndex) ?: return
|
val currentLine = lines.getOrNull(currentIndex) ?: return
|
||||||
val elapsedInSentence = audioPlayer.currentPosition - currentLine.startTime
|
val elapsedInSentence = audioPlayer.currentPosition - currentLine.startTime
|
||||||
@@ -139,14 +157,14 @@ internal class PlaybackRepositoryImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun goToNextSentence() {
|
override fun goToNextSentence() {
|
||||||
val lines = subtitleState.value.lines
|
val lines = subtitle.value.lines
|
||||||
val currentIndex = currentSentenceIndex() ?: return
|
val currentIndex = currentSentenceIndex() ?: return
|
||||||
seekToSentence((currentIndex + 1).coerceAtMost(lines.lastIndex))
|
seekToSentence((currentIndex + 1).coerceAtMost(lines.lastIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentSentenceIndex(): Int? =
|
private fun currentSentenceIndex(): Int? =
|
||||||
getCurrentSubtitleIndex(
|
getCurrentSubtitleIndex(
|
||||||
subtitle = subtitleState.value,
|
subtitle = subtitle.value,
|
||||||
position = audioPlayer.currentPosition,
|
position = audioPlayer.currentPosition,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+2
-11
@@ -3,6 +3,7 @@ package fr.ajaury.gwenedeg.player.domain
|
|||||||
import fr.ajaury.gwenedeg.core.model.Record
|
import fr.ajaury.gwenedeg.core.model.Record
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackTiming
|
import fr.ajaury.gwenedeg.player.model.PlaybackTiming
|
||||||
|
import fr.ajaury.gwenedeg.player.model.PlayerState
|
||||||
import fr.ajaury.gwenedeg.subtitle.model.Subtitle
|
import fr.ajaury.gwenedeg.subtitle.model.Subtitle
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@@ -16,17 +17,7 @@ import kotlin.time.Duration
|
|||||||
* Keeps audio and subtitle in sync.
|
* Keeps audio and subtitle in sync.
|
||||||
*/
|
*/
|
||||||
interface PlaybackRepository {
|
interface PlaybackRepository {
|
||||||
val playbackState: StateFlow<PlaybackState>
|
val playerState: Flow<PlayerState>
|
||||||
|
|
||||||
val subtitle: StateFlow<Subtitle>
|
|
||||||
|
|
||||||
val currentPosition: Flow<Duration>
|
|
||||||
|
|
||||||
val currentSubtitleIndex: Flow<Int?>
|
|
||||||
|
|
||||||
val duration: Duration
|
|
||||||
|
|
||||||
val playbackTiming: Flow<PlaybackTiming>
|
|
||||||
|
|
||||||
suspend fun load(record: Record)
|
suspend fun load(record: Record)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package fr.ajaury.gwenedeg.player.model
|
||||||
|
|
||||||
|
import fr.ajaury.gwenedeg.core.model.Phrase
|
||||||
|
import fr.ajaury.gwenedeg.subtitle.model.SubtitleLine
|
||||||
|
|
||||||
|
data class PlayerState(
|
||||||
|
val recordTitle: Phrase = Phrase(transcription = ""),
|
||||||
|
val playbackState: PlaybackState = PlaybackState.IDLE,
|
||||||
|
val playbackTiming: PlaybackTiming = PlaybackTiming(),
|
||||||
|
val subtitleLines: List<SubtitleLine> = emptyList(),
|
||||||
|
val currentSubtitleIndex: Int? = null,
|
||||||
|
)
|
||||||
@@ -25,6 +25,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import fr.ajaury.gwenedeg.core.model.Phrase
|
import fr.ajaury.gwenedeg.core.model.Phrase
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackTiming
|
import fr.ajaury.gwenedeg.player.model.PlaybackTiming
|
||||||
|
import fr.ajaury.gwenedeg.player.model.PlayerState
|
||||||
import fr.ajaury.gwenedeg.player.ui.viewmodel.PlayerUiState
|
import fr.ajaury.gwenedeg.player.ui.viewmodel.PlayerUiState
|
||||||
import fr.ajaury.gwenedeg.player.ui.viewmodel.PlayerViewModel
|
import fr.ajaury.gwenedeg.player.ui.viewmodel.PlayerViewModel
|
||||||
import fr.ajaury.gwenedeg.subtitle.model.SubtitleLine
|
import fr.ajaury.gwenedeg.subtitle.model.SubtitleLine
|
||||||
@@ -77,12 +78,12 @@ fun PlayerScreen(
|
|||||||
title = {
|
title = {
|
||||||
Column {
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = uiState.recordTitle,
|
text = uiState.recordTitle.transcription,
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
uiState.recordTitleTranslation?.let { translation ->
|
uiState.recordTitle.translation?.let { translation ->
|
||||||
Text(
|
Text(
|
||||||
text = translation,
|
text = translation,
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
@@ -112,8 +113,8 @@ fun PlayerScreen(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
SubtitleList(
|
SubtitleList(
|
||||||
lines = uiState.subtitleLines,
|
lines = uiState.playerState.subtitleLines,
|
||||||
currentIndex = uiState.currentSubtitleIndex,
|
currentIndex = uiState.playerState.currentSubtitleIndex,
|
||||||
onSeek = onSeekToSentence,
|
onSeek = onSeekToSentence,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
@@ -121,8 +122,8 @@ fun PlayerScreen(
|
|||||||
)
|
)
|
||||||
|
|
||||||
PlayerControl(
|
PlayerControl(
|
||||||
playbackState = uiState.playbackState,
|
playbackState = uiState.playerState.playbackState,
|
||||||
playbackTiming = uiState.playbackTiming,
|
playbackTiming = uiState.playerState.playbackTiming,
|
||||||
onSeek = onSeekToTimePart,
|
onSeek = onSeekToTimePart,
|
||||||
onMainPlayActionButtonClicked = onMainPlayActionButtonClicked,
|
onMainPlayActionButtonClicked = onMainPlayActionButtonClicked,
|
||||||
onPreviousSentenceClicked = onPreviousSentenceClicked,
|
onPreviousSentenceClicked = onPreviousSentenceClicked,
|
||||||
@@ -163,13 +164,17 @@ private fun PlayerScreenPlayingPreview() {
|
|||||||
GwenedegTheme {
|
GwenedegTheme {
|
||||||
PlayerScreen(
|
PlayerScreen(
|
||||||
uiState = PlayerUiState(
|
uiState = PlayerUiState(
|
||||||
recordTitle = "Demat",
|
recordTitle = Phrase(
|
||||||
recordTitleTranslation = "Bonjour",
|
transcription = "Demat",
|
||||||
|
translation = "Bonjour",
|
||||||
|
),
|
||||||
|
playerState = PlayerState(
|
||||||
playbackState = PlaybackState.PLAYING,
|
playbackState = PlaybackState.PLAYING,
|
||||||
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
||||||
subtitleLines = previewSubtitleLines,
|
subtitleLines = previewSubtitleLines,
|
||||||
currentSubtitleIndex = 1,
|
currentSubtitleIndex = 1,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
onMainPlayActionButtonClicked = {},
|
onMainPlayActionButtonClicked = {},
|
||||||
onSeekToSentence = {},
|
onSeekToSentence = {},
|
||||||
onBackClicked = {},
|
onBackClicked = {},
|
||||||
@@ -183,13 +188,17 @@ private fun PlayerScreenPausedPreview() {
|
|||||||
GwenedegTheme {
|
GwenedegTheme {
|
||||||
PlayerScreen(
|
PlayerScreen(
|
||||||
uiState = PlayerUiState(
|
uiState = PlayerUiState(
|
||||||
recordTitle = "Demat",
|
recordTitle = Phrase(
|
||||||
recordTitleTranslation = "Bonjour",
|
transcription = "Demat",
|
||||||
|
translation = "Bonjour",
|
||||||
|
),
|
||||||
|
playerState = PlayerState(
|
||||||
playbackState = PlaybackState.PAUSED,
|
playbackState = PlaybackState.PAUSED,
|
||||||
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
||||||
subtitleLines = previewSubtitleLines,
|
subtitleLines = previewSubtitleLines,
|
||||||
currentSubtitleIndex = 1,
|
currentSubtitleIndex = 1,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
onMainPlayActionButtonClicked = {},
|
onMainPlayActionButtonClicked = {},
|
||||||
onSeekToSentence = {},
|
onSeekToSentence = {},
|
||||||
onBackClicked = {},
|
onBackClicked = {},
|
||||||
@@ -203,13 +212,17 @@ private fun PlayerScreenEndedPreview() {
|
|||||||
GwenedegTheme {
|
GwenedegTheme {
|
||||||
PlayerScreen(
|
PlayerScreen(
|
||||||
uiState = PlayerUiState(
|
uiState = PlayerUiState(
|
||||||
recordTitle = "Demat",
|
recordTitle = Phrase(
|
||||||
recordTitleTranslation = "Bonjour",
|
transcription = "Demat",
|
||||||
|
translation = "Bonjour",
|
||||||
|
),
|
||||||
|
playerState = PlayerState(
|
||||||
playbackState = PlaybackState.ENDED,
|
playbackState = PlaybackState.ENDED,
|
||||||
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
||||||
subtitleLines = previewSubtitleLines,
|
subtitleLines = previewSubtitleLines,
|
||||||
currentSubtitleIndex = 2,
|
currentSubtitleIndex = 2,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
onMainPlayActionButtonClicked = {},
|
onMainPlayActionButtonClicked = {},
|
||||||
onSeekToSentence = {},
|
onSeekToSentence = {},
|
||||||
onBackClicked = {},
|
onBackClicked = {},
|
||||||
|
|||||||
+4
-9
@@ -1,14 +1,9 @@
|
|||||||
package fr.ajaury.gwenedeg.player.ui.viewmodel
|
package fr.ajaury.gwenedeg.player.ui.viewmodel
|
||||||
|
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackState
|
import fr.ajaury.gwenedeg.core.model.Phrase
|
||||||
import fr.ajaury.gwenedeg.player.model.PlaybackTiming
|
import fr.ajaury.gwenedeg.player.model.PlayerState
|
||||||
import fr.ajaury.gwenedeg.subtitle.model.SubtitleLine
|
|
||||||
|
|
||||||
data class PlayerUiState(
|
data class PlayerUiState(
|
||||||
val recordTitle: String = "",
|
val recordTitle: Phrase = Phrase(transcription = ""),
|
||||||
val recordTitleTranslation: String? = null,
|
val playerState: PlayerState = PlayerState(),
|
||||||
val playbackState: PlaybackState = PlaybackState.IDLE,
|
|
||||||
val playbackTiming: PlaybackTiming = PlaybackTiming(),
|
|
||||||
val subtitleLines: List<SubtitleLine> = emptyList(),
|
|
||||||
val currentSubtitleIndex: Int? = null,
|
|
||||||
)
|
)
|
||||||
|
|||||||
+8
-14
@@ -3,6 +3,7 @@ package fr.ajaury.gwenedeg.player.ui.viewmodel
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import fr.ajaury.gwenedeg.core.logging.domain.Logger
|
import fr.ajaury.gwenedeg.core.logging.domain.Logger
|
||||||
|
import fr.ajaury.gwenedeg.core.model.Phrase
|
||||||
import fr.ajaury.gwenedeg.core.model.Record
|
import fr.ajaury.gwenedeg.core.model.Record
|
||||||
import fr.ajaury.gwenedeg.player.domain.AudioSessionManager
|
import fr.ajaury.gwenedeg.player.domain.AudioSessionManager
|
||||||
import fr.ajaury.gwenedeg.player.domain.PlaybackRepository
|
import fr.ajaury.gwenedeg.player.domain.PlaybackRepository
|
||||||
@@ -13,7 +14,6 @@ import kotlinx.coroutines.flow.SharingStarted
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.WhileSubscribed
|
import kotlinx.coroutines.flow.WhileSubscribed
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.onStart
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
@@ -30,18 +30,11 @@ class PlayerViewModel(
|
|||||||
|
|
||||||
val uiState: StateFlow<PlayerUiState> = combine(
|
val uiState: StateFlow<PlayerUiState> = combine(
|
||||||
record,
|
record,
|
||||||
playbackRepository.playbackState,
|
playbackRepository.playerState,
|
||||||
playbackRepository.playbackTiming,
|
) { record, playerState ->
|
||||||
playbackRepository.subtitle,
|
|
||||||
playbackRepository.currentSubtitleIndex,
|
|
||||||
) { record, playbackState, playbackTiming, subtitle, currentSubtitleIndex ->
|
|
||||||
PlayerUiState(
|
PlayerUiState(
|
||||||
recordTitle = record?.title.orEmpty(),
|
recordTitle = record?.title ?: Phrase(transcription = ""),
|
||||||
recordTitleTranslation = record?.titleTranslation,
|
playerState = playerState,
|
||||||
playbackState = playbackState,
|
|
||||||
playbackTiming = playbackTiming,
|
|
||||||
subtitleLines = subtitle.lines,
|
|
||||||
currentSubtitleIndex = currentSubtitleIndex,
|
|
||||||
)
|
)
|
||||||
}.stateIn(
|
}.stateIn(
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
@@ -75,7 +68,7 @@ class PlayerViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun performMainPlayAction() {
|
fun performMainPlayAction() {
|
||||||
when (uiState.value.playbackState) {
|
when (uiState.value.playerState.playbackState) {
|
||||||
PlaybackState.PLAYING -> playbackRepository.pause()
|
PlaybackState.PLAYING -> playbackRepository.pause()
|
||||||
PlaybackState.ENDED -> playbackRepository.replay()
|
PlaybackState.ENDED -> playbackRepository.replay()
|
||||||
PlaybackState.PAUSED, PlaybackState.IDLE -> playbackRepository.play()
|
PlaybackState.PAUSED, PlaybackState.IDLE -> playbackRepository.play()
|
||||||
@@ -83,7 +76,8 @@ class PlayerViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun seekToTimePart(progress: Float) {
|
fun seekToTimePart(progress: Float) {
|
||||||
val position = (progress.toDouble() * uiState.value.playbackTiming.durationMs).milliseconds
|
val playbackTiming = uiState.value.playerState.playbackTiming
|
||||||
|
val position = (progress.toDouble() * playbackTiming.durationMs).milliseconds
|
||||||
playbackRepository.seekTo(position)
|
playbackRepository.seekTo(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user