mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
feature: add content progress and autoscroll to next up media to SeriesComponents
This commit is contained in:
@@ -18,21 +18,27 @@ object ContentMockData {
|
||||
title = "E1: The Beginning",
|
||||
description = "The crew assembles for the first time as the anomaly begins to expand rapidly near Saturn's rings.",
|
||||
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",
|
||||
progress = 40.0,
|
||||
watched = false
|
||||
)
|
||||
val episode2 = SeriesEpisodeUiModel(
|
||||
id = "2",
|
||||
title = "E2: Event Horizon",
|
||||
description = "Dr. Cole discovers a frequency embedded in the rift's radiation that suggests intelligent design.",
|
||||
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",
|
||||
progress = 100.0,
|
||||
watched = true
|
||||
)
|
||||
val episode3 = SeriesEpisodeUiModel(
|
||||
id = "3",
|
||||
title = "E3: Singularity",
|
||||
description = "Tension rises as the ship approaches the event horizon, and the AI begins to behave erratically.",
|
||||
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",
|
||||
progress = 40.0,
|
||||
watched = false
|
||||
)
|
||||
return SeriesUiModel(
|
||||
title = "Interstellar Horizon: The Series",
|
||||
@@ -45,18 +51,18 @@ object ContentMockData {
|
||||
seasonTabs = listOf(
|
||||
SeriesSeasonUiModel(
|
||||
name = "Season 1",
|
||||
isSelected = true,
|
||||
episodes = listOf(episode1, episode2, episode3)
|
||||
episodes = listOf(episode1, episode2, episode3),
|
||||
unplayedCount = 2
|
||||
),
|
||||
SeriesSeasonUiModel(
|
||||
name = "Season 2",
|
||||
isSelected = false,
|
||||
episodes = listOf(episode1, episode2, episode3)
|
||||
episodes = listOf(episode1, episode2, episode3),
|
||||
unplayedCount = 0
|
||||
),
|
||||
SeriesSeasonUiModel(
|
||||
name = "Season 3",
|
||||
isSelected = false,
|
||||
episodes = listOf(episode1, episode2, episode3)
|
||||
episodes = listOf(episode1, episode2, episode3),
|
||||
unplayedCount = 1
|
||||
)
|
||||
),
|
||||
cast = listOf(
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -34,6 +35,7 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -169,9 +171,20 @@ private fun SeasonTab(
|
||||
|
||||
@Composable
|
||||
internal fun EpisodeCarousel(episodes: List<SeriesEpisodeUiModel>, modifier: Modifier = Modifier) {
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
LaunchedEffect(episodes) {
|
||||
val firstUnwatchedIndex = episodes.indexOfFirst { !it.watched }.let { if (it == -1) 0 else it }
|
||||
if (firstUnwatchedIndex != 0) {
|
||||
listState.animateScrollToItem(firstUnwatchedIndex)
|
||||
} else {
|
||||
listState.scrollToItem(0)
|
||||
}
|
||||
}
|
||||
|
||||
LazyRow(
|
||||
state = listState,
|
||||
modifier = modifier,
|
||||
// contentPadding = PaddingValues(horizontal = 20.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
items(episodes) { episode ->
|
||||
|
||||
@@ -5,13 +5,15 @@ data class SeriesEpisodeUiModel(
|
||||
val title: String,
|
||||
val description: String,
|
||||
val duration: String,
|
||||
val imageUrl: String
|
||||
val imageUrl: String,
|
||||
val watched: Boolean,
|
||||
val progress: Double?
|
||||
)
|
||||
|
||||
data class SeriesSeasonUiModel(
|
||||
val name: String,
|
||||
val isSelected: Boolean,
|
||||
val episodes: List<SeriesEpisodeUiModel>
|
||||
val episodes: List<SeriesEpisodeUiModel>,
|
||||
val unplayedCount: Int?
|
||||
)
|
||||
|
||||
data class SeriesCastMemberUiModel(
|
||||
@@ -30,4 +32,15 @@ data class SeriesUiModel(
|
||||
val heroImageUrl: String,
|
||||
val seasonTabs: List<SeriesSeasonUiModel>,
|
||||
val cast: List<SeriesCastMemberUiModel>
|
||||
)
|
||||
) {
|
||||
fun getNextEpisode(): SeriesEpisodeUiModel {
|
||||
for (season in seasonTabs) {
|
||||
for (episode in season.episodes) {
|
||||
if (!episode.watched) {
|
||||
return episode
|
||||
}
|
||||
}
|
||||
}
|
||||
return seasonTabs.first().episodes.first()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,14 @@ private fun SeriesScreenInternal(
|
||||
val textMutedStrong = scheme.onSurfaceVariant.copy(alpha = 0.7f)
|
||||
|
||||
fun getDefaultSeason() : SeriesSeasonUiModel {
|
||||
// TODO get next next episodes season selected or add logic to it.
|
||||
for (season in series.seasonTabs) {
|
||||
val firstUnwatchedEpisode = season.episodes.firstOrNull {
|
||||
it.watched.not()
|
||||
}
|
||||
if (firstUnwatchedEpisode != null) {
|
||||
return season
|
||||
}
|
||||
}
|
||||
return series.seasonTabs.first()
|
||||
}
|
||||
val selectedSeason = remember { mutableStateOf<SeriesSeasonUiModel>(getDefaultSeason()) }
|
||||
|
||||
@@ -79,14 +79,15 @@ class SeriesViewModel @Inject constructor(
|
||||
title = episode.name ?: "Unknown",
|
||||
description = episode.overview ?: "",
|
||||
duration = "58m",
|
||||
imageUrl = JellyfinImageHelper.toImageUrl(url = serverUrl, itemId = episode.id, type = ImageType.PRIMARY)
|
||||
imageUrl = JellyfinImageHelper.toImageUrl(url = serverUrl, itemId = episode.id, type = ImageType.PRIMARY),
|
||||
progress = episode.userData!!.playedPercentage,
|
||||
watched = episode.userData!!.played
|
||||
)
|
||||
}
|
||||
SeriesSeasonUiModel(
|
||||
name = season.name ?: "Unknown",
|
||||
episodes = episodeItemUiModels,
|
||||
// TODO add actual logic or remove
|
||||
isSelected = false,
|
||||
unplayedCount = season.userData!!.unplayedItemCount
|
||||
)
|
||||
}
|
||||
return SeriesUiModel(
|
||||
|
||||
@@ -167,6 +167,7 @@ class JellyfinApiClient @Inject constructor(
|
||||
val result = api.tvShowsApi.getSeasons(
|
||||
userId = getUserId(),
|
||||
seriesId = seriesId,
|
||||
enableUserData = true
|
||||
)
|
||||
Log.d("getSeasons response: {}", result.content.toString())
|
||||
return result.content.items
|
||||
|
||||
Reference in New Issue
Block a user