refactor: moved CompositeMediaRepository to the domain level + changes in connected classes

This commit is contained in:
2026-04-24 09:04:51 +02:00
parent 8423e63937
commit a9bd23e26c
7 changed files with 40 additions and 55 deletions

View File

@@ -1,7 +0,0 @@
package hu.bbara.purefin.data
import java.util.UUID
interface EpisodeSeriesLookup {
suspend fun preferenceKeyFor(mediaId: UUID): String
}

View File

@@ -3,10 +3,11 @@ package hu.bbara.purefin.data
import hu.bbara.purefin.model.Episode import hu.bbara.purefin.model.Episode
import hu.bbara.purefin.model.Movie import hu.bbara.purefin.model.Movie
import hu.bbara.purefin.model.Series import hu.bbara.purefin.model.Series
import java.util.UUID
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import java.util.UUID
//TODO rename MediaRepository
interface MediaCatalogReader { interface MediaCatalogReader {
val movies: StateFlow<Map<UUID, Movie>> val movies: StateFlow<Map<UUID, Movie>>
val series: StateFlow<Map<UUID, Series>> val series: StateFlow<Map<UUID, Series>>

View File

@@ -1,16 +0,0 @@
package hu.bbara.purefin.data.catalog
import hu.bbara.purefin.data.EpisodeSeriesLookup
import hu.bbara.purefin.data.MediaCatalogReader
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class DefaultEpisodeSeriesLookup @Inject constructor(
private val mediaCatalogReader: MediaCatalogReader,
) : EpisodeSeriesLookup {
override suspend fun preferenceKeyFor(mediaId: UUID): String {
return mediaCatalogReader.episodes.value[mediaId]?.seriesId?.toString() ?: mediaId.toString()
}
}

View File

@@ -0,0 +1,16 @@
package hu.bbara.purefin.data.module
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import hu.bbara.purefin.data.OfflineCatalogReader
import hu.bbara.purefin.data.catalog.OfflineMediaRepository
@Module
@InstallIn(SingletonComponent::class)
abstract class MediaRepositoryModule {
@Binds
abstract fun bindOfflineCatalogReader(impl: OfflineMediaRepository): OfflineCatalogReader
}

View File

@@ -4,14 +4,13 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import hu.bbara.purefin.data.EpisodeSeriesLookup
import hu.bbara.purefin.data.PlayableMediaRepository
import hu.bbara.purefin.core.player.manager.PlayerManager import hu.bbara.purefin.core.player.manager.PlayerManager
import hu.bbara.purefin.core.player.manager.ProgressManager import hu.bbara.purefin.core.player.manager.ProgressManager
import hu.bbara.purefin.core.player.model.MediaContext import hu.bbara.purefin.core.player.model.MediaContext
import hu.bbara.purefin.core.player.model.PlayerUiState import hu.bbara.purefin.core.player.model.PlayerUiState
import hu.bbara.purefin.core.player.model.TrackOption import hu.bbara.purefin.core.player.model.TrackOption
import hu.bbara.purefin.core.player.preference.TrackPreferencesRepository import hu.bbara.purefin.core.player.preference.TrackPreferencesRepository
import hu.bbara.purefin.data.PlayableMediaRepository
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -30,7 +29,6 @@ class PlayerViewModel @Inject constructor(
private val playerManager: PlayerManager, private val playerManager: PlayerManager,
private val playableMediaRepository: PlayableMediaRepository, private val playableMediaRepository: PlayableMediaRepository,
private val trackPreferencesRepository: TrackPreferencesRepository, private val trackPreferencesRepository: TrackPreferencesRepository,
private val episodeSeriesLookup: EpisodeSeriesLookup,
private val progressManager: ProgressManager, private val progressManager: ProgressManager,
) : ViewModel() { ) : ViewModel() {
companion object { companion object {
@@ -156,7 +154,10 @@ class PlayerViewModel @Inject constructor(
if (result != null) { if (result != null) {
val (mediaItem, resumePositionMs) = result val (mediaItem, resumePositionMs) = result
val preferenceKey = episodeSeriesLookup.preferenceKeyFor(uuid)
// TODO use CatalogReader for this instead of episodeSeriesLookup
// val preferenceKey = episodeSeriesLookup.preferenceKeyFor(uuid)
val preferenceKey = uuid.toString()
val preferences = trackPreferencesRepository.getMediaPreferences(preferenceKey).first() val preferences = trackPreferencesRepository.getMediaPreferences(preferenceKey).first()
val mediaSegments = playableMediaRepository.getMediaSegments(uuid) val mediaSegments = playableMediaRepository.getMediaSegments(uuid)

View File

@@ -1,8 +1,7 @@
package hu.bbara.purefin.data.catalog package hu.bbara.purefin.data
import hu.bbara.purefin.data.MediaCatalogReader import hu.bbara.purefin.data.catalog.InMemoryMediaRepository
import hu.bbara.purefin.data.MediaProgressWriter import hu.bbara.purefin.data.catalog.OfflineMediaRepository
import hu.bbara.purefin.data.NetworkMonitor
import hu.bbara.purefin.model.Episode import hu.bbara.purefin.model.Episode
import hu.bbara.purefin.model.Movie import hu.bbara.purefin.model.Movie
import hu.bbara.purefin.model.Series import hu.bbara.purefin.model.Series
@@ -13,7 +12,6 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
@@ -26,34 +24,31 @@ import javax.inject.Singleton
class CompositeMediaRepository @Inject constructor( class CompositeMediaRepository @Inject constructor(
private val offlineRepository: OfflineMediaRepository, private val offlineRepository: OfflineMediaRepository,
private val onlineRepository: InMemoryMediaRepository, private val onlineRepository: InMemoryMediaRepository,
private val networkMonitor: NetworkMonitor,
) : MediaCatalogReader, MediaProgressWriter { ) : MediaCatalogReader, MediaProgressWriter {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val activeRepository: Flow<MediaCatalogReader> = // TODO move this into the domain layer and there you can use NetworkMonitor. Data should be free of android stuff.
networkMonitor.isOnline.flatMapLatest { online -> private val activeRepository: Flow<MediaCatalogReader> = flowOf(onlineRepository)
flowOf(if (online) onlineRepository else offlineRepository)
}
override val movies: StateFlow<Map<UUID, Movie>> = activeRepository override val movies: StateFlow<Map<UUID, Movie>> = activeRepository
.flatMapLatest { it.movies } .flatMapLatest { it.movies }
.stateIn(scope, SharingStarted.Eagerly, emptyMap()) .stateIn(scope, SharingStarted.Companion.Eagerly, emptyMap())
override val series: StateFlow<Map<UUID, Series>> = activeRepository override val series: StateFlow<Map<UUID, Series>> = activeRepository
.flatMapLatest { it.series } .flatMapLatest { it.series }
.stateIn(scope, SharingStarted.Eagerly, emptyMap()) .stateIn(scope, SharingStarted.Companion.Eagerly, emptyMap())
override val episodes: StateFlow<Map<UUID, Episode>> = activeRepository override val episodes: StateFlow<Map<UUID, Episode>> = activeRepository
.flatMapLatest { it.episodes } .flatMapLatest { it.episodes }
.stateIn(scope, SharingStarted.Eagerly, emptyMap()) .stateIn(scope, SharingStarted.Companion.Eagerly, emptyMap())
override fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> { override fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> {
return activeRepository.flatMapLatest { it.observeSeriesWithContent(seriesId) } return activeRepository.flatMapLatest { it.observeSeriesWithContent(seriesId) }
} }
override suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long) { override suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long) {
val repository = if (networkMonitor.isOnline.first()) onlineRepository else offlineRepository val repository = onlineRepository
repository.updateWatchProgress(mediaId, positionMs, durationMs) repository.updateWatchProgress(mediaId, positionMs, durationMs)
} }
} }

View File

@@ -1,18 +1,19 @@
package hu.bbara.purefin.data.catalog package hu.bbara.purefin.module
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import hu.bbara.purefin.data.EpisodeSeriesLookup import hu.bbara.purefin.data.CompositeMediaRepository
import hu.bbara.purefin.data.HomeRepository import hu.bbara.purefin.data.HomeRepository
import hu.bbara.purefin.data.MediaCatalogReader import hu.bbara.purefin.data.MediaCatalogReader
import hu.bbara.purefin.data.MediaProgressWriter import hu.bbara.purefin.data.MediaProgressWriter
import hu.bbara.purefin.data.OfflineCatalogReader import hu.bbara.purefin.data.catalog.InMemoryAppContentRepository
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
abstract class MediaRepositoryModule { abstract class RepositoryModule {
@Binds @Binds
abstract fun bindHomeRepository(impl: InMemoryAppContentRepository): HomeRepository abstract fun bindHomeRepository(impl: InMemoryAppContentRepository): HomeRepository
@@ -21,11 +22,5 @@ abstract class MediaRepositoryModule {
abstract fun bindMediaCatalogReader(impl: CompositeMediaRepository): MediaCatalogReader abstract fun bindMediaCatalogReader(impl: CompositeMediaRepository): MediaCatalogReader
@Binds @Binds
abstract fun bindMediaProgressWriter(impl: CompositeMediaRepository): MediaProgressWriter abstract fun bindMediaProgressWrite(impl: CompositeMediaRepository): MediaProgressWriter
@Binds
abstract fun bindOfflineCatalogReader(impl: OfflineMediaRepository): OfflineCatalogReader
@Binds
abstract fun bindEpisodeSeriesLookup(impl: DefaultEpisodeSeriesLookup): EpisodeSeriesLookup
} }