mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-23 19:26:50 +00:00
refactor(core): separate data loading from repository reads
Move implicit loading side effects out of getX methods into explicit loadX methods, making data flow predictable. Remove seriesTitle StateFlow in favor of direct seriesName access. Add proper error handling to repository load operations.
This commit is contained in:
@@ -67,6 +67,27 @@ class CompositeLocalMediaRepository @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadMovie(id: UUID) {
|
||||
runOnlineOrOfflineNoOp(
|
||||
onlineAction = { onlineRepository.loadMovie(id) },
|
||||
offlineAction = { offlineRepository.loadMovie(id) },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadSeries(id: UUID) {
|
||||
runOnlineOrOfflineNoOp(
|
||||
onlineAction = { onlineRepository.loadSeries(id) },
|
||||
offlineAction = { offlineRepository.loadSeries(id) },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadEpisode(id: UUID) {
|
||||
runOnlineOrOfflineNoOp(
|
||||
onlineAction = { onlineRepository.loadEpisode(id) },
|
||||
offlineAction = { offlineRepository.loadEpisode(id) },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadSeasons(seriesId: UUID) {
|
||||
runOnlineOrOfflineNoOp(
|
||||
onlineAction = { onlineRepository.loadSeasons(seriesId) },
|
||||
|
||||
@@ -14,6 +14,9 @@ interface LocalMediaRepository : MediaMetadataUpdater {
|
||||
suspend fun getMovie(id: UUID): Flow<Movie?>
|
||||
suspend fun getSeries(id: UUID): Flow<Series?>
|
||||
suspend fun getEpisode(id: UUID): Flow<Episode?>
|
||||
suspend fun loadMovie(id: UUID)
|
||||
suspend fun loadSeries(id: UUID)
|
||||
suspend fun loadEpisode(id: UUID)
|
||||
suspend fun loadSeasons(seriesId: UUID)
|
||||
suspend fun loadSeasonEpisodes(seriesId: UUID, seasonId: UUID)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
@@ -47,17 +46,6 @@ class EpisodeScreenViewModel @Inject constructor(
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val seriesTitle: StateFlow<String?> = _episode
|
||||
.flatMapLatest { episode ->
|
||||
if (episode == null) {
|
||||
flowOf(null)
|
||||
} else {
|
||||
mediaCatalogReader(episode.offline).getSeries(episode.seriesId).map { it?.name }
|
||||
}
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
|
||||
|
||||
private val _downloadState = MutableStateFlow<DownloadState>(DownloadState.NotDownloaded)
|
||||
val downloadState: StateFlow<DownloadState> = _downloadState.asStateFlow()
|
||||
|
||||
@@ -76,6 +64,9 @@ class EpisodeScreenViewModel @Inject constructor(
|
||||
|
||||
fun selectEpisode(episode: EpisodeDto) {
|
||||
_episode.value = episode
|
||||
viewModelScope.launch {
|
||||
mediaCatalogReader(episode.offline).loadEpisode(episode.id)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
mediaDownloadManager.observeDownloadState(episode.id.toString()).collect {
|
||||
_downloadState.value = it
|
||||
|
||||
@@ -63,6 +63,9 @@ class MovieScreenViewModel @Inject constructor(
|
||||
|
||||
fun selectMovie(movie: MovieDto) {
|
||||
_movie.value = movie
|
||||
viewModelScope.launch {
|
||||
mediaCatalogReader(movie.offline).loadMovie(movie.id)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
mediaDownloadManager.observeDownloadState(movie.id.toString()).collect {
|
||||
_downloadState.value = it
|
||||
|
||||
@@ -195,7 +195,9 @@ class SeriesViewModel @Inject constructor(
|
||||
fun selectSeries(series: SeriesDto) {
|
||||
_series.value = series
|
||||
viewModelScope.launch {
|
||||
mediaCatalogReader(series.offline).loadSeasons(series.id)
|
||||
val mediaCatalogReader = mediaCatalogReader(series.offline)
|
||||
mediaCatalogReader.loadSeries(series.id)
|
||||
mediaCatalogReader.loadSeasons(series.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,8 +169,7 @@ class PlayerViewModel @Inject constructor(
|
||||
_uiState.update { it.copy(error = dataErrorMessage) }
|
||||
return
|
||||
}
|
||||
//TODO hack to preload the series media
|
||||
mediaCatalogReader.getEpisode(UUID.fromString(id))
|
||||
mediaCatalogReader.loadEpisode(UUID.fromString(id))
|
||||
viewModelScope.launch {
|
||||
runCatching {
|
||||
playerManager.play(uuid)
|
||||
@@ -243,6 +242,7 @@ class PlayerViewModel @Inject constructor(
|
||||
private suspend fun PlayableMedia.toPlaylistElementUiModel(currentMediaId: UUID?): PlaylistElementUiModel? {
|
||||
return when (this) {
|
||||
is PlayableMedia.Movie -> {
|
||||
mediaCatalogReader.loadMovie(id)
|
||||
val movie = mediaCatalogReader.getMovie(id).first()
|
||||
if (movie == null) {
|
||||
Timber.tag(TAG).e("Movie not found for playlist item: $id")
|
||||
@@ -261,6 +261,7 @@ class PlayerViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is PlayableMedia.Series -> {
|
||||
mediaCatalogReader.loadSeries(id)
|
||||
val series = mediaCatalogReader.getSeries(id).first()
|
||||
if (series == null) {
|
||||
Timber.tag(TAG).e("Series not found for playlist item: $id")
|
||||
@@ -279,6 +280,7 @@ class PlayerViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is PlayableMedia.Episode -> {
|
||||
mediaCatalogReader.loadEpisode(id)
|
||||
val episode = mediaCatalogReader.getEpisode(id).first()
|
||||
if (episode == null) {
|
||||
Timber.tag(TAG).e("Episode not found for playlist item: $id")
|
||||
|
||||
Reference in New Issue
Block a user