More options for movies

This commit is contained in:
Damontecres 2025-10-07 15:37:42 -04:00
parent 4d603d9d41
commit 4f3dbcac6e
No known key found for this signature in database
3 changed files with 92 additions and 10 deletions

View file

@ -9,6 +9,7 @@ import org.jellyfin.sdk.api.client.extensions.imageApi
import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.ImageType
import org.jellyfin.sdk.model.extensions.ticks
@Serializable
data class BaseItem(
@ -25,6 +26,13 @@ data class BaseItem(
@Transient
val indexNumber = data.indexNumber
@Transient
val resumeMs =
data.userData
?.playbackPositionTicks
?.ticks
?.inWholeMilliseconds
fun destination(): Destination {
val result =
// Redirect episodes & seasons to their series if possible

View file

@ -11,6 +11,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@ -41,6 +44,9 @@ import com.github.damontecres.dolphin.data.model.Video
import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.cards.ChapterRow
import com.github.damontecres.dolphin.ui.cards.PersonRow
import com.github.damontecres.dolphin.ui.components.DialogItem
import com.github.damontecres.dolphin.ui.components.DialogParams
import com.github.damontecres.dolphin.ui.components.DialogPopup
import com.github.damontecres.dolphin.ui.components.ErrorMessage
import com.github.damontecres.dolphin.ui.components.ExpandablePlayButtons
import com.github.damontecres.dolphin.ui.components.LoadingPage
@ -55,9 +61,11 @@ import com.github.damontecres.dolphin.ui.tryRequestFocus
import com.github.damontecres.dolphin.util.ExceptionHandler
import com.github.damontecres.dolphin.util.LoadingState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.playStateApi
import org.jellyfin.sdk.model.extensions.ticks
import java.util.UUID
import javax.inject.Inject
@ -69,14 +77,16 @@ class MovieViewModel
constructor(
api: ApiClient,
) : LoadingItemViewModel<Video>(api) {
private lateinit var itemId: UUID
val people = MutableLiveData<List<Person>>(listOf())
val chapters = MutableLiveData<List<Chapter>>(listOf())
override fun init(
itemId: UUID,
potential: BaseItem?,
): Job? =
viewModelScope.launch(ExceptionHandler()) {
): Job? {
this.itemId = itemId
return viewModelScope.launch(ExceptionHandler()) {
super.init(itemId, potential)?.join()
item.value?.let { item ->
people.value =
@ -88,6 +98,17 @@ class MovieViewModel
}
}
fun setWatched(played: Boolean) =
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
if (played) {
api.playStateApi.markPlayedItem(itemId)
} else {
api.playStateApi.markUnplayedItem(itemId)
}
init(itemId, null)
}
}
@Composable
fun MovieDetails(
preferences: UserPreferences,
@ -105,6 +126,7 @@ fun MovieDetails(
val loading by viewModel.loading.observeAsState(LoadingState.Loading)
var overviewDialog by remember { mutableStateOf<ItemDetailsDialogInfo?>(null) }
var moreDialog by remember { mutableStateOf<DialogParams?>(null) }
when (val state = loading) {
is LoadingState.Error -> ErrorMessage(state)
@ -137,8 +159,46 @@ fun MovieDetails(
.orEmpty(),
)
},
moreOnClick = {},
watchOnClick = {},
moreOnClick = {
moreDialog =
DialogParams(
fromLongClick = false,
title = movie.name + " (${movie.data.productionYear ?: ""})",
items =
listOf(
DialogItem(
"Play",
Icons.Default.PlayArrow,
iconColor = Color.Green.copy(alpha = .8f),
) {
navigationManager.navigateTo(
Destination.Playback(
movie.id,
movie.resumeMs ?: 0L,
movie,
),
)
},
DialogItem(
"Playback Settings",
Icons.Default.Settings,
// iconColor = Color.Green.copy(alpha = .8f),
) {
// TODO choose audio or subtitle tracks?
},
DialogItem(
"Play Version",
Icons.Default.PlayArrow,
iconColor = Color.Green.copy(alpha = .8f),
) {
// TODO only show for multiple files
},
),
)
},
watchOnClick = {
viewModel.setWatched((movie.data.userData?.played ?: false).not())
},
modifier = modifier,
)
}
@ -151,6 +211,16 @@ fun MovieDetails(
modifier = Modifier,
)
}
moreDialog?.let { params ->
DialogPopup(
showDialog = true,
title = params.title,
dialogItems = params.items,
onDismissRequest = { moreDialog = null },
dismissOnClick = true,
waitToLoad = params.fromLongClick,
)
}
}
@Composable

View file

@ -3,6 +3,7 @@ package com.github.damontecres.dolphin.ui.detail.series
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@ -192,11 +193,7 @@ fun SeriesOverview(
navigationManager.navigateTo(
Destination.Playback(
ep.id,
ep.data.userData
?.playbackPositionTicks
?.ticks
?.inWholeMilliseconds
?: 0L,
ep.resumeMs ?: 0L,
ep,
),
)
@ -215,12 +212,19 @@ fun SeriesOverview(
),
)
},
DialogItem(
"Playback Settings",
Icons.Default.Settings,
// iconColor = Color.Green.copy(alpha = .8f),
) {
// TODO choose audio or subtitle tracks?
},
DialogItem(
"Play Version",
Icons.Default.PlayArrow,
iconColor = Color.Green.copy(alpha = .8f),
) {
// TODO
// TODO only show for multiple files
},
),
)