diff --git a/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeItem.kt b/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeItem.kt index 571da9e..18e95e3 100644 --- a/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeItem.kt +++ b/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeItem.kt @@ -1,54 +1,113 @@ package com.sundaegukbap.banchango.feature.recipe.recommend +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.focusModifier +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.imageResource +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight.Companion.Bold import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.util.lerp import com.sundaegukbap.banchango.Recipe import com.sundaegukbap.banchango.core.designsystem.component.NetworkImage import com.sundaegukbap.banchango.core.designsystem.theme.BanchangoTheme +import com.sundaegukbap.banchango.feature.reciperecommend.R @Composable fun RecipeItem( recipeItemUiState: RecipeRecommendItemUiState, + pageOffset: Float, onRecipeClick: (Recipe) -> Unit = {}, onRecipeLikeClick: (Recipe) -> Unit = {}, ) { Box( modifier = Modifier .fillMaxSize() - + .graphicsLayer { + scaleX = lerp( + start = 0.9f, + stop = 1f, + fraction = 1f - pageOffset.coerceIn(0f, 1f) + ) + scaleY = lerp( + start = 0.9f, + stop = 1f, + fraction = 1f - pageOffset.coerceIn(0f, 1f) + ) + } + .clip(shape = RoundedCornerShape(44.dp)) + .clickable { + onRecipeClick(recipeItemUiState.recipe) + } ) { NetworkImage( modifier = Modifier - .clip(shape = RoundedCornerShape(32.dp)) - .fillMaxSize() - .clickable { - onRecipeClick(recipeItemUiState.recipe) - }, + .fillMaxSize(), url = recipeItemUiState.recipe.image, ) RecipeInfo( recipeItemUiState.recipe, modifier = Modifier.fillMaxSize(), - onLikeClick = { onRecipeLikeClick(recipeItemUiState.recipe) } ) + + RecipeIngredientCount( + modifier = Modifier + .align(Alignment.BottomStart), + have = recipeItemUiState.recipe.have.count(), + need = recipeItemUiState.recipe.need.count(), + imageSize = 95, + ) + + RecipeLikeButton( + modifier = Modifier + .align(Alignment.BottomEnd), + isLiked = recipeItemUiState.isLiked, + onLikeClick = { onRecipeLikeClick(recipeItemUiState.recipe) }, + ) + + Box( + Modifier + .fillMaxSize() + .background( + color = Color.Black.copy( + alpha = lerp( + start = 0.5f, + stop = 0f, + fraction = 1f - pageOffset.coerceIn(0f, 1f) + ) + ), + ) + ) { + + } } } @@ -56,42 +115,58 @@ fun RecipeItem( private fun RecipeInfo( recipe: Recipe, modifier: Modifier, - onLikeClick: () -> Unit, ) { Box(modifier = modifier) { Text( text = recipe.name, color = Color.White, - fontSize = 16.sp, + fontSize = 24.sp, + maxLines = 2, + minLines = 2, style = TextStyle(fontWeight = Bold), textAlign = TextAlign.Center, modifier = Modifier - .padding(horizontal = 24.dp, vertical = 12.dp) - .clip(shape = RoundedCornerShape(32.dp)) - .background(Color.Black.copy(alpha = 0.5f)) + .background( + brush = Brush.verticalGradient(listOf(Color.Black, Color.Transparent)), + alpha = 0.8f + ) .fillMaxWidth() - .padding(16.dp), + .padding(top = 40.dp, bottom = 40.dp), ) + } +} - Text( - text = "${recipe.have.count()} / ${recipe.need.count() + recipe.have.count()}", - modifier = Modifier - .align(Alignment.BottomStart) - .padding(start = 24.dp, bottom = 24.dp), - color = Color.White, +@Composable +fun RecipeLikeButton( + modifier: Modifier, + isLiked: Boolean, + onLikeClick: () -> Unit, +) { + Box( + modifier = modifier + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() }, + onClick = onLikeClick + ) + ) { + Image( + painter = painterResource(id = R.drawable.img_btn_right), + contentDescription = null, + modifier = Modifier.size(95.dp), ) - Button( + Image( + painter = painterResource(id = if (isLiked) R.drawable.ic_heart_filled else R.drawable.ic_heart), + contentDescription = null, modifier = Modifier - .align(Alignment.BottomEnd) - .padding(end = 24.dp, bottom = 12.dp), - onClick = onLikeClick, - ) { - Text("좋아요") - } + .size(32.dp) + .align(Alignment.Center) + .padding(top = 8.dp), + ) } } -@Preview(showBackground = true) +@Preview(showBackground = false) @Composable fun RecipeItemPreview() { BanchangoTheme { @@ -112,6 +187,43 @@ fun RecipeItemPreview() { ), isLiked = true, ), + pageOffset = 0f, ) } } + +@Composable +fun RecipeIngredientCount( + modifier: Modifier, + imageSize: Int, + have: Int, + need: Int, +) { + Box(modifier = modifier) { + Image( + modifier = Modifier.size(imageSize.dp), + painter = painterResource(id = R.drawable.img_wave), + contentDescription = null, + ) + Text( + text = "$have / ${need + have}", + modifier = Modifier + .padding(top = 32.dp) + .align(Alignment.Center), + color = Color.White, + style = TextStyle( + letterSpacing = 0.1.sp, + fontWeight = Bold, + fontSize = 20.sp + ), + ) + } +} + +@Preview(showBackground = false) +@Composable +fun RecipeIngredientCountPreview() { + BanchangoTheme { + RecipeIngredientCount(modifier = Modifier, have = 3, need = 7, imageSize = 120) + } +} diff --git a/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeRecommendViewModel.kt b/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeRecommendViewModel.kt index f77ffaf..c0efaba 100644 --- a/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeRecommendViewModel.kt +++ b/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipeRecommendViewModel.kt @@ -22,11 +22,12 @@ class RecipeRecommendViewModel @Inject constructor( init { viewModelScope.launch { - recipeRepository.getRecipeRecommendation().onSuccess { recipes -> - _uiState.value = RecipeRecommendUiState.Success(recipes.toUiState()) - }.onFailure { throwable -> - throwable.printStackTrace() - } + recipeRepository.getRecipeRecommendation() + .onSuccess { recipes -> + _uiState.value = RecipeRecommendUiState.Success(recipes.toUiState()) + }.onFailure { throwable -> + throwable.printStackTrace() + } } } @@ -49,7 +50,7 @@ class RecipeRecommendViewModel @Inject constructor( val successUiState = _uiState.value as? RecipeRecommendUiState.Success ?: return val likedRecipeUiStates = successUiState.recipes.map { recipeUiState -> if (recipeUiState.recipe.id == recipe.id) { - recipeUiState.copy(isLiked = true) + recipeUiState.copy(isLiked = !recipeUiState.isLiked) } else { recipeUiState } diff --git a/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipesRecommendScreen.kt b/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipesRecommendScreen.kt index f96f44a..463b29d 100644 --- a/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipesRecommendScreen.kt +++ b/Android/feature/recipe/src/main/java/com/sundaegukbap/banchango/feature/recipe/recommend/RecipesRecommendScreen.kt @@ -18,6 +18,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.sundaegukbap.banchango.Recipe import com.sundaegukbap.banchango.core.designsystem.theme.BanchangoTheme +import kotlin.math.absoluteValue @Composable fun RecipeRecommendRoute( @@ -92,10 +93,13 @@ private fun RecipeRecommendScreen( if (page >= recipeRecommends.size - 2) { onLastPageVisible() } + val pageOffset = + (pagerState.currentPage - page + pagerState.currentPageOffsetFraction).absoluteValue RecipeItem( recipeItemUiState = recipeRecommends[page], onRecipeClick = onRecipeClick, onRecipeLikeClick = onLikeClick, + pageOffset = pageOffset, ) } } diff --git a/Android/feature/recipe/src/main/res/drawable/ic_heart.xml b/Android/feature/recipe/src/main/res/drawable/ic_heart.xml new file mode 100644 index 0000000..c7181cd --- /dev/null +++ b/Android/feature/recipe/src/main/res/drawable/ic_heart.xml @@ -0,0 +1,10 @@ + + + diff --git a/Android/feature/recipe/src/main/res/drawable/ic_heart_filled.xml b/Android/feature/recipe/src/main/res/drawable/ic_heart_filled.xml new file mode 100644 index 0000000..cb9cbf8 --- /dev/null +++ b/Android/feature/recipe/src/main/res/drawable/ic_heart_filled.xml @@ -0,0 +1,10 @@ + + + diff --git a/Android/feature/recipe/src/main/res/drawable/img_btn_right.xml b/Android/feature/recipe/src/main/res/drawable/img_btn_right.xml new file mode 100644 index 0000000..c44994e --- /dev/null +++ b/Android/feature/recipe/src/main/res/drawable/img_btn_right.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/Android/feature/recipe/src/main/res/drawable/img_wave.xml b/Android/feature/recipe/src/main/res/drawable/img_wave.xml new file mode 100644 index 0000000..166c514 --- /dev/null +++ b/Android/feature/recipe/src/main/res/drawable/img_wave.xml @@ -0,0 +1,16 @@ + + + + + + +