new: add support for record title translations
This commit is contained in:
@@ -72,12 +72,23 @@ fun PlayerScreen(
|
|||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Column {
|
||||||
text = uiState.recordTitle,
|
Text(
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
text = uiState.recordTitle,
|
||||||
maxLines = 1,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
overflow = TextOverflow.Ellipsis,
|
maxLines = 1,
|
||||||
)
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
uiState.recordTitleTranslation?.let { translation ->
|
||||||
|
Text(
|
||||||
|
text = translation,
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackClicked) {
|
IconButton(onClick = onBackClicked) {
|
||||||
@@ -132,6 +143,7 @@ private fun PlayerScreenPlayingPreview() {
|
|||||||
PlayerScreen(
|
PlayerScreen(
|
||||||
uiState = PlayerUiState(
|
uiState = PlayerUiState(
|
||||||
recordTitle = "Demat",
|
recordTitle = "Demat",
|
||||||
|
recordTitleTranslation = "Bonjour",
|
||||||
playbackState = PlaybackState.PLAYING,
|
playbackState = PlaybackState.PLAYING,
|
||||||
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
||||||
subtitleLines = previewSubtitleLines,
|
subtitleLines = previewSubtitleLines,
|
||||||
@@ -151,6 +163,7 @@ private fun PlayerScreenPausedPreview() {
|
|||||||
PlayerScreen(
|
PlayerScreen(
|
||||||
uiState = PlayerUiState(
|
uiState = PlayerUiState(
|
||||||
recordTitle = "Demat",
|
recordTitle = "Demat",
|
||||||
|
recordTitleTranslation = "Bonjour",
|
||||||
playbackState = PlaybackState.PAUSED,
|
playbackState = PlaybackState.PAUSED,
|
||||||
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
||||||
subtitleLines = previewSubtitleLines,
|
subtitleLines = previewSubtitleLines,
|
||||||
@@ -170,6 +183,7 @@ private fun PlayerScreenEndedPreview() {
|
|||||||
PlayerScreen(
|
PlayerScreen(
|
||||||
uiState = PlayerUiState(
|
uiState = PlayerUiState(
|
||||||
recordTitle = "Demat",
|
recordTitle = "Demat",
|
||||||
|
recordTitleTranslation = "Bonjour",
|
||||||
playbackState = PlaybackState.ENDED,
|
playbackState = PlaybackState.ENDED,
|
||||||
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
playbackTiming = PlaybackTiming(positionMs = 1234, durationMs = 5000),
|
||||||
subtitleLines = previewSubtitleLines,
|
subtitleLines = previewSubtitleLines,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import fr.ajaury.gwenedeg.subtitle.domain.SubtitleLine
|
|||||||
|
|
||||||
data class PlayerUiState(
|
data class PlayerUiState(
|
||||||
val recordTitle: String = "",
|
val recordTitle: String = "",
|
||||||
|
val recordTitleTranslation: String? = null,
|
||||||
val playbackState: PlaybackState = PlaybackState.IDLE,
|
val playbackState: PlaybackState = PlaybackState.IDLE,
|
||||||
val playbackTiming: PlaybackTiming = PlaybackTiming(),
|
val playbackTiming: PlaybackTiming = PlaybackTiming(),
|
||||||
val subtitleLines: List<SubtitleLine> = emptyList(),
|
val subtitleLines: List<SubtitleLine> = emptyList(),
|
||||||
|
|||||||
+11
-11
@@ -6,7 +6,7 @@ import fr.ajaury.gwenedeg.core.logging.domain.Logger
|
|||||||
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
|
||||||
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.records.domain.Record
|
||||||
import fr.ajaury.gwenedeg.records.domain.RecordRepository
|
import fr.ajaury.gwenedeg.records.domain.RecordRepository
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
@@ -26,26 +26,26 @@ class PlayerViewModel(
|
|||||||
private val audioSessionManager: AudioSessionManager,
|
private val audioSessionManager: AudioSessionManager,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val recordTitle = MutableStateFlow("")
|
private val record = MutableStateFlow<Record?>(null)
|
||||||
|
|
||||||
private var recordLoaded = false
|
private var recordLoaded = false
|
||||||
|
|
||||||
val uiState: StateFlow<PlayerUiState> = combine(
|
val uiState: StateFlow<PlayerUiState> = combine(
|
||||||
recordTitle,
|
record,
|
||||||
playbackRepository.playbackState,
|
playbackRepository.playbackState,
|
||||||
playbackRepository.playbackTiming,
|
playbackRepository.playbackTiming,
|
||||||
playbackRepository.subtitle,
|
playbackRepository.subtitle,
|
||||||
playbackRepository.currentSubtitleIndex,
|
playbackRepository.currentSubtitleIndex,
|
||||||
) { recordTitle, playbackState, playbackTiming, subtitle, currentSubtitleIndex ->
|
) { record, playbackState, playbackTiming, subtitle, currentSubtitleIndex ->
|
||||||
PlayerUiState(
|
PlayerUiState(
|
||||||
recordTitle = recordTitle,
|
recordTitle = record?.title.orEmpty(),
|
||||||
|
recordTitleTranslation = record?.titleTranslation,
|
||||||
playbackState = playbackState,
|
playbackState = playbackState,
|
||||||
playbackTiming = playbackTiming,
|
playbackTiming = playbackTiming,
|
||||||
subtitleLines = subtitle.lines,
|
subtitleLines = subtitle.lines,
|
||||||
currentSubtitleIndex = currentSubtitleIndex,
|
currentSubtitleIndex = currentSubtitleIndex,
|
||||||
)
|
)
|
||||||
}
|
}.onStart { loadRecord() }
|
||||||
.onStart { loadRecord() }
|
|
||||||
.stateIn(
|
.stateIn(
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
started = SharingStarted.WhileSubscribed(5.seconds),
|
started = SharingStarted.WhileSubscribed(5.seconds),
|
||||||
@@ -65,14 +65,14 @@ class PlayerViewModel(
|
|||||||
recordLoaded = true
|
recordLoaded = true
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val record = recordRepository.getRecord(id = recordId)
|
val loadedRecord = recordRepository.getRecord(id = recordId)
|
||||||
if (record == null) {
|
if (loadedRecord == null) {
|
||||||
logger.error(message = "Record not found: $recordId")
|
logger.error(message = "Record not found: $recordId")
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
recordTitle.value = record.title
|
record.value = loadedRecord
|
||||||
playbackRepository.load(record = record)
|
playbackRepository.load(record = loadedRecord)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ data class Record(
|
|||||||
val id: Int,
|
val id: Int,
|
||||||
val index: Int,
|
val index: Int,
|
||||||
val title: String,
|
val title: String,
|
||||||
|
val titleTranslation: String? = null,
|
||||||
val audioResourcePath: String,
|
val audioResourcePath: String,
|
||||||
val subtitleResourcePath: String,
|
val subtitleResourcePath: String,
|
||||||
val translationSubtitleResourcePath: String? = null,
|
val translationSubtitleResourcePath: String? = null,
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package fr.ajaury.gwenedeg.records.ui
|
|||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -32,7 +34,16 @@ fun RecordView(
|
|||||||
text = record.index.toString().padStart(2),
|
text = record.index.toString().padStart(2),
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
)
|
)
|
||||||
Text(text = record.title)
|
Column {
|
||||||
|
Text(text = record.title)
|
||||||
|
record.titleTranslation?.let { translation ->
|
||||||
|
Text(
|
||||||
|
text = translation,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +56,7 @@ private fun RecordViewPreview() {
|
|||||||
id = 1,
|
id = 1,
|
||||||
index = 1,
|
index = 1,
|
||||||
title = "Sample Record",
|
title = "Sample Record",
|
||||||
|
titleTranslation = "Exemple d'enregistrement",
|
||||||
audioResourcePath = "files/Chom_bev_01.ogg",
|
audioResourcePath = "files/Chom_bev_01.ogg",
|
||||||
subtitleResourcePath = "files/Chom_bev_01_st_bzh.lrc",
|
subtitleResourcePath = "files/Chom_bev_01_st_bzh.lrc",
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user