diff --git a/.gitignore b/.gitignore index 4a5682ef..4a341cb5 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ output.json misc.xml deploymentTargetDropDown.xml render.experimental.xml +deploymentTargetSelector.xml # Keystore files *.jks diff --git a/app/src/main/java/com/kuit/ourmenu/data/di/ServiceModule.kt b/app/src/main/java/com/kuit/ourmenu/data/di/ServiceModule.kt index 21fecad8..367d7d46 100644 --- a/app/src/main/java/com/kuit/ourmenu/data/di/ServiceModule.kt +++ b/app/src/main/java/com/kuit/ourmenu/data/di/ServiceModule.kt @@ -3,6 +3,7 @@ package com.kuit.ourmenu.data.di import com.kuit.ourmenu.data.service.AuthService import com.kuit.ourmenu.data.service.CacheService import com.kuit.ourmenu.data.service.DummyService +import com.kuit.ourmenu.data.service.HomeService import com.kuit.ourmenu.data.service.MapService import com.kuit.ourmenu.data.service.MenuFolderService import com.kuit.ourmenu.data.service.MenuInfoService @@ -48,6 +49,11 @@ object ServiceModule { fun provideMenuFolderService(retrofit: Retrofit): MenuFolderService = retrofit.create(MenuFolderService::class.java) + @Provides + @Singleton + fun provideHomeService(retrofit: Retrofit): HomeService = + retrofit.create(HomeService::class.java) + @Provides @Singleton fun provideMenuInfoService(retrofit: Retrofit): MenuInfoService = diff --git a/app/src/main/java/com/kuit/ourmenu/data/model/home/request/HomeAnswerRequest.kt b/app/src/main/java/com/kuit/ourmenu/data/model/home/request/HomeAnswerRequest.kt new file mode 100644 index 00000000..7bedb794 --- /dev/null +++ b/app/src/main/java/com/kuit/ourmenu/data/model/home/request/HomeAnswerRequest.kt @@ -0,0 +1,8 @@ +package com.kuit.ourmenu.data.model.home.request + +import kotlinx.serialization.Serializable + +@Serializable +data class HomeAnswerRequest( + val answer: String +) diff --git a/app/src/main/java/com/kuit/ourmenu/data/model/home/response/HomeQuestionResponse.kt b/app/src/main/java/com/kuit/ourmenu/data/model/home/response/HomeQuestionResponse.kt new file mode 100644 index 00000000..1e733013 --- /dev/null +++ b/app/src/main/java/com/kuit/ourmenu/data/model/home/response/HomeQuestionResponse.kt @@ -0,0 +1,15 @@ +package com.kuit.ourmenu.data.model.home.response + +import kotlinx.serialization.Serializable + +@Serializable +data class HomeQuestionResponse( + val question: String, + val answers: List +) + +@Serializable +data class Answer( + val answer: String, + val answerImgUrl: String +) \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/data/model/home/response/HomeResponse.kt b/app/src/main/java/com/kuit/ourmenu/data/model/home/response/HomeResponse.kt new file mode 100644 index 00000000..abdcbee1 --- /dev/null +++ b/app/src/main/java/com/kuit/ourmenu/data/model/home/response/HomeResponse.kt @@ -0,0 +1,21 @@ +package com.kuit.ourmenu.data.model.home.response + +import kotlinx.serialization.Serializable + +@Serializable +data class HomeResponse( + val answerImgUrl: String = "", + val answerRecommendMenus: List = emptyList(), + val tagRecommendImgUrl: String = "", + val tagRecommendMenus: List = emptyList(), + val otherRecommendImgUrl: String = "", + val otherRecommendMenus: List = emptyList(), +) + +@Serializable +data class RecommendMenuList( + val menuId: Long = 0, + val menuTitle: String = "", + val storeName: String = "", + val menuImgUrl: String = "", +) \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/data/repository/HomeRepository.kt b/app/src/main/java/com/kuit/ourmenu/data/repository/HomeRepository.kt new file mode 100644 index 00000000..4c5d6fe8 --- /dev/null +++ b/app/src/main/java/com/kuit/ourmenu/data/repository/HomeRepository.kt @@ -0,0 +1,26 @@ +package com.kuit.ourmenu.data.repository + +import com.kuit.ourmenu.data.model.base.handleBaseResponse +import com.kuit.ourmenu.data.model.home.request.HomeAnswerRequest +import com.kuit.ourmenu.data.service.HomeService +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class HomeRepository @Inject constructor( + private val homeService: HomeService, +) { + suspend fun getHome() = runCatching { + homeService.getHome().handleBaseResponse().getOrThrow() + } + + suspend fun postHomeQuestion() = runCatching { + homeService.postHomeQuestion().handleBaseResponse().getOrThrow() + } + + suspend fun postHomeAnswer(answer: String) = runCatching { + homeService.postHomeAnswer(HomeAnswerRequest(answer)) + .handleBaseResponse() + .getOrThrow() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/data/service/HomeService.kt b/app/src/main/java/com/kuit/ourmenu/data/service/HomeService.kt new file mode 100644 index 00000000..cec9c97f --- /dev/null +++ b/app/src/main/java/com/kuit/ourmenu/data/service/HomeService.kt @@ -0,0 +1,22 @@ +package com.kuit.ourmenu.data.service + +import com.kuit.ourmenu.data.model.base.BaseResponse +import com.kuit.ourmenu.data.model.home.request.HomeAnswerRequest +import com.kuit.ourmenu.data.model.home.response.HomeQuestionResponse +import com.kuit.ourmenu.data.model.home.response.HomeResponse +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.POST + +interface HomeService { + @GET("api/home") + suspend fun getHome(): BaseResponse + + @POST("/api/home/questions") + suspend fun postHomeQuestion(): BaseResponse + + @POST("/api/home/questions/answers") + suspend fun postHomeAnswer( + @Body answerRequest: HomeAnswerRequest + ): BaseResponse +} \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/ui/common/dialog/DialogBigButton.kt b/app/src/main/java/com/kuit/ourmenu/ui/common/dialog/DialogBigButton.kt deleted file mode 100644 index ed71fa1a..00000000 --- a/app/src/main/java/com/kuit/ourmenu/ui/common/dialog/DialogBigButton.kt +++ /dev/null @@ -1,115 +0,0 @@ -package com.kuit.ourmenu.ui.common.dialog - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -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.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon -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.res.painterResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.kuit.ourmenu.R -import com.kuit.ourmenu.ui.theme.Neutral400 -import com.kuit.ourmenu.ui.theme.NeutralWhite -import com.kuit.ourmenu.ui.theme.Primary500Main -import com.kuit.ourmenu.ui.theme.ourMenuTypography - -/** - * Dialog 에 사용되는 Big Button - * - * Width : fillMaxWidth - * - * Height : 48dp - * - * Padding 값 없음 - * - * Round Corner : 12dp - * - * Text Style : Pretendard 700 20sp - * - * Text Color : NeutralWhite - * - * @param buttonText: 버튼 텍스트 - * @param buttonIcon: 버튼 아이콘 - * @param hasIcon: 아이콘 여부 - * @param containerColor: 버튼 색상 - * */ -@Composable -fun DialogBigButton( - buttonText: String, - modifier: Modifier = Modifier, - hasIcon: Boolean = true, - buttonIcon: String = "", - containerColor: Color, - onClick: () -> Unit = { /* TODO */ } -) { - Button( - onClick = onClick, - modifier = modifier, - shape = RoundedCornerShape(12.dp), - colors = ButtonDefaults.buttonColors( - containerColor = containerColor, - contentColor = NeutralWhite - ) - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - if (hasIcon) { - Icon( - painter = painterResource(R.drawable.img_home_popup_thumbsup), - contentDescription = null, - tint = Color.Unspecified, - modifier = Modifier - .padding(end = 8.dp) - .size(28.dp) - ) - } - Text( - text = buttonText, - style = ourMenuTypography().pretendard_700_20.copy( - fontSize = 18.sp - ) - ) - } - } -} - -@Preview -@Composable -private fun IBBPreview() { - Column { - DialogBigButton( - modifier = Modifier - .fillMaxWidth() - .height(48.dp), - buttonText = "좋아!", - hasIcon = true, - containerColor = Primary500Main - ) - Spacer(modifier = Modifier.height(16.dp)) - DialogBigButton( - modifier = Modifier - .fillMaxWidth() - .height(48.dp), - buttonText = "확인", - hasIcon = false, - containerColor = Neutral400 - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/ui/common/topappbar/OurMenuAddButtonTopAppBar.kt b/app/src/main/java/com/kuit/ourmenu/ui/common/topappbar/OurMenuAddButtonTopAppBar.kt index 28e9d333..c2ef9122 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/common/topappbar/OurMenuAddButtonTopAppBar.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/common/topappbar/OurMenuAddButtonTopAppBar.kt @@ -18,7 +18,10 @@ import com.kuit.ourmenu.ui.theme.NeutralWhite @OptIn(ExperimentalMaterial3Api::class) @Composable -fun OurMenuAddButtonTopAppBar(modifier: Modifier = Modifier) { +fun OurMenuAddButtonTopAppBar( + modifier: Modifier = Modifier, + onAddMenuClick: () -> Unit = {} +) { // 기본 TopAppBar( modifier = modifier.fillMaxWidth(), @@ -35,7 +38,7 @@ fun OurMenuAddButtonTopAppBar(modifier: Modifier = Modifier) { }, actions = { IconButton( - onClick = { /* TODO : Add Menu Button Click Event */ }, + onClick = onAddMenuClick, modifier = Modifier.padding(end = 20.dp) ) { Icon( diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialog.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialog.kt index b5cdff6a..da24c181 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialog.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialog.kt @@ -1,26 +1,34 @@ package com.kuit.ourmenu.ui.home.component.dialog import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -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.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog -import com.kuit.ourmenu.ui.common.dialog.DialogBigButton +import coil3.compose.SubcomposeAsyncImage +import com.kuit.ourmenu.R +import com.kuit.ourmenu.data.model.home.response.Answer +import com.kuit.ourmenu.data.model.home.response.HomeQuestionResponse import com.kuit.ourmenu.ui.theme.Neutral500 import com.kuit.ourmenu.ui.theme.Neutral900 import com.kuit.ourmenu.ui.theme.NeutralWhite @@ -28,13 +36,13 @@ import com.kuit.ourmenu.ui.theme.Primary500Main import com.kuit.ourmenu.ui.theme.ourMenuTypography @Composable -fun HomePopUpDialog(modifier: Modifier = Modifier) { - - Dialog( - onDismissRequest = { - // TODO : Dismiss Dialog Event - }, - ) { +fun HomePopUpDialog( + questionData: HomeQuestionResponse, + onDismissRequest: () -> Unit, + onAnswerSelected: (String) -> Unit, + onDiceClick: () -> Unit, +) { + Dialog(onDismissRequest = onDismissRequest) { Surface( modifier = Modifier .shadow(elevation = 8.dp) @@ -59,19 +67,14 @@ fun HomePopUpDialog(modifier: Modifier = Modifier) { ) { HomeDialogAssets( - onDiceClick = { - // TODO : Dice Click Event - }, - onCloseClick = { - // TODO : Close Click Event - } + onDiceClick = onDiceClick, + onCloseClick = onDismissRequest ) Text( modifier = Modifier .padding(top = 13.dp) .fillMaxWidth(), - text = "안녕하세요!\n" + - "오늘의 기분은 어떠신가요?", // TODO : 추천 문구 반영 + text = stringResource(R.string.hello) + questionData.question, style = ourMenuTypography().pretendard_700_20.copy( color = Neutral900 ), @@ -81,33 +84,44 @@ fun HomePopUpDialog(modifier: Modifier = Modifier) { modifier = Modifier .padding(top = 13.dp, bottom = 19.dp) .fillMaxWidth(), - text = "질문에 답해 기분에 맞는 메뉴를\n" + - "추천받아보세요!", + text = stringResource(R.string.home_recommend), style = ourMenuTypography().pretendard_500_14.copy( fontWeight = FontWeight(500), color = Neutral500 ), textAlign = TextAlign.Center ) + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + questionData.answers.forEach { answer -> + SubcomposeAsyncImage( + model = answer.answerImgUrl, + contentDescription = answer.answer, + modifier = Modifier + .width(248.dp) + .height(48.dp) + .clickable { onAnswerSelected(answer.answer) }, + loading = { + Button( + modifier = Modifier + .width(248.dp) + .height(48.dp), + shape = RoundedCornerShape(8.dp), + colors = ButtonDefaults.buttonColors( + containerColor = Primary500Main, + contentColor = NeutralWhite + ), + onClick = {} + ) { - DialogBigButton( - modifier = Modifier - .padding(bottom = 8.dp) - .padding(horizontal = 4.dp) - .fillMaxWidth() - .height(48.dp), - buttonText = "좋아!", - containerColor = Primary500Main - ) - - DialogBigButton( - modifier = Modifier - .padding(horizontal = 4.dp) - .fillMaxWidth() - .height(48.dp), - buttonText = "별로야..", - containerColor = Primary500Main - ) + } + }, + ) + } + } } } } @@ -119,5 +133,22 @@ fun HomePopUpDialog(modifier: Modifier = Modifier) { ) @Composable private fun HomePopUpDialogPreview() { - HomePopUpDialog() + HomePopUpDialog( + questionData = HomeQuestionResponse( + question = "스트레스 받을 때는 어떤 음식을 드시나요?", + answers = listOf( + Answer( + "SWEET", + "https://ourmenu-s3-default.s3.ap-northeast-2.amazonaws.com/answers/SWEET.svg" + ), + Answer( + "SPICY", + "https://ourmenu-s3-default.s3.ap-northeast-2.amazonaws.com/answers/SPICY.svg" + ), + ) + ), + onDismissRequest = {}, + onAnswerSelected = {}, + onDiceClick = {} + ) } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialogAssets.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialogAssets.kt index f66b7077..d235d722 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialogAssets.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/dialog/HomeDialogAssets.kt @@ -1,6 +1,7 @@ package com.kuit.ourmenu.ui.home.component.dialog import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -8,10 +9,7 @@ import androidx.compose.foundation.layout.aspectRatio 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.material3.Icon -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -20,8 +18,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.kuit.ourmenu.R -import com.kuit.ourmenu.ui.theme.Neutral700 -import com.kuit.ourmenu.ui.theme.ourMenuTypography @Composable fun HomeDialogAssets( @@ -49,6 +45,7 @@ fun HomeDialogAssets( modifier = Modifier .aspectRatio(1f) .weight(24f) + .clickable { onCloseClick() } ) } Image( @@ -60,6 +57,7 @@ fun HomeDialogAssets( .padding(horizontal = 82.dp) .fillMaxWidth() .aspectRatio(1f) + .clickable { onDiceClick() } ) // TODO : Add Dice shadow asset } diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendation.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendation.kt index e2e93266..a5fb2cfd 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendation.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendation.kt @@ -1,22 +1,20 @@ package com.kuit.ourmenu.ui.home.component.recommendation.main import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer 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.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.kuit.ourmenu.ui.home.dummy.HomeDummyData +import com.kuit.ourmenu.data.model.home.response.RecommendMenuList @Composable fun HomeMainRecommendation( modifier: Modifier = Modifier, - homeMainDataList : List + imgUrl: String = "", + homeMainDataList: List, + onItemClick: (Long) -> Unit ) { Column( modifier = modifier @@ -24,8 +22,8 @@ fun HomeMainRecommendation( HomeMainRecommendationText( modifier = Modifier .padding(horizontal = 20.dp) - .width(278.dp) - .height(144.dp) + .height(148.dp), + imgUrl = imgUrl ) HomeMainRecommendationList( @@ -33,16 +31,8 @@ fun HomeMainRecommendation( .fillMaxWidth() .padding(top = 32.dp) .height(244.dp), - homeMainDataList = homeMainDataList + homeMainDataList = homeMainDataList, + onItemClick = onItemClick ) } } - -@Preview(showBackground = true) -@Composable -private fun MainRecommendationPreview() { - HomeMainRecommendation( - modifier = Modifier.padding(top = 16.dp), - homeMainDataList = HomeDummyData.dummyData - ) -} diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationItem.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationItem.kt index ac655278..4740fddf 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationItem.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationItem.kt @@ -1,6 +1,6 @@ package com.kuit.ourmenu.ui.home.component.recommendation.main -import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -17,26 +17,28 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shadow import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.kuit.ourmenu.R -import com.kuit.ourmenu.ui.home.dummy.HomeDummyData +import coil3.compose.AsyncImage +import com.kuit.ourmenu.data.model.home.response.RecommendMenuList import com.kuit.ourmenu.ui.theme.NeutralWhite import com.kuit.ourmenu.ui.theme.ourMenuTypography @Composable fun HomeMainRecommendationItem( modifier: Modifier = Modifier, - recommendData: HomeDummyData + recommendData: RecommendMenuList, + onItemClick: (Long) -> Unit ) { Box( - modifier = modifier, + modifier = modifier.clickable{ + onItemClick(recommendData.menuId) + }, contentAlignment = Alignment.BottomStart ) { - Image( - painter = painterResource(recommendData.imageRes), // TODO : 추후 Async Image Loading 적용 + AsyncImage( + model = recommendData.menuImgUrl, contentDescription = "Main Recommendation Image", contentScale = ContentScale.Crop, modifier = Modifier @@ -55,7 +57,7 @@ fun HomeMainRecommendationItem( contentAlignment = Alignment.CenterStart, // 수직 및 수평 중앙 정렬 ) { Text( - text = recommendData.name, + text = recommendData.menuTitle, style = ourMenuTypography().pretendard_700_24.copy( shadow = Shadow( color = Color.Black.copy(alpha = 0.2f), // 그림자 색상 및 투명도 @@ -74,7 +76,7 @@ fun HomeMainRecommendationItem( contentAlignment = Alignment.CenterStart, // 수직 및 수평 중앙 정렬 ) { Text( - text = recommendData.store, + text = recommendData.storeName, style = ourMenuTypography().pretendard_600_16.copy( shadow = Shadow( color = Color.Black.copy(alpha = 0.2f), // 그림자 색상 및 투명도 diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationList.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationList.kt index cce7aea0..d59e9e19 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationList.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationList.kt @@ -12,14 +12,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.kuit.ourmenu.ui.home.dummy.HomeDummyData +import com.kuit.ourmenu.data.model.home.response.RecommendMenuList @OptIn(ExperimentalFoundationApi::class) @Composable fun HomeMainRecommendationList( modifier: Modifier = Modifier, - homeMainDataList: List + homeMainDataList: List, + onItemClick: (Long) -> Unit ) { + // 리스트가 비어있으면 아무것도 표시하지 않음 + if (homeMainDataList.isEmpty()) return + val state = rememberLazyListState() // TODO : hoisting val startIndex = (Int.MAX_VALUE / 2) - (Int.MAX_VALUE / 2) % homeMainDataList.size LaunchedEffect(Unit) { @@ -40,7 +44,8 @@ fun HomeMainRecommendationList( .height(244.dp) .width(304.dp) .padding(horizontal = 6.dp), - recommendData = homeMainDataList[itemIndex] + recommendData = homeMainDataList[itemIndex], + onItemClick = onItemClick ) } } diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationText.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationText.kt index 51e80d03..0b5f0fa9 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationText.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/main/HomeMainRecommendationText.kt @@ -1,24 +1,18 @@ package com.kuit.ourmenu.ui.home.component.recommendation.main -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.unit.dp -import com.kuit.ourmenu.R +import coil3.compose.AsyncImage @Composable fun HomeMainRecommendationText( modifier: Modifier = Modifier, imgUrl: String = "" ) { - Image( + AsyncImage( modifier = modifier, - painter = painterResource(id = R.drawable.ic_home_reco_1), - contentDescription = "Home Banner" + model = imgUrl, + contentDescription = "Home Banner", ) } diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendation.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendation.kt index ff4d9451..ffb4197f 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendation.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendation.kt @@ -1,38 +1,30 @@ package com.kuit.ourmenu.ui.home.component.recommendation.sub import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row 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.wrapContentHeight import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.Icon -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.res.painterResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.kuit.ourmenu.R -import com.kuit.ourmenu.ui.home.dummy.HomeDummyData -import com.kuit.ourmenu.ui.theme.Neutral900 -import com.kuit.ourmenu.ui.theme.ourMenuTypography +import com.kuit.ourmenu.data.model.home.response.RecommendMenuList @Composable fun HomeSubRecommendation( modifier: Modifier = Modifier, - homeSubDataList: List = listOf() + imgUrl: String = "", + homeSubDataList: List, + onItemClick: (Long) -> Unit ) { val state = rememberLazyListState() // TODO : hoisting Column(modifier = modifier) { HomeSubRecommendationText( modifier = Modifier - .padding(start = 20.dp, end = 20.dp, bottom = 11.dp), - icon = R.drawable.ic_home_sub_reco_1, - text = "추천 메뉴" + .padding(start = 20.dp, end = 20.dp, bottom = 12.dp) + .height(32.dp), + imgUrl = imgUrl ) HomeSubRecommendationList( @@ -40,18 +32,8 @@ fun HomeSubRecommendation( .fillMaxWidth() .wrapContentHeight(), state = state, - homeSubDataList = homeSubDataList + homeSubDataList = homeSubDataList, + onItemClick = onItemClick ) } } - -@Preview(showBackground = true) -@Composable -private fun HomeSubRecommendationListPreview() { - HomeSubRecommendation( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight(), - HomeDummyData.dummyData - ) -} diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationItem.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationItem.kt index 414e42b4..0e57496f 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationItem.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationItem.kt @@ -1,6 +1,6 @@ package com.kuit.ourmenu.ui.home.component.recommendation.sub -import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -11,15 +11,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import coil3.compose.AsyncImage import com.kuit.ourmenu.R -import com.kuit.ourmenu.ui.home.dummy.HomeDummyData +import com.kuit.ourmenu.data.model.home.response.RecommendMenuList import com.kuit.ourmenu.ui.theme.Neutral700 import com.kuit.ourmenu.ui.theme.Neutral900 import com.kuit.ourmenu.ui.theme.ourMenuTypography @@ -27,13 +27,16 @@ import com.kuit.ourmenu.ui.theme.ourMenuTypography @Composable fun HomeSubRecommendationItem( - recommendData: HomeDummyData + recommendData: RecommendMenuList, + onItemClick: (Long) -> Unit ) { Column( - modifier = Modifier.padding(end = 11.dp) + modifier = Modifier + .padding(end = 11.dp) + .clickable { onItemClick(recommendData.menuId) } ) { - Image( - painter = painterResource(recommendData.imageRes), + AsyncImage( + model = recommendData.menuImgUrl, contentDescription = "Home Sub Recommendation Image", contentScale = ContentScale.Crop, modifier = Modifier @@ -43,14 +46,14 @@ fun HomeSubRecommendationItem( .clip(shape = RoundedCornerShape(12.dp)) ) Text( - text = recommendData.name, + text = recommendData.menuTitle, style = ourMenuTypography().pretendard_600_18.copy( color = Neutral900, lineHeight = 27.sp ) ) Text( - text = recommendData.store, + text = recommendData.storeName, style = TextStyle( // TODO : Design system 적용 fontSize = 14.sp, diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationList.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationList.kt index 27a93cc2..3bf6b746 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationList.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationList.kt @@ -1,20 +1,19 @@ package com.kuit.ourmenu.ui.home.component.recommendation.sub import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyRow import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.kuit.ourmenu.ui.home.dummy.HomeDummyData +import com.kuit.ourmenu.data.model.home.response.RecommendMenuList @Composable fun HomeSubRecommendationList( modifier: Modifier = Modifier, state: LazyListState, - homeSubDataList: List + homeSubDataList: List, + onItemClick: (Long) -> Unit ) { LazyRow( modifier = modifier, @@ -25,7 +24,8 @@ fun HomeSubRecommendationList( ) { items(homeSubDataList.size) { data -> HomeSubRecommendationItem( - recommendData = homeSubDataList[data] + recommendData = homeSubDataList[data], + onItemClick = onItemClick ) } } diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationText.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationText.kt index 83ce0b53..dfabd375 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationText.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/component/recommendation/sub/HomeSubRecommendationText.kt @@ -1,45 +1,19 @@ package com.kuit.ourmenu.ui.home.component.recommendation.sub -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.material3.Icon -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.res.painterResource -import androidx.compose.ui.unit.dp -import com.kuit.ourmenu.ui.theme.Neutral900 -import com.kuit.ourmenu.ui.theme.ourMenuTypography +import coil3.compose.AsyncImage @Composable fun HomeSubRecommendationText( modifier: Modifier = Modifier, - icon: Int, - text: String, + imgUrl: String = "", ) { - Row( + AsyncImage( modifier = modifier, - verticalAlignment = Alignment.CenterVertically - ) { - // TODO : Async Image Loading - Icon( - painter = painterResource(icon), - modifier = Modifier - .size(32.dp) - .padding(end = 4.dp), - contentDescription = "Home Sub Recommendation 1", - tint = Color.Unspecified - ) - Text( - text = text, - style = ourMenuTypography().pretendard_700_24.copy( - color = Neutral900 - ) - ) - } + model = imgUrl, + contentDescription = "Home Sub Recommendation 1", + ) } diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/dummy/HomeDummyData.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/dummy/HomeDummyData.kt deleted file mode 100644 index c89c5c28..00000000 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/dummy/HomeDummyData.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.kuit.ourmenu.ui.home.dummy - -import com.kuit.ourmenu.R - -data class HomeDummyData( - val imageRes: Int, - val name: String, - val store: String, -) { - - companion object { - val dummyData = listOf( - HomeDummyData( - imageRes = R.drawable.img_dummy_pizza, - name = "초코 소프트콘 1", - store = "아이스크림세계할인점", - ), - HomeDummyData( - imageRes = R.drawable.img_dummy_pizza, - name = "초코 소프트콘 2", - store = "아이스크림세계할인점", - ), - HomeDummyData( - imageRes = R.drawable.img_dummy_pizza, - name = "초코 소프트콘 3", - store = "아이스크림세계할인점", - ), - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/navigation/HomeNavigation.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/navigation/HomeNavigation.kt index 2fecea7e..0a8419ef 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/navigation/HomeNavigation.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/navigation/HomeNavigation.kt @@ -14,11 +14,14 @@ fun NavController.navigateToHome(navOptions: NavOptions) { fun NavGraphBuilder.homeNavGraph( padding: PaddingValues, - // navigate 이벤트 + navigateToMenuInfo: (Long) -> Unit, + navigateToAddMenu: () -> Unit, ) { composable { HomeScreen( - // navigate 이벤트 + 기타 이벤트 + padding = padding, + onNavigateToMenuInfo = navigateToMenuInfo, + onNavigateToAddMenu = navigateToAddMenu, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/screen/HomeScreen.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/screen/HomeScreen.kt index 13b803d0..f821368a 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/home/screen/HomeScreen.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/screen/HomeScreen.kt @@ -1,6 +1,8 @@ package com.kuit.ourmenu.ui.home.screen +import android.annotation.SuppressLint import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight @@ -8,29 +10,68 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.rememberNavController import com.kuit.ourmenu.ui.common.topappbar.OurMenuAddButtonTopAppBar +import com.kuit.ourmenu.ui.home.component.dialog.HomePopUpDialog import com.kuit.ourmenu.ui.home.component.recommendation.main.HomeMainRecommendation import com.kuit.ourmenu.ui.home.component.recommendation.sub.HomeSubRecommendation -import com.kuit.ourmenu.ui.home.dummy.HomeDummyData +import com.kuit.ourmenu.ui.home.viewmodel.HomeViewModel +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable -fun HomeScreen(modifier: Modifier = Modifier) { +fun HomeScreen( + padding: PaddingValues, + onNavigateToMenuInfo: (Long) -> Unit = {}, + onNavigateToAddMenu: () -> Unit = {}, + viewModel: HomeViewModel = hiltViewModel() +) { val scrollState = rememberScrollState() + val homeData by viewModel.home.collectAsStateWithLifecycle() + val questionData by viewModel.questionState.collectAsStateWithLifecycle() + val showDialog by viewModel.showDialog.collectAsStateWithLifecycle() + + val answerImgUrl = homeData.answerImgUrl + val answerRecommendMenus = homeData.answerRecommendMenus + val tagRecommendImgUrl = homeData.tagRecommendImgUrl + val tagRecommendMenus = homeData.tagRecommendMenus + val otherRecommendImgUrl = homeData.otherRecommendImgUrl + val otherRecommendMenus = homeData.otherRecommendMenus + + if (showDialog && questionData != null) { + HomePopUpDialog( + questionData = questionData!!, + onAnswerSelected = { selectedAnswer -> + viewModel.selectAnswer(selectedAnswer) + }, + onDismissRequest = { + viewModel.onDialogDismiss() + }, + onDiceClick = { + viewModel.refreshQuestion() + } + ) + } + Scaffold( topBar = { - OurMenuAddButtonTopAppBar() + OurMenuAddButtonTopAppBar( + onAddMenuClick = onNavigateToAddMenu + ) } - ) { innerPadding -> + ) { Column( modifier = Modifier - .padding(innerPadding) + .padding(padding) +// .padding(innerPadding) .verticalScroll(scrollState), horizontalAlignment = Alignment.Start ) { @@ -38,7 +79,9 @@ fun HomeScreen(modifier: Modifier = Modifier) { HomeMainRecommendation( modifier = Modifier .padding(top = 16.dp, bottom = 29.dp), - homeMainDataList = HomeDummyData.dummyData + imgUrl = answerImgUrl, + homeMainDataList = answerRecommendMenus, + onItemClick = onNavigateToMenuInfo ) @@ -47,7 +90,9 @@ fun HomeScreen(modifier: Modifier = Modifier) { .fillMaxWidth() .wrapContentHeight() .padding(bottom = 25.dp), - homeSubDataList = HomeDummyData.dummyData + imgUrl = tagRecommendImgUrl, + homeSubDataList = tagRecommendMenus, + onItemClick = onNavigateToMenuInfo ) HomeSubRecommendation( @@ -55,7 +100,9 @@ fun HomeScreen(modifier: Modifier = Modifier) { .fillMaxWidth() .wrapContentHeight() .padding(bottom = 25.dp), - homeSubDataList = HomeDummyData.dummyData + imgUrl = otherRecommendImgUrl, + homeSubDataList = otherRecommendMenus, + onItemClick = onNavigateToMenuInfo ) } } @@ -68,5 +115,8 @@ fun HomeScreen(modifier: Modifier = Modifier) { @Composable private fun HomeScreenPreview() { val navController = rememberNavController() - HomeScreen() + HomeScreen( + padding = PaddingValues(0.dp), +// viewModel = hiltViewModel(navController = navController) + ) } \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/ui/home/viewmodel/HomeViewModel.kt b/app/src/main/java/com/kuit/ourmenu/ui/home/viewmodel/HomeViewModel.kt new file mode 100644 index 00000000..92e52235 --- /dev/null +++ b/app/src/main/java/com/kuit/ourmenu/ui/home/viewmodel/HomeViewModel.kt @@ -0,0 +1,129 @@ +package com.kuit.ourmenu.ui.home.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.kuit.ourmenu.data.model.base.OurMenuApiFailureException +import com.kuit.ourmenu.data.model.home.response.HomeQuestionResponse +import com.kuit.ourmenu.data.model.home.response.HomeResponse +import com.kuit.ourmenu.data.repository.HomeRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class HomeViewModel @Inject constructor( + private val homeRepository: HomeRepository +): ViewModel() { + private val _questionState = MutableStateFlow(null) + val questionState = _questionState.asStateFlow() + + private val _home = MutableStateFlow(HomeResponse()) + val home = _home.asStateFlow() + + private val _showDialog = MutableStateFlow(true) + val showDialog = _showDialog.asStateFlow() + + private val _error: MutableStateFlow = MutableStateFlow(null) + val error = _error.asStateFlow() + + private val _isLoading = MutableStateFlow(false) + val isLoading = _isLoading.asStateFlow() + + init { + fetchQuestion() + } + + fun refreshQuestion() { + fetchQuestion() + } + + fun selectAnswer(answer: String) { + viewModelScope.launch { + _isLoading.value = true + _error.value = null + + homeRepository.postHomeAnswer(answer) + .fold( + onSuccess = { + getHome() + }, + onFailure = { throwable -> + _error.value = throwable.message ?: "답변 제출 중 오류가 발생했습니다." + onDialogDismiss() + _isLoading.value = false + } + ) + + _isLoading.value = false + } + } + + fun onDialogDismiss() { + _showDialog.value = false + } + + private fun fetchQuestion() { + viewModelScope.launch { + _isLoading.value = true + _error.value = null + + homeRepository.postHomeQuestion() + .fold( + onSuccess = { response -> + _questionState.value = response + if (response == null) { + onDialogDismiss() + getHome() + } else { + _isLoading.value = false + } + }, + onFailure = { throwable -> + handleFailure(throwable) + _isLoading.value = false + } + ) + } + } + fun getHome() { + viewModelScope.launch { + _isLoading.value = true + _error.value = null + + homeRepository.getHome() + .fold( + onSuccess = { response -> + if (response != null) { + _home.value = response + } + onDialogDismiss() + _isLoading.value = false + }, + onFailure = { throwable -> + handleFailure(throwable) + _isLoading.value = false + } + ) + } + } + + private fun handleFailure(throwable: Throwable) { + when (throwable) { + is OurMenuApiFailureException -> { + if (throwable.code == "H400") { + _showDialog.value = true + fetchQuestion() + } else { + _error.value = throwable.message ?: "알 수 없는 서버 오류입니다." + onDialogDismiss() + } + } + else -> { + _error.value = "네트워크 연결을 확인해주세요." + onDialogDismiss() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kuit/ourmenu/ui/navigator/MainNavHost.kt b/app/src/main/java/com/kuit/ourmenu/ui/navigator/MainNavHost.kt index 2b03ee12..7ae86c79 100644 --- a/app/src/main/java/com/kuit/ourmenu/ui/navigator/MainNavHost.kt +++ b/app/src/main/java/com/kuit/ourmenu/ui/navigator/MainNavHost.kt @@ -57,6 +57,8 @@ fun MainNavHost( homeNavGraph( padding = padding, + navigateToMenuInfo = navController::navigateToMenuInfo, + navigateToAddMenu = navController::navigateToAddMenu, ) menuFolderNavGraph( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a70adc52..59f19642 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -128,4 +128,8 @@ 로그아웃 하시겠습니까? 탈퇴 하시겠습니까? 탈퇴 시 계정 및 이용 기록은 모두 삭제되며,\n삭제된 데이터는 복구가 불가능합니다. + + + 안녕하세요!\n + 질문에 답해 기분에 맞는 메뉴를\n추천받아보세요! \ No newline at end of file