Add screen previews

This commit is contained in:
2026-03-24 21:34:49 +01:00
parent f85624b159
commit 262d2624ea
3 changed files with 217 additions and 13 deletions

View File

@@ -4,6 +4,7 @@ import android.Manifest
import android.os.Build import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -26,8 +27,11 @@ import hu.bbara.purefin.core.data.navigation.LocalNavigationBackStack
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
import hu.bbara.purefin.core.data.navigation.Route import hu.bbara.purefin.core.data.navigation.Route
import hu.bbara.purefin.core.model.Episode import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.feature.download.DownloadState import hu.bbara.purefin.feature.download.DownloadState
import hu.bbara.purefin.feature.shared.content.episode.EpisodeScreenViewModel import hu.bbara.purefin.feature.shared.content.episode.EpisodeScreenViewModel
import hu.bbara.purefin.ui.theme.AppTheme
import java.util.UUID
@Composable @Composable
fun EpisodeScreen( fun EpisodeScreen(
@@ -142,4 +146,43 @@ private fun EpisodeScreenInternal(
} }
} }
@Preview(showBackground = true)
@Composable
private fun EpisodeScreenPreview() {
AppTheme {
EpisodeScreenInternal(
episode = previewEpisode(),
seriesTitle = "Severance",
topBarShortcut = EpisodeTopBarShortcut.Series(onClick = {}),
downloadState = DownloadState.Downloading(progressPercent = 0.42f),
onBack = {},
onSeriesClick = {},
onDownloadClick = {}
)
}
}
private fun previewEpisode(): Episode {
val seriesId = UUID.fromString("11111111-1111-1111-1111-111111111111")
val seasonId = UUID.fromString("22222222-2222-2222-2222-222222222222")
return Episode(
id = UUID.fromString("33333333-3333-3333-3333-333333333333"),
seriesId = seriesId,
seasonId = seasonId,
index = 4,
title = "The You You Are",
synopsis = "Mark is pulled deeper into Lumon's fractured world as the team chases a clue that reframes everything they thought they understood.",
releaseDate = "2025",
rating = "16+",
runtime = "49m",
progress = 63.0,
watched = false,
format = "4K",
heroImageUrl = "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee",
cast = listOf(
CastMember("Adam Scott", "Mark Scout", null),
CastMember("Britt Lower", "Helly R.", null),
CastMember("John Turturro", "Irving B.", null)
)
)
}

View File

@@ -4,6 +4,7 @@ import android.Manifest
import android.os.Build import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -21,9 +22,12 @@ import androidx.hilt.navigation.compose.hiltViewModel
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.components.MediaHero
import hu.bbara.purefin.core.data.navigation.MovieDto import hu.bbara.purefin.core.data.navigation.MovieDto
import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.core.model.Movie import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.feature.download.DownloadState import hu.bbara.purefin.feature.download.DownloadState
import hu.bbara.purefin.feature.shared.content.movie.MovieScreenViewModel import hu.bbara.purefin.feature.shared.content.movie.MovieScreenViewModel
import hu.bbara.purefin.ui.theme.AppTheme
import java.util.UUID
@Composable @Composable
fun MovieScreen( fun MovieScreen(
@@ -107,3 +111,38 @@ private fun MovieScreenInternal(
} }
} }
} }
@Preview(showBackground = true)
@Composable
private fun MovieScreenPreview() {
AppTheme {
MovieScreenInternal(
movie = previewMovie(),
downloadState = DownloadState.NotDownloaded,
onDownloadClick = {},
onBack = {}
)
}
}
private fun previewMovie(): Movie =
Movie(
id = UUID.fromString("44444444-4444-4444-4444-444444444444"),
libraryId = UUID.fromString("55555555-5555-5555-5555-555555555555"),
title = "Blade Runner 2049",
progress = 18.0,
watched = false,
year = "2017",
rating = "16+",
runtime = "2h 44m",
format = "Dolby Vision",
synopsis = "A new blade runner uncovers a buried secret that forces him to trace the vanished footsteps of Rick Deckard.",
heroImageUrl = "https://images.unsplash.com/photo-1519608487953-e999c86e7455",
audioTrack = "English 5.1",
subtitles = "English CC",
cast = listOf(
CastMember("Ryan Gosling", "K", null),
CastMember("Ana de Armas", "Joi", null),
CastMember("Harrison Ford", "Rick Deckard", null)
)
)

View File

@@ -19,6 +19,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
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
@@ -27,10 +28,14 @@ import hu.bbara.purefin.common.ui.MediaSynopsis
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.components.MediaHero
import hu.bbara.purefin.core.data.navigation.SeriesDto import hu.bbara.purefin.core.data.navigation.SeriesDto
import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.core.model.Season import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.core.model.Series import hu.bbara.purefin.core.model.Series
import hu.bbara.purefin.feature.download.DownloadState import hu.bbara.purefin.feature.download.DownloadState
import hu.bbara.purefin.feature.shared.content.series.SeriesViewModel import hu.bbara.purefin.feature.shared.content.series.SeriesViewModel
import hu.bbara.purefin.ui.theme.AppTheme
import java.util.UUID
@Composable @Composable
fun SeriesScreen( fun SeriesScreen(
@@ -51,7 +56,19 @@ fun SeriesScreen(
} }
SeriesScreenInternal( SeriesScreenInternal(
series = seriesData, series = seriesData,
viewModel = viewModel, seriesDownloadState = viewModel.seriesDownloadState.collectAsState().value,
seasonDownloadState = viewModel.seasonDownloadState.collectAsState().value,
onDownloadOptionSelected = { option, selectedSeason ->
when (option) {
SeriesDownloadOption.SEASON ->
viewModel.downloadSeason(selectedSeason.episodes)
SeriesDownloadOption.SERIES ->
viewModel.downloadSeries(seriesData)
SeriesDownloadOption.SMART ->
viewModel.enableSmartDownload(seriesData.id)
}
},
onObserveSeasonDownloadState = viewModel::observeSeasonDownloadState,
onBack = viewModel::onBack, onBack = viewModel::onBack,
modifier = modifier modifier = modifier
) )
@@ -63,7 +80,10 @@ fun SeriesScreen(
@Composable @Composable
private fun SeriesScreenInternal( private fun SeriesScreenInternal(
series: Series, series: Series,
viewModel: SeriesViewModel, seriesDownloadState: DownloadState,
seasonDownloadState: DownloadState,
onDownloadOptionSelected: (SeriesDownloadOption, Season) -> Unit,
onObserveSeasonDownloadState: (List<Episode>) -> Unit,
onBack: () -> Unit, onBack: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@@ -89,10 +109,8 @@ private fun SeriesScreenInternal(
} ?: series.seasons.firstOrNull()?.episodes?.firstOrNull() } ?: series.seasons.firstOrNull()?.episodes?.firstOrNull()
} }
val seriesDownloadState by viewModel.seriesDownloadState.collectAsState()
val seasonDownloadState by viewModel.seasonDownloadState.collectAsState()
LaunchedEffect(selectedSeason.id, selectedSeason.episodes) { LaunchedEffect(selectedSeason.id, selectedSeason.episodes) {
viewModel.observeSeasonDownloadState(selectedSeason.episodes) onObserveSeasonDownloadState(selectedSeason.episodes)
} }
Scaffold( Scaffold(
@@ -138,14 +156,7 @@ private fun SeriesScreenInternal(
selectedSeason = selectedSeason, selectedSeason = selectedSeason,
seasonDownloadState = seasonDownloadState, seasonDownloadState = seasonDownloadState,
onDownloadOptionSelected = { option -> onDownloadOptionSelected = { option ->
when (option) { onDownloadOptionSelected(option, selectedSeason)
SeriesDownloadOption.SEASON ->
viewModel.downloadSeason(selectedSeason.episodes)
SeriesDownloadOption.SERIES ->
viewModel.downloadSeries(series)
SeriesDownloadOption.SMART ->
viewModel.enableSmartDownload(series.id)
}
} }
) )
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
@@ -180,3 +191,114 @@ private fun SeriesScreenInternal(
} }
} }
} }
@Preview(showBackground = true)
@Composable
private fun SeriesScreenPreview() {
AppTheme {
SeriesScreenInternal(
series = previewSeries(),
seriesDownloadState = DownloadState.Downloading(progressPercent = 0.58f),
seasonDownloadState = DownloadState.NotDownloaded,
onDownloadOptionSelected = { _, _ -> },
onObserveSeasonDownloadState = {},
onBack = {}
)
}
}
private fun previewSeries(): Series {
val libraryId = UUID.fromString("66666666-6666-6666-6666-666666666666")
val seriesId = UUID.fromString("77777777-7777-7777-7777-777777777777")
val seasonOneId = UUID.fromString("88888888-8888-8888-8888-888888888888")
val seasonTwoId = UUID.fromString("99999999-9999-9999-9999-999999999999")
val seasonOneEpisodes = listOf(
Episode(
id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa1"),
seriesId = seriesId,
seasonId = seasonOneId,
index = 1,
title = "A Fresh Start",
synopsis = "A fractured crew tries to reassemble after a year apart.",
releaseDate = "2024",
rating = "16+",
runtime = "51m",
progress = 100.0,
watched = true,
format = "4K",
heroImageUrl = "https://images.unsplash.com/photo-1497032205916-ac775f0649ae",
cast = emptyList()
),
Episode(
id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa2"),
seriesId = seriesId,
seasonId = seasonOneId,
index = 2,
title = "Signals",
synopsis = "Anomalies around the station point to a cover-up.",
releaseDate = "2024",
rating = "16+",
runtime = "48m",
progress = 34.0,
watched = false,
format = "4K",
heroImageUrl = "https://images.unsplash.com/photo-1520034475321-cbe63696469a",
cast = emptyList()
)
)
val seasonTwoEpisodes = listOf(
Episode(
id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa3"),
seriesId = seriesId,
seasonId = seasonTwoId,
index = 1,
title = "Return Window",
synopsis = "A high-risk jump changes the rules of the mission.",
releaseDate = "2025",
rating = "16+",
runtime = "54m",
progress = null,
watched = false,
format = "4K",
heroImageUrl = "https://images.unsplash.com/photo-1500534314209-a25ddb2bd429",
cast = emptyList()
)
)
return Series(
id = seriesId,
libraryId = libraryId,
name = "Constellation",
synopsis = "When an experiment in orbit goes wrong, the survivors return home to a world that no longer fits their memories.",
year = "2024",
heroImageUrl = "https://images.unsplash.com/photo-1446776811953-b23d57bd21aa",
unwatchedEpisodeCount = 2,
seasonCount = 2,
seasons = listOf(
Season(
id = seasonOneId,
seriesId = seriesId,
name = "Season 1",
index = 1,
unwatchedEpisodeCount = 1,
episodeCount = seasonOneEpisodes.size,
episodes = seasonOneEpisodes
),
Season(
id = seasonTwoId,
seriesId = seriesId,
name = "Season 2",
index = 2,
unwatchedEpisodeCount = 1,
episodeCount = seasonTwoEpisodes.size,
episodes = seasonTwoEpisodes
)
),
cast = listOf(
CastMember("Noomi Rapace", "Jo", null),
CastMember("Jonathan Banks", "Henry", null),
CastMember("James D'Arcy", "Magnus", null)
)
)
}