feature: add season and episode numbers to every episode occurence

This commit is contained in:
2026-01-26 17:37:10 +01:00
parent 3dc9ec7524
commit 71812f076f
12 changed files with 32 additions and 13 deletions

View File

@@ -16,6 +16,8 @@ object ContentMockData {
val episode1 = SeriesEpisodeUiModel( val episode1 = SeriesEpisodeUiModel(
id = "1", id = "1",
title = "E1: The Beginning", title = "E1: The Beginning",
seasonNumber = 1,
episodeNumber = 1,
description = "The crew assembles for the first time as the anomaly begins to expand rapidly near Saturn's rings.", description = "The crew assembles for the first time as the anomaly begins to expand rapidly near Saturn's rings.",
duration = "58m", duration = "58m",
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuC6OPszCXCIP_FMO3BJJUrjpCtDNw9aeHYOGyOAXdqF078hDFNrH7KXbaQ7qtipz6aIPLivd8VBBffNMbeAiYIjjWjn5GMb6Xn9iiJz0D2rzhCKi0TBeFrN6tC1IXJkzQyQKJNhTnyokWy9dd-YtN65V7er7RT6hP5jdVBXhtK1xZMjlgrm1bk_FTTmKd8Afu3zPtJCaaC98Z608vav5zhYlkrdA1wKNSTWTpzwMSyDIY3pNQNPFauWf0n-iEu7QsYTAwhCG_zfxz0", imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuC6OPszCXCIP_FMO3BJJUrjpCtDNw9aeHYOGyOAXdqF078hDFNrH7KXbaQ7qtipz6aIPLivd8VBBffNMbeAiYIjjWjn5GMb6Xn9iiJz0D2rzhCKi0TBeFrN6tC1IXJkzQyQKJNhTnyokWy9dd-YtN65V7er7RT6hP5jdVBXhtK1xZMjlgrm1bk_FTTmKd8Afu3zPtJCaaC98Z608vav5zhYlkrdA1wKNSTWTpzwMSyDIY3pNQNPFauWf0n-iEu7QsYTAwhCG_zfxz0",
@@ -25,6 +27,8 @@ object ContentMockData {
val episode2 = SeriesEpisodeUiModel( val episode2 = SeriesEpisodeUiModel(
id = "2", id = "2",
title = "E2: Event Horizon", title = "E2: Event Horizon",
seasonNumber = 1,
episodeNumber = 2,
description = "Dr. Cole discovers a frequency embedded in the rift's radiation that suggests intelligent design.", description = "Dr. Cole discovers a frequency embedded in the rift's radiation that suggests intelligent design.",
duration = "54m", duration = "54m",
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBExsf-wEzAVjMxasU2ImGhlreqQo9biBSN1yHyAbW8MyuhuppRw9ho7OD3vsbySSJ3kNluEgH1Qun45PmLnZWixZsFU4Qc7UGGJNKMS5Nkm4GZAsKdFvb3z_i1tkCvaXXvGpqmwI0qjFuo1QyjjhYPA5Yp3I8ZhrnDYdQv_GxbhR6Vl3mY1rbxd2BIUEE5oMTwTF-QmJztUEaViZkSGSG2VgVXZ5VAREn4xWE902OH2sysllvXQJQIaj439JIC2_Vg61m0-F-F1Vc", imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBExsf-wEzAVjMxasU2ImGhlreqQo9biBSN1yHyAbW8MyuhuppRw9ho7OD3vsbySSJ3kNluEgH1Qun45PmLnZWixZsFU4Qc7UGGJNKMS5Nkm4GZAsKdFvb3z_i1tkCvaXXvGpqmwI0qjFuo1QyjjhYPA5Yp3I8ZhrnDYdQv_GxbhR6Vl3mY1rbxd2BIUEE5oMTwTF-QmJztUEaViZkSGSG2VgVXZ5VAREn4xWE902OH2sysllvXQJQIaj439JIC2_Vg61m0-F-F1Vc",
@@ -34,6 +38,8 @@ object ContentMockData {
val episode3 = SeriesEpisodeUiModel( val episode3 = SeriesEpisodeUiModel(
id = "3", id = "3",
title = "E3: Singularity", title = "E3: Singularity",
seasonNumber = 1,
episodeNumber = 3,
description = "Tension rises as the ship approaches the event horizon, and the AI begins to behave erratically.", description = "Tension rises as the ship approaches the event horizon, and the AI begins to behave erratically.",
duration = "1h 02m", duration = "1h 02m",
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuA5CFDWsWYO4YxdRoLd2QfH5Su2KLhtj5xSDb8qmzWHvPE888ac_HAAj1wu1uqdFNSncdmmJ-bWsc--h6NYKxVXkhd4vHaFWi0XTJXgsR0F3cBu_l2SynSX4TMNSy5C3XWDurgeSH789byOe1HvoxHCHTJYaSf3OyEbil-NOp9g_9mZ24CIZOI79nx57CRzmooxoswycqssPpfTNkrnoYrrAczt5qbncwLM9NVU442YxyBFisr2Ds9H-CNBOakiCtaKnoJ6npznM7U", imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuA5CFDWsWYO4YxdRoLd2QfH5Su2KLhtj5xSDb8qmzWHvPE888ac_HAAj1wu1uqdFNSncdmmJ-bWsc--h6NYKxVXkhd4vHaFWi0XTJXgsR0F3cBu_l2SynSX4TMNSy5C3XWDurgeSH789byOe1HvoxHCHTJYaSf3OyEbil-NOp9g_9mZ24CIZOI79nx57CRzmooxoswycqssPpfTNkrnoYrrAczt5qbncwLM9NVU442YxyBFisr2Ds9H-CNBOakiCtaKnoJ6npznM7U",
@@ -154,6 +160,8 @@ object ContentMockData {
return EpisodeUiModel( return EpisodeUiModel(
id = UUID.randomUUID(), id = UUID.randomUUID(),
title = "S1E1 · Event Horizon", title = "S1E1 · Event Horizon",
seasonNumber = 1,
episodeNumber = 1,
releaseDate = "Oct 12, 2024", releaseDate = "Oct 12, 2024",
rating = "TV-MA", rating = "TV-MA",
runtime = "58m", runtime = "58m",

View File

@@ -89,6 +89,13 @@ internal fun EpisodeDetails(
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
lineHeight = 38.sp lineHeight = 38.sp
) )
Spacer(modifier = Modifier.height(4.dp))
Text(
text = "Season ${episode.seasonNumber}, Episode ${episode.episodeNumber}",
color = scheme.onBackground,
fontSize = 14.sp,
fontWeight = FontWeight.Medium
)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
FlowRow( FlowRow(
horizontalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),

View File

@@ -11,6 +11,8 @@ data class CastMember(
data class EpisodeUiModel( data class EpisodeUiModel(
val id: UUID, val id: UUID,
val title: String, val title: String,
val seasonNumber: Int,
val episodeNumber: Int,
val releaseDate: String, val releaseDate: String,
val rating: String, val rating: String,
val runtime: String, val runtime: String,

View File

@@ -70,7 +70,7 @@ private fun EpisodeScreenInternal(
MediaHero( MediaHero(
imageUrl = episode.heroImageUrl, imageUrl = episode.heroImageUrl,
backgroundColor = MaterialTheme.colorScheme.background, backgroundColor = MaterialTheme.colorScheme.background,
height = 300.dp, height = 250.dp,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
EpisodeDetails( EpisodeDetails(

View File

@@ -91,6 +91,8 @@ class EpisodeScreenViewModel @Inject constructor(
return EpisodeUiModel( return EpisodeUiModel(
id = id, id = id,
title = name ?: "Unknown title", title = name ?: "Unknown title",
seasonNumber = parentIndexNumber!!,
episodeNumber = indexNumber!!,
releaseDate = releaseDate, releaseDate = releaseDate,
rating = rating, rating = rating,
runtime = runtime, runtime = runtime,

View File

@@ -65,7 +65,7 @@ private fun MovieScreenInternal(
MediaHero( MediaHero(
imageUrl = movie.heroImageUrl, imageUrl = movie.heroImageUrl,
backgroundColor = MaterialTheme.colorScheme.background, backgroundColor = MaterialTheme.colorScheme.background,
height = 300.dp, height = 250.dp,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
MovieDetails( MovieDetails(

View File

@@ -249,22 +249,21 @@ private fun EpisodeCard(
} }
} }
Column( Column(
verticalArrangement = Arrangement.spacedBy(6.dp) //verticalArrangement = Arrangement.spacedBy(2.dp)
) { ) {
Text( Text(
text = episode.title, text = episode.title,
color = scheme.onBackground, color = scheme.onBackground,
fontSize = 13.sp, fontSize = 14.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
Text( Text(
text = episode.description, text = "S${episode.seasonNumber} • E${episode.episodeNumber}",
color = mutedStrong, color = mutedStrong,
fontSize = 11.sp, fontSize = 12.sp,
lineHeight = 16.sp, maxLines = 1,
maxLines = 2,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
} }

View File

@@ -3,6 +3,8 @@ package hu.bbara.purefin.app.content.series
data class SeriesEpisodeUiModel( data class SeriesEpisodeUiModel(
val id: String, val id: String,
val title: String, val title: String,
val seasonNumber: Int,
val episodeNumber: Int,
val description: String, val description: String,
val duration: String, val duration: String,
val imageUrl: String, val imageUrl: String,

View File

@@ -90,7 +90,7 @@ private fun SeriesScreenInternal(
) { ) {
MediaHero( MediaHero(
imageUrl = series.heroImageUrl, imageUrl = series.heroImageUrl,
height = 350.dp, height = 250.dp,
backgroundColor = MaterialTheme.colorScheme.background, backgroundColor = MaterialTheme.colorScheme.background,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
@@ -125,7 +125,6 @@ private fun SeriesScreenInternal(
selectedSeason = selectedSeason.value, selectedSeason = selectedSeason.value,
onSelect = { selectedSeason.value = it } onSelect = { selectedSeason.value = it }
) )
// Spacer(modifier = Modifier.height(16.dp))
EpisodeCarousel( EpisodeCarousel(
episodes = selectedSeason.value.episodes episodes = selectedSeason.value.episodes
) )

View File

@@ -77,6 +77,8 @@ class SeriesViewModel @Inject constructor(
SeriesEpisodeUiModel( SeriesEpisodeUiModel(
id = episode.id.toString(), id = episode.id.toString(),
title = episode.name ?: "Unknown", title = episode.name ?: "Unknown",
seasonNumber = episode.parentIndexNumber!!,
episodeNumber = episode.indexNumber!!,
description = episode.overview ?: "", description = episode.overview ?: "",
duration = "58m", duration = "58m",
imageUrl = JellyfinImageHelper.toImageUrl(url = serverUrl, itemId = episode.id, type = ImageType.PRIMARY), imageUrl = JellyfinImageHelper.toImageUrl(url = serverUrl, itemId = episode.id, type = ImageType.PRIMARY),

View File

@@ -98,7 +98,7 @@ class HomePageViewModel @Inject constructor(
id = it.id, id = it.id,
type = BaseItemKind.EPISODE, type = BaseItemKind.EPISODE,
primaryText = it.seriesName!!, primaryText = it.seriesName!!,
secondaryText = it.name!!, secondaryText = "S${it.parentIndexNumber!!}:${it.indexNumber!!} - ${it.name!!}",
progress = it.userData!!.playedPercentage!!, progress = it.userData!!.playedPercentage!!,
colors = listOf(Color.Red, Color.Green), colors = listOf(Color.Red, Color.Green),
) )

View File

@@ -89,8 +89,6 @@ class JellyfinApiClient @Inject constructor(
val getResumeItemsRequest = GetResumeItemsRequest( val getResumeItemsRequest = GetResumeItemsRequest(
userId = userId, userId = userId,
startIndex = 0, startIndex = 0,
//TODO remove this limit if needed
// limit = 10
) )
val response: Response<BaseItemDtoQueryResult> = api.itemsApi.getResumeItems(getResumeItemsRequest) val response: Response<BaseItemDtoQueryResult> = api.itemsApi.getResumeItems(getResumeItemsRequest)
Log.d("getContinueWatching response: {}", response.content.toString()) Log.d("getContinueWatching response: {}", response.content.toString())