From db1059f7de2133b998074e8e8c16c1d772237670 Mon Sep 17 00:00:00 2001 From: Owen LeJeune Date: Mon, 29 Aug 2022 22:20:08 -0400 Subject: [PATCH] refactor people view --- .../ui/screens/main/DetailViewCommon.kt | 123 ----------- .../tvtime/ui/screens/main/MediaDetailView.kt | 4 +- .../ui/screens/main/PeopleDetailView.kt | 207 ++++++++++-------- 3 files changed, 118 insertions(+), 216 deletions(-) diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/DetailViewCommon.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/DetailViewCommon.kt index 8cc0752..7dc0121 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/DetailViewCommon.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/DetailViewCommon.kt @@ -30,96 +30,8 @@ import com.owenlejeune.tvtime.ui.components.PosterItem import com.owenlejeune.tvtime.ui.components.RatingRing import com.owenlejeune.tvtime.utils.TmdbUtils -@Composable -fun DetailContent( - modifier: Modifier = Modifier, - content: @Composable () -> Unit -) { - Box(modifier = modifier - .background(color = MaterialTheme.colorScheme.background) - .verticalScroll(rememberScrollState()) - ) { - content() - } -} - @Composable fun DetailHeader( - appNavController: NavController, - title: String, - modifier: Modifier = Modifier, - backdropUrl: String? = null, - posterUrl: String? = null, - backdropContentDescription: String? = null, - posterContentDescription: String? = null, - rating: Float? = null -) { - ConstraintLayout(modifier = modifier - .fillMaxWidth() - .wrapContentHeight() - ) { - val ( - backButton, backdropImage, posterImage, titleText, ratingsView - ) = createRefs() - - Backdrop( - modifier = Modifier - .constrainAs(backdropImage) { - top.linkTo(parent.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, - imageUrl = backdropUrl, - contentDescription = backdropContentDescription - ) - - PosterItem( - modifier = Modifier - .constrainAs(posterImage) { - bottom.linkTo(backdropImage.bottom) - start.linkTo(parent.start, margin = 16.dp) - top.linkTo(backButton.bottom) - }, - url = posterUrl, - contentDescription = posterContentDescription - ) - - TitleText( - modifier = Modifier - .constrainAs(titleText) { - bottom.linkTo(posterImage.bottom) - start.linkTo(posterImage.end, margin = 8.dp) - end.linkTo(parent.end, margin = 16.dp) - }, - title = title - ) - - rating?.let { - RatingView( - modifier = Modifier - .constrainAs(ratingsView) { - bottom.linkTo(titleText.top) - start.linkTo(posterImage.end, margin = 20.dp) - }, - progress = rating - ) - } - - BackButton( - modifier = Modifier.constrainAs(backButton) { - top.linkTo(parent.top)//, 8.dp) - start.linkTo(parent.start, 8.dp) - bottom.linkTo(posterImage.top) - }, - appNavController = appNavController - ) - } -} - -@Composable -fun DetailHeader2( - appNavController: NavController, - title: String, modifier: Modifier = Modifier, backdropUrl: String? = null, posterUrl: String? = null, @@ -188,22 +100,6 @@ private fun Backdrop(modifier: Modifier, imageUrl: String?, contentDescription: ) } -@Composable -private fun TitleText(modifier: Modifier, title: String) { - Text( - text = title, - color = MaterialTheme.colorScheme.primary, - modifier = modifier - .padding(start = 16.dp, end = 16.dp) - .fillMaxWidth(.6f), - style = MaterialTheme.typography.headlineMedium, - textAlign = TextAlign.Start, - softWrap = true, - maxLines = 3, - overflow = TextOverflow.Ellipsis - ) -} - @Composable fun RatingView( progress: Float, @@ -225,23 +121,4 @@ fun RatingView( size = 50.dp ) } -} - -@Composable -private fun BackButton(modifier: Modifier, appNavController: NavController) { - val start = if (isSystemInDarkTheme()) Color.Black else Color.White - IconButton( - onClick = { appNavController.popBackStack() }, - modifier = modifier - .background( - brush = Brush.radialGradient(colors = listOf(start, Color.Transparent)) - ) - .wrapContentSize() - ) { - Icon( - imageVector = Icons.Filled.ArrowBack, - contentDescription = stringResource(R.string.content_description_back_button), - tint = MaterialTheme.colorScheme.primary - ) - } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt index 27cf8ba..9455f14 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/MediaDetailView.kt @@ -108,9 +108,7 @@ fun MediaDetailView( .padding(bottom = 16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - DetailHeader2( - appNavController = appNavController, - title = mediaItem.value?.title ?: "", + DetailHeader( posterUrl = TmdbUtils.getFullPosterPath(mediaItem.value?.posterPath), posterContentDescription = mediaItem.value?.title, backdropUrl = TmdbUtils.getFullBackdropPath(mediaItem.value?.backdropPath), diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt index 54b41ef..50e5313 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/main/PeopleDetailView.kt @@ -1,17 +1,20 @@ package com.owenlejeune.tvtime.ui.screens.main +import androidx.compose.animation.rememberSplineBasedDecay import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -30,6 +33,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +@OptIn(ExperimentalMaterial3Api::class) @Composable fun PersonDetailView( appNavController: NavController, @@ -42,108 +46,131 @@ fun PersonDetailView( } } - Column( - modifier = Modifier - .background(color = MaterialTheme.colorScheme.background) - .verticalScroll(rememberScrollState()) - .fillMaxSize() - .padding(bottom = 16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - DetailHeader( - appNavController = appNavController, - title = person.value?.name ?: "", - posterUrl = TmdbUtils.getFullPersonImagePath(person.value?.profilePath), - posterContentDescription = person.value?.name - ) + val decayAnimationSpec = rememberSplineBasedDecay() + val topAppBarScrollState = rememberTopAppBarScrollState() + val scrollBehaviour = remember(decayAnimationSpec) { + TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec, topAppBarScrollState) + } - Column( - modifier = Modifier.padding(horizontal = 16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - - BiographyCard(person = person.value) - - val credits = remember { mutableStateOf(null) } - personId?.let { - if (credits.value == null) { - fetchCredits(personId, credits) - } - } - - ContentCard(title = stringResource(R.string.known_for_label)) { - LazyRow( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(12.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp) - ) { - items(credits.value?.cast?.size ?: 0) { i -> - val content = credits.value!!.cast[i] - - TwoLineImageTextCard( - title = content.name, - titleTextColor = MaterialTheme.colorScheme.primary, - subtitle = content.character, - modifier = Modifier - .width(124.dp) - .wrapContentHeight(), - imageUrl = TmdbUtils.getFullPosterPath(content.posterPath), - onItemClicked = { - personId?.let { - appNavController.navigate( - "${MainNavItem.DetailView.route}/${content.mediaType}/${content.id}" - ) - } - } + Scaffold( + modifier = Modifier.nestedScroll(scrollBehaviour.nestedScrollConnection), + topBar = { + SmallTopAppBar( + scrollBehavior = scrollBehaviour, + colors = TopAppBarDefaults + .largeTopAppBarColors( + scrolledContainerColor = MaterialTheme.colorScheme.background, + titleContentColor = MaterialTheme.colorScheme.primary + ), + title = { Text(text = person.value?.name ?: "") }, + navigationIcon = { + IconButton(onClick = { appNavController.popBackStack() }) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = stringResource(id = R.string.content_description_back_button), + tint = MaterialTheme.colorScheme.primary ) } } - } + ) + } + ) { innerPadding -> + Box(modifier = Modifier.padding(innerPadding)) { + Column( + modifier = Modifier + .background(color = MaterialTheme.colorScheme.background) + .verticalScroll(state = rememberScrollState()) + .padding(bottom = 16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + DetailHeader( + posterUrl = TmdbUtils.getFullPersonImagePath(person.value?.profilePath), + posterContentDescription = person.value?.profilePath + ) - val departments = credits.value?.crew?.map { it.department }?.toSet() ?: emptySet() - if (departments.isNotEmpty()) { - ContentCard(title = stringResource(R.string.also_known_for_label)) { - Column( + BiographyCard(person = person.value) + + val credits = remember { mutableStateOf(null) } + personId?.let { + if (credits.value == null) { + fetchCredits(personId, credits) + } + } + + ContentCard(title = stringResource(R.string.known_for_label)) { + LazyRow( modifier = Modifier .fillMaxWidth() .wrapContentHeight() .padding(12.dp), - verticalArrangement = Arrangement.spacedBy(8.dp) + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - departments.forEach { department -> - Text(text = department, color = MaterialTheme.colorScheme.primary) - LazyRow( + items(credits.value?.cast?.size ?: 0) { i -> + val content = credits.value!!.cast[i] + + TwoLineImageTextCard( + title = content.name, + titleTextColor = MaterialTheme.colorScheme.primary, + subtitle = content.character, modifier = Modifier - .fillMaxWidth() + .width(124.dp) .wrapContentHeight(), - horizontalArrangement = Arrangement.spacedBy(4.dp) - ) { - val jobsInDepartment = - credits.value!!.crew.filter { it.department == department } - items(jobsInDepartment.size) { i -> - val content = jobsInDepartment[i] - val title = if (content.mediaType == MediaViewType.MOVIE) { - content.title ?: "" - } else { - content.name ?: "" + imageUrl = TmdbUtils.getFullPosterPath(content.posterPath), + onItemClicked = { + personId?.let { + appNavController.navigate( + "${MainNavItem.DetailView.route}/${content.mediaType}/${content.id}" + ) } - TwoLineImageTextCard( - title = title, - subtitle = content.job, - modifier = Modifier - .width(124.dp) - .wrapContentHeight(), - imageUrl = TmdbUtils.getFullPosterPath(content.posterPath), - onItemClicked = { - personId?.let { - appNavController.navigate( - "${MainNavItem.DetailView.route}/${content.mediaType}/${content.id}" - ) - } + } + ) + } + } + } + + val departments = credits.value?.crew?.map { it.department }?.toSet() ?: emptySet() + if (departments.isNotEmpty()) { + ContentCard(title = stringResource(R.string.also_known_for_label)) { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + departments.forEach { department -> + Text(text = department, color = MaterialTheme.colorScheme.primary) + LazyRow( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + val jobsInDepartment = + credits.value!!.crew.filter { it.department == department } + items(jobsInDepartment.size) { i -> + val content = jobsInDepartment[i] + val title = if (content.mediaType == MediaViewType.MOVIE) { + content.title ?: "" + } else { + content.name ?: "" } - ) + TwoLineImageTextCard( + title = title, + subtitle = content.job, + modifier = Modifier + .width(124.dp) + .wrapContentHeight(), + imageUrl = TmdbUtils.getFullPosterPath(content.posterPath), + onItemClicked = { + personId?.let { + appNavController.navigate( + "${MainNavItem.DetailView.route}/${content.mediaType}/${content.id}" + ) + } + } + ) + } } } }