From 0f8e1ad76c9a25c1a00d06e410cf6e80e4837fd3 Mon Sep 17 00:00:00 2001 From: Slee Date: Thu, 25 Jan 2024 13:09:17 -0800 Subject: [PATCH] Cleanup by using reified type --- .../com/sample/tmdb/common/model/TMDbType.kt | 5 - .../sample/tmdb/feed/FeedCollectionList.kt | 228 ---------------- .../java/com/sample/tmdb/feed/FeedScreen.kt | 243 +++++++++++++++++- 3 files changed, 235 insertions(+), 241 deletions(-) delete mode 100644 common/src/main/java/com/sample/tmdb/common/model/TMDbType.kt delete mode 100644 features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedCollectionList.kt diff --git a/common/src/main/java/com/sample/tmdb/common/model/TMDbType.kt b/common/src/main/java/com/sample/tmdb/common/model/TMDbType.kt deleted file mode 100644 index c4be2ea..0000000 --- a/common/src/main/java/com/sample/tmdb/common/model/TMDbType.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.sample.tmdb.common.model - -enum class TMDbType { - MOVIES, TV_SERIES -} \ No newline at end of file diff --git a/features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedCollectionList.kt b/features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedCollectionList.kt deleted file mode 100644 index 6137ed4..0000000 --- a/features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedCollectionList.kt +++ /dev/null @@ -1,228 +0,0 @@ -package com.sample.tmdb.feed - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Card -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import androidx.navigation.NavController -import coil.compose.AsyncImage -import com.sample.tmdb.common.MainDestinations -import com.sample.tmdb.common.model.TMDbItem -import com.sample.tmdb.common.model.TMDbType -import com.sample.tmdb.common.ui.Dimens -import com.sample.tmdb.common.ui.theme.TmdbPagingComposeTheme -import com.sample.tmdb.domain.model.FeedWrapper -import com.sample.tmdb.domain.model.Movie -import com.sample.tmdb.domain.model.SortType - -@Composable -fun FeedCollectionList( - tmdbType: TMDbType, - navController: NavController, - collection: List>, - onFeedClick: (TMDbItem) -> Unit -) { - LazyColumn { - item { - Spacer( - Modifier.windowInsetsTopHeight( - WindowInsets.statusBars.add(WindowInsets(top = 56.dp)) - ) - ) - } - itemsIndexed(collection) { index, feedCollection -> - FeedCollection( - tmdbType = tmdbType, - navController = navController, - feedCollection = feedCollection, - onFeedClick = onFeedClick, - index = index - ) - } - } -} - -@Composable -private fun FeedCollection( - tmdbType: TMDbType, - navController: NavController, - feedCollection: FeedWrapper, - onFeedClick: (TMDbItem) -> Unit, - index: Int, - modifier: Modifier = Modifier, -) { - Column(modifier = modifier) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .heightIn(min = 36.dp) - .padding(start = Dimens.PaddingNormal) - ) { - Text( - text = stringResource(id = feedCollection.sortTypeResourceId), - maxLines = 1, - color = MaterialTheme.colors.onSurface, - modifier = Modifier - .weight(1f) - .wrapContentWidth(Alignment.Start) - ) - Text( - text = stringResource(R.string.more_item), - color = MaterialTheme.colors.onSurface, - modifier = Modifier - .align(Alignment.CenterVertically) - .clickable { - when (tmdbType) { - TMDbType.MOVIES -> { - when (feedCollection.sortType) { - SortType.TRENDING -> { - navController.navigate(MainDestinations.TMDB_TRENDING_MOVIES_ROUTE) - } - - SortType.MOST_POPULAR -> { - navController.navigate(MainDestinations.TMDB_POPULAR_MOVIES_ROUTE) - } - - SortType.NOW_PLAYING -> { - navController.navigate(MainDestinations.TMDB_NOW_PLAYING_MOVIES_ROUTE) - } - - SortType.UPCOMING -> { - navController.navigate(MainDestinations.TMDB_UPCOMING_MOVIES_ROUTE) - } - - SortType.HIGHEST_RATED -> { - navController.navigate(MainDestinations.TMDB_TOP_RATED_MOVIES_ROUTE) - } - - SortType.DISCOVER -> { - navController.navigate(MainDestinations.TMDB_DISCOVER_MOVIES_ROUTE) - } - } - } - - TMDbType.TV_SERIES -> { - when (feedCollection.sortType) { - SortType.TRENDING -> { - navController.navigate(MainDestinations.TMDB_TRENDING_TV_SHOW_ROUTE) - } - - SortType.MOST_POPULAR -> { - navController.navigate(MainDestinations.TMDB_POPULAR_TV_SHOW_ROUTE) - } - - SortType.NOW_PLAYING -> { - navController.navigate(MainDestinations.TMDB_AIRING_TODAY_TV_SHOW_ROUTE) - } - - SortType.UPCOMING -> { - navController.navigate(MainDestinations.TMDB_ON_THE_AIR_TV_SHOW_ROUTE) - } - - SortType.HIGHEST_RATED -> { - navController.navigate(MainDestinations.TMDB_TOP_RATED_TV_SHOW_ROUTE) - } - - SortType.DISCOVER -> { - navController.navigate(MainDestinations.TMDB_DISCOVER_TV_SHOW_ROUTE) - } - } - } - } - } - .padding(Dimens.PaddingNormal) - ) - } - Feeds(feedCollection.feeds, onFeedClick, index) - } -} - -@Composable -private fun Feeds( - feeds: List, - onFeedClick: (TMDbItem) -> Unit, - index: Int, - modifier: Modifier = Modifier -) { - LazyRow( - modifier = modifier, - contentPadding = PaddingValues(start = Dimens.PaddingMicro, end = Dimens.PaddingMicro) - ) { - items(feeds) { feed -> - TMDbItem(feed, onFeedClick, index) - } - } -} - -@Composable -private fun TMDbItem( - tmdbItem: T, - onFeedClick: (TMDbItem) -> Unit, - index: Int -) { - val itemWidth: Dp - val imageUrl: String? - if (index % 3 == 0) { - itemWidth = 220.dp - imageUrl = tmdbItem.backdropUrl - } else { - itemWidth = 120.dp - imageUrl = tmdbItem.posterUrl - } - Card( - modifier = Modifier - .padding(Dimens.PaddingSmall) - .clickable(onClick = { onFeedClick(tmdbItem) }), - shape = RoundedCornerShape(10.dp) - ) { - Column { - AsyncImage( - model = imageUrl, - contentDescription = null, - modifier = Modifier - .size(width = itemWidth, height = 180.dp), - contentScale = ContentScale.Crop - ) - Text( - text = tmdbItem.name, - fontSize = TmdbPagingComposeTheme.fontSizes.sp_11, - color = MaterialTheme.colors.onSurface, - textAlign = TextAlign.Center, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - modifier = Modifier - .size(width = itemWidth, height = 36.dp) - .wrapContentHeight() - ) - } - } -} - -@Preview("default") -@Composable -fun FeedCardPreview() { - TmdbPagingComposeTheme { - val movie = Movie(1, "", null, null, null, "Movie", 1.0, 2) - TMDbItem( - tmdbItem = movie, - onFeedClick = {}, - 0 - ) - } -} \ No newline at end of file diff --git a/features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedScreen.kt b/features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedScreen.kt index c76421e..0bdb49c 100644 --- a/features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedScreen.kt +++ b/features/feature-feed/src/main/java/com/sample/tmdb/feed/FeedScreen.kt @@ -1,15 +1,52 @@ package com.sample.tmdb.feed import androidx.annotation.StringRes +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.add +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsTopHeight +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import coil.compose.AsyncImage +import com.sample.tmdb.common.MainDestinations import com.sample.tmdb.common.model.TMDbItem -import com.sample.tmdb.common.model.TMDbType import com.sample.tmdb.common.ui.Content +import com.sample.tmdb.common.ui.Dimens import com.sample.tmdb.common.ui.component.DestinationBar +import com.sample.tmdb.common.ui.theme.TmdbPagingComposeTheme +import com.sample.tmdb.domain.model.FeedWrapper +import com.sample.tmdb.domain.model.Movie +import com.sample.tmdb.domain.model.SortType +import com.sample.tmdb.domain.model.TVShow import com.sample.tmdb.common.R as R1 @Composable @@ -21,7 +58,6 @@ fun MovieFeedScreen( ) { FeedScreen( viewModel = viewModel, - type = TMDbType.MOVIES, navController = navController, onSearchClicked = onSearchMovie, onClick = onClick, @@ -38,7 +74,6 @@ fun TVShowFeedScreen( ) { FeedScreen( viewModel = viewModel, - type = TMDbType.TV_SERIES, navController = navController, onSearchClicked = onSearchTVShow, onClick = onClick, @@ -47,18 +82,17 @@ fun TVShowFeedScreen( } @Composable -private fun FeedScreen( +private inline fun FeedScreen( viewModel: BaseFeedViewModel, - type: TMDbType, navController: NavController, - onSearchClicked: () -> Unit, - onClick: (TMDbItem) -> Unit, + noinline onSearchClicked: () -> Unit, + crossinline onClick: (TMDbItem) -> Unit, @StringRes resourceId: Int ) { Content(viewModel = viewModel) { feeds -> Box { - FeedCollectionList(type, navController, feeds, onClick) + FeedCollectionList(navController, feeds, onClick) DestinationBar( title = stringResource( R.string.app_title, stringResource(resourceId) @@ -66,4 +100,197 @@ private fun FeedScreen( ) } } +} + +@Composable +private inline fun FeedCollectionList( + navController: NavController, + collection: List>, + crossinline onFeedClick: (TMDbItem) -> Unit +) { + LazyColumn { + item { + Spacer( + Modifier.windowInsetsTopHeight( + WindowInsets.statusBars.add(WindowInsets(top = 56.dp)) + ) + ) + } + itemsIndexed(collection) { index, feedCollection -> + FeedCollection( + navController = navController, + feedCollection = feedCollection, + onFeedClick = onFeedClick, + index = index + ) + } + } +} + +@Composable +private inline fun FeedCollection( + navController: NavController, + feedCollection: FeedWrapper, + crossinline onFeedClick: (TMDbItem) -> Unit, + index: Int, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .heightIn(min = 36.dp) + .padding(start = Dimens.PaddingNormal) + ) { + Text( + text = stringResource(id = feedCollection.sortTypeResourceId), + maxLines = 1, + color = MaterialTheme.colors.onSurface, + modifier = Modifier + .weight(1f) + .wrapContentWidth(Alignment.Start) + ) + Text( + text = stringResource(R.string.more_item), + color = MaterialTheme.colors.onSurface, + modifier = Modifier + .align(Alignment.CenterVertically) + .clickable { + when (T::class) { + Movie::class -> { + when (feedCollection.sortType) { + SortType.TRENDING -> { + navController.navigate(MainDestinations.TMDB_TRENDING_MOVIES_ROUTE) + } + + SortType.MOST_POPULAR -> { + navController.navigate(MainDestinations.TMDB_POPULAR_MOVIES_ROUTE) + } + + SortType.NOW_PLAYING -> { + navController.navigate(MainDestinations.TMDB_NOW_PLAYING_MOVIES_ROUTE) + } + + SortType.UPCOMING -> { + navController.navigate(MainDestinations.TMDB_UPCOMING_MOVIES_ROUTE) + } + + SortType.HIGHEST_RATED -> { + navController.navigate(MainDestinations.TMDB_TOP_RATED_MOVIES_ROUTE) + } + + SortType.DISCOVER -> { + navController.navigate(MainDestinations.TMDB_DISCOVER_MOVIES_ROUTE) + } + } + } + + TVShow::class -> { + when (feedCollection.sortType) { + SortType.TRENDING -> { + navController.navigate(MainDestinations.TMDB_TRENDING_TV_SHOW_ROUTE) + } + + SortType.MOST_POPULAR -> { + navController.navigate(MainDestinations.TMDB_POPULAR_TV_SHOW_ROUTE) + } + + SortType.NOW_PLAYING -> { + navController.navigate(MainDestinations.TMDB_AIRING_TODAY_TV_SHOW_ROUTE) + } + + SortType.UPCOMING -> { + navController.navigate(MainDestinations.TMDB_ON_THE_AIR_TV_SHOW_ROUTE) + } + + SortType.HIGHEST_RATED -> { + navController.navigate(MainDestinations.TMDB_TOP_RATED_TV_SHOW_ROUTE) + } + + SortType.DISCOVER -> { + navController.navigate(MainDestinations.TMDB_DISCOVER_TV_SHOW_ROUTE) + } + } + } + } + } + .padding(Dimens.PaddingNormal) + ) + } + Feeds(feedCollection.feeds, onFeedClick, index) + } +} + +@Composable +private inline fun Feeds( + feeds: List, + crossinline onFeedClick: (TMDbItem) -> Unit, + index: Int, + modifier: Modifier = Modifier +) { + LazyRow( + modifier = modifier, + contentPadding = PaddingValues(start = Dimens.PaddingMicro, end = Dimens.PaddingMicro) + ) { + items(feeds) { feed -> + TMDbItem(feed, onFeedClick, index) + } + } +} + +@Composable +private inline fun TMDbItem( + tmdbItem: T, + crossinline onFeedClick: (TMDbItem) -> Unit, + index: Int +) { + val itemWidth: Dp + val imageUrl: String? + if (index % 3 == 0) { + itemWidth = 220.dp + imageUrl = tmdbItem.backdropUrl + } else { + itemWidth = 120.dp + imageUrl = tmdbItem.posterUrl + } + Card( + modifier = Modifier + .padding(Dimens.PaddingSmall) + .clickable(onClick = { onFeedClick(tmdbItem) }), + shape = RoundedCornerShape(10.dp) + ) { + Column { + AsyncImage( + model = imageUrl, + contentDescription = null, + modifier = Modifier + .size(width = itemWidth, height = 180.dp), + contentScale = ContentScale.Crop + ) + Text( + text = tmdbItem.name, + fontSize = TmdbPagingComposeTheme.fontSizes.sp_11, + color = MaterialTheme.colors.onSurface, + textAlign = TextAlign.Center, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .size(width = itemWidth, height = 36.dp) + .wrapContentHeight() + ) + } + } +} + +@Preview("default") +@Composable +fun FeedCardPreview() { + TmdbPagingComposeTheme { + val movie = Movie(1, "", null, null, null, "Movie", 1.0, 2) + TMDbItem( + tmdbItem = movie, + onFeedClick = {}, + 0 + ) + } } \ No newline at end of file