mirror of
https://github.com/bbara04/Purefin.git
synced 2026-04-01 01:30:08 +02:00
refactor media screens and consolidate mock data
- Move `EpisodeCard` and `MovieCard` logic directly into `EpisodeScreen` and `MovieScreen` as internal components. - Delete `SeriesCard.kt` and merge its content into `SeriesScreen.kt`. - Create `ContentMockData.kt` to centralize mock data for movies, series, and episodes, replacing local mock objects. - Add Compose previews for `EpisodeScreen`, `MovieScreen`, and `SeriesScreen`. - Clean up unused imports and streamline layout structures in content components.
This commit is contained in:
@@ -0,0 +1,162 @@
|
|||||||
|
package hu.bbara.purefin.app.content
|
||||||
|
|
||||||
|
import hu.bbara.purefin.app.content.episode.EpisodeUiModel
|
||||||
|
import hu.bbara.purefin.app.content.movie.MovieUiModel
|
||||||
|
import hu.bbara.purefin.app.content.series.SeriesCastMemberUiModel
|
||||||
|
import hu.bbara.purefin.app.content.series.SeriesEpisodeUiModel
|
||||||
|
import hu.bbara.purefin.app.content.series.SeriesSeasonUiModel
|
||||||
|
import hu.bbara.purefin.app.content.series.SeriesUiModel
|
||||||
|
import org.jellyfin.sdk.model.UUID
|
||||||
|
import hu.bbara.purefin.app.content.episode.CastMember as EpisodeCastMember
|
||||||
|
import hu.bbara.purefin.app.content.movie.CastMember as MovieCastMember
|
||||||
|
|
||||||
|
object ContentMockData {
|
||||||
|
fun series(): SeriesUiModel {
|
||||||
|
val heroUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuD3hBjDpw00tDCQsK5xNcnJra301k1T4LksWVZzHieH9KHQItEQkVzhwevJvf8RkaQKdVKvObzRlfDDqa3_PNwLUlUQc1LpDih8p94VTGobEV62qi7QrmNyQm_o55KRMNWiTG3zLLpblGqo3uUNQcYmPFqfNML95dClXQ4lQNl85-zgerPPAbGPr23dswbIYCigyTAaXgrmdV_nbNQ5LdDB0Wh5cMHtP0uxz6k3ARjNom6clhphGIUF9e6YSvKuwuiZ-1lMYFg8C_4"
|
||||||
|
val episode1 = SeriesEpisodeUiModel(
|
||||||
|
id = "1",
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
return SeriesUiModel(
|
||||||
|
title = "Interstellar Horizon: The Series",
|
||||||
|
year = "2024",
|
||||||
|
rating = "TV-MA",
|
||||||
|
seasons = "3 Seasons",
|
||||||
|
format = "4K HDR",
|
||||||
|
synopsis = "When a mysterious cosmic rift appears near Saturn, a team of seasoned astronauts and theoretical physicists must embark on a high-stakes voyage across dimensions. They seek to unlock the secrets of time-dilated anomalies that threaten the very fabric of human existence on Earth.",
|
||||||
|
heroImageUrl = heroUrl,
|
||||||
|
seasonTabs = listOf(
|
||||||
|
SeriesSeasonUiModel(
|
||||||
|
name = "Season 1",
|
||||||
|
isSelected = true,
|
||||||
|
episodes = listOf(episode1, episode2, episode3)
|
||||||
|
),
|
||||||
|
SeriesSeasonUiModel(
|
||||||
|
name = "Season 2",
|
||||||
|
isSelected = false,
|
||||||
|
episodes = listOf(episode1, episode2, episode3)
|
||||||
|
),
|
||||||
|
SeriesSeasonUiModel(
|
||||||
|
name = "Season 3",
|
||||||
|
isSelected = false,
|
||||||
|
episodes = listOf(episode1, episode2, episode3)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
cast = listOf(
|
||||||
|
SeriesCastMemberUiModel(
|
||||||
|
name = "Marcus Thorne",
|
||||||
|
role = "Cmdr. Vance",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuC6OPszCXCIP_FMO3BJJUrjpCtDNw9aeHYOGyOAXdqF078hDFNrH7KXbaQ7qtipz6aIPLivd8VBBffNMbeAiYIjjWjn5GMb6Xn9iiJz0D2rzhCKi0TBeFrN6tC1IXJkzQyQKJNhTnyokWy9dd-YtN65V7er7RT6hP5jdVBXhtK1xZMjlgrm1bk_FTTmKd8Afu3zPtJCaaC98Z608vav5zhYlkrdA1wKNSTWTpzwMSyDIY3pNQNPFauWf0n-iEu7QsYTAwhCG_zfxz0"
|
||||||
|
),
|
||||||
|
SeriesCastMemberUiModel(
|
||||||
|
name = "Elena Rossi",
|
||||||
|
role = "Dr. Sarah Cole",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBExsf-wEzAVjMxasU2ImGhlreqQo9biBSN1yHyAbW8MyuhuppRw9ho7OD3vsbySSJ3kNluEgH1Qun45PmLnZWixZsFU4Qc7UGGJNKMS5Nkm4GZAsKdFvb3z_i1tkCvaXXvGpqmwI0qjFuo1QyjjhYPA5Yp3I8ZhrnDYdQv_GxbhR6Vl3mY1rbxd2BIUEE5oMTwTF-QmJztUEaViZkSGSG2VgVXZ5VAREn4xWE902OH2sysllvXQJQIaj439JIC2_Vg61m0-F-F1Vc"
|
||||||
|
),
|
||||||
|
SeriesCastMemberUiModel(
|
||||||
|
name = "Julian Chen",
|
||||||
|
role = "Tech Officer Lin",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuA5CFDWsWYO4YxdRoLd2QfH5Su2KLhtj5xSDb8qmzWHvPE888ac_HAAj1wu1uqdFNSncdmmJ-bWsc--h6NYKxVXkhd4vHaFWi0XTJXgsR0F3cBu_l2SynSX4TMNSy5C3XWDurgeSH789byOe1HvoxHCHTJYaSf3OyEbil-NOp9g_9mZ24CIZOI79nx57CRzmooxoswycqssPpfTNkrnoYrrAczt5qbncwLM9NVU442YxyBFisr2Ds9H-CNBOakiCtaKnoJ6npznM7U"
|
||||||
|
),
|
||||||
|
SeriesCastMemberUiModel(
|
||||||
|
name = "Sarah Jenkins",
|
||||||
|
role = "Mission Pilot",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBN6_72VggBdNx7ITLvEvIA6OSre5iJI6kQiUVMpKAlYgd8TpT-Jx6DzZwGsGACLnAXOUuzT2R7mx9A9DNZcqi5BF_jSaEdeYpfcBvJttmVPAwiCiq1_PI2BwoZZH_Ccmq2AHV5lQqcYaA2rPkf4e7YLLLgpmVbGjKhncTotQtxiZvmLNzCbLUdlEb7XLgHKfjS6FU6djV9ocOo9bxZ_YtrQj-mMFvYGzCxeFYC8OF0kIV2NN3kQYH8x1X-rYMqu2-d7klJfQdhKHw"
|
||||||
|
),
|
||||||
|
SeriesCastMemberUiModel(
|
||||||
|
name = "David Wu",
|
||||||
|
role = "The AI (Voice)",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuCnNkjaBc2hU2zJ5hAF8iZZ_ZZvMlU79o4JtPNCP2MEfttpF0fe_BHWsMMl6h3S37FJ1dTLk8AQuvRQ_ggy1u-71xlQWULB76rT8pdZiRE7TkInQ8gwpigs84KNWbTRxVUI7Nia9RPyJeFE7egZqnT46TQWUeN8llWF9EDQ6mpfVLH0vHhKUlko39iDgMnBIequYntugSFgWJQc1jH-AxZ4OpJr_-uZGkwtQ_CVYNV69u9y107gk5BwaUFwPeipe8Bn9I655kyHIuQ"
|
||||||
|
),
|
||||||
|
SeriesCastMemberUiModel(
|
||||||
|
name = "Alex Reed",
|
||||||
|
role = "Engineer",
|
||||||
|
imageUrl = null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun movie(): MovieUiModel {
|
||||||
|
val castMembers = listOf(
|
||||||
|
MovieCastMember(
|
||||||
|
name = "Elena Rossi",
|
||||||
|
role = "Dr. Sarah Cole",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBExsf-wEzAVjMxasU2ImGhlreqQo9biBSN1yHyAbW8MyuhuppRw9ho7OD3vsbySSJ3kNluEgH1Qun45PmLnZWixZsFU4Qc7UGGJNKMS5Nkm4GZAsKdFvb3z_i1tkCvaXXvGpqmwI0qjFuo1QyjjhYPA5Yp3I8ZhrnDYdQv_GxbhR6Vl3mY1rbxd2BIUEE5oMTwTF-QmJztUEaViZkSGSG2VgVXZ5VAREn4xWE902OH2sysllvXQJQIaj439JIC2_Vg61m0-F-F1Vc"
|
||||||
|
),
|
||||||
|
MovieCastMember(
|
||||||
|
name = "Marcus Thorne",
|
||||||
|
role = "Cmdr. Vance",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuC6OPszCXCIP_FMO3BJJUrjpCtDNw9aeHYOGyOAXdqF078hDFNrH7KXbaQ7qtipz6aIPLivd8VBBffNMbeAiYIjjWjn5GMb6Xn9iiJz0D2rzhCKi0TBeFrN6tC1IXJkzQyQKJNhTnyokWy9dd-YtN65V7er7RT6hP5jdVBXhtK1xZMjlgrm1bk_FTTmKd8Afu3zPtJCaaC98Z608vav5zhYlkrdA1wKNSTWTpzwMSyDIY3pNQNPFauWf0n-iEu7QsYTAwhCG_zfxz0"
|
||||||
|
),
|
||||||
|
MovieCastMember(
|
||||||
|
name = "Julian Chen",
|
||||||
|
role = "Tech Officer Lin",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuA5CFDWsWYO4YxdRoLd2QfH5Su2KLhtj5xSDb8qmzWHvPE888ac_HAAj1wu1uqdFNSncdmmJ-bWsc--h6NYKxVXkhd4vHaFWi0XTJXgsR0F3cBu_l2SynSX4TMNSy5C3XWDurgeSH789byOe1HvoxHCHTJYaSf3OyEbil-NOp9g_9mZ24CIZOI79nx57CRzmooxoswycqssPpfTNkrnoYrrAczt5qbncwLM9NVU442YxyBFisr2Ds9H-CNBOakiCtaKnoJ6npznM7U"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return MovieUiModel(
|
||||||
|
id = UUID.randomUUID(),
|
||||||
|
title = "Interstellar Horizon",
|
||||||
|
year = "2024",
|
||||||
|
rating = "PG-13",
|
||||||
|
runtime = "2h 14m",
|
||||||
|
format = "4K HDR",
|
||||||
|
synopsis = "A deep-space rescue crew is dispatched to intercept a derelict vessel drifting back from a temporal rift. As timelines fracture around them, they must decide which reality is worth saving.",
|
||||||
|
heroImageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuD3hBjDpw00tDCQsK5xNcnJra301k1T4LksWVZzHieH9KHQItEQkVzhwevJvf8RkaQKdVKvObzRlfDDqa3_PNwLUlUQc1LpDih8p94VTGobEV62qi7QrmNyQm_o55KRMNWiTG3zLLpblGqo3uUNQcYmPFqfNML95dClXQ4lQNl85-zgerPPAbGPr23dswbIYCigyTAaXgrmdV_nbNQ5LdDB0Wh5cMHtP0uxz6k3ARjNom6clhphGIUF9e6YSvKuwuiZ-1lMYFg8C_4",
|
||||||
|
audioTrack = "English (Dolby Atmos)",
|
||||||
|
subtitles = "English, Spanish, French",
|
||||||
|
cast = castMembers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun episode(): EpisodeUiModel {
|
||||||
|
val castMembers = listOf(
|
||||||
|
EpisodeCastMember(
|
||||||
|
name = "Elena Rossi",
|
||||||
|
role = "Dr. Sarah Cole",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBExsf-wEzAVjMxasU2ImGhlreqQo9biBSN1yHyAbW8MyuhuppRw9ho7OD3vsbySSJ3kNluEgH1Qun45PmLnZWixZsFU4Qc7UGGJNKMS5Nkm4GZAsKdFvb3z_i1tkCvaXXvGpqmwI0qjFuo1QyjjhYPA5Yp3I8ZhrnDYdQv_GxbhR6Vl3mY1rbxd2BIUEE5oMTwTF-QmJztUEaViZkSGSG2VgVXZ5VAREn4xWE902OH2sysllvXQJQIaj439JIC2_Vg61m0-F-F1Vc"
|
||||||
|
),
|
||||||
|
EpisodeCastMember(
|
||||||
|
name = "Marcus Thorne",
|
||||||
|
role = "Cmdr. Vance",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuC6OPszCXCIP_FMO3BJJUrjpCtDNw9aeHYOGyOAXdqF078hDFNrH7KXbaQ7qtipz6aIPLivd8VBBffNMbeAiYIjjWjn5GMb6Xn9iiJz0D2rzhCKi0TBeFrN6tC1IXJkzQyQKJNhTnyokWy9dd-YtN65V7er7RT6hP5jdVBXhtK1xZMjlgrm1bk_FTTmKd8Afu3zPtJCaaC98Z608vav5zhYlkrdA1wKNSTWTpzwMSyDIY3pNQNPFauWf0n-iEu7QsYTAwhCG_zfxz0"
|
||||||
|
),
|
||||||
|
EpisodeCastMember(
|
||||||
|
name = "David Wu",
|
||||||
|
role = "The AI (Voice)",
|
||||||
|
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuCnNkjaBc2hU2zJ5hAF8iZZ_ZZvMlU79o4JtPNCP2MEfttpF0fe_BHWsMMl6h3S37FJ1dTLk8AQuvRQ_ggy1u-71xlQWULB76rT8pdZiRE7TkInQ8gwpigs84KNWbTRxVUI7Nia9RPyJeFE7egZqnT46TQWUeN8llWF9EDQ6mpfVLH0vHhKUlko39iDgMnBIequYntugSFgWJQc1jH-AxZ4OpJr_-uZGkwtQ_CVYNV69u9y107gk5BwaUFwPeipe8Bn9I655kyHIuQ"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return EpisodeUiModel(
|
||||||
|
id = UUID.randomUUID(),
|
||||||
|
title = "S1E1 · Event Horizon",
|
||||||
|
releaseDate = "Oct 12, 2024",
|
||||||
|
rating = "TV-MA",
|
||||||
|
runtime = "58m",
|
||||||
|
format = "4K HDR",
|
||||||
|
synopsis = "As the anomaly near Saturn destabilizes, the crew boards the research vessel Helios to intercept what might be a distress signal from another timeline.",
|
||||||
|
heroImageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuC6OPszCXCIP_FMO3BJJUrjpCtDNw9aeHYOGyOAXdqF078hDFNrH7KXbaQ7qtipz6aIPLivd8VBBffNMbeAiYIjjWjn5GMb6Xn9iiJz0D2rzhCKi0TBeFrN6tC1IXJkzQyQKJNhTnyokWy9dd-YtN65V7er7RT6hP5jdVBXhtK1xZMjlgrm1bk_FTTmKd8Afu3zPtJCaaC98Z608vav5zhYlkrdA1wKNSTWTpzwMSyDIY3pNQNPFauWf0n-iEu7QsYTAwhCG_zfxz0",
|
||||||
|
audioTrack = "English (Dolby Atmos)",
|
||||||
|
subtitles = "English, Spanish, German",
|
||||||
|
cast = castMembers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +1,20 @@
|
|||||||
package hu.bbara.purefin.app.content.episode
|
package hu.bbara.purefin.app.content.episode
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.offset
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
import androidx.compose.material.icons.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.outlined.Cast
|
import androidx.compose.material.icons.outlined.Cast
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
import androidx.compose.material.icons.outlined.MoreVert
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -36,13 +22,10 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||||||
import hu.bbara.purefin.common.ui.MediaActionButtons
|
import hu.bbara.purefin.common.ui.MediaActionButtons
|
||||||
import hu.bbara.purefin.common.ui.MediaCastMember
|
import hu.bbara.purefin.common.ui.MediaCastMember
|
||||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
import hu.bbara.purefin.common.ui.MediaCastRow
|
||||||
import hu.bbara.purefin.common.ui.MediaFloatingPlayButton
|
|
||||||
import hu.bbara.purefin.common.ui.MediaGhostIconButton
|
import hu.bbara.purefin.common.ui.MediaGhostIconButton
|
||||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
import hu.bbara.purefin.common.ui.MediaMetaChip
|
||||||
import hu.bbara.purefin.common.ui.MediaPlaybackSettings
|
import hu.bbara.purefin.common.ui.MediaPlaybackSettings
|
||||||
import hu.bbara.purefin.common.ui.components.MediaHero
|
|
||||||
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
||||||
import hu.bbara.purefin.player.PlayerActivity
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun EpisodeTopBar(
|
internal fun EpisodeTopBar(
|
||||||
@@ -140,99 +123,6 @@ internal fun EpisodeDetails(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun EpisodeCard(
|
|
||||||
episode: EpisodeUiModel,
|
|
||||||
backGroundColor: Color,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
val colors = rememberEpisodeColors().toMediaDetailColors()
|
|
||||||
val context = LocalContext.current
|
|
||||||
val playAction = remember(episode.id) {
|
|
||||||
{
|
|
||||||
val intent = Intent(context, PlayerActivity::class.java)
|
|
||||||
intent.putExtra("MEDIA_ID", episode.id.toString())
|
|
||||||
context.startActivity(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxWithConstraints(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(colors.background)
|
|
||||||
) {
|
|
||||||
val isWide = maxWidth >= 900.dp
|
|
||||||
val contentPadding = if (isWide) 32.dp else 20.dp
|
|
||||||
|
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
|
||||||
if (isWide) {
|
|
||||||
Row(modifier = Modifier.fillMaxSize()) {
|
|
||||||
MediaHero(
|
|
||||||
imageUrl = episode.heroImageUrl,
|
|
||||||
height = 300.dp,
|
|
||||||
backgroundColor = backGroundColor,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.weight(0.5f)
|
|
||||||
)
|
|
||||||
EpisodeDetails(
|
|
||||||
episode = episode,
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(0.5f)
|
|
||||||
.fillMaxHeight()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(
|
|
||||||
start = contentPadding,
|
|
||||||
end = contentPadding,
|
|
||||||
top = 96.dp,
|
|
||||||
bottom = 32.dp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
MediaHero(
|
|
||||||
imageUrl = episode.heroImageUrl,
|
|
||||||
backgroundColor = backGroundColor,
|
|
||||||
height = 400.dp,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
EpisodeDetails(
|
|
||||||
episode = episode,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = contentPadding)
|
|
||||||
.offset(y = (-48).dp)
|
|
||||||
.padding(bottom = 96.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeTopBar(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 16.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!isWide) {
|
|
||||||
MediaFloatingPlayButton(
|
|
||||||
containerColor = colors.primary,
|
|
||||||
onContainerColor = colors.onPrimary,
|
|
||||||
onClick = playAction,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.BottomEnd)
|
|
||||||
.padding(20.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun CastMember.toMediaCastMember() = MediaCastMember(
|
private fun CastMember.toMediaCastMember() = MediaCastMember(
|
||||||
name = name,
|
name = name,
|
||||||
role = role,
|
role = role,
|
||||||
|
|||||||
@@ -1,13 +1,37 @@
|
|||||||
package hu.bbara.purefin.app.content.episode
|
package hu.bbara.purefin.app.content.episode
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import hu.bbara.purefin.app.content.ContentMockData
|
||||||
|
import hu.bbara.purefin.common.ui.MediaFloatingPlayButton
|
||||||
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
||||||
|
import hu.bbara.purefin.common.ui.components.MediaHero
|
||||||
|
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
||||||
import hu.bbara.purefin.navigation.ItemDto
|
import hu.bbara.purefin.navigation.ItemDto
|
||||||
|
import hu.bbara.purefin.player.PlayerActivity
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EpisodeScreen(
|
fun EpisodeScreen(
|
||||||
@@ -22,13 +46,115 @@ fun EpisodeScreen(
|
|||||||
|
|
||||||
val episode = viewModel.episode.collectAsState()
|
val episode = viewModel.episode.collectAsState()
|
||||||
|
|
||||||
if (episode.value != null) {
|
if (episode.value == null) {
|
||||||
EpisodeCard(
|
PurefinWaitingScreen()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
EpisodeScreenInternal(
|
||||||
episode = episode.value!!,
|
episode = episode.value!!,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
backGroundColor = MaterialTheme.colorScheme.background
|
backGroundColor = MaterialTheme.colorScheme.background
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun EpisodeScreenInternal(
|
||||||
|
episode: EpisodeUiModel,
|
||||||
|
backGroundColor: Color,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val colors = rememberEpisodeColors().toMediaDetailColors()
|
||||||
|
val context = LocalContext.current
|
||||||
|
val playAction = remember(episode.id) {
|
||||||
|
{
|
||||||
|
val intent = Intent(context, PlayerActivity::class.java)
|
||||||
|
intent.putExtra("MEDIA_ID", episode.id.toString())
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxWithConstraints(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(colors.background)
|
||||||
|
) {
|
||||||
|
val isWide = maxWidth >= 900.dp
|
||||||
|
val contentPadding = if (isWide) 32.dp else 20.dp
|
||||||
|
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
if (isWide) {
|
||||||
|
Row(modifier = Modifier.fillMaxSize()) {
|
||||||
|
MediaHero(
|
||||||
|
imageUrl = episode.heroImageUrl,
|
||||||
|
height = 300.dp,
|
||||||
|
backgroundColor = backGroundColor,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.weight(0.5f)
|
||||||
|
)
|
||||||
|
EpisodeDetails(
|
||||||
|
episode = episode,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(0.5f)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(
|
||||||
|
start = contentPadding,
|
||||||
|
end = contentPadding,
|
||||||
|
top = 96.dp,
|
||||||
|
bottom = 32.dp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PurefinWaitingScreen()
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
MediaHero(
|
||||||
|
imageUrl = episode.heroImageUrl,
|
||||||
|
backgroundColor = backGroundColor,
|
||||||
|
height = 400.dp,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
EpisodeDetails(
|
||||||
|
episode = episode,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = contentPadding)
|
||||||
|
.offset(y = (-48).dp)
|
||||||
|
.padding(bottom = 96.dp)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EpisodeTopBar(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isWide) {
|
||||||
|
MediaFloatingPlayButton(
|
||||||
|
containerColor = colors.primary,
|
||||||
|
onContainerColor = colors.onPrimary,
|
||||||
|
onClick = playAction,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomEnd)
|
||||||
|
.padding(20.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun EpisodeScreenPreview() {
|
||||||
|
EpisodeScreenInternal(
|
||||||
|
episode = ContentMockData.episode(),
|
||||||
|
backGroundColor = MaterialTheme.colorScheme.background
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,34 +1,20 @@
|
|||||||
package hu.bbara.purefin.app.content.movie
|
package hu.bbara.purefin.app.content.movie
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.offset
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
import androidx.compose.material.icons.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.outlined.Cast
|
import androidx.compose.material.icons.outlined.Cast
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
import androidx.compose.material.icons.outlined.MoreVert
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -36,13 +22,10 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||||||
import hu.bbara.purefin.common.ui.MediaActionButtons
|
import hu.bbara.purefin.common.ui.MediaActionButtons
|
||||||
import hu.bbara.purefin.common.ui.MediaCastMember
|
import hu.bbara.purefin.common.ui.MediaCastMember
|
||||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
import hu.bbara.purefin.common.ui.MediaCastRow
|
||||||
import hu.bbara.purefin.common.ui.MediaFloatingPlayButton
|
|
||||||
import hu.bbara.purefin.common.ui.MediaGhostIconButton
|
import hu.bbara.purefin.common.ui.MediaGhostIconButton
|
||||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
import hu.bbara.purefin.common.ui.MediaMetaChip
|
||||||
import hu.bbara.purefin.common.ui.MediaPlaybackSettings
|
import hu.bbara.purefin.common.ui.MediaPlaybackSettings
|
||||||
import hu.bbara.purefin.common.ui.components.MediaHero
|
|
||||||
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
||||||
import hu.bbara.purefin.player.PlayerActivity
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun MovieTopBar(
|
internal fun MovieTopBar(
|
||||||
@@ -140,100 +123,6 @@ internal fun MovieDetails(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MovieCard(
|
|
||||||
movie: MovieUiModel,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
val context = LocalContext.current
|
|
||||||
val playAction = remember(movie.id) {
|
|
||||||
{
|
|
||||||
val intent = Intent(context, PlayerActivity::class.java)
|
|
||||||
intent.putExtra("MEDIA_ID", movie.id.toString())
|
|
||||||
context.startActivity(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxWithConstraints(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
) {
|
|
||||||
val isWide = maxWidth >= 900.dp
|
|
||||||
val contentPadding = if (isWide) 32.dp else 20.dp
|
|
||||||
|
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
|
||||||
if (isWide) {
|
|
||||||
Row(modifier = Modifier.fillMaxSize()) {
|
|
||||||
MediaHero(
|
|
||||||
imageUrl = movie.heroImageUrl,
|
|
||||||
backgroundColor = MaterialTheme.colorScheme.background,
|
|
||||||
height = 300.dp,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.weight(0.5f)
|
|
||||||
)
|
|
||||||
MovieDetails(
|
|
||||||
movie = movie,
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(0.5f)
|
|
||||||
.fillMaxHeight()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(
|
|
||||||
start = contentPadding,
|
|
||||||
end = contentPadding,
|
|
||||||
top = 96.dp,
|
|
||||||
bottom = 32.dp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
MediaHero(
|
|
||||||
imageUrl = movie.heroImageUrl,
|
|
||||||
height = 400.dp,
|
|
||||||
backgroundColor = MaterialTheme.colorScheme.background,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
MovieDetails(
|
|
||||||
movie = movie,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = contentPadding)
|
|
||||||
.offset(y = (-48).dp)
|
|
||||||
.padding(bottom = 96.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MovieTopBar(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 16.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!isWide) {
|
|
||||||
MediaFloatingPlayButton(
|
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
|
||||||
onContainerColor = MaterialTheme.colorScheme.onPrimary,
|
|
||||||
|
|
||||||
onClick = playAction,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.BottomEnd)
|
|
||||||
.padding(20.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun CastMember.toMediaCastMember() = MediaCastMember(
|
private fun CastMember.toMediaCastMember() = MediaCastMember(
|
||||||
name = name,
|
name = name,
|
||||||
role = role,
|
role = role,
|
||||||
|
|||||||
@@ -1,18 +1,39 @@
|
|||||||
package hu.bbara.purefin.app.content.movie
|
package hu.bbara.purefin.app.content.movie
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import hu.bbara.purefin.app.content.ContentMockData
|
||||||
|
import hu.bbara.purefin.common.ui.MediaFloatingPlayButton
|
||||||
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
||||||
|
import hu.bbara.purefin.common.ui.components.MediaHero
|
||||||
import hu.bbara.purefin.navigation.ItemDto
|
import hu.bbara.purefin.navigation.ItemDto
|
||||||
|
import hu.bbara.purefin.player.PlayerActivity
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MovieScreen(
|
fun MovieScreen(
|
||||||
movie: ItemDto,
|
movie: ItemDto, viewModel: MovieScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier
|
||||||
viewModel: MovieScreenViewModel = hiltViewModel(),
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
) {
|
||||||
LaunchedEffect(movie.id) {
|
LaunchedEffect(movie.id) {
|
||||||
viewModel.selectMovie(movie.id)
|
viewModel.selectMovie(movie.id)
|
||||||
@@ -21,11 +42,107 @@ fun MovieScreen(
|
|||||||
val movieItem = viewModel.movie.collectAsState()
|
val movieItem = viewModel.movie.collectAsState()
|
||||||
|
|
||||||
if (movieItem.value != null) {
|
if (movieItem.value != null) {
|
||||||
MovieCard(
|
MovieScreenInternal(
|
||||||
movie = movieItem.value!!,
|
movie = movieItem.value!!, modifier = modifier
|
||||||
modifier = modifier
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
PurefinWaitingScreen()
|
PurefinWaitingScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun MovieScreenInternal(
|
||||||
|
movie: MovieUiModel,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val playAction = remember(movie.id) {
|
||||||
|
{
|
||||||
|
val intent = Intent(context, PlayerActivity::class.java)
|
||||||
|
intent.putExtra("MEDIA_ID", movie.id.toString())
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxWithConstraints(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(MaterialTheme.colorScheme.background)
|
||||||
|
) {
|
||||||
|
val isWide = maxWidth >= 900.dp
|
||||||
|
val contentPadding = if (isWide) 32.dp else 20.dp
|
||||||
|
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
if (isWide) {
|
||||||
|
Row(modifier = Modifier.fillMaxSize()) {
|
||||||
|
MediaHero(
|
||||||
|
imageUrl = movie.heroImageUrl,
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.background,
|
||||||
|
height = 300.dp,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.weight(0.5f)
|
||||||
|
)
|
||||||
|
MovieDetails(
|
||||||
|
movie = movie,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(0.5f)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(
|
||||||
|
start = contentPadding,
|
||||||
|
end = contentPadding,
|
||||||
|
top = 96.dp,
|
||||||
|
bottom = 32.dp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
MediaHero(
|
||||||
|
imageUrl = movie.heroImageUrl,
|
||||||
|
height = 400.dp,
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.background,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
MovieDetails(
|
||||||
|
movie = movie,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = contentPadding)
|
||||||
|
.offset(y = (-48).dp)
|
||||||
|
.padding(bottom = 96.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MovieTopBar(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isWide) {
|
||||||
|
MediaFloatingPlayButton(
|
||||||
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
|
onContainerColor = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
|
||||||
|
onClick = playAction,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomEnd)
|
||||||
|
.padding(20.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MovieScreenPreview() {
|
||||||
|
MovieScreenInternal(movie = ContentMockData.movie())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
package hu.bbara.purefin.app.content.series
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.offset
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SeriesCard(
|
|
||||||
series: SeriesUiModel,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
val colors = rememberSeriesColors()
|
|
||||||
|
|
||||||
BoxWithConstraints(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(colors.background)
|
|
||||||
) {
|
|
||||||
val heroHeight = maxHeight * 0.4f
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
SeriesHero(
|
|
||||||
imageUrl = series.heroImageUrl,
|
|
||||||
height = heroHeight
|
|
||||||
)
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.offset(y = (-96).dp)
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 20.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = series.title,
|
|
||||||
color = colors.textPrimary,
|
|
||||||
fontSize = 30.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
lineHeight = 36.sp
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
SeriesMetaChips(series = series)
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
SeriesActionButtons()
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
Text(
|
|
||||||
text = "Synopsis",
|
|
||||||
color = colors.textPrimary,
|
|
||||||
fontSize = 18.sp,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
Text(
|
|
||||||
text = series.synopsis,
|
|
||||||
color = colors.textMutedStrong,
|
|
||||||
fontSize = 13.sp,
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(28.dp))
|
|
||||||
Text(
|
|
||||||
text = "Episodes",
|
|
||||||
color = colors.textPrimary,
|
|
||||||
fontSize = 18.sp,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(28.dp))
|
|
||||||
SeasonTabs(seasons = series.seasonTabs)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeCarousel(
|
|
||||||
episodes = series.seasonTabs.firstOrNull { it.isSelected }?.episodes
|
|
||||||
?: series.seasonTabs.firstOrNull()?.episodes
|
|
||||||
?: emptyList()
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 0.dp, bottom = 0.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Cast",
|
|
||||||
color = colors.textPrimary,
|
|
||||||
fontSize = 18.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
modifier = Modifier.padding(horizontal = 20.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
|
||||||
CastRow(cast = series.cast)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SeriesTopBar(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 16.dp)
|
|
||||||
.align(Alignment.TopCenter)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun SeriesCardPreview() {
|
|
||||||
SeriesCard(series = SeriesMockData.series())
|
|
||||||
}
|
|
||||||
@@ -31,88 +31,3 @@ data class SeriesUiModel(
|
|||||||
val seasonTabs: List<SeriesSeasonUiModel>,
|
val seasonTabs: List<SeriesSeasonUiModel>,
|
||||||
val cast: List<SeriesCastMemberUiModel>
|
val cast: List<SeriesCastMemberUiModel>
|
||||||
)
|
)
|
||||||
|
|
||||||
internal object SeriesMockData {
|
|
||||||
fun series(): SeriesUiModel {
|
|
||||||
val heroUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuD3hBjDpw00tDCQsK5xNcnJra301k1T4LksWVZzHieH9KHQItEQkVzhwevJvf8RkaQKdVKvObzRlfDDqa3_PNwLUlUQc1LpDih8p94VTGobEV62qi7QrmNyQm_o55KRMNWiTG3zLLpblGqo3uUNQcYmPFqfNML95dClXQ4lQNl85-zgerPPAbGPr23dswbIYCigyTAaXgrmdV_nbNQ5LdDB0Wh5cMHtP0uxz6k3ARjNom6clhphGIUF9e6YSvKuwuiZ-1lMYFg8C_4"
|
|
||||||
val episode1 = SeriesEpisodeUiModel(
|
|
||||||
id = "1",
|
|
||||||
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"
|
|
||||||
)
|
|
||||||
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"
|
|
||||||
)
|
|
||||||
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"
|
|
||||||
)
|
|
||||||
return SeriesUiModel(
|
|
||||||
title = "Interstellar Horizon: The Series",
|
|
||||||
year = "2024",
|
|
||||||
rating = "TV-MA",
|
|
||||||
seasons = "3 Seasons",
|
|
||||||
format = "4K HDR",
|
|
||||||
synopsis = "When a mysterious cosmic rift appears near Saturn, a team of seasoned astronauts and theoretical physicists must embark on a high-stakes voyage across dimensions. They seek to unlock the secrets of time-dilated anomalies that threaten the very fabric of human existence on Earth.",
|
|
||||||
heroImageUrl = heroUrl,
|
|
||||||
seasonTabs = listOf(
|
|
||||||
SeriesSeasonUiModel(
|
|
||||||
name = "Season 1",
|
|
||||||
isSelected = true,
|
|
||||||
episodes = listOf(episode1, episode2, episode3)
|
|
||||||
),
|
|
||||||
SeriesSeasonUiModel(
|
|
||||||
name = "Season 2",
|
|
||||||
isSelected = false,
|
|
||||||
episodes = listOf(episode1, episode2, episode3)
|
|
||||||
),
|
|
||||||
SeriesSeasonUiModel(
|
|
||||||
name = "Season 3",
|
|
||||||
isSelected = false,
|
|
||||||
episodes = listOf(episode1, episode2, episode3)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
cast = listOf(
|
|
||||||
SeriesCastMemberUiModel(
|
|
||||||
name = "Marcus Thorne",
|
|
||||||
role = "Cmdr. Vance",
|
|
||||||
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuC6OPszCXCIP_FMO3BJJUrjpCtDNw9aeHYOGyOAXdqF078hDFNrH7KXbaQ7qtipz6aIPLivd8VBBffNMbeAiYIjjWjn5GMb6Xn9iiJz0D2rzhCKi0TBeFrN6tC1IXJkzQyQKJNhTnyokWy9dd-YtN65V7er7RT6hP5jdVBXhtK1xZMjlgrm1bk_FTTmKd8Afu3zPtJCaaC98Z608vav5zhYlkrdA1wKNSTWTpzwMSyDIY3pNQNPFauWf0n-iEu7QsYTAwhCG_zfxz0"
|
|
||||||
),
|
|
||||||
SeriesCastMemberUiModel(
|
|
||||||
name = "Elena Rossi",
|
|
||||||
role = "Dr. Sarah Cole",
|
|
||||||
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBExsf-wEzAVjMxasU2ImGhlreqQo9biBSN1yHyAbW8MyuhuppRw9ho7OD3vsbySSJ3kNluEgH1Qun45PmLnZWixZsFU4Qc7UGGJNKMS5Nkm4GZAsKdFvb3z_i1tkCvaXXvGpqmwI0qjFuo1QyjjhYPA5Yp3I8ZhrnDYdQv_GxbhR6Vl3mY1rbxd2BIUEE5oMTwTF-QmJztUEaViZkSGSG2VgVXZ5VAREn4xWE902OH2sysllvXQJQIaj439JIC2_Vg61m0-F-F1Vc"
|
|
||||||
),
|
|
||||||
SeriesCastMemberUiModel(
|
|
||||||
name = "Julian Chen",
|
|
||||||
role = "Tech Officer Lin",
|
|
||||||
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuA5CFDWsWYO4YxdRoLd2QfH5Su2KLhtj5xSDb8qmzWHvPE888ac_HAAj1wu1uqdFNSncdmmJ-bWsc--h6NYKxVXkhd4vHaFWi0XTJXgsR0F3cBu_l2SynSX4TMNSy5C3XWDurgeSH789byOe1HvoxHCHTJYaSf3OyEbil-NOp9g_9mZ24CIZOI79nx57CRzmooxoswycqssPpfTNkrnoYrrAczt5qbncwLM9NVU442YxyBFisr2Ds9H-CNBOakiCtaKnoJ6npznM7U"
|
|
||||||
),
|
|
||||||
SeriesCastMemberUiModel(
|
|
||||||
name = "Sarah Jenkins",
|
|
||||||
role = "Mission Pilot",
|
|
||||||
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuBN6_72VggBdNx7ITLvEvIA6OSre5iJI6kQiUVMpKAlYgd8TpT-Jx6DzZwGsGACLnAXOUuzT2R7mx9A9DNZcqi5BF_jSaEdeYpfcBvJttmVPAwiCiq1_PI2BwoZZH_Ccmq2AHV5lQqcYaA2rPkf4e7YLLLgpmVbGjKhncTotQtxiZvmLNzCbLUdlEb7XLgHKfjS6FU6djV9ocOo9bxZ_YtrQj-mMFvYGzCxeFYC8OF0kIV2NN3kQYH8x1X-rYMqu2-d7klJfQdhKHw"
|
|
||||||
),
|
|
||||||
SeriesCastMemberUiModel(
|
|
||||||
name = "David Wu",
|
|
||||||
role = "The AI (Voice)",
|
|
||||||
imageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuCnNkjaBc2hU2zJ5hAF8iZZ_ZZvMlU79o4JtPNCP2MEfttpF0fe_BHWsMMl6h3S37FJ1dTLk8AQuvRQ_ggy1u-71xlQWULB76rT8pdZiRE7TkInQ8gwpigs84KNWbTRxVUI7Nia9RPyJeFE7egZqnT46TQWUeN8llWF9EDQ6mpfVLH0vHhKUlko39iDgMnBIequYntugSFgWJQc1jH-AxZ4OpJr_-uZGkwtQ_CVYNV69u9y107gk5BwaUFwPeipe8Bn9I655kyHIuQ"
|
|
||||||
),
|
|
||||||
SeriesCastMemberUiModel(
|
|
||||||
name = "Alex Reed",
|
|
||||||
role = "Engineer",
|
|
||||||
imageUrl = null
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,28 @@
|
|||||||
package hu.bbara.purefin.app.content.series
|
package hu.bbara.purefin.app.content.series
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import hu.bbara.purefin.app.content.ContentMockData
|
||||||
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
||||||
import hu.bbara.purefin.navigation.ItemDto
|
import hu.bbara.purefin.navigation.ItemDto
|
||||||
|
|
||||||
@@ -21,7 +39,7 @@ fun SeriesScreen(
|
|||||||
val series = viewModel.series.collectAsState()
|
val series = viewModel.series.collectAsState()
|
||||||
|
|
||||||
if (series.value != null) {
|
if (series.value != null) {
|
||||||
SeriesCard(
|
SeriesScreenInternal(
|
||||||
series = series.value!!,
|
series = series.value!!,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
@@ -29,3 +47,110 @@ fun SeriesScreen(
|
|||||||
PurefinWaitingScreen()
|
PurefinWaitingScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SeriesScreenInternal(
|
||||||
|
series: SeriesUiModel,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val colors = rememberSeriesColors()
|
||||||
|
|
||||||
|
BoxWithConstraints(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(colors.background)
|
||||||
|
) {
|
||||||
|
val heroHeight = maxHeight * 0.4f
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
SeriesHero(
|
||||||
|
imageUrl = series.heroImageUrl,
|
||||||
|
height = heroHeight
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.offset(y = (-96).dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 20.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = series.title,
|
||||||
|
color = colors.textPrimary,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
lineHeight = 36.sp
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
SeriesMetaChips(series = series)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
SeriesActionButtons()
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
Text(
|
||||||
|
text = "Synopsis",
|
||||||
|
color = colors.textPrimary,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = series.synopsis,
|
||||||
|
color = colors.textMutedStrong,
|
||||||
|
fontSize = 13.sp,
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(28.dp))
|
||||||
|
Text(
|
||||||
|
text = "Episodes",
|
||||||
|
color = colors.textPrimary,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(28.dp))
|
||||||
|
SeasonTabs(seasons = series.seasonTabs)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
EpisodeCarousel(
|
||||||
|
episodes = series.seasonTabs.firstOrNull { it.isSelected }?.episodes
|
||||||
|
?: series.seasonTabs.firstOrNull()?.episodes
|
||||||
|
?: emptyList()
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 0.dp, bottom = 0.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Cast",
|
||||||
|
color = colors.textPrimary,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.padding(horizontal = 20.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
CastRow(cast = series.cast)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SeriesTopBar(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SeriesScreenPreview() {
|
||||||
|
SeriesScreenInternal(series = ContentMockData.series())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user