mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Show indicator for multiple versions of media file (#652)
## Description Adds an indicator to cards on grid pages if there are more than a single version of the item. Also adds the count to the video stream label, much like for multiple audio/subtitle tracks. No behavior changes, just visual changes. You still need to select the version from More->Choose Version. ### Related issues Closes #612 ### Screenshots <img width="535" height="476" alt="image" src="https://github.com/user-attachments/assets/5bf80d36-7abd-4a0e-a14d-062439f024d9" /> <img width="958" height="581" alt="image" src="https://github.com/user-attachments/assets/e3a0ac4e-a283-4bcf-bc16-e61d81401207" />
This commit is contained in:
parent
d2e0d527dd
commit
2cd34692e9
13 changed files with 67 additions and 19 deletions
|
|
@ -51,6 +51,7 @@ val DefaultItemFields =
|
|||
ItemFields.SORT_NAME,
|
||||
ItemFields.CHAPTERS,
|
||||
ItemFields.MEDIA_SOURCES,
|
||||
ItemFields.MEDIA_SOURCE_COUNT,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
@ -63,6 +64,7 @@ val SlimItemFields =
|
|||
ItemFields.CHILD_COUNT,
|
||||
ItemFields.OVERVIEW,
|
||||
ItemFields.SORT_NAME,
|
||||
ItemFields.MEDIA_SOURCE_COUNT,
|
||||
)
|
||||
|
||||
object Cards {
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ fun EpisodeCard(
|
|||
watched = dto?.userData?.played ?: false,
|
||||
unwatchedCount = dto?.userData?.unplayedItemCount ?: -1,
|
||||
watchedPercent = dto?.userData?.playedPercentage,
|
||||
numberOfVersions = dto?.mediaSourceCount ?: 0,
|
||||
useFallbackText = false,
|
||||
modifier =
|
||||
Modifier
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ fun ExtrasRow(
|
|||
isPlayed = false,
|
||||
unplayedItemCount = -1,
|
||||
playedPercentage = -1.0,
|
||||
numberOfVersions = -1,
|
||||
aspectRatio = AspectRatios.FOUR_THREE, // TODO
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ fun GridCard(
|
|||
watched = dto?.userData?.played ?: false,
|
||||
unwatchedCount = dto?.userData?.unplayedItemCount ?: -1,
|
||||
watchedPercent = dto?.userData?.playedPercentage,
|
||||
numberOfVersions = dto?.mediaSourceCount ?: 0,
|
||||
useFallbackText = false,
|
||||
contentScale = imageContentScale,
|
||||
modifier =
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ fun ItemCardImage(
|
|||
watched: Boolean,
|
||||
unwatchedCount: Int,
|
||||
watchedPercent: Double?,
|
||||
numberOfVersions: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
imageType: ImageType = ImageType.PRIMARY,
|
||||
useFallbackText: Boolean = true,
|
||||
|
|
@ -86,6 +87,7 @@ fun ItemCardImage(
|
|||
watched = watched,
|
||||
unwatchedCount = unwatchedCount,
|
||||
watchedPercent = watchedPercent,
|
||||
numberOfVersions = numberOfVersions,
|
||||
modifier =
|
||||
modifier.onLayoutRectChanged(
|
||||
throttleMillis = 100,
|
||||
|
|
@ -107,6 +109,7 @@ fun ItemCardImage(
|
|||
watched: Boolean,
|
||||
unwatchedCount: Int,
|
||||
watchedPercent: Double?,
|
||||
numberOfVersions: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
useFallbackText: Boolean = true,
|
||||
contentScale: ContentScale = ContentScale.Fit,
|
||||
|
|
@ -143,6 +146,7 @@ fun ItemCardImage(
|
|||
watched = watched,
|
||||
unwatchedCount = unwatchedCount,
|
||||
watchedPercent = watchedPercent,
|
||||
numberOfVersions = numberOfVersions,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -198,21 +202,46 @@ fun ItemCardImageOverlay(
|
|||
watched: Boolean,
|
||||
unwatchedCount: Int,
|
||||
watchedPercent: Double?,
|
||||
numberOfVersions: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier.fillMaxSize()) {
|
||||
if (favorite) {
|
||||
Text(
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.padding(8.dp),
|
||||
.padding(4.dp),
|
||||
) {
|
||||
if (numberOfVersions > 1) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.background(
|
||||
AppColors.TransparentBlack50,
|
||||
shape = RoundedCornerShape(25),
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = numberOfVersions.toString(),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
// fontSize = 16.sp,
|
||||
modifier = Modifier.padding(4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
if (favorite) {
|
||||
Text(
|
||||
color = colorResource(android.R.color.holo_red_light),
|
||||
text = stringResource(R.string.fa_heart),
|
||||
fontSize = 20.sp,
|
||||
fontFamily = FontAwesome,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ fun PersonCard(
|
|||
favorite = item.favorite,
|
||||
watched = false,
|
||||
unwatchedCount = -1,
|
||||
numberOfVersions = -1,
|
||||
watchedPercent = null,
|
||||
useFallbackText = false,
|
||||
modifier =
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ fun SeasonCard(
|
|||
isPlayed = item?.data?.userData?.played ?: false,
|
||||
unplayedItemCount = item?.data?.userData?.unplayedItemCount ?: 0,
|
||||
playedPercentage = item?.data?.userData?.playedPercentage ?: 0.0,
|
||||
numberOfVersions = item?.data?.mediaSourceCount ?: 0,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
modifier = modifier,
|
||||
|
|
@ -112,6 +113,7 @@ fun SeasonCard(
|
|||
isPlayed: Boolean,
|
||||
unplayedItemCount: Int,
|
||||
playedPercentage: Double,
|
||||
numberOfVersions: Int,
|
||||
onClick: () -> Unit,
|
||||
onLongClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -172,6 +174,7 @@ fun SeasonCard(
|
|||
watched = isPlayed,
|
||||
unwatchedCount = unplayedItemCount,
|
||||
watchedPercent = playedPercentage,
|
||||
numberOfVersions = numberOfVersions,
|
||||
useFallbackText = false,
|
||||
modifier =
|
||||
Modifier
|
||||
|
|
|
|||
|
|
@ -47,12 +47,14 @@ import org.jellyfin.sdk.model.api.VideoRangeType
|
|||
@NonRestartableComposable
|
||||
fun VideoStreamDetails(
|
||||
chosenStreams: ChosenStreams?,
|
||||
numberOfVersions: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) = VideoStreamDetails(
|
||||
chosenStreams?.source,
|
||||
chosenStreams?.videoStream,
|
||||
chosenStreams?.audioStream,
|
||||
chosenStreams?.subtitleStream,
|
||||
numberOfVersions,
|
||||
modifier,
|
||||
)
|
||||
|
||||
|
|
@ -62,6 +64,7 @@ fun VideoStreamDetails(
|
|||
videoStream: MediaStream?,
|
||||
audioStream: MediaStream?,
|
||||
subtitleStream: MediaStream?,
|
||||
numberOfVersions: Int = 0,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
|
@ -86,13 +89,16 @@ fun VideoStreamDetails(
|
|||
null
|
||||
}
|
||||
val range = formatVideoRange(context, it.videoRange, it.videoRangeType, it.videoDoViTitle)
|
||||
listOfNotNull(
|
||||
resName.concatWithSpace(range),
|
||||
it.codec?.uppercase(),
|
||||
)
|
||||
}.orEmpty()
|
||||
resName.concatWithSpace(range)
|
||||
}
|
||||
video.forEach {
|
||||
}
|
||||
video?.let {
|
||||
StreamLabel(
|
||||
text = it,
|
||||
count = numberOfVersions,
|
||||
)
|
||||
}
|
||||
videoStream?.codec?.uppercase()?.let {
|
||||
StreamLabel(it)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -444,6 +444,7 @@ fun PlaylistItem(
|
|||
watched = item?.data?.userData?.played ?: false,
|
||||
unwatchedCount = item?.data?.userData?.unplayedItemCount ?: -1,
|
||||
watchedPercent = 0.0,
|
||||
numberOfVersions = item?.data?.mediaSourceCount ?: 0,
|
||||
modifier = Modifier.width(160.dp),
|
||||
useFallbackText = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ fun EpisodeDetailsHeader(
|
|||
|
||||
VideoStreamDetails(
|
||||
chosenStreams = chosenStreams,
|
||||
numberOfVersions = dto.mediaSourceCount ?: 0,
|
||||
modifier = Modifier.padding(bottom = padding),
|
||||
)
|
||||
dto.taglines?.firstOrNull()?.let { tagline ->
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ fun MovieDetailsHeader(
|
|||
|
||||
VideoStreamDetails(
|
||||
chosenStreams = chosenStreams,
|
||||
numberOfVersions = movie.data.mediaSourceCount ?: 0,
|
||||
modifier = Modifier.padding(bottom = padding),
|
||||
)
|
||||
dto.taglines?.firstOrNull()?.let { tagline ->
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ fun FocusedEpisodeHeader(
|
|||
if (dto != null) {
|
||||
VideoStreamDetails(
|
||||
chosenStreams = chosenStreams,
|
||||
numberOfVersions = dto.mediaSourceCount ?: 0,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,8 @@ import com.github.damontecres.wholphin.R
|
|||
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||
import com.github.damontecres.wholphin.preferences.AppThemeColors
|
||||
import com.github.damontecres.wholphin.ui.AspectRatios
|
||||
import com.github.damontecres.wholphin.ui.cards.BannerCard
|
||||
import com.github.damontecres.wholphin.ui.cards.SeasonCard
|
||||
import com.github.damontecres.wholphin.ui.cards.WatchedIcon
|
||||
import com.github.damontecres.wholphin.ui.components.ExpandableFaButton
|
||||
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
|
||||
import com.github.damontecres.wholphin.ui.nav.NavItem
|
||||
import com.github.damontecres.wholphin.ui.playback.PlaybackButton
|
||||
|
|
@ -109,6 +107,7 @@ private fun ThemeExample(theme: AppThemeColors) {
|
|||
isPlayed = true,
|
||||
unplayedItemCount = 2,
|
||||
playedPercentage = 50.0,
|
||||
numberOfVersions = 2,
|
||||
onClick = { },
|
||||
onLongClick = {},
|
||||
imageHeight = 120.dp,
|
||||
|
|
@ -125,6 +124,7 @@ private fun ThemeExample(theme: AppThemeColors) {
|
|||
isPlayed = true,
|
||||
unplayedItemCount = 2,
|
||||
playedPercentage = 0.0,
|
||||
numberOfVersions = 0,
|
||||
onClick = { },
|
||||
onLongClick = {},
|
||||
imageHeight = 120.dp,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue