Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] feat: 레시피 추천 목록 프로토타입 구현(#13) #14

Merged
merged 8 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.org.jetbrains.kotlin.kapt)
alias(libs.plugins.hilt)
}

android {
Expand Down Expand Up @@ -59,11 +61,26 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.lifecycle.runtime.compose.android)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)

implementation(libs.dagger.hilt.android)
kapt(libs.dagger.hilt.compiler)
implementation(libs.lifecycle.viewmodel.ktx)

// navigation
implementation(libs.navigation.compose)
implementation(libs.hilt.navigation.compose)

// status bar
implementation(libs.accompanist.systemuicontroller)

// glide
implementation(libs.glide.compose)
}
7 changes: 5 additions & 2 deletions Android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".BanchangoApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -11,9 +14,9 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Banchango"
tools:targetApi="31">
tools:targetApi="34">
<activity
android:name=".MainActivity"
android:name=".presentation.reciperecommend.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Banchango">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sundaegukbap.banchango

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class BanchangoApplication : Application()

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.sundaegukbap.banchango.core.designsystem

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.layout.ContentScale
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
import com.bumptech.glide.integration.compose.GlideImage
import com.bumptech.glide.integration.compose.placeholder

@OptIn(ExperimentalGlideComposeApi::class)
@Composable
fun NetworkImage(modifier: Modifier, url: String) {
GlideImage(
model = url,
contentScale = ContentScale.Crop,
contentDescription = null,
modifier = modifier.fillMaxSize(),
loading = placeholder(ColorPainter(Color(0xD9FFFFFF))),
failure = placeholder(ColorPainter(Color(0xD9FFFFFF))),
)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.sundaegukbap.banchango.model

data class Recipe(
val id: Long,
val name: String,
val introduction: String,
val image: String,
val link: String,
val cookingTime: Int,
val servings: Int,
val difficulty: String,
val have: List<Int>,
val need: List<Int>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.sundaegukbap.banchango.presentation.reciperecommend

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.ui.graphics.Color
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.sundaegukbap.banchango.ui.theme.BanchangoTheme
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : ComponentActivity() {

private val viewModel: RecipeRecommendViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
viewModel.getRecipeRecommendation()
setContent {
BanchangoTheme {
val systemUiController = rememberSystemUiController()
systemUiController.setSystemBarsColor(color = Color(0xBFFFFFFF), darkIcons = true)
systemUiController.setNavigationBarColor(
color = Color(0xFFFFFFFF)
)
RecipesRecommendScreen()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.sundaegukbap.banchango.presentation.reciperecommend

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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.dp
import androidx.compose.ui.unit.sp
import com.sundaegukbap.banchango.core.designsystem.NetworkImage
import com.sundaegukbap.banchango.model.Recipe
import com.sundaegukbap.banchango.ui.theme.BanchangoTheme

@Composable
fun RecipeCard(
page: Int,
recipe: Recipe,
onHateClick: (page: Int) -> Unit = {},
onLikeClick: (page: Int) -> Unit = {},
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black),
contentAlignment = Alignment.Center,
) {
NetworkImage(
modifier = Modifier
.fillMaxSize(),
url = recipe.image,
)
RecipeInfo(recipe, page, onHateClick, onLikeClick)
}
}

@Composable
private fun RecipeInfo(
recipe: Recipe,
page: Int,
onHateClick: (page: Int) -> Unit,
onLikeClick: (page: Int) -> Unit
) {
Box {
Column {
Text(
recipe.name,
color = Color.White,
fontSize = 24.sp,
style = TextStyle(fontWeight = Bold),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
Text(
text = page.toString(),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
color = Color.White,
fontSize = 60.sp
)
Row(
modifier = Modifier
.align(Alignment.CenterHorizontally)
) {
Button(
modifier = Modifier.padding(end = 16.dp),
onClick = {
onHateClick(page + 1)
}
) {
Text("싫어요")
}
Button(
onClick = {
onLikeClick(page + 1)
},
) {
Text("좋아요")
}
}
}
}
}


@Preview(showBackground = true)
@Composable
fun RecipeCardPreview() {
BanchangoTheme {
RecipeCard(
page = 1, recipe = Recipe(
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 = "Easy",
have = listOf(1, 2, 3, 4, 5),
need = listOf(6, 7, 8, 9, 10),
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.sundaegukbap.banchango.presentation.reciperecommend

import androidx.lifecycle.ViewModel
import com.sundaegukbap.banchango.model.Recipe
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject

@HiltViewModel
class RecipeRecommendViewModel @Inject constructor() : ViewModel() {

private val _recipes: MutableStateFlow<List<Recipe>> = MutableStateFlow(emptyList())
val recipes: StateFlow<List<Recipe>> = _recipes.asStateFlow()

fun getRecipeRecommendation() {
_recipes.value = List(10) {
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 = "Easy",
have = listOf(1, 2, 3, 4, 5),
need = listOf(6, 7, 8, 9, 10)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.sundaegukbap.banchango.presentation.reciperecommend

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.pager.VerticalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.launch

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun RecipesRecommendScreen(
modifier: Modifier = Modifier,
viewModel: RecipeRecommendViewModel = hiltViewModel(),
) {
val recipesUiState by viewModel.recipes.collectAsStateWithLifecycle()

val pagerState = rememberPagerState(
pageCount = {
recipesUiState.size
}
)
val coroutineScope = rememberCoroutineScope()
VerticalPager(
modifier = modifier,
state = pagerState,
contentPadding = PaddingValues(vertical = 200.dp, horizontal = 40.dp),
pageSpacing = 40.dp,
) { page ->
RecipeCard(
page = page,
recipe = recipesUiState[page],
onLikeClick = {
coroutineScope.launch { pagerState.animateScrollToPage(it) }
},
onHateClick = {
coroutineScope.launch { pagerState.animateScrollToPage(it) }
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sundaegukbap.banchango.repository

import com.sundaegukbap.banchango.model.Recipe

interface RecipeRepository {
fun getRecipeRecommendation(): List<Recipe>
}
Loading
Loading