Skip to content

Commit

Permalink
[Android] feat: API 명세 변경 대응 및 레시피 추천 디자인 수정(#31)(#32) (#33)
Browse files Browse the repository at this point in the history
* feat: 레시피 추천 Response 객체 정의

* feat: 레시피와 식재료 객체를 분리한다

* feat: 변경된 레시피 객체에 맞게 저장소를 재정의한다

* refactor: 필요없는 이전 레시피 추천 객체를 삭제한다

* feat: 레시피가 아닌 레시피 추천 객체를 요청한다

* feat: 레시피 추천, 상세 화면에 레시피 추천 객체를 전달한다

* feat: model 은 kotlin Serializable 로 직렬화

* feat: 레시피 추천 화면 디자인 시스템 추가

* feat(Stars): 별의 크기를 조절할 수 있다

* feat(IngredientResponse): 재료 이미지 응답값은 nullable 이다

* feat: 레시피 추천의 레시피 컴포넌트를 그린다

* feat: 스크린은 바텀 네비게이션만큼 띄우고 화면을 구성한다

* refactor: recipe 재사용 component 패키지 묶기

* feat(LikableHeart): 좋아요 가능한 하트 구성

* feat(FakeRecipeRepository): 가짜 레시피 저장소 아이템 개수 증가

* feat: 레시피 추천 새로고침 적용
  • Loading branch information
SeongHoonC authored Aug 2, 2024
1 parent 3b6c362 commit 980997a
Show file tree
Hide file tree
Showing 33 changed files with 673 additions and 471 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.sundaegukbap.banchango.core.data.repository.api

import com.sundaegukbap.banchango.LikableRecipe
import com.sundaegukbap.banchango.Recipe
import com.sundaegukbap.banchango.RecommendedRecipe

interface RecipeRepository {
suspend fun getRecipeRecommendation(): Result<List<Recipe>>
suspend fun getRecipeRecommendation(): Result<List<RecommendedRecipe>>

suspend fun getRecipeDetail(id: Long): Result<LikableRecipe>
suspend fun getRecipeDetail(id: Long): Result<RecommendedRecipe>

suspend fun likeRecipe(
id: Long,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package com.sundaegukbap.banchango.core.data.api

import com.sundaegukbap.banchango.core.data.api.model.RecipeRecommendResponse
import com.sundaegukbap.banchango.core.data.api.model.RecommendedRecipeResponse
import com.sundaegukbap.banchango.core.data.api.model.RecommendedRecipesResponse
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Path

internal interface RecipeApi {
@GET("api/recipe/recommand/{userId}")
suspend fun getRecipeRecommendation(
@Path("userId") userId: Long
): Response<List<RecipeRecommendResponse>>
@Path("userId") userId: Long,
): Response<RecommendedRecipesResponse>

@GET("api/recipe/{userId}/{recipeId}")
suspend fun getRecipeDetail(
@Path("userId") userId: Long,
@Path("recipeId") recipeId: Long
): Response<RecipeRecommendResponse>
@Path("recipeId") recipeId: Long,
): Response<RecommendedRecipeResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sundaegukbap.banchango.core.data.api.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class HaveResponse(
@SerialName("ingredientDtos")
val ingredients: List<IngredientResponse>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.sundaegukbap.banchango.core.data.api.model

import kotlinx.serialization.Serializable

@Serializable
data class IngredientResponse(
val id: Long,
val name: String,
val kind: String,
val image: String?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sundaegukbap.banchango.core.data.api.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class NeedResponse(
@SerialName("ingredientDtos")
val ingredients: List<IngredientResponse>,
)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package com.sundaegukbap.banchango.core.data.api.model
import kotlinx.serialization.Serializable

@Serializable
data class RecipeRecommendResponse(
data class RecipeResponse(
val id: Long,
val name: String,
val introduction: String,
val image: String,
val link: String,
val have: List<String>,
val need: List<String>,
val servings: Int,
val cookingTime: Int,
val difficulty: String
val difficulty: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sundaegukbap.banchango.core.data.api.model

import kotlinx.serialization.Serializable

@Serializable
data class RecommendedRecipeResponse(
val recipe: RecipeResponse,
val have: HaveResponse,
val need: NeedResponse,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sundaegukbap.banchango.core.data.api.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class RecommendedRecipesResponse(
@SerialName("recommandedRecipeResponses")
val recommendedRecipeResponses: List<RecommendedRecipeResponse>,
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.sundaegukbap.banchango.core.data.di

import com.sundaegukbap.banchango.core.data.repository.DefaultRecipeRepository
import com.sundaegukbap.banchango.core.data.repository.FakeRecipeRepository
import com.sundaegukbap.banchango.core.data.repository.api.RecipeRepository
import dagger.Binds
import dagger.Module
Expand All @@ -11,7 +10,6 @@ import dagger.hilt.components.SingletonComponent
@InstallIn(SingletonComponent::class)
@Module
internal abstract class RepositoryModule {

@Binds
abstract fun bindsRecipeRepository(recipeRepository: FakeRecipeRepository): RecipeRepository
abstract fun bindsRecipeRepository(recipeRepository: DefaultRecipeRepository): RecipeRepository
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,58 @@
package com.sundaegukbap.banchango.core.data.mapper

import com.sundaegukbap.banchango.Ingredient
import com.sundaegukbap.banchango.IngredientKind
import com.sundaegukbap.banchango.Recipe
import com.sundaegukbap.banchango.RecipeDifficulty
import com.sundaegukbap.banchango.core.data.api.model.RecipeRecommendResponse
import com.sundaegukbap.banchango.RecommendedRecipe
import com.sundaegukbap.banchango.core.data.api.model.IngredientResponse
import com.sundaegukbap.banchango.core.data.api.model.RecipeResponse
import com.sundaegukbap.banchango.core.data.api.model.RecommendedRecipeResponse
import com.sundaegukbap.banchango.core.data.api.model.RecommendedRecipesResponse

internal fun List<RecipeRecommendResponse>.toData(): List<Recipe> = map { it.toData() }

internal fun RecipeRecommendResponse.toData(): Recipe {
val difficulty = when (difficulty) {
"아무나" -> RecipeDifficulty.ANYONE
"초보" -> RecipeDifficulty.BEGINNER
"중급" -> RecipeDifficulty.INTERMEDIATE
"고급" -> RecipeDifficulty.ADVANCED
"신의경지" -> RecipeDifficulty.GODLIKE
else -> RecipeDifficulty.ANYONE
internal fun List<IngredientResponse>.toData() =
map {
Ingredient(
id = it.id,
name = it.name,
image = it.image ?: "",
kind =
when (it.kind) {
"육류" -> IngredientKind.MEAT
"해산물" -> IngredientKind.SEAFOOD
"채소" -> IngredientKind.VEGETABLE
"과일" -> IngredientKind.FRUIT
"기타" -> IngredientKind.ETC
else -> IngredientKind.ETC
},
)
}
return Recipe(

internal fun RecommendedRecipesResponse.toData() = recommendedRecipeResponses.map { it.toData() }

internal fun RecommendedRecipeResponse.toData() =
RecommendedRecipe(
recipe = recipe.toData(),
hadIngredients = have.ingredients.toData(),
neededIngredients = need.ingredients.toData(),
)

internal fun RecipeResponse.toData() =
Recipe(
id = id,
name = name,
introduction = introduction,
image = image,
link = link,
have = have,
need = need,
servings = servings,
cookingTime = cookingTime,
difficulty = difficulty,
difficulty =
when (difficulty) {
"아무나" -> RecipeDifficulty.ANYONE
"초보" -> RecipeDifficulty.BEGINNER
"중급" -> RecipeDifficulty.INTERMEDIATE
"고급" -> RecipeDifficulty.ADVANCED
"신의경지" -> RecipeDifficulty.GODLIKE
else -> RecipeDifficulty.ANYONE
},
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.sundaegukbap.banchango.core.data.repository

import com.sundaegukbap.banchango.LikableRecipe
import com.sundaegukbap.banchango.Recipe
import com.sundaegukbap.banchango.RecommendedRecipe
import com.sundaegukbap.banchango.core.data.api.RecipeApi
import com.sundaegukbap.banchango.core.data.mapper.toData
import com.sundaegukbap.banchango.core.data.repository.api.RecipeRepository
Expand All @@ -12,7 +11,7 @@ internal class DefaultRecipeRepository
constructor(
private val recipeApi: RecipeApi,
) : RecipeRepository {
override suspend fun getRecipeRecommendation(): Result<List<Recipe>> =
override suspend fun getRecipeRecommendation(): Result<List<RecommendedRecipe>> =
runCatching {
val response = recipeApi.getRecipeRecommendation(1)
if (response.isSuccessful) {
Expand All @@ -25,14 +24,14 @@ internal class DefaultRecipeRepository
}
}

override suspend fun getRecipeDetail(id: Long): Result<LikableRecipe> =
override suspend fun getRecipeDetail(id: Long): Result<RecommendedRecipe> =
runCatching {
val response = recipeApi.getRecipeDetail(1, id)
if (response.isSuccessful) {
if (response.body() == null) {
throw IllegalStateException("Response body is null")
}
LikableRecipe(response.body()!!.toData(), false)
response.body()!!.toData()
} else {
throw IllegalStateException("Response is not successful")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,59 @@
package com.sundaegukbap.banchango.core.data.repository

import com.sundaegukbap.banchango.LikableRecipe
import com.sundaegukbap.banchango.Ingredient
import com.sundaegukbap.banchango.IngredientKind
import com.sundaegukbap.banchango.Recipe
import com.sundaegukbap.banchango.RecipeDifficulty
import com.sundaegukbap.banchango.RecommendedRecipe
import com.sundaegukbap.banchango.core.data.repository.api.RecipeRepository
import javax.inject.Inject

class FakeRecipeRepository
@Inject
constructor() : RecipeRepository {
override suspend fun getRecipeRecommendation(): Result<List<Recipe>> =
override suspend fun getRecipeRecommendation(): Result<List<RecommendedRecipe>> =
Result.success(
List(3) {
List(10) {
RecommendedRecipe(
Recipe(
id = (it + 1).toLong(),
name = "간장계란볶음밥",
introduction = "아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요. 아이들이 더 좋아할거예요.",
image = "https://recipe1.ezmember.co.kr/cache/recipe/2018/05/26/d0c6701bc673ac5c18183b47212a58571.jpg",
link = "https://www.10000recipe.com/recipe/6889616",
cookingTime = 10,
servings = 2,
difficulty = RecipeDifficulty.BEGINNER,
),
hadIngredients =
listOf(
Ingredient(1L, "계란", IngredientKind.ETC, ""),
Ingredient(1L, "간장", IngredientKind.ETC, ""),
),
neededIngredients = listOf(Ingredient(1L, "참기름", IngredientKind.ETC, "")),
)
},
)

override suspend fun getRecipeDetail(id: Long): Result<RecommendedRecipe> =
Result.success(
RecommendedRecipe(
Recipe(
id = (it + 1).toLong(),
id = 1,
name = "간장계란볶음밥",
introduction = "아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요. 아이들이 더 좋아할거예요.",
image = "https://recipe1.ezmember.co.kr/cache/recipe/2018/05/26/d0c6701bc673ac5c18183b47212a58571.jpg",
link = "https://www.10000recipe.com/recipe/6889616",
cookingTime = 10,
servings = 2,
difficulty = RecipeDifficulty.BEGINNER,
have = listOf("계란", "간장"),
need = listOf("식초", "당근", "감자"),
)
},
)

override suspend fun getRecipeDetail(id: Long): Result<LikableRecipe> =
Result.success(
LikableRecipe(
recipe =
Recipe(
id = id,
name = "간장계란볶음밥",
introduction =
"아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요. 아이들이 더 좋아할거예요." +
"아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요. \n " +
"아이들이 더 좋아할거예요. \n" +
"아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요.\n" +
" 아이들이 더 좋아할거예요.\n" +
" 아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요.\n 아이들이 더 좋아할거예요.\n " +
"아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요.\n 아이들이 더 좋아할거예요.\n " +
"아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요.\n 아이들이 더 좋아할거예요.\n" +
" 아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요.\n 아이들이 더 좋아할거예요.\n " +
"아주 간단하면서 맛있는 계란간장볶음밥으로 한끼식사 만들어보세요.\n 아이들이 더 좋아할거예요.\n",
image = "https://recipe1.ezmember.co.kr/cache/recipe/2018/05/26/d0c6701bc673ac5c18183b47212a58571.jpg",
link = "https://www.10000recipe.com/recipe/6889616",
cookingTime = 10,
servings = 2,
difficulty = RecipeDifficulty.BEGINNER,
have = listOf("계란", "간장"),
need = listOf("식초", "당근", "감자"),
),
hadIngredients =
listOf(
Ingredient(1L, "계란", IngredientKind.ETC, ""),
Ingredient(1L, "간장", IngredientKind.ETC, ""),
),
isLiked = false,
neededIngredients = listOf(Ingredient(1L, "참기름", IngredientKind.ETC, "")),
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ val Orange = Color(0xFFFF7A00)
val LightOrange = Color(0xFFFFC085)
val White = Color(0xFFFFFFFF)
val Black = Color(0xFF000000)
val lightGray = Color(0xFFF5F1EE)

// 투명도 50%
val SemiTransparentOrange = Color(0x80FF7A00)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.sundaegukbap.banchango

data class Ingredient(
val id: Long,
val name: String,
val kind: IngredientKind,
val image: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sundaegukbap.banchango

enum class IngredientKind {
MEAT,
VEGETABLE,
FRUIT,
SEAFOOD,
SAUCE,
ETC,
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.sundaegukbap.banchango

data class LikableRecipe(
val recipe: Recipe,
val recommendedRecipe: RecommendedRecipe,
val isLiked: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ data class Recipe(
val cookingTime: Int,
val servings: Int,
val difficulty: RecipeDifficulty,
val have: List<String>,
val need: List<String>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sundaegukbap.banchango

data class RecommendedRecipe(
val recipe: Recipe,
val hadIngredients: List<Ingredient>,
val neededIngredients: List<Ingredient>,
)
Loading

0 comments on commit 980997a

Please sign in to comment.