From ac469b081ca2cce8597bbfb1af04c7e7a979d1a8 Mon Sep 17 00:00:00 2001 From: Owen LeJeune Date: Sat, 19 Feb 2022 22:41:11 -0500 Subject: [PATCH] refactor common details view code --- .../tvtime/api/tmdb/DetailService.kt | 3 + .../owenlejeune/tvtime/api/tmdb/MoviesApi.kt | 3 + .../tvtime/api/tmdb/MoviesService.kt | 4 + .../com/owenlejeune/tvtime/api/tmdb/TvApi.kt | 3 + .../owenlejeune/tvtime/api/tmdb/TvService.kt | 4 + .../owenlejeune/tvtime/ui/components/Cards.kt | 96 ++++++++++ .../tvtime/ui/components/Colors.kt | 103 +++++++++++ .../tvtime/ui/components/Widgets.kt | 98 ---------- .../tvtime/ui/screens/DetailView.kt | 174 +++++++++--------- 9 files changed, 298 insertions(+), 190 deletions(-) create mode 100644 app/src/main/java/com/owenlejeune/tvtime/ui/components/Cards.kt create mode 100644 app/src/main/java/com/owenlejeune/tvtime/ui/components/Colors.kt diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/DetailService.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/DetailService.kt index 4fd7b7f..b624a5d 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/DetailService.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/DetailService.kt @@ -3,6 +3,7 @@ package com.owenlejeune.tvtime.api.tmdb import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem +import com.owenlejeune.tvtime.api.tmdb.model.HomePageResponse import retrofit2.Response interface DetailService { @@ -13,4 +14,6 @@ interface DetailService { suspend fun getCastAndCrew(id: Int): Response + suspend fun getSimilar(id: Int, page: Int): Response + } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesApi.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesApi.kt index d9a7327..018e7db 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesApi.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesApi.kt @@ -32,4 +32,7 @@ interface MoviesApi { @GET("movie/{id}/release_dates") suspend fun getReleaseDates(@Path("id") id: Int): Response + @GET("movie/{id}/recommendations") + suspend fun getSimilarMovies(@Path("id") id: Int, @Query("page") page: Int = 1): Response + } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesService.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesService.kt index 4e27309..82ea340 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesService.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/MoviesService.kt @@ -40,4 +40,8 @@ class MoviesService: KoinComponent, DetailService, HomePageService { return service.getCastAndCrew(id) } + override suspend fun getSimilar(id: Int, page: Int): Response { + return service.getSimilarMovies(id, page) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvApi.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvApi.kt index 11847ff..9232155 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvApi.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvApi.kt @@ -32,4 +32,7 @@ interface TvApi { @GET("tv/{id}/content_ratings") suspend fun getContentRatings(@Path("id") id: Int): Response + @GET("tv/{id}/similar") + suspend fun getSimilarTvShows(@Path("id") id: Int, @Query("page") page: Int = 1): Response + } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvService.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvService.kt index 9c9f950..3c89d37 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvService.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/TvService.kt @@ -39,4 +39,8 @@ class TvService: KoinComponent, DetailService, HomePageService { suspend fun getContentRatings(id: Int): Response { return service.getContentRatings(id) } + + override suspend fun getSimilar(id: Int, page: Int): Response { + return service.getSimilarTvShows(id, page) + } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Cards.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Cards.kt new file mode 100644 index 0000000..0c28641 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Cards.kt @@ -0,0 +1,96 @@ +package com.owenlejeune.tvtime.ui.components + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import coil.compose.rememberImagePainter +import coil.transform.RoundedCornersTransformation +import com.owenlejeune.tvtime.R +import com.owenlejeune.tvtime.extensions.dpToPx + +@Composable +fun ContentCard( + modifier: Modifier = Modifier, + title: String? = null, + backgroundColor: Color = MaterialTheme.colorScheme.surfaceVariant, + textColor: Color = MaterialTheme.colorScheme.onSurfaceVariant, + content: @Composable () -> Unit = {} +) { + Card( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight(), + shape = RoundedCornerShape(10.dp), + backgroundColor = backgroundColor, + elevation = 8.dp + ) { + Column(modifier = Modifier.fillMaxSize()) { + title?.let { + Text( + text = title, + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.padding(start = 12.dp, top = 8.dp), + color = textColor + ) + } + content() + } + } +} + +@Composable +fun ImageTextCard( + title: String, + modifier: Modifier = Modifier, + subtitle: String? = null, + imageUrl: String? = null, + noDataImage: Int = R.drawable.placeholder, + placeholder: Int = R.drawable.placeholder, + titleTextColor: Color = MaterialTheme.colorScheme.onSurfaceVariant, + subtitleTextColor: Color = MaterialTheme.colorScheme.onSurfaceVariant +) { + val context = LocalContext.current + Column( + modifier = modifier + .padding(end = 12.dp) + ) { + Image( + modifier = Modifier + .size(width = 120.dp, height = 180.dp), + painter = rememberImagePainter( + data = imageUrl ?: noDataImage, + builder = { + transformations(RoundedCornersTransformation(5f.dpToPx(context))) + placeholder(placeholder) + } + ), + contentDescription = "" + ) + MinLinesText( + modifier = Modifier + .fillMaxWidth() + .padding(top = 5.dp), + minLines = 2, + text = title, + color = titleTextColor, + style = MaterialTheme.typography.bodyMedium + ) + subtitle?.let { + MinLinesText( + modifier = Modifier.fillMaxWidth(), + minLines = 2, + text = subtitle, + style = MaterialTheme.typography.bodySmall, + color = subtitleTextColor + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Colors.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Colors.kt new file mode 100644 index 0000000..2361375 --- /dev/null +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Colors.kt @@ -0,0 +1,103 @@ +package com.owenlejeune.tvtime.ui.components + +import androidx.compose.material.ContentAlpha +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.compositeOver + + +class CustomSwitchColors private constructor( + val lightUncheckedTrackColor: Color, + val darkUncheckedTrackColor: Color, + val lightUncheckedThumbColor: Color, + val darkUncheckedThumbColor: Color, + val lightCheckedTrackColor: Color, + val darkCheckedTrackColor: Color, + val lightCheckedThumbColor: Color, + val darkCheckedThumbColor: Color, + val lightDisabledTrackColor: Color, + val darkDisabledTrackColor: Color, + val lightDisabledThumbColor: Color, + val darkDisabledThumbColor: Color +){ + companion object { + @Composable + fun topLevelColors( + lightUncheckedTrackColor: Color = MaterialTheme.colorScheme.outline, + darkUncheckedTrackColor: Color = MaterialTheme.colorScheme.surfaceVariant, + lightUncheckedThumbColor: Color = MaterialTheme.colorScheme.surfaceVariant, + darkUncheckedThumbColor: Color = MaterialTheme.colorScheme.outline, + lightCheckedTrackColor: Color = MaterialTheme.colorScheme.primary, + darkCheckedTrackColor: Color = MaterialTheme.colorScheme.outline, + lightCheckedThumbColor: Color = MaterialTheme.colorScheme.primaryContainer, + darkCheckedThumbColor: Color = MaterialTheme.colorScheme.primary, + lightDisabledTrackColor: Color = lightUncheckedTrackColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface), + darkDisabledTrackColor: Color = darkUncheckedTrackColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface), + lightDisabledThumbColor: Color = lightUncheckedThumbColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface), + darkDisabledThumbColor: Color = darkUncheckedThumbColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface) + ): CustomSwitchColors { + return CustomSwitchColors( + lightUncheckedTrackColor, + darkUncheckedTrackColor, + lightUncheckedThumbColor, + darkUncheckedThumbColor, + lightCheckedTrackColor, + darkCheckedTrackColor, + lightCheckedThumbColor, + darkCheckedThumbColor, + lightDisabledTrackColor, + darkDisabledTrackColor, + lightDisabledThumbColor, + darkDisabledThumbColor + ) + } + + @Composable + fun standardColors( + lightUncheckedTrackColor: Color = MaterialTheme.colorScheme.outline, + darkUncheckedTrackColor: Color = MaterialTheme.colorScheme.surfaceVariant, + lightUncheckedThumbColor: Color = MaterialTheme.colorScheme.surfaceVariant, + darkUncheckedThumbColor: Color = MaterialTheme.colorScheme.outline, + lightCheckedTrackColor: Color = MaterialTheme.colorScheme.primary, + darkCheckedTrackColor: Color = MaterialTheme.colorScheme.secondaryContainer, + lightCheckedThumbColor: Color = MaterialTheme.colorScheme.primaryContainer, + darkCheckedThumbColor: Color = MaterialTheme.colorScheme.primary, + lightDisabledTrackColor: Color = lightUncheckedTrackColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface), + darkDisabledTrackColor: Color = darkUncheckedTrackColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface), + lightDisabledThumbColor: Color = lightUncheckedThumbColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface), + darkDisabledThumbColor: Color = darkUncheckedThumbColor + .copy(alpha = ContentAlpha.disabled) + .compositeOver(MaterialTheme.colorScheme.surface) + ): CustomSwitchColors { + return CustomSwitchColors( + lightUncheckedTrackColor, + darkUncheckedTrackColor, + lightUncheckedThumbColor, + darkUncheckedThumbColor, + lightCheckedTrackColor, + darkCheckedTrackColor, + lightCheckedThumbColor, + darkCheckedThumbColor, + lightDisabledTrackColor, + darkDisabledTrackColor, + lightDisabledThumbColor, + darkDisabledThumbColor + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt index 747e3e6..7115953 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/Widgets.kt @@ -13,8 +13,6 @@ import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Card -import androidx.compose.material.ContentAlpha -import androidx.compose.material.Switch import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search import androidx.compose.material3.* @@ -28,7 +26,6 @@ import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity @@ -95,101 +92,6 @@ fun TopLevelSwitch( } } -class CustomSwitchColors private constructor( - val lightUncheckedTrackColor: Color, - val darkUncheckedTrackColor: Color, - val lightUncheckedThumbColor: Color, - val darkUncheckedThumbColor: Color, - val lightCheckedTrackColor: Color, - val darkCheckedTrackColor: Color, - val lightCheckedThumbColor: Color, - val darkCheckedThumbColor: Color, - val lightDisabledTrackColor: Color, - val darkDisabledTrackColor: Color, - val lightDisabledThumbColor: Color, - val darkDisabledThumbColor: Color -){ - companion object { - @Composable - fun topLevelColors( - lightUncheckedTrackColor: Color = MaterialTheme.colorScheme.outline, - darkUncheckedTrackColor: Color =MaterialTheme.colorScheme.surfaceVariant, - lightUncheckedThumbColor: Color = MaterialTheme.colorScheme.surfaceVariant, - darkUncheckedThumbColor: Color = MaterialTheme.colorScheme.outline, - lightCheckedTrackColor: Color = MaterialTheme.colorScheme.primary, - darkCheckedTrackColor: Color = MaterialTheme.colorScheme.outline, - lightCheckedThumbColor: Color = MaterialTheme.colorScheme.primaryContainer, - darkCheckedThumbColor: Color = MaterialTheme.colorScheme.primary, - lightDisabledTrackColor: Color = lightUncheckedTrackColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface), - darkDisabledTrackColor: Color = darkUncheckedTrackColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface), - lightDisabledThumbColor: Color = lightUncheckedThumbColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface), - darkDisabledThumbColor: Color = darkUncheckedThumbColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface) - ): CustomSwitchColors { - return CustomSwitchColors( - lightUncheckedTrackColor, - darkUncheckedTrackColor, - lightUncheckedThumbColor, - darkUncheckedThumbColor, - lightCheckedTrackColor, - darkCheckedTrackColor, - lightCheckedThumbColor, - darkCheckedThumbColor, - lightDisabledTrackColor, - darkDisabledTrackColor, - lightDisabledThumbColor, - darkDisabledThumbColor - ) - } - - @Composable - fun standardColors( - lightUncheckedTrackColor: Color = MaterialTheme.colorScheme.outline, - darkUncheckedTrackColor: Color = MaterialTheme.colorScheme.surfaceVariant, - lightUncheckedThumbColor: Color = MaterialTheme.colorScheme.surfaceVariant, - darkUncheckedThumbColor: Color = MaterialTheme.colorScheme.outline, - lightCheckedTrackColor: Color = MaterialTheme.colorScheme.primary, - darkCheckedTrackColor: Color = MaterialTheme.colorScheme.secondaryContainer, - lightCheckedThumbColor: Color = MaterialTheme.colorScheme.primaryContainer, - darkCheckedThumbColor: Color = MaterialTheme.colorScheme.primary, - lightDisabledTrackColor: Color = lightUncheckedTrackColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface), - darkDisabledTrackColor: Color = darkUncheckedTrackColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface), - lightDisabledThumbColor: Color = lightUncheckedThumbColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface), - darkDisabledThumbColor: Color = darkUncheckedThumbColor - .copy(alpha = ContentAlpha.disabled) - .compositeOver(MaterialTheme.colorScheme.surface) - ): CustomSwitchColors { - return CustomSwitchColors( - lightUncheckedTrackColor, - darkUncheckedTrackColor, - lightUncheckedThumbColor, - darkUncheckedThumbColor, - lightCheckedTrackColor, - darkCheckedTrackColor, - lightCheckedThumbColor, - darkCheckedThumbColor, - lightDisabledTrackColor, - darkDisabledTrackColor, - lightDisabledThumbColor, - darkDisabledThumbColor - ) - } - } -} - @Composable fun CustomSwitch( modifier: Modifier = Modifier, diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/DetailView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/DetailView.kt index 5a4035b..a1a227f 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/DetailView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/DetailView.kt @@ -1,13 +1,10 @@ package com.owenlejeune.tvtime.ui.screens -import androidx.compose.foundation.Image 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.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Card import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.Icon @@ -21,24 +18,17 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.constraintlayout.compose.ConstraintLayout import androidx.navigation.NavController -import coil.compose.rememberImagePainter -import coil.transform.RoundedCornersTransformation import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.DetailService import com.owenlejeune.tvtime.api.tmdb.MoviesService import com.owenlejeune.tvtime.api.tmdb.TvService import com.owenlejeune.tvtime.api.tmdb.model.* -import com.owenlejeune.tvtime.extensions.dpToPx -import com.owenlejeune.tvtime.ui.components.BackdropImage -import com.owenlejeune.tvtime.ui.components.ChipGroup -import com.owenlejeune.tvtime.ui.components.MinLinesText -import com.owenlejeune.tvtime.ui.components.PosterItem +import com.owenlejeune.tvtime.ui.components.* import com.owenlejeune.tvtime.utils.TmdbUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -160,12 +150,7 @@ private fun BackButton(modifier: Modifier, appNavController: NavController) { onClick = { appNavController.popBackStack() }, modifier = modifier .background( - brush = Brush.radialGradient( - colors = listOf( - Color.Black, - Color.Transparent - ) - ) + brush = Brush.radialGradient(colors = listOf(Color.Black, Color.Transparent)) ) .wrapContentSize() ) { @@ -178,11 +163,12 @@ private fun BackButton(modifier: Modifier, appNavController: NavController) { } @Composable -private fun ContentColumn(modifier: Modifier, - itemId: Int?, - mediaItem: MutableState, - service: DetailService, - mediaType: MediaViewType +private fun ContentColumn( + modifier: Modifier, + itemId: Int?, + mediaItem: MutableState, + service: DetailService, + mediaType: MediaViewType ) { Column( modifier = modifier @@ -190,7 +176,6 @@ private fun ContentColumn(modifier: Modifier, .wrapContentHeight() .padding(start = 16.dp, end = 16.dp, bottom = 16.dp) ) { - if (mediaType == MediaViewType.MOVIE) { MiscMovieDetails(mediaItem = mediaItem, service as MoviesService) } else { @@ -198,10 +183,12 @@ private fun ContentColumn(modifier: Modifier, } if (mediaItem.value?.overview?.isNotEmpty() == true) { - OverviewCard(mediaItem = mediaItem) + OverviewCard(mediaItem = mediaItem, modifier = Modifier.padding(bottom = 16.dp)) } - CastCard(itemId = itemId, service = service) + CastCard(itemId = itemId, service = service, modifier = Modifier.padding(bottom = 16.dp)) + + SimilarContent(itemId = itemId, service = service)//, modifier = Modifier.padding(bottom = 16.dp)) } } @@ -286,15 +273,9 @@ private fun MiscDetails( } @Composable -private fun OverviewCard(mediaItem: MutableState) { - Card( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(bottom = 16.dp), - shape = RoundedCornerShape(10.dp), - backgroundColor = MaterialTheme.colorScheme.surfaceVariant, - elevation = 8.dp +private fun OverviewCard(mediaItem: MutableState, modifier: Modifier = Modifier) { + ContentCard( + modifier = modifier ) { Text( modifier = Modifier @@ -309,7 +290,7 @@ private fun OverviewCard(mediaItem: MutableState) { } @Composable -private fun CastCard(itemId: Int?, service: DetailService) { +private fun CastCard(itemId: Int?, service: DetailService, modifier: Modifier = Modifier) { val castAndCrew = remember { mutableStateOf(null) } itemId?.let { if (castAndCrew.value == null) { @@ -317,29 +298,19 @@ private fun CastCard(itemId: Int?, service: DetailService) { } } - Card( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight(), - shape = RoundedCornerShape(10.dp), + ContentCard( + modifier = modifier, + title = stringResource(R.string.cast_label), backgroundColor = MaterialTheme.colorScheme.primary, - elevation = 8.dp + textColor = MaterialTheme.colorScheme.background ) { - Column(modifier = Modifier.fillMaxSize()) { - Text( - text = stringResource(R.string.cast_label), - style = MaterialTheme.typography.titleLarge, - modifier = Modifier.padding(start = 12.dp, top = 12.dp) - ) - LazyRow(modifier = Modifier - .fillMaxWidth() - .padding(12.dp) - ) { - items(castAndCrew.value?.cast?.size ?: 0) { i -> - val castMember = castAndCrew.value!!.cast[i] - - CastCrewCard(person = castMember) - } + LazyRow(modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + ) { + items(castAndCrew.value?.cast?.size ?: 0) { i -> + val castMember = castAndCrew.value!!.cast[i] + CastCrewCard(person = castMember) } } } @@ -347,45 +318,53 @@ private fun CastCard(itemId: Int?, service: DetailService) { @Composable private fun CastCrewCard(person: Person) { - val context = LocalContext.current - Column( + ImageTextCard( + title = person.name, modifier = Modifier .width(124.dp) - .wrapContentHeight() - .padding(end = 12.dp) + .wrapContentHeight(), + subtitle = when (person) { + is CastMember -> person.character + is CrewMember -> person.job + else -> null + }, + imageUrl = TmdbUtils.getFullPersonImagePath(person), + noDataImage = R.drawable.no_person_photo, + titleTextColor = MaterialTheme.colorScheme.onPrimary, + subtitleTextColor = Color.Unspecified + ) +} + +@Composable +fun SimilarContent(itemId: Int?, service: DetailService, modifier: Modifier = Modifier) { + val similarContent = remember { mutableStateOf(null) } + itemId?.let { + if (similarContent.value == null) { + fetchSimilarContent(itemId, service, similarContent) + } + } + + ContentCard( + modifier = modifier, + title = "Recommended" ) { - Image( - modifier = Modifier - .size(width = 120.dp, height = 180.dp), - painter = rememberImagePainter( - data = TmdbUtils.getFullPersonImagePath(person) ?: R.drawable.no_person_photo, - builder = { - transformations(RoundedCornersTransformation(5f.dpToPx(context))) - placeholder(R.drawable.placeholder) - } - ), - contentDescription = "" - ) - MinLinesText( - modifier = Modifier - .fillMaxWidth() - .padding(top = 5.dp), - minLines = 2, - text = person.name, - color = MaterialTheme.colorScheme.onPrimary, - style = MaterialTheme.typography.bodyMedium - ) - MinLinesText( - modifier = Modifier - .fillMaxWidth(), - minLines = 2, - text = when (person) { - is CastMember -> person.character - is CrewMember -> person.job - else -> "" - }, - style = MaterialTheme.typography.bodySmall - ) + LazyRow(modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(12.dp) + ) { + items(similarContent.value?.results?.size ?: 0) { i -> + val content = similarContent.value!!.results[i] + + ImageTextCard( + title = content.title, + modifier = Modifier + .width(124.dp) + .wrapContentHeight(), + imageUrl = TmdbUtils.getFullPosterPath(content) + ) + } + } } } @@ -444,4 +423,15 @@ private fun fetchTvContentRating(id: Int, service: TvService, contentRating: Mut } } } +} + +private fun fetchSimilarContent(id: Int, service: DetailService, similarContent: MutableState) { + CoroutineScope(Dispatchers.IO).launch { + val results = service.getSimilar(id, 1) + if (results.isSuccessful) { + withContext(Dispatchers.Main) { + similarContent.value = results.body() + } + } + } } \ No newline at end of file