mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Show overlay for extra items (#1320)
## Description Shows the overlay (watched, progress bar) for extras appearing as single items. Grouped extras individually show the overlay when clicking into. If all of the grouped are played, the group is show with the watched indicator. Also very slightly optimizations the UI by offloading the title/subtitle/imageUrl to object creation time instead of when they're shown on screen. ### Related issues Closes #1311 ### Testing Shield testing with different extras ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
8cf99900e5
commit
5571654a22
3 changed files with 69 additions and 42 deletions
|
|
@ -15,7 +15,11 @@ sealed interface ExtrasItem {
|
||||||
val parentId: UUID
|
val parentId: UUID
|
||||||
val type: ExtraType
|
val type: ExtraType
|
||||||
val destination: Destination
|
val destination: Destination
|
||||||
val title: String?
|
val imageUrl: String?
|
||||||
|
val title: String
|
||||||
|
val subtitle: String?
|
||||||
|
val isPlayed: Boolean
|
||||||
|
val playedPercentage: Double
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents multiple extras of the same type
|
* Represents multiple extras of the same type
|
||||||
|
|
@ -24,11 +28,16 @@ sealed interface ExtrasItem {
|
||||||
override val parentId: UUID,
|
override val parentId: UUID,
|
||||||
override val type: ExtraType,
|
override val type: ExtraType,
|
||||||
val items: List<BaseItem>,
|
val items: List<BaseItem>,
|
||||||
|
override val imageUrl: String?,
|
||||||
|
override val title: String,
|
||||||
|
override val subtitle: String,
|
||||||
|
override val isPlayed: Boolean,
|
||||||
) : ExtrasItem {
|
) : ExtrasItem {
|
||||||
override val destination: Destination =
|
override val destination: Destination =
|
||||||
Destination.ItemGrid(null, type.stringRes, items.map { it.id })
|
Destination.ItemGrid(null, type.stringRes, items.map { it.id })
|
||||||
|
|
||||||
override val title: String? = null
|
override val playedPercentage
|
||||||
|
get() = -1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -38,12 +47,18 @@ sealed interface ExtrasItem {
|
||||||
override val parentId: UUID,
|
override val parentId: UUID,
|
||||||
override val type: ExtraType,
|
override val type: ExtraType,
|
||||||
val item: BaseItem,
|
val item: BaseItem,
|
||||||
|
override val imageUrl: String?,
|
||||||
|
override val title: String,
|
||||||
|
override val subtitle: String?,
|
||||||
) : ExtrasItem {
|
) : ExtrasItem {
|
||||||
override val destination: Destination =
|
override val destination: Destination =
|
||||||
Destination.Playback(
|
Destination.Playback(
|
||||||
item = item,
|
item = item,
|
||||||
)
|
)
|
||||||
override val title: String? get() = item.title
|
override val isPlayed: Boolean
|
||||||
|
get() = item.played
|
||||||
|
override val playedPercentage
|
||||||
|
get() = item.data.userData?.playedPercentage ?: 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
package com.github.damontecres.wholphin.services
|
package com.github.damontecres.wholphin.services
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.ExtrasItem
|
import com.github.damontecres.wholphin.data.ExtrasItem
|
||||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
|
import com.github.damontecres.wholphin.data.pluralRes
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import org.jellyfin.sdk.api.client.ApiClient
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||||
import org.jellyfin.sdk.model.api.ExtraType
|
import org.jellyfin.sdk.model.api.ExtraType
|
||||||
|
import org.jellyfin.sdk.model.api.ImageType
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
@ -19,6 +24,8 @@ class ExtrasService
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val api: ApiClient,
|
private val api: ApiClient,
|
||||||
|
@param:ApplicationContext private val context: Context,
|
||||||
|
private val imageUrlService: ImageUrlService,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Get the [ExtrasItem]s for the given item
|
* Get the [ExtrasItem]s for the given item
|
||||||
|
|
@ -39,9 +46,45 @@ class ExtrasService
|
||||||
extrasMap
|
extrasMap
|
||||||
.mapNotNull { (type, items) ->
|
.mapNotNull { (type, items) ->
|
||||||
if (items.size == 1) {
|
if (items.size == 1) {
|
||||||
ExtrasItem.Single(itemId, type, items.first())
|
val item = items.first()
|
||||||
|
val title =
|
||||||
|
item.title ?: context.resources.getQuantityString(type.pluralRes, 1)
|
||||||
|
val subtitle =
|
||||||
|
if (item.title == null) {
|
||||||
|
context.resources.getQuantityString(type.pluralRes, 1)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
ExtrasItem.Single(
|
||||||
|
parentId = itemId,
|
||||||
|
type = type,
|
||||||
|
item = item,
|
||||||
|
title = title,
|
||||||
|
subtitle = subtitle,
|
||||||
|
imageUrl = imageUrlService.getItemImageUrl(item, ImageType.PRIMARY),
|
||||||
|
)
|
||||||
} else if (items.size > 1) {
|
} else if (items.size > 1) {
|
||||||
ExtrasItem.Group(itemId, type, items)
|
val title =
|
||||||
|
context.resources.getQuantityString(type.pluralRes, items.size)
|
||||||
|
val subtitle =
|
||||||
|
context.resources.getQuantityString(
|
||||||
|
R.plurals.items,
|
||||||
|
items.size,
|
||||||
|
items.size,
|
||||||
|
)
|
||||||
|
ExtrasItem.Group(
|
||||||
|
parentId = itemId,
|
||||||
|
type = type,
|
||||||
|
items = items,
|
||||||
|
title = title,
|
||||||
|
subtitle = subtitle,
|
||||||
|
isPlayed = items.all { it.played },
|
||||||
|
imageUrl =
|
||||||
|
imageUrlService.getItemImageUrl(
|
||||||
|
items.random(),
|
||||||
|
ImageType.PRIMARY,
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,13 @@
|
||||||
package com.github.damontecres.wholphin.ui.cards
|
package com.github.damontecres.wholphin.ui.cards
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalResources
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.ExtrasItem
|
import com.github.damontecres.wholphin.data.ExtrasItem
|
||||||
import com.github.damontecres.wholphin.data.pluralRes
|
|
||||||
import com.github.damontecres.wholphin.ui.AspectRatios
|
import com.github.damontecres.wholphin.ui.AspectRatios
|
||||||
import com.github.damontecres.wholphin.ui.Cards
|
import com.github.damontecres.wholphin.ui.Cards
|
||||||
import com.github.damontecres.wholphin.ui.LocalImageUrlService
|
|
||||||
import org.jellyfin.sdk.model.api.ImageType
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ExtrasRow(
|
fun ExtrasRow(
|
||||||
|
|
@ -22,52 +16,27 @@ fun ExtrasRow(
|
||||||
onLongClickItem: (Int, ExtrasItem) -> Unit,
|
onLongClickItem: (Int, ExtrasItem) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
|
||||||
val resources = LocalResources.current
|
|
||||||
ItemRow(
|
ItemRow(
|
||||||
title = stringResource(R.string.extras),
|
title = stringResource(R.string.extras),
|
||||||
items = extras,
|
items = extras,
|
||||||
onClickItem = onClickItem,
|
onClickItem = onClickItem,
|
||||||
onLongClickItem = onLongClickItem,
|
onLongClickItem = onLongClickItem,
|
||||||
cardContent = { index, item, mod, onClick, onLongClick ->
|
cardContent = { index, item, mod, onClick, onLongClick ->
|
||||||
val imageUrlService = LocalImageUrlService.current
|
|
||||||
val imageUrl =
|
|
||||||
remember {
|
|
||||||
val item =
|
|
||||||
when (item) {
|
|
||||||
is ExtrasItem.Group -> item.items.random()
|
|
||||||
is ExtrasItem.Single -> item.item
|
|
||||||
null -> null
|
|
||||||
}
|
|
||||||
imageUrlService.getItemImageUrl(item, ImageType.PRIMARY)
|
|
||||||
}
|
|
||||||
SeasonCard(
|
SeasonCard(
|
||||||
title =
|
title = item?.title,
|
||||||
when (item) {
|
|
||||||
is ExtrasItem.Group -> item.type.pluralRes.let { resources.getQuantityString(it, item.items.size) }
|
|
||||||
is ExtrasItem.Single -> item.title ?: item.type.pluralRes.let { resources.getQuantityString(it, 1) }
|
|
||||||
null -> null
|
|
||||||
},
|
|
||||||
name = null,
|
name = null,
|
||||||
subtitle =
|
subtitle = item?.subtitle,
|
||||||
if (item is ExtrasItem.Single && item.title != null) {
|
|
||||||
item.type.pluralRes.let { resources.getQuantityString(it, 1) }
|
|
||||||
} else if (item is ExtrasItem.Group) {
|
|
||||||
resources.getQuantityString(R.plurals.items, item.items.size, item.items.size)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
},
|
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
modifier = mod,
|
modifier = mod,
|
||||||
showImageOverlay = true,
|
showImageOverlay = true,
|
||||||
imageHeight = Cards.height2x3 * .75f,
|
imageHeight = Cards.heightEpisode,
|
||||||
imageWidth = Dp.Unspecified,
|
imageWidth = Dp.Unspecified,
|
||||||
imageUrl = imageUrl,
|
imageUrl = item?.imageUrl,
|
||||||
isFavorite = false,
|
isFavorite = false,
|
||||||
isPlayed = false,
|
isPlayed = item?.isPlayed == true,
|
||||||
unplayedItemCount = -1,
|
unplayedItemCount = -1,
|
||||||
playedPercentage = -1.0,
|
playedPercentage = item?.playedPercentage ?: 0.0,
|
||||||
numberOfVersions = -1,
|
numberOfVersions = -1,
|
||||||
aspectRatio = AspectRatios.FOUR_THREE, // TODO
|
aspectRatio = AspectRatios.FOUR_THREE, // TODO
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue