From b0d270380ddea2022e8ca18ecbf448ac6c5692ba Mon Sep 17 00:00:00 2001 From: Damontecres Date: Wed, 30 Sep 2026 17:35:29 -0400 Subject: [PATCH] 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 image ## AI or LLM usage None --- .../wholphin/data/model/BaseItem.kt | 107 ++++++++++++------ .../ui/components/CollectionFolderGrid.kt | 2 + .../wholphin/ui/components/TitleOrLogo.kt | 5 +- .../damontecres/wholphin/ui/main/HomePage.kt | 27 ++++- app/src/main/res/values/strings.xml | 5 + 5 files changed, 108 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt index eefb001b..94dc23c2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt @@ -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 diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt index fc6d132a..1d70553e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt @@ -212,6 +212,8 @@ val CollectionType.baseItemKinds: List CollectionType.HOMEVIDEOS -> { listOf(BaseItemKind.VIDEO) + listOf(BaseItemKind.PHOTO) + listOf(BaseItemKind.PHOTO_ALBUM) } CollectionType.MUSIC -> { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/TitleOrLogo.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/TitleOrLogo.kt index 99288b9a..c5da7565 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/TitleOrLogo.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/TitleOrLogo.kt @@ -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) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt index c2822b4e..bf24ae00 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt @@ -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, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1b0915b5..423530a3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -927,4 +927,9 @@ Remove from playlist Credentials expired, please login in again You are not authorized to access the server at this time + + %1$d Episodes + %1$d Episode + %1$d Episodes +