mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Bump dependency versions (#170)
Also tries out using assisted injection for item IDs No user facing changes
This commit is contained in:
parent
bdc475e7b6
commit
18556b5058
3 changed files with 106 additions and 70 deletions
|
|
@ -39,6 +39,7 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
|
|
@ -89,12 +90,16 @@ fun MovieDetails(
|
|||
preferences: UserPreferences,
|
||||
destination: Destination.MediaItem,
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: MovieViewModel = hiltViewModel(),
|
||||
viewModel: MovieViewModel =
|
||||
hiltViewModel<MovieViewModel, MovieViewModel.Factory>(
|
||||
creationCallback = { it.create(destination.itemId) },
|
||||
),
|
||||
playlistViewModel: AddPlaylistViewModel = hiltViewModel(),
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.init(destination.itemId)
|
||||
LifecycleResumeEffect(Unit) {
|
||||
viewModel.init()
|
||||
onPauseOrDispose { }
|
||||
}
|
||||
val item by viewModel.item.observeAsState()
|
||||
val people by viewModel.people.observeAsState(listOf())
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.github.damontecres.wholphin.ui.detail.movie
|
|||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
|
|
@ -16,7 +17,6 @@ import com.github.damontecres.wholphin.data.model.RemoteTrailer
|
|||
import com.github.damontecres.wholphin.data.model.Trailer
|
||||
import com.github.damontecres.wholphin.preferences.ThemeSongVolume
|
||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||
import com.github.damontecres.wholphin.ui.detail.LoadingItemViewModel
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
|
|
@ -26,10 +26,15 @@ 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.util.ThemeSongPlayer
|
||||
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.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
|
|
@ -39,26 +44,53 @@ import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
|||
import org.jellyfin.sdk.model.api.MediaStreamType
|
||||
import org.jellyfin.sdk.model.api.request.GetSimilarItemsRequest
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@HiltViewModel(assistedFactory = MovieViewModel.Factory::class)
|
||||
class MovieViewModel
|
||||
@Inject
|
||||
@AssistedInject
|
||||
constructor(
|
||||
api: ApiClient,
|
||||
private val api: ApiClient,
|
||||
@param:ApplicationContext private val context: Context,
|
||||
private val navigationManager: NavigationManager,
|
||||
val serverRepository: ServerRepository,
|
||||
val itemPlaybackRepository: ItemPlaybackRepository,
|
||||
private val themeSongPlayer: ThemeSongPlayer,
|
||||
) : LoadingItemViewModel(api) {
|
||||
@Assisted val itemId: UUID,
|
||||
) : ViewModel() {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(itemId2: 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 similar = MutableLiveData<List<BaseItem>>()
|
||||
val chosenStreams = MutableLiveData<ChosenStreams?>(null)
|
||||
|
||||
fun init(itemId: UUID): Job? =
|
||||
init {
|
||||
init()
|
||||
}
|
||||
|
||||
private fun fetchAndSetItem(): Deferred<BaseItem> =
|
||||
viewModelScope.async(
|
||||
Dispatchers.IO +
|
||||
LoadingExceptionHandler(
|
||||
loading,
|
||||
"Error fetching movie",
|
||||
),
|
||||
) {
|
||||
val item =
|
||||
api.userLibraryApi.getItem(itemId).content.let {
|
||||
BaseItem.from(it, api)
|
||||
}
|
||||
this@MovieViewModel.item.setValueOnMain(item)
|
||||
item
|
||||
}
|
||||
|
||||
fun init(): Job =
|
||||
viewModelScope.launch(
|
||||
Dispatchers.IO +
|
||||
LoadingExceptionHandler(
|
||||
|
|
@ -66,84 +98,83 @@ class MovieViewModel
|
|||
"Error fetching movie",
|
||||
),
|
||||
) {
|
||||
fetchAndSetItem(itemId)
|
||||
item.value?.let { item ->
|
||||
val result = itemPlaybackRepository.getSelectedTracks(item.id, item)
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = result
|
||||
loading.value = LoadingState.Success
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
val remoteTrailers =
|
||||
item.data.remoteTrailers
|
||||
?.mapNotNull { t ->
|
||||
t.url?.let { url ->
|
||||
val name =
|
||||
t.name
|
||||
// TODO would be nice to clean up the trailer name
|
||||
val item = fetchAndSetItem().await()
|
||||
val result = itemPlaybackRepository.getSelectedTracks(item.id, item)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.item.value = item
|
||||
chosenStreams.value = result
|
||||
loading.value = LoadingState.Success
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
val remoteTrailers =
|
||||
item.data.remoteTrailers
|
||||
?.mapNotNull { t ->
|
||||
t.url?.let { url ->
|
||||
val name =
|
||||
t.name
|
||||
// TODO would be nice to clean up the trailer name
|
||||
// ?.replace(item.name ?: "", "")
|
||||
// ?.removePrefix(" - ")
|
||||
?: context.getString(R.string.trailer)
|
||||
RemoteTrailer(name, url)
|
||||
}
|
||||
}.orEmpty()
|
||||
.sortedBy { it.name }
|
||||
val localTrailerCount = item.data.localTrailerCount ?: 0
|
||||
val localTrailers =
|
||||
if (localTrailerCount > 0) {
|
||||
api.userLibraryApi.getLocalTrailers(itemId).content.map {
|
||||
LocalTrailer(BaseItem.Companion.from(it, api))
|
||||
?: context.getString(R.string.trailer)
|
||||
RemoteTrailer(name, url)
|
||||
}
|
||||
} else {
|
||||
listOf()
|
||||
}.orEmpty()
|
||||
.sortedBy { it.name }
|
||||
val localTrailerCount = item.data.localTrailerCount ?: 0
|
||||
val localTrailers =
|
||||
if (localTrailerCount > 0) {
|
||||
api.userLibraryApi.getLocalTrailers(itemId).content.map {
|
||||
LocalTrailer(BaseItem.Companion.from(it, api))
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.trailers.value = localTrailers + remoteTrailers
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
people.value =
|
||||
item.data.people
|
||||
?.letNotEmpty { people ->
|
||||
people.map { Person.fromDto(it, api) }
|
||||
}.orEmpty()
|
||||
chapters.value = Chapter.fromDto(item.data, api)
|
||||
}
|
||||
if (!similar.isInitialized) {
|
||||
val similar =
|
||||
api.libraryApi
|
||||
.getSimilarItems(
|
||||
GetSimilarItemsRequest(
|
||||
userId = serverRepository.currentUser?.id,
|
||||
itemId = itemId,
|
||||
fields = SlimItemFields,
|
||||
limit = 25,
|
||||
),
|
||||
).content.items
|
||||
.map { BaseItem.Companion.from(it, api) }
|
||||
this@MovieViewModel.similar.setValueOnMain(similar)
|
||||
this@MovieViewModel.trailers.value = localTrailers + remoteTrailers
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
people.value =
|
||||
item.data.people
|
||||
?.letNotEmpty { people ->
|
||||
people.map { Person.fromDto(it, api) }
|
||||
}.orEmpty()
|
||||
chapters.value = Chapter.fromDto(item.data, api)
|
||||
}
|
||||
if (!similar.isInitialized) {
|
||||
val similar =
|
||||
api.libraryApi
|
||||
.getSimilarItems(
|
||||
GetSimilarItemsRequest(
|
||||
userId = serverRepository.currentUser?.id,
|
||||
itemId = itemId,
|
||||
fields = SlimItemFields,
|
||||
limit = 25,
|
||||
),
|
||||
).content.items
|
||||
.map { BaseItem.Companion.from(it, api) }
|
||||
this@MovieViewModel.similar.setValueOnMain(similar)
|
||||
}
|
||||
}
|
||||
|
||||
fun setWatched(played: Boolean) =
|
||||
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
||||
if (played) {
|
||||
api.playStateApi.markPlayedItem(itemUuid)
|
||||
api.playStateApi.markPlayedItem(itemId)
|
||||
} else {
|
||||
api.playStateApi.markUnplayedItem(itemUuid)
|
||||
api.playStateApi.markUnplayedItem(itemId)
|
||||
}
|
||||
fetchAndSetItem(itemUuid)
|
||||
fetchAndSetItem()
|
||||
}
|
||||
|
||||
fun setFavorite(favorite: Boolean) =
|
||||
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
||||
if (favorite) {
|
||||
api.userLibraryApi.markFavoriteItem(itemUuid)
|
||||
api.userLibraryApi.markFavoriteItem(itemId)
|
||||
} else {
|
||||
api.userLibraryApi.unmarkFavoriteItem(itemUuid)
|
||||
api.userLibraryApi.unmarkFavoriteItem(itemId)
|
||||
}
|
||||
fetchAndSetItem(itemUuid)
|
||||
fetchAndSetItem()
|
||||
}
|
||||
|
||||
fun savePlayVersion(
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ kotlin = "2.2.21"
|
|||
ksp = "2.3.0"
|
||||
coreKtx = "1.17.0"
|
||||
appcompat = "1.7.1"
|
||||
composeBom = "2025.10.01"
|
||||
composeBom = "2025.11.00"
|
||||
compose-runtime = "1.9.4"
|
||||
multiplatformMarkdownRenderer = "0.37.0"
|
||||
multiplatformMarkdownRenderer = "0.38.1"
|
||||
programguide = "1.6.0"
|
||||
slf4j2Timber = "1.2"
|
||||
timber = "5.0.1"
|
||||
|
|
@ -23,8 +23,8 @@ activityCompose = "1.11.0"
|
|||
androidx-media3 = "1.8.0"
|
||||
coil = "3.3.0"
|
||||
jellyfin-sdk = "1.7.1"
|
||||
nav3Core = "1.0.0-beta01"
|
||||
lifecycleViewmodelNav3 = "2.10.0-beta01"
|
||||
nav3Core = "1.0.0-rc01"
|
||||
lifecycleViewmodelNav3 = "2.10.0-rc01"
|
||||
material3AdaptiveNav3 = "1.0.0-alpha03"
|
||||
protobuf = "0.9.5"
|
||||
datastore = "1.1.7"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue