Bump dependency versions (#170)

Also tries out using assisted injection for item IDs

No user facing changes
This commit is contained in:
damontecres 2025-11-07 10:09:59 -05:00 committed by GitHub
parent bdc475e7b6
commit 18556b5058
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 106 additions and 70 deletions

View file

@ -39,6 +39,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.LifecycleStartEffect import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.tv.material3.MaterialTheme import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text import androidx.tv.material3.Text
@ -89,12 +90,16 @@ fun MovieDetails(
preferences: UserPreferences, preferences: UserPreferences,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: MovieViewModel = hiltViewModel(), viewModel: MovieViewModel =
hiltViewModel<MovieViewModel, MovieViewModel.Factory>(
creationCallback = { it.create(destination.itemId) },
),
playlistViewModel: AddPlaylistViewModel = hiltViewModel(), playlistViewModel: AddPlaylistViewModel = hiltViewModel(),
) { ) {
val context = LocalContext.current val context = LocalContext.current
LaunchedEffect(Unit) { LifecycleResumeEffect(Unit) {
viewModel.init(destination.itemId) viewModel.init()
onPauseOrDispose { }
} }
val item by viewModel.item.observeAsState() val item by viewModel.item.observeAsState()
val people by viewModel.people.observeAsState(listOf()) val people by viewModel.people.observeAsState(listOf())

View file

@ -2,6 +2,7 @@ package com.github.damontecres.wholphin.ui.detail.movie
import android.content.Context import android.content.Context
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ChosenStreams 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.data.model.Trailer
import com.github.damontecres.wholphin.preferences.ThemeSongVolume import com.github.damontecres.wholphin.preferences.ThemeSongVolume
import com.github.damontecres.wholphin.ui.SlimItemFields 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.launchIO
import com.github.damontecres.wholphin.ui.letNotEmpty import com.github.damontecres.wholphin.ui.letNotEmpty
import com.github.damontecres.wholphin.ui.nav.Destination 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.LoadingExceptionHandler
import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.LoadingState
import com.github.damontecres.wholphin.util.ThemeSongPlayer 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.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.ApiClient 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.MediaStreamType
import org.jellyfin.sdk.model.api.request.GetSimilarItemsRequest import org.jellyfin.sdk.model.api.request.GetSimilarItemsRequest
import java.util.UUID import java.util.UUID
import javax.inject.Inject
@HiltViewModel @HiltViewModel(assistedFactory = MovieViewModel.Factory::class)
class MovieViewModel class MovieViewModel
@Inject @AssistedInject
constructor( constructor(
api: ApiClient, private val api: ApiClient,
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
private val navigationManager: NavigationManager, private val navigationManager: NavigationManager,
val serverRepository: ServerRepository, val serverRepository: ServerRepository,
val itemPlaybackRepository: ItemPlaybackRepository, val itemPlaybackRepository: ItemPlaybackRepository,
private val themeSongPlayer: ThemeSongPlayer, 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 trailers = MutableLiveData<List<Trailer>>(listOf())
val people = MutableLiveData<List<Person>>(listOf()) val people = MutableLiveData<List<Person>>(listOf())
val chapters = MutableLiveData<List<Chapter>>(listOf()) val chapters = MutableLiveData<List<Chapter>>(listOf())
val similar = MutableLiveData<List<BaseItem>>() val similar = MutableLiveData<List<BaseItem>>()
val chosenStreams = MutableLiveData<ChosenStreams?>(null) 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( viewModelScope.launch(
Dispatchers.IO + Dispatchers.IO +
LoadingExceptionHandler( LoadingExceptionHandler(
@ -66,10 +98,10 @@ class MovieViewModel
"Error fetching movie", "Error fetching movie",
), ),
) { ) {
fetchAndSetItem(itemId) val item = fetchAndSetItem().await()
item.value?.let { item ->
val result = itemPlaybackRepository.getSelectedTracks(item.id, item) val result = itemPlaybackRepository.getSelectedTracks(item.id, item)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
this@MovieViewModel.item.value = item
chosenStreams.value = result chosenStreams.value = result
loading.value = LoadingState.Success loading.value = LoadingState.Success
} }
@ -124,26 +156,25 @@ class MovieViewModel
this@MovieViewModel.similar.setValueOnMain(similar) this@MovieViewModel.similar.setValueOnMain(similar)
} }
} }
}
fun setWatched(played: Boolean) = fun setWatched(played: Boolean) =
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) { viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
if (played) { if (played) {
api.playStateApi.markPlayedItem(itemUuid) api.playStateApi.markPlayedItem(itemId)
} else { } else {
api.playStateApi.markUnplayedItem(itemUuid) api.playStateApi.markUnplayedItem(itemId)
} }
fetchAndSetItem(itemUuid) fetchAndSetItem()
} }
fun setFavorite(favorite: Boolean) = fun setFavorite(favorite: Boolean) =
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) { viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
if (favorite) { if (favorite) {
api.userLibraryApi.markFavoriteItem(itemUuid) api.userLibraryApi.markFavoriteItem(itemId)
} else { } else {
api.userLibraryApi.unmarkFavoriteItem(itemUuid) api.userLibraryApi.unmarkFavoriteItem(itemId)
} }
fetchAndSetItem(itemUuid) fetchAndSetItem()
} }
fun savePlayVersion( fun savePlayVersion(

View file

@ -10,9 +10,9 @@ kotlin = "2.2.21"
ksp = "2.3.0" ksp = "2.3.0"
coreKtx = "1.17.0" coreKtx = "1.17.0"
appcompat = "1.7.1" appcompat = "1.7.1"
composeBom = "2025.10.01" composeBom = "2025.11.00"
compose-runtime = "1.9.4" compose-runtime = "1.9.4"
multiplatformMarkdownRenderer = "0.37.0" multiplatformMarkdownRenderer = "0.38.1"
programguide = "1.6.0" programguide = "1.6.0"
slf4j2Timber = "1.2" slf4j2Timber = "1.2"
timber = "5.0.1" timber = "5.0.1"
@ -23,8 +23,8 @@ activityCompose = "1.11.0"
androidx-media3 = "1.8.0" androidx-media3 = "1.8.0"
coil = "3.3.0" coil = "3.3.0"
jellyfin-sdk = "1.7.1" jellyfin-sdk = "1.7.1"
nav3Core = "1.0.0-beta01" nav3Core = "1.0.0-rc01"
lifecycleViewmodelNav3 = "2.10.0-beta01" lifecycleViewmodelNav3 = "2.10.0-rc01"
material3AdaptiveNav3 = "1.0.0-alpha03" material3AdaptiveNav3 = "1.0.0-alpha03"
protobuf = "0.9.5" protobuf = "0.9.5"
datastore = "1.1.7" datastore = "1.1.7"