mirror of
https://github.com/bbara04/Purefin.git
synced 2026-04-01 01:30:08 +02:00
refactor: add CompositeMediaRepository to switch between offline/online based on user session
Extract AppContentRepository interface from MediaRepository for home/library-specific features. CompositeMediaRepository delegates to OfflineMediaRepository or AppContentRepository based on UserSessionRepository.isOfflineMode, allowing content ViewModels to use a single MediaRepository interface that automatically switches data source.
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
package hu.bbara.purefin.core.data
|
||||||
|
|
||||||
|
import hu.bbara.purefin.core.model.Episode
|
||||||
|
import hu.bbara.purefin.core.model.Library
|
||||||
|
import hu.bbara.purefin.core.model.Media
|
||||||
|
import hu.bbara.purefin.core.model.MediaRepositoryState
|
||||||
|
import hu.bbara.purefin.core.model.Movie
|
||||||
|
import hu.bbara.purefin.core.model.Series
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
interface AppContentRepository : MediaRepository {
|
||||||
|
|
||||||
|
val libraries: StateFlow<List<Library>>
|
||||||
|
val state: StateFlow<MediaRepositoryState>
|
||||||
|
val continueWatching: StateFlow<List<Media>>
|
||||||
|
val nextUp: StateFlow<List<Media>>
|
||||||
|
val latestLibraryContent: StateFlow<Map<UUID, List<Media>>>
|
||||||
|
suspend fun ensureReady()
|
||||||
|
suspend fun refreshHomeData()
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package hu.bbara.purefin.core.data
|
||||||
|
|
||||||
|
import hu.bbara.purefin.core.data.session.UserSessionRepository
|
||||||
|
import hu.bbara.purefin.core.model.Episode
|
||||||
|
import hu.bbara.purefin.core.model.Movie
|
||||||
|
import hu.bbara.purefin.core.model.Series
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import java.util.UUID
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches between [OfflineMediaRepository] and [AppContentRepository] based on
|
||||||
|
* [UserSessionRepository.isOfflineMode]. When offline mode is enabled, all reads
|
||||||
|
* and writes go through the offline (downloaded) repository; otherwise the online
|
||||||
|
* repository is used.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Singleton
|
||||||
|
class CompositeMediaRepository @Inject constructor(
|
||||||
|
private val offlineRepository: OfflineMediaRepository,
|
||||||
|
private val onlineRepository: AppContentRepository,
|
||||||
|
private val userSessionRepository: UserSessionRepository,
|
||||||
|
) : MediaRepository {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
|
private val activeRepository: Flow<MediaRepository> =
|
||||||
|
userSessionRepository.isOfflineMode.flatMapLatest { offline ->
|
||||||
|
kotlinx.coroutines.flow.flowOf(if (offline) offlineRepository else onlineRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val movies: StateFlow<Map<UUID, Movie>> = activeRepository
|
||||||
|
.flatMapLatest { it.movies }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
override val series: StateFlow<Map<UUID, Series>> = activeRepository
|
||||||
|
.flatMapLatest { it.series }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
override val episodes: StateFlow<Map<UUID, Episode>> = activeRepository
|
||||||
|
.flatMapLatest { it.episodes }
|
||||||
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
|
override fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> {
|
||||||
|
return activeRepository.flatMapLatest { it.observeSeriesWithContent(seriesId) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long) {
|
||||||
|
val isOffline = userSessionRepository.isOfflineMode.stateIn(scope).value
|
||||||
|
val repo = if (isOffline) offlineRepository else onlineRepository
|
||||||
|
repo.updateWatchProgress(mediaId, positionMs, durationMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,11 +39,11 @@ import javax.inject.Inject
|
|||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class InMemoryMediaRepository @Inject constructor(
|
class InMemoryAppContentRepository @Inject constructor(
|
||||||
val userSessionRepository: UserSessionRepository,
|
val userSessionRepository: UserSessionRepository,
|
||||||
val jellyfinApiClient: JellyfinApiClient,
|
val jellyfinApiClient: JellyfinApiClient,
|
||||||
private val homeCacheDataStore: DataStore<HomeCache>
|
private val homeCacheDataStore: DataStore<HomeCache>
|
||||||
) : MediaRepository {
|
) : AppContentRepository {
|
||||||
|
|
||||||
private val ready = CompletableDeferred<Unit>()
|
private val ready = CompletableDeferred<Unit>()
|
||||||
private val readyMutex = Mutex()
|
private val readyMutex = Mutex()
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
package hu.bbara.purefin.core.data
|
package hu.bbara.purefin.core.data
|
||||||
|
|
||||||
import hu.bbara.purefin.core.model.Episode
|
import hu.bbara.purefin.core.model.Episode
|
||||||
import hu.bbara.purefin.core.model.Library
|
|
||||||
import hu.bbara.purefin.core.model.Media
|
|
||||||
import hu.bbara.purefin.core.model.MediaRepositoryState
|
|
||||||
import hu.bbara.purefin.core.model.Movie
|
import hu.bbara.purefin.core.model.Movie
|
||||||
import hu.bbara.purefin.core.model.Series
|
import hu.bbara.purefin.core.model.Series
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -11,21 +8,9 @@ import kotlinx.coroutines.flow.StateFlow
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
interface MediaRepository {
|
interface MediaRepository {
|
||||||
|
|
||||||
val libraries: StateFlow<List<Library>>
|
|
||||||
val movies: StateFlow<Map<UUID, Movie>>
|
val movies: StateFlow<Map<UUID, Movie>>
|
||||||
val series: StateFlow<Map<UUID, Series>>
|
val series: StateFlow<Map<UUID, Series>>
|
||||||
val episodes: StateFlow<Map<UUID, Episode>>
|
val episodes: StateFlow<Map<UUID, Episode>>
|
||||||
val state: StateFlow<MediaRepositoryState>
|
|
||||||
|
|
||||||
val continueWatching: StateFlow<List<Media>>
|
|
||||||
val nextUp: StateFlow<List<Media>>
|
|
||||||
val latestLibraryContent: StateFlow<Map<UUID, List<Media>>>
|
|
||||||
|
|
||||||
fun observeSeriesWithContent(seriesId: UUID): Flow<Series?>
|
fun observeSeriesWithContent(seriesId: UUID): Flow<Series?>
|
||||||
|
|
||||||
suspend fun ensureReady()
|
|
||||||
|
|
||||||
suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long)
|
suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long)
|
||||||
suspend fun refreshHomeData()
|
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,9 @@ import dagger.hilt.components.SingletonComponent
|
|||||||
abstract class MediaRepositoryModule {
|
abstract class MediaRepositoryModule {
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindInMemoryMediaRepository(impl: InMemoryMediaRepository): MediaRepository
|
abstract fun bindAppContentRepository(impl: InMemoryAppContentRepository): AppContentRepository
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindMediaRepository(impl: CompositeMediaRepository): MediaRepository
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,23 +22,23 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
class OfflineMediaRepository @Inject constructor(
|
class OfflineMediaRepository @Inject constructor(
|
||||||
private val localDataSource: OfflineRoomMediaLocalDataSource
|
private val localDataSource: OfflineRoomMediaLocalDataSource
|
||||||
) {
|
) : MediaRepository {
|
||||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
val movies: StateFlow<Map<UUID, Movie>> = localDataSource.moviesFlow
|
override val movies: StateFlow<Map<UUID, Movie>> = localDataSource.moviesFlow
|
||||||
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
val series: StateFlow<Map<UUID, Series>> = localDataSource.seriesFlow
|
override val series: StateFlow<Map<UUID, Series>> = localDataSource.seriesFlow
|
||||||
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
val episodes: StateFlow<Map<UUID, Episode>> = localDataSource.episodesFlow
|
override val episodes: StateFlow<Map<UUID, Episode>> = localDataSource.episodesFlow
|
||||||
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
.stateIn(scope, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> {
|
override fun observeSeriesWithContent(seriesId: UUID): Flow<Series?> {
|
||||||
return localDataSource.observeSeriesWithContent(seriesId)
|
return localDataSource.observeSeriesWithContent(seriesId)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long) {
|
override suspend fun updateWatchProgress(mediaId: UUID, positionMs: Long, durationMs: Long) {
|
||||||
if (durationMs <= 0) return
|
if (durationMs <= 0) return
|
||||||
val progressPercent = (positionMs.toDouble() / durationMs.toDouble()) * 100.0
|
val progressPercent = (positionMs.toDouble() / durationMs.toDouble()) * 100.0
|
||||||
val watched = progressPercent >= 90.0
|
val watched = progressPercent >= 90.0
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package hu.bbara.purefin.core.data.domain.usecase
|
package hu.bbara.purefin.core.data.domain.usecase
|
||||||
|
|
||||||
import hu.bbara.purefin.core.data.MediaRepository
|
import hu.bbara.purefin.core.data.AppContentRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RefreshHomeDataUseCase @Inject constructor(
|
class RefreshHomeDataUseCase @Inject constructor(
|
||||||
private val repository: MediaRepository
|
private val repository: AppContentRepository
|
||||||
) {
|
) {
|
||||||
suspend operator fun invoke() {
|
suspend operator fun invoke() {
|
||||||
repository.refreshHomeData()
|
repository.refreshHomeData()
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import kotlinx.coroutines.flow.SharingStarted
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.jellyfin.sdk.model.UUID
|
import org.jellyfin.sdk.model.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -31,10 +30,6 @@ class EpisodeScreenViewModel @Inject constructor(
|
|||||||
id?.let { episodesMap[it] }
|
id?.let { episodesMap[it] }
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
|
||||||
|
|
||||||
init {
|
|
||||||
viewModelScope.launch { mediaRepository.ensureReady() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onBack() {
|
fun onBack() {
|
||||||
navigationManager.pop()
|
navigationManager.pop()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.StateFlow
|
|||||||
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
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.jellyfin.sdk.model.UUID
|
import org.jellyfin.sdk.model.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -34,20 +33,14 @@ class SeriesViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
|
||||||
|
|
||||||
init {
|
fun onSelectEpisode(seriesId: UUID, seasonId: UUID, episodeId: UUID) {
|
||||||
viewModelScope.launch { mediaRepository.ensureReady() }
|
navigationManager.navigate(Route.EpisodeRoute(
|
||||||
}
|
EpisodeDto(
|
||||||
|
id = episodeId,
|
||||||
fun onSelectEpisode(seriesId: UUID, seasonId:UUID, episodeId: UUID) {
|
seasonId = seasonId,
|
||||||
viewModelScope.launch {
|
seriesId = seriesId
|
||||||
navigationManager.navigate(Route.EpisodeRoute(
|
)
|
||||||
EpisodeDto(
|
))
|
||||||
id = episodeId,
|
|
||||||
seasonId = seasonId,
|
|
||||||
seriesId = seriesId
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onBack() {
|
fun onBack() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package hu.bbara.purefin.feature.shared.home
|
|||||||
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.core.data.MediaRepository
|
import hu.bbara.purefin.core.data.AppContentRepository
|
||||||
import hu.bbara.purefin.core.data.domain.usecase.RefreshHomeDataUseCase
|
import hu.bbara.purefin.core.data.domain.usecase.RefreshHomeDataUseCase
|
||||||
import hu.bbara.purefin.core.data.navigation.EpisodeDto
|
import hu.bbara.purefin.core.data.navigation.EpisodeDto
|
||||||
import hu.bbara.purefin.core.data.navigation.LibraryDto
|
import hu.bbara.purefin.core.data.navigation.LibraryDto
|
||||||
@@ -25,7 +25,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class HomePageViewModel @Inject constructor(
|
class HomePageViewModel @Inject constructor(
|
||||||
private val mediaRepository: MediaRepository,
|
private val appContentRepository: AppContentRepository,
|
||||||
private val userSessionRepository: UserSessionRepository,
|
private val userSessionRepository: UserSessionRepository,
|
||||||
private val navigationManager: NavigationManager,
|
private val navigationManager: NavigationManager,
|
||||||
private val refreshHomeDataUseCase: RefreshHomeDataUseCase
|
private val refreshHomeDataUseCase: RefreshHomeDataUseCase
|
||||||
@@ -37,7 +37,7 @@ class HomePageViewModel @Inject constructor(
|
|||||||
initialValue = ""
|
initialValue = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
val libraries = mediaRepository.libraries.map { libraries ->
|
val libraries = appContentRepository.libraries.map { libraries ->
|
||||||
libraries.map {
|
libraries.map {
|
||||||
LibraryItem(
|
LibraryItem(
|
||||||
id = it.id,
|
id = it.id,
|
||||||
@@ -45,8 +45,8 @@ class HomePageViewModel @Inject constructor(
|
|||||||
type = it.type,
|
type = it.type,
|
||||||
posterUrl = it.posterUrl,
|
posterUrl = it.posterUrl,
|
||||||
isEmpty = when(it.type) {
|
isEmpty = when(it.type) {
|
||||||
CollectionType.MOVIES -> mediaRepository.movies.value.isEmpty()
|
CollectionType.MOVIES -> appContentRepository.movies.value.isEmpty()
|
||||||
CollectionType.TVSHOWS -> mediaRepository.series.value.isEmpty()
|
CollectionType.TVSHOWS -> appContentRepository.series.value.isEmpty()
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -60,9 +60,9 @@ class HomePageViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val continueWatching = combine(
|
val continueWatching = combine(
|
||||||
mediaRepository.continueWatching,
|
appContentRepository.continueWatching,
|
||||||
mediaRepository.movies,
|
appContentRepository.movies,
|
||||||
mediaRepository.episodes
|
appContentRepository.episodes
|
||||||
) { list, moviesMap, episodesMap ->
|
) { list, moviesMap, episodesMap ->
|
||||||
list.mapNotNull { media ->
|
list.mapNotNull { media ->
|
||||||
when (media) {
|
when (media) {
|
||||||
@@ -82,8 +82,8 @@ class HomePageViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val nextUp = combine(
|
val nextUp = combine(
|
||||||
mediaRepository.nextUp,
|
appContentRepository.nextUp,
|
||||||
mediaRepository.episodes
|
appContentRepository.episodes
|
||||||
) { list, episodesMap ->
|
) { list, episodesMap ->
|
||||||
list.mapNotNull { media ->
|
list.mapNotNull { media ->
|
||||||
when (media) {
|
when (media) {
|
||||||
@@ -100,10 +100,10 @@ class HomePageViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val latestLibraryContent = combine(
|
val latestLibraryContent = combine(
|
||||||
mediaRepository.latestLibraryContent,
|
appContentRepository.latestLibraryContent,
|
||||||
mediaRepository.movies,
|
appContentRepository.movies,
|
||||||
mediaRepository.series,
|
appContentRepository.series,
|
||||||
mediaRepository.episodes
|
appContentRepository.episodes
|
||||||
) { libraryMap, moviesMap, seriesMap, episodesMap ->
|
) { libraryMap, moviesMap, seriesMap, episodesMap ->
|
||||||
libraryMap.mapValues { (_, items) ->
|
libraryMap.mapValues { (_, items) ->
|
||||||
items.mapNotNull { media ->
|
items.mapNotNull { media ->
|
||||||
@@ -131,7 +131,7 @@ class HomePageViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch { mediaRepository.ensureReady() }
|
viewModelScope.launch { appContentRepository.ensureReady() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onLibrarySelected(id: UUID, name: String) {
|
fun onLibrarySelected(id: UUID, name: String) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ 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.feature.shared.home.PosterItem
|
import hu.bbara.purefin.feature.shared.home.PosterItem
|
||||||
import hu.bbara.purefin.core.data.MediaRepository
|
import hu.bbara.purefin.core.data.AppContentRepository
|
||||||
import hu.bbara.purefin.core.data.navigation.MovieDto
|
import hu.bbara.purefin.core.data.navigation.MovieDto
|
||||||
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
||||||
import hu.bbara.purefin.core.data.navigation.Route
|
import hu.bbara.purefin.core.data.navigation.Route
|
||||||
@@ -22,13 +22,13 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class LibraryViewModel @Inject constructor(
|
class LibraryViewModel @Inject constructor(
|
||||||
private val mediaRepository: MediaRepository,
|
private val appContentRepository: AppContentRepository,
|
||||||
private val navigationManager: NavigationManager
|
private val navigationManager: NavigationManager
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val selectedLibrary = MutableStateFlow<UUID?>(null)
|
private val selectedLibrary = MutableStateFlow<UUID?>(null)
|
||||||
|
|
||||||
val contents: StateFlow<List<PosterItem>> = combine(selectedLibrary, mediaRepository.libraries) {
|
val contents: StateFlow<List<PosterItem>> = combine(selectedLibrary, appContentRepository.libraries) {
|
||||||
libraryId, libraries ->
|
libraryId, libraries ->
|
||||||
if (libraryId == null) {
|
if (libraryId == null) {
|
||||||
return@combine emptyList()
|
return@combine emptyList()
|
||||||
@@ -46,7 +46,7 @@ class LibraryViewModel @Inject constructor(
|
|||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
|
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch { mediaRepository.ensureReady() }
|
viewModelScope.launch { appContentRepository.ensureReady() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMovieSelected(movieId: UUID) {
|
fun onMovieSelected(movieId: UUID) {
|
||||||
|
|||||||
Reference in New Issue
Block a user