Better home page header for Seasons (#2016)
## Description Updates the home page header & card text when a Season type is shown, such as in recently added for a TV Show library. The title or logo for the series is shown with the season name as the title. The "quick details" has the year of the season. The card shows the unplayed count of episodes. ### Related issues Closes #1958 ### Testing Emulator over a few days to see different seasons ## Screenshots <img width="313" height="153" alt="image" src="https://github.com/user-attachments/assets/c41e9edd-9f2a-4f62-b76d-e452e83dd8bf" /> ## AI or LLM usage None
This commit is contained in:
parent
cf74736579
commit
b0d270380d
5 changed files with 108 additions and 38 deletions
|
|
@ -112,21 +112,31 @@ data class BaseItem(
|
|||
val ui =
|
||||
BaseItemUi(
|
||||
episodeCornerText =
|
||||
data.indexNumber?.let { formatEpisodeNumber(it) }
|
||||
?: data.premiereDate?.let(::formatDateTime),
|
||||
episodeUnplayedCornerText =
|
||||
if (type == BaseItemKind.SERIES ||
|
||||
type == BaseItemKind.SEASON ||
|
||||
type == BaseItemKind.EPISODE ||
|
||||
type == BaseItemKind.BOX_SET
|
||||
) {
|
||||
if (type == BaseItemKind.EPISODE) {
|
||||
data.indexNumber?.let { formatEpisodeNumber(it) }
|
||||
?: data.userData
|
||||
?: data.premiereDate?.let(::formatDateTime)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
episodeUnplayedCornerText =
|
||||
when (type) {
|
||||
BaseItemKind.EPISODE -> {
|
||||
data.indexNumber?.let { formatEpisodeNumber(it) }
|
||||
}
|
||||
|
||||
BaseItemKind.SERIES,
|
||||
BaseItemKind.SEASON,
|
||||
BaseItemKind.BOX_SET,
|
||||
-> {
|
||||
data.userData
|
||||
?.unplayedItemCount
|
||||
?.takeIf { it > 0 }
|
||||
?.let { abbreviateNumber(it) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
else -> {
|
||||
null
|
||||
}
|
||||
},
|
||||
quickDetails =
|
||||
QuickDetailsData(
|
||||
|
|
@ -134,33 +144,64 @@ data class BaseItem(
|
|||
buildAnnotatedString {
|
||||
val details =
|
||||
buildList {
|
||||
if (type == BaseItemKind.EPISODE) {
|
||||
data.seasonEpisode?.let(::add)
|
||||
data.premiereDate?.let { add(getDateFormatter().format(it)) }
|
||||
} else if (type == BaseItemKind.SERIES) {
|
||||
data.seriesProductionYears?.let(::add)
|
||||
} else if (type == BaseItemKind.PHOTO) {
|
||||
if (data.productionYear != null) {
|
||||
add(data.productionYear!!.toString())
|
||||
} else if (data.premiereDate != null) {
|
||||
add(data.premiereDate!!.toLocalDate().toString())
|
||||
}
|
||||
} else if (type == BaseItemKind.BOX_SET) {
|
||||
data.productionYear?.let { add(it.toString()) }
|
||||
data.childCount?.let { add("$it items") }
|
||||
} else if (type == BaseItemKind.PROGRAM) {
|
||||
data.channelName?.let(::add)
|
||||
if (data.isSeries == true) {
|
||||
// TV episode
|
||||
when (type) {
|
||||
BaseItemKind.EPISODE -> {
|
||||
data.seasonEpisode?.let(::add)
|
||||
data.premiereDate?.let {
|
||||
add(getDateFormatter().format(it))
|
||||
add(
|
||||
getDateFormatter().format(
|
||||
it,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
BaseItemKind.SEASON -> {
|
||||
data.childCount?.let { childCount ->
|
||||
add(
|
||||
WholphinApplication.instance.resources.getQuantityString(
|
||||
R.plurals.episodes_count,
|
||||
childCount,
|
||||
childCount,
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
data.productionYear?.let { add(it.toString()) }
|
||||
}
|
||||
} else {
|
||||
data.productionYear?.let { add(it.toString()) }
|
||||
|
||||
BaseItemKind.SERIES -> {
|
||||
data.seriesProductionYears?.let(::add)
|
||||
}
|
||||
|
||||
BaseItemKind.PHOTO -> {
|
||||
if (data.productionYear != null) {
|
||||
add(data.productionYear!!.toString())
|
||||
} else if (data.premiereDate != null) {
|
||||
add(data.premiereDate!!.toLocalDate().toString())
|
||||
}
|
||||
}
|
||||
|
||||
BaseItemKind.BOX_SET -> {
|
||||
data.productionYear?.let { add(it.toString()) }
|
||||
data.childCount?.let { add("$it items") }
|
||||
}
|
||||
|
||||
BaseItemKind.PROGRAM -> {
|
||||
data.channelName?.let(::add)
|
||||
if (data.isSeries == true) {
|
||||
// TV episode
|
||||
data.seasonEpisode?.let(::add)
|
||||
data.premiereDate?.let {
|
||||
add(getDateFormatter().format(it))
|
||||
}
|
||||
} else {
|
||||
data.productionYear?.let { add(it.toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
data.productionYear?.let { add(it.toString()) }
|
||||
}
|
||||
}
|
||||
data.runTimeTicks
|
||||
?.ticks
|
||||
|
|
|
|||
|
|
@ -212,6 +212,8 @@ val CollectionType.baseItemKinds: List<BaseItemKind>
|
|||
|
||||
CollectionType.HOMEVIDEOS -> {
|
||||
listOf(BaseItemKind.VIDEO)
|
||||
listOf(BaseItemKind.PHOTO)
|
||||
listOf(BaseItemKind.PHOTO_ALBUM)
|
||||
}
|
||||
|
||||
CollectionType.MUSIC -> {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,10 @@ fun TitleOrLogo(
|
|||
fun rememberLogoUrl(item: BaseItem?): String? {
|
||||
val imageUrlService = LocalImageUrlService.current
|
||||
return remember(item?.id) {
|
||||
if (item?.type == BaseItemKind.EPISODE && item.data.seriesId != null && item.data.parentLogoImageTag != null) {
|
||||
if ((item?.type == BaseItemKind.EPISODE || item?.type == BaseItemKind.SEASON) &&
|
||||
item.data.seriesId != null &&
|
||||
item.data.parentLogoImageTag != null
|
||||
) {
|
||||
imageUrlService.getItemImageUrl(item.data.seriesId!!, ImageType.LOGO)
|
||||
} else if (ImageType.LOGO in item?.data?.imageTags.orEmpty()) {
|
||||
imageUrlService.getItemImageUrl(item, ImageType.LOGO)
|
||||
|
|
|
|||
|
|
@ -545,11 +545,30 @@ fun HomePageHeader(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val isEpisode = item?.type == BaseItemKind.EPISODE
|
||||
val dto = item?.data
|
||||
val title =
|
||||
remember(item?.id) {
|
||||
when (item?.type) {
|
||||
BaseItemKind.EPISODE,
|
||||
BaseItemKind.SEASON,
|
||||
-> item.data.seriesName
|
||||
|
||||
else -> item?.title
|
||||
}
|
||||
}
|
||||
val subtitle =
|
||||
remember(item?.id) {
|
||||
when (item?.type) {
|
||||
BaseItemKind.SEASON,
|
||||
BaseItemKind.EPISODE,
|
||||
-> item.name
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
HomePageHeader(
|
||||
title = item?.title,
|
||||
subtitle = if (isEpisode) dto?.name else null,
|
||||
overview = dto?.overview,
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
overview = item?.data?.overview,
|
||||
overviewTwoLines = isEpisode,
|
||||
quickDetails = item?.ui?.quickDetails,
|
||||
timeRemaining = item?.timeRemainingOrRuntime,
|
||||
|
|
|
|||
|
|
@ -927,4 +927,9 @@
|
|||
<string name="remove_from_playlist">Remove from playlist</string>
|
||||
<string name="login_credentials_expired">Credentials expired, please login in again</string>
|
||||
<string name="login_not_authorized">You are not authorized to access the server at this time</string>
|
||||
<plurals name="episodes_count">
|
||||
<item quantity="zero">%1$d Episodes</item>
|
||||
<item quantity="one">%1$d Episode</item>
|
||||
<item quantity="other">%1$d Episodes</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue