refactor: use SSoT for playback speed
This commit is contained in:
@@ -11,10 +11,12 @@ kotlin {
|
|||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
// Core modules
|
// Core modules
|
||||||
implementation(projects.core.audioplayer)
|
implementation(projects.core.audioplayer)
|
||||||
|
implementation(projects.core.coroutines)
|
||||||
implementation(projects.core.logging)
|
implementation(projects.core.logging)
|
||||||
implementation(projects.core.model)
|
implementation(projects.core.model)
|
||||||
|
|
||||||
// Data modules
|
// Data modules
|
||||||
|
implementation(projects.data.preferences)
|
||||||
implementation(projects.data.records)
|
implementation(projects.data.records)
|
||||||
implementation(projects.data.resources)
|
implementation(projects.data.resources)
|
||||||
implementation(projects.data.subtitle)
|
implementation(projects.data.subtitle)
|
||||||
|
|||||||
+24
-1
@@ -1,5 +1,6 @@
|
|||||||
package fr.ajaury.gwenedeg.player.data
|
package fr.ajaury.gwenedeg.player.data
|
||||||
|
|
||||||
|
import fr.ajaury.gwenedeg.core.coroutines.domain.DispatcherProvider
|
||||||
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.Phrase
|
||||||
import fr.ajaury.gwenedeg.player.domain.AudioPlayer
|
import fr.ajaury.gwenedeg.player.domain.AudioPlayer
|
||||||
@@ -7,12 +8,16 @@ 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.player.model.PlayerState
|
||||||
|
import fr.ajaury.gwenedeg.preferences.domain.PreferencesRepository
|
||||||
import fr.ajaury.gwenedeg.records.model.Record
|
import fr.ajaury.gwenedeg.records.model.Record
|
||||||
import fr.ajaury.gwenedeg.resources.domain.ResourceReader
|
import fr.ajaury.gwenedeg.resources.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
|
||||||
import fr.ajaury.gwenedeg.subtitle.model.Subtitle
|
import fr.ajaury.gwenedeg.subtitle.model.Subtitle
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -22,6 +27,7 @@ import kotlinx.coroutines.flow.flatMapLatest
|
|||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
@@ -30,9 +36,15 @@ internal class PlaybackRepositoryImpl(
|
|||||||
private val audioPlayer: AudioPlayer,
|
private val audioPlayer: AudioPlayer,
|
||||||
private val resourceReader: ResourceReader,
|
private val resourceReader: ResourceReader,
|
||||||
private val subtitleRepository: SubtitleRepository,
|
private val subtitleRepository: SubtitleRepository,
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val getCurrentSubtitleIndex: GetCurrentSubtitleIndexUseCase,
|
private val getCurrentSubtitleIndex: GetCurrentSubtitleIndexUseCase,
|
||||||
|
private val dispatcherProvider: DispatcherProvider,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
) : PlaybackRepository {
|
) : PlaybackRepository {
|
||||||
|
// Audio operations must run on the main thread (e.g. ExoPlayer), so keep the scope on it.
|
||||||
|
private val scope = CoroutineScope(SupervisorJob() + dispatcherProvider.main)
|
||||||
|
private var speedObservationJob: Job? = null
|
||||||
|
|
||||||
private val recordTitle = MutableStateFlow(Phrase(transcription = ""))
|
private val recordTitle = MutableStateFlow(Phrase(transcription = ""))
|
||||||
private val subtitle = MutableStateFlow(Subtitle(emptyList()))
|
private val subtitle = MutableStateFlow(Subtitle(emptyList()))
|
||||||
|
|
||||||
@@ -91,6 +103,17 @@ internal class PlaybackRepositoryImpl(
|
|||||||
playAudio(filePath = record.audioResourcePath)
|
playAudio(filePath = record.audioResourcePath)
|
||||||
subtitle.value = loadSubtitle(record = record)
|
subtitle.value = loadSubtitle(record = record)
|
||||||
recordTitle.value = record.title
|
recordTitle.value = record.title
|
||||||
|
|
||||||
|
observePlaybackSpeed()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observePlaybackSpeed() {
|
||||||
|
speedObservationJob?.cancel()
|
||||||
|
speedObservationJob = scope.launch {
|
||||||
|
preferencesRepository.playbackPreferences.collect { playbackPreferences ->
|
||||||
|
setSpeed(speed = playbackPreferences.speed)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playAudio(filePath: String) {
|
private fun playAudio(filePath: String) {
|
||||||
@@ -136,7 +159,7 @@ internal class PlaybackRepositoryImpl(
|
|||||||
audioPlayer.seekTo(position)
|
audioPlayer.seekTo(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSpeed(speed: Float) {
|
private fun setSpeed(speed: Float) {
|
||||||
audioPlayer.setSpeed(speed)
|
audioPlayer.setSpeed(speed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-2
@@ -25,8 +25,6 @@ interface PlaybackRepository {
|
|||||||
|
|
||||||
fun seekTo(position: Duration)
|
fun seekTo(position: Duration)
|
||||||
|
|
||||||
fun setSpeed(speed: Float)
|
|
||||||
|
|
||||||
fun seekToSentence(sentenceIndex: Int)
|
fun seekToSentence(sentenceIndex: Int)
|
||||||
|
|
||||||
fun goToPreviousSentence()
|
fun goToPreviousSentence()
|
||||||
|
|||||||
+1
-8
@@ -62,7 +62,6 @@ class PlayerViewModel(
|
|||||||
if (alreadyLoadedRecord != null) {
|
if (alreadyLoadedRecord != null) {
|
||||||
logger.debug("Record $recordId already loaded")
|
logger.debug("Record $recordId already loaded")
|
||||||
playbackRepository.load(record = alreadyLoadedRecord)
|
playbackRepository.load(record = alreadyLoadedRecord)
|
||||||
applyCurrentSpeed()
|
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,16 +72,10 @@ class PlayerViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
playbackRepository.load(record = loadedRecord)
|
playbackRepository.load(record = loadedRecord)
|
||||||
applyCurrentSpeed()
|
|
||||||
record.value = loadedRecord
|
record.value = loadedRecord
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun applyCurrentSpeed() {
|
|
||||||
val playbackPreferences = preferencesRepository.playbackPreferences.firstOrNull() ?: return
|
|
||||||
playbackRepository.setSpeed(playbackPreferences.speed)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun performMainPlayAction() {
|
fun performMainPlayAction() {
|
||||||
when (uiState.value.playerState.playbackState) {
|
when (uiState.value.playerState.playbackState) {
|
||||||
PlaybackState.PLAYING -> playbackRepository.pause()
|
PlaybackState.PLAYING -> playbackRepository.pause()
|
||||||
@@ -113,9 +106,9 @@ class PlayerViewModel(
|
|||||||
PlaybackPreferences.MIN_SPEED,
|
PlaybackPreferences.MIN_SPEED,
|
||||||
PlaybackPreferences.MAX_SPEED,
|
PlaybackPreferences.MAX_SPEED,
|
||||||
)
|
)
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
preferencesRepository.setPlaybackSpeed(clampedSpeed)
|
preferencesRepository.setPlaybackSpeed(clampedSpeed)
|
||||||
playbackRepository.setSpeed(clampedSpeed)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user