mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Refactor movie page to use use state flow (#1183)
## Description Refactors the movie page & view model to use a `StateFlow` instead of many `LiveData` objects. This is in keeping with best practices. There are no user facing changes. ### Related issues None ### Testing Emulator ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
feb8c31791
commit
44d1ac484f
3 changed files with 316 additions and 307 deletions
|
|
@ -14,6 +14,7 @@ import androidx.tv.material3.MaterialTheme
|
|||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.ui.detail.DebugViewModel.Companion.sendAppLogs
|
||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||
import com.github.damontecres.wholphin.util.LoadingState
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
|
|
@ -98,3 +99,13 @@ fun ErrorMessage(
|
|||
exception = error.exception,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun ErrorMessage(
|
||||
error: DataLoadingState.Error,
|
||||
modifier: Modifier = Modifier,
|
||||
) = ErrorMessage(
|
||||
message = error.message,
|
||||
exception = error.exception,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.compose.runtime.livedata.observeAsState
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
|
|
@ -28,10 +29,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
import com.github.damontecres.wholphin.data.ExtrasItem
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.Chapter
|
||||
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
||||
import com.github.damontecres.wholphin.data.model.Person
|
||||
import com.github.damontecres.wholphin.data.model.Trailer
|
||||
|
|
@ -67,11 +66,11 @@ import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome
|
|||
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForPerson
|
||||
import com.github.damontecres.wholphin.ui.discover.DiscoverRow
|
||||
import com.github.damontecres.wholphin.ui.discover.DiscoverRowData
|
||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.rememberInt
|
||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingState
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.MediaStreamType
|
||||
|
|
@ -98,16 +97,7 @@ fun MovieDetails(
|
|||
viewModel.init()
|
||||
onPauseOrDispose { }
|
||||
}
|
||||
val item by viewModel.item.observeAsState()
|
||||
val people by viewModel.people.observeAsState(listOf())
|
||||
val chapters by viewModel.chapters.observeAsState(listOf())
|
||||
val trailers by viewModel.trailers.observeAsState(listOf())
|
||||
val extras by viewModel.extras.observeAsState(listOf())
|
||||
val similar by viewModel.similar.observeAsState(listOf())
|
||||
val loading by viewModel.loading.observeAsState(LoadingState.Loading)
|
||||
val chosenStreams by viewModel.chosenStreams.observeAsState(null)
|
||||
val discovered by viewModel.discovered.collectAsState()
|
||||
val canDelete by viewModel.canDelete.collectAsState()
|
||||
val state by viewModel.state.collectAsState()
|
||||
|
||||
var overviewDialog by remember { mutableStateOf<ItemDetailsDialogInfo?>(null) }
|
||||
var moreDialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||
|
|
@ -140,19 +130,21 @@ fun MovieDetails(
|
|||
onClickDelete = { showDeleteDialog = it },
|
||||
)
|
||||
|
||||
when (val state = loading) {
|
||||
is LoadingState.Error -> {
|
||||
ErrorMessage(state, modifier)
|
||||
when (val s = state.loading) {
|
||||
is DataLoadingState.Error -> {
|
||||
ErrorMessage(s, modifier)
|
||||
}
|
||||
|
||||
LoadingState.Loading,
|
||||
LoadingState.Pending,
|
||||
DataLoadingState.Loading,
|
||||
DataLoadingState.Pending,
|
||||
-> {
|
||||
LoadingPage(modifier)
|
||||
}
|
||||
|
||||
LoadingState.Success -> {
|
||||
item?.let { movie ->
|
||||
is DataLoadingState.Success -> {
|
||||
val unknownStr = stringResource(R.string.unknown)
|
||||
val movie by rememberUpdatedState(s.data)
|
||||
val chosenStreams by rememberUpdatedState(state.chosenStreams)
|
||||
LifecycleResumeEffect(destination.itemId) {
|
||||
viewModel.maybePlayThemeSong(
|
||||
destination.itemId,
|
||||
|
|
@ -165,12 +157,7 @@ fun MovieDetails(
|
|||
MovieDetailsContent(
|
||||
preferences = preferences,
|
||||
movie = movie,
|
||||
chosenStreams = chosenStreams,
|
||||
people = people,
|
||||
chapters = chapters,
|
||||
extras = extras,
|
||||
trailers = trailers,
|
||||
similar = similar,
|
||||
state = state,
|
||||
onClickItem = { index, item ->
|
||||
viewModel.navigateTo(item.destination())
|
||||
},
|
||||
|
|
@ -193,7 +180,7 @@ fun MovieDetails(
|
|||
overviewOnClick = {
|
||||
overviewDialog =
|
||||
ItemDetailsDialogInfo(
|
||||
title = movie.name ?: context.getString(R.string.unknown),
|
||||
title = movie.name ?: unknownStr,
|
||||
overview = movie.data.overview,
|
||||
genres = movie.data.genres.orEmpty(),
|
||||
files = movie.data.mediaSources.orEmpty(),
|
||||
|
|
@ -212,8 +199,8 @@ fun MovieDetails(
|
|||
favorite = movie.data.userData?.isFavorite ?: false,
|
||||
seriesId = null,
|
||||
sourceId = chosenStreams?.source?.id?.toUUIDOrNull(),
|
||||
canClearChosenStreams = chosenStreams?.itemPlayback != null || chosenStreams?.plc != null,
|
||||
canDelete = canDelete,
|
||||
canClearChosenStreams = chosenStreams.let { it?.itemPlayback != null || it?.plc != null },
|
||||
canDelete = state.canDelete,
|
||||
actions = moreActions,
|
||||
onChooseVersion = {
|
||||
chooseVersion =
|
||||
|
|
@ -230,7 +217,6 @@ fun MovieDetails(
|
|||
moreDialog = null
|
||||
},
|
||||
onChooseTracks = { type ->
|
||||
|
||||
viewModel.streamChoiceService
|
||||
.chooseSource(
|
||||
movie.data,
|
||||
|
|
@ -262,9 +248,7 @@ fun MovieDetails(
|
|||
onShowOverview = {
|
||||
overviewDialog =
|
||||
ItemDetailsDialogInfo(
|
||||
title =
|
||||
movie.name
|
||||
?: context.getString(R.string.unknown),
|
||||
title = movie.name ?: unknownStr,
|
||||
overview = movie.data.overview,
|
||||
genres = movie.data.genres.orEmpty(),
|
||||
files = movie.data.mediaSources.orEmpty(),
|
||||
|
|
@ -321,17 +305,15 @@ fun MovieDetails(
|
|||
onClickExtra = { index, extra ->
|
||||
viewModel.navigateTo(extra.destination)
|
||||
},
|
||||
discovered = discovered,
|
||||
onClickDiscover = { index, item ->
|
||||
viewModel.navigateTo(item.destination)
|
||||
},
|
||||
canDelete = canDelete,
|
||||
deleteOnClick = { showDeleteDialog = movie },
|
||||
canDelete = state.canDelete,
|
||||
deleteOnClick = { showDeleteDialog = state.movie },
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
overviewDialog?.let { info ->
|
||||
ItemDetailsDialog(
|
||||
info = info,
|
||||
|
|
@ -403,13 +385,7 @@ private const val DISCOVER_ROW = SIMILAR_ROW + 1
|
|||
fun MovieDetailsContent(
|
||||
preferences: UserPreferences,
|
||||
movie: BaseItem,
|
||||
chosenStreams: ChosenStreams?,
|
||||
people: List<Person>,
|
||||
chapters: List<Chapter>,
|
||||
trailers: List<Trailer>,
|
||||
extras: List<ExtrasItem>,
|
||||
similar: List<BaseItem>,
|
||||
discovered: List<DiscoverItem>,
|
||||
state: MovieState,
|
||||
playOnClick: (Duration) -> Unit,
|
||||
trailerOnClick: (Trailer) -> Unit,
|
||||
overviewOnClick: () -> Unit,
|
||||
|
|
@ -454,7 +430,7 @@ fun MovieDetailsContent(
|
|||
MovieDetailsHeader(
|
||||
preferences = preferences,
|
||||
movie = movie,
|
||||
chosenStreams = chosenStreams,
|
||||
chosenStreams = state.chosenStreams,
|
||||
bringIntoViewRequester = bringIntoViewRequester,
|
||||
overviewOnClick = overviewOnClick,
|
||||
modifier =
|
||||
|
|
@ -481,7 +457,7 @@ fun MovieDetailsContent(
|
|||
}
|
||||
}
|
||||
},
|
||||
trailers = trailers,
|
||||
trailers = state.trailers,
|
||||
trailerOnClick = {
|
||||
position = TRAILER_ROW
|
||||
trailerOnClick.invoke(it)
|
||||
|
|
@ -496,7 +472,7 @@ fun MovieDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (people.isNotEmpty()) {
|
||||
state.people.letNotEmpty { people ->
|
||||
item {
|
||||
PersonRow(
|
||||
people = people,
|
||||
|
|
@ -515,7 +491,7 @@ fun MovieDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (chapters.isNotEmpty()) {
|
||||
state.chapters.letNotEmpty { chapters ->
|
||||
item {
|
||||
ChapterRow(
|
||||
chapters = chapters,
|
||||
|
|
@ -532,7 +508,7 @@ fun MovieDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (extras.isNotEmpty()) {
|
||||
state.extras.letNotEmpty { extras ->
|
||||
item {
|
||||
ExtrasRow(
|
||||
extras = extras,
|
||||
|
|
@ -548,7 +524,7 @@ fun MovieDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (similar.isNotEmpty()) {
|
||||
state.similar.letNotEmpty { similar ->
|
||||
item {
|
||||
val imageHeight =
|
||||
remember(movie.type) {
|
||||
|
|
@ -587,7 +563,7 @@ fun MovieDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (discovered.isNotEmpty()) {
|
||||
state.discovered.letNotEmpty { discovered ->
|
||||
item {
|
||||
DiscoverRow(
|
||||
row =
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.github.damontecres.wholphin.ui.detail.movie
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
import com.github.damontecres.wholphin.data.ExtrasItem
|
||||
|
|
@ -30,36 +28,28 @@ import com.github.damontecres.wholphin.services.TrailerService
|
|||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||
import com.github.damontecres.wholphin.services.deleteItem
|
||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||
import com.github.damontecres.wholphin.ui.combinePair
|
||||
import com.github.damontecres.wholphin.ui.launchDefault
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.LoadingState
|
||||
import com.github.damontecres.wholphin.ui.showToast
|
||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.api.client.extensions.libraryApi
|
||||
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||
import org.jellyfin.sdk.model.api.MediaStreamType
|
||||
import org.jellyfin.sdk.model.api.request.GetSimilarItemsRequest
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
|
||||
@HiltViewModel(assistedFactory = MovieViewModel.Factory::class)
|
||||
|
|
@ -89,94 +79,99 @@ class MovieViewModel
|
|||
fun create(itemId: UUID): MovieViewModel
|
||||
}
|
||||
|
||||
val loading = MutableLiveData<LoadingState>(LoadingState.Pending)
|
||||
val item = MutableLiveData<BaseItem?>(null)
|
||||
val trailers = MutableLiveData<List<Trailer>>(listOf())
|
||||
val people = MutableLiveData<List<Person>>(listOf())
|
||||
val chapters = MutableLiveData<List<Chapter>>(listOf())
|
||||
val extras = MutableLiveData<List<ExtrasItem>>(listOf())
|
||||
val similar = MutableLiveData<List<BaseItem>>()
|
||||
val chosenStreams = MutableLiveData<ChosenStreams?>(null)
|
||||
val discovered = MutableStateFlow<List<DiscoverItem>>(listOf())
|
||||
|
||||
val canDelete = MutableStateFlow(false)
|
||||
private val _state = MutableStateFlow(MovieState())
|
||||
val state: StateFlow<MovieState> = _state
|
||||
|
||||
init {
|
||||
init()
|
||||
viewModelScope.launchDefault {
|
||||
item
|
||||
.asFlow()
|
||||
.filterNotNull()
|
||||
.combinePair(userPreferencesService.flow.map { it.appPreferences })
|
||||
.collectLatest { (item, preferences) ->
|
||||
canDelete.update { mediaManagementService.canDelete(item, preferences) }
|
||||
userPreferencesService.flow.collectLatest { preferences ->
|
||||
_state.update {
|
||||
val canDelete =
|
||||
it.movie?.let {
|
||||
mediaManagementService.canDelete(
|
||||
it,
|
||||
preferences.appPreferences,
|
||||
)
|
||||
}
|
||||
it.copy(
|
||||
canDelete = canDelete ?: false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchAndSetItem(): Deferred<BaseItem> =
|
||||
viewModelScope.async(
|
||||
Dispatchers.IO +
|
||||
LoadingExceptionHandler(
|
||||
loading,
|
||||
"Error fetching movie",
|
||||
),
|
||||
) {
|
||||
private suspend fun getMovie(): BaseItem {
|
||||
val item =
|
||||
api.userLibraryApi.getItem(itemId).content.let {
|
||||
BaseItem.from(it, api)
|
||||
BaseItem(it)
|
||||
}
|
||||
this@MovieViewModel.item.setValueOnMain(item)
|
||||
item
|
||||
return item
|
||||
}
|
||||
|
||||
fun init(): Job =
|
||||
viewModelScope.launch(
|
||||
Dispatchers.IO +
|
||||
LoadingExceptionHandler(
|
||||
loading,
|
||||
"Error fetching movie",
|
||||
),
|
||||
) {
|
||||
val item = fetchAndSetItem().await()
|
||||
val result =
|
||||
viewModelScope.launchDefault {
|
||||
val movie =
|
||||
try {
|
||||
getMovie()
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Failed to fetch movie %s", itemId)
|
||||
_state.update { it.copy(loading = DataLoadingState.Error(ex)) }
|
||||
return@launchDefault
|
||||
}
|
||||
val chosenStreams =
|
||||
itemPlaybackRepository.getSelectedTracks(
|
||||
item.id,
|
||||
item,
|
||||
itemId,
|
||||
movie,
|
||||
userPreferencesService.getCurrent(),
|
||||
)
|
||||
val remoteTrailers = trailerService.getRemoteTrailers(item)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.item.value = item
|
||||
chosenStreams.value = result
|
||||
this@MovieViewModel.trailers.value = remoteTrailers
|
||||
loading.value = LoadingState.Success
|
||||
backdropService.submit(item)
|
||||
val remoteTrailers = trailerService.getRemoteTrailers(movie)
|
||||
val chapters = Chapter.fromDto(movie.data, api)
|
||||
_state.update {
|
||||
it.copy(
|
||||
loading = DataLoadingState.Success(movie),
|
||||
chosenStreams = chosenStreams,
|
||||
trailers = remoteTrailers,
|
||||
chapters = chapters,
|
||||
)
|
||||
}
|
||||
backdropService.submit(movie)
|
||||
viewModelScope.launchIO {
|
||||
trailerService.getLocalTrailers(item).letNotEmpty { localTrailers ->
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.trailers.value = localTrailers + remoteTrailers
|
||||
trailerService.getLocalTrailers(movie).letNotEmpty { localTrailers ->
|
||||
_state.update {
|
||||
it.copy(
|
||||
trailers = localTrailers + remoteTrailers,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
val people = peopleFavorites.getPeopleFor(item)
|
||||
this@MovieViewModel.people.setValueOnMain(people)
|
||||
val people = peopleFavorites.getPeopleFor(movie)
|
||||
_state.update {
|
||||
it.copy(
|
||||
people = people,
|
||||
)
|
||||
}
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
val extras = extrasService.getExtras(item.id)
|
||||
this@MovieViewModel.extras.setValueOnMain(extras)
|
||||
val extras = extrasService.getExtras(itemId)
|
||||
_state.update {
|
||||
it.copy(
|
||||
extras = extras,
|
||||
)
|
||||
}
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
val results = seerrService.similar(item).orEmpty()
|
||||
discovered.update { results }
|
||||
val results = seerrService.similar(movie).orEmpty()
|
||||
_state.update {
|
||||
it.copy(
|
||||
discovered = results,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
chapters.value = Chapter.fromDto(item.data, api)
|
||||
}
|
||||
if (!similar.isInitialized) {
|
||||
if (state.value.similar.isEmpty()) {
|
||||
val similar =
|
||||
api.libraryApi
|
||||
.getSimilarItems(
|
||||
|
|
@ -187,31 +182,48 @@ class MovieViewModel
|
|||
limit = 25,
|
||||
),
|
||||
).content.items
|
||||
.map { BaseItem.Companion.from(it, api) }
|
||||
this@MovieViewModel.similar.setValueOnMain(similar)
|
||||
.map { BaseItem(it) }
|
||||
|
||||
_state.update { it.copy(similar = similar) }
|
||||
}
|
||||
}
|
||||
|
||||
fun setWatched(
|
||||
itemId: UUID,
|
||||
played: Boolean,
|
||||
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
||||
) = viewModelScope.launchDefault {
|
||||
try {
|
||||
favoriteWatchManager.setWatched(itemId, played)
|
||||
fetchAndSetItem()
|
||||
getMovie().let { movie ->
|
||||
_state.update {
|
||||
it.copy(loading = DataLoadingState.Success(movie))
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Error updating watch status for movie %s", itemId)
|
||||
showToast(context, "Something went wrong...")
|
||||
}
|
||||
}
|
||||
|
||||
fun setFavorite(
|
||||
itemId: UUID,
|
||||
favorite: Boolean,
|
||||
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
||||
) = viewModelScope.launchDefault {
|
||||
try {
|
||||
favoriteWatchManager.setFavorite(itemId, favorite)
|
||||
val item = item.value
|
||||
fetchAndSetItem()
|
||||
if (item != null && itemId != item.id) {
|
||||
viewModelScope.launchIO {
|
||||
val people = peopleFavorites.getPeopleFor(item)
|
||||
this@MovieViewModel.people.setValueOnMain(people)
|
||||
val movie = getMovie()
|
||||
_state.update {
|
||||
it.copy(loading = DataLoadingState.Success(movie))
|
||||
}
|
||||
if (itemId != movie.id) {
|
||||
viewModelScope.launchIO {
|
||||
val people = peopleFavorites.getPeopleFor(movie)
|
||||
_state.update { it.copy(people = people) }
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Error updating favorite %s", itemId)
|
||||
showToast(context, "Something went wrong...")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227,9 +239,7 @@ class MovieViewModel
|
|||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
}
|
||||
_state.update { it.copy(chosenStreams = chosen) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,9 +263,7 @@ class MovieViewModel
|
|||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
}
|
||||
_state.update { it.copy(chosenStreams = chosen) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -283,14 +291,14 @@ class MovieViewModel
|
|||
fun clearChosenStreams(chosenStreams: ChosenStreams?) {
|
||||
viewModelScope.launchIO {
|
||||
itemPlaybackRepository.deleteChosenStreams(chosenStreams)
|
||||
item.value?.let { item ->
|
||||
state.value.movie?.let { item ->
|
||||
val result =
|
||||
itemPlaybackRepository.getSelectedTracks(
|
||||
itemId,
|
||||
item,
|
||||
userPreferencesService.getCurrent(),
|
||||
)
|
||||
this@MovieViewModel.chosenStreams.setValueOnMain(result)
|
||||
_state.update { it.copy(chosenStreams = result) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -301,3 +309,17 @@ class MovieViewModel
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class MovieState(
|
||||
val loading: DataLoadingState<BaseItem> = DataLoadingState.Pending,
|
||||
val trailers: List<Trailer> = emptyList(),
|
||||
val people: List<Person> = emptyList(),
|
||||
val chapters: List<Chapter> = emptyList(),
|
||||
val extras: List<ExtrasItem> = emptyList(),
|
||||
val similar: List<BaseItem> = emptyList(),
|
||||
val discovered: List<DiscoverItem> = emptyList(),
|
||||
val chosenStreams: ChosenStreams? = null,
|
||||
val canDelete: Boolean = false,
|
||||
) {
|
||||
val movie: BaseItem? = (loading as? DataLoadingState.Success<BaseItem>)?.data
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue