From b09ca86a92b167331865bf06568fbff90ee75962 Mon Sep 17 00:00:00 2001 From: sgsk88 Date: Sun, 4 Feb 2024 17:33:23 +0900 Subject: [PATCH 1/8] =?UTF-8?q?[feature/withdraw]=20=ED=83=88=ED=87=B4?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=ED=83=80=EC=9D=B4=ED=8B=80=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20=EA=B0=80=EA=B2=8C=20=EC=95=A0=EB=8B=88?= =?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/main/MainScreen.kt | 6 +++- .../presentation/ui/mypage/WithDrawScreen.kt | 29 ++++++++++++++++++- .../ui/restaurant/DetailRestaurantScreen.kt | 11 ++++++- .../presentation/ui/save/SaveScreen.kt | 6 ++-- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt index 32464c8d..51eb02ff 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt @@ -114,7 +114,11 @@ fun MainScreen( ReviewSearchScreen(navController = navController) } composable(route = EveryMealRoute.WITH_DRAW.route) { - WithDrawScreen() + WithDrawScreen( + onBackClick = { + navController.popBackStack() + } + ) } composable(route = EveryMealRoute.SEARCH.route) { SearchScreen(navController = navController) diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt index 113f70d1..1830914c 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt @@ -1,8 +1,35 @@ package com.everymeal.presentation.ui.mypage +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.everymeal.presentation.ui.save.SaveTopBar @Composable -fun WithDrawScreen() { +fun WithDrawScreen( + onBackClick: () -> Unit = {} +) { + Scaffold( + topBar = { + SaveTopBar( + title = "탈퇴하기", + onBackClick = onBackClick + ) + } + ) { innerPadding -> + LazyColumn( + modifier = Modifier.padding(innerPadding) + ) { + } + } +} + +@Preview +@Composable +fun WithDrawScreenPreview() { + WithDrawScreen() } \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/restaurant/DetailRestaurantScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/restaurant/DetailRestaurantScreen.kt index 7b7296bb..a93b79ab 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/restaurant/DetailRestaurantScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/restaurant/DetailRestaurantScreen.kt @@ -1,5 +1,10 @@ package com.everymeal.presentation.ui.restaurant +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkHorizontally +import androidx.compose.animation.slideInHorizontally import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -150,7 +155,11 @@ fun DetailRestaurantScreen( ) } } - if (viewState.isFabClicked) { + AnimatedVisibility( + visible = viewState.isFabClicked, + enter = fadeIn() + slideInHorizontally(), + exit = fadeOut() + shrinkHorizontally() + ) { Box( modifier = Modifier .fillMaxSize() diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/save/SaveScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/save/SaveScreen.kt index ffcf1e41..9351b863 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/save/SaveScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/save/SaveScreen.kt @@ -32,6 +32,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.everymeal.presentation.R import com.everymeal.presentation.ui.save.chip.ChipStyle import com.everymeal.presentation.ui.save.chip.Chips +import com.everymeal.presentation.ui.theme.EveryMealTypography import com.everymeal.presentation.ui.theme.Gray800 import com.everymeal.presentation.ui.theme.Grey2 import com.everymeal.presentation.ui.theme.Grey7 @@ -86,10 +87,7 @@ fun SaveTopBar( title = { Text( text = title, - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight.Bold - ) + style = EveryMealTypography.Subtitle2 ) }, navigationIcon = { From c0ace2e1fee05c6b971fc1919709931d320037dc Mon Sep 17 00:00:00 2001 From: sgsk88 Date: Sun, 4 Feb 2024 18:44:18 +0900 Subject: [PATCH 2/8] =?UTF-8?q?[feature/withdraw]=20=ED=83=88=ED=87=B4?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20Click=20Extension=20=EC=B6=94=EA=B0=80=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/main/MainScreen.kt | 2 +- .../presentation/ui/mypage/MyPageScreen.kt | 3 +- .../presentation/ui/mypage/WithDrawScreen.kt | 35 ----- .../ui/withdraw/WithDrawContract.kt | 29 +++++ .../ui/withdraw/WithDrawScreen.kt | 123 ++++++++++++++++++ .../ui/withdraw/WithDrawViewModel.kt | 23 ++++ .../everymeal/presentation/util/Extension.kt | 19 +++ .../res/drawable/icon_check_circle_mono.xml | 10 ++ 8 files changed, 207 insertions(+), 37 deletions(-) delete mode 100644 presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt create mode 100644 presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawContract.kt create mode 100644 presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawScreen.kt create mode 100644 presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawViewModel.kt create mode 100644 presentation/src/main/java/com/everymeal/presentation/util/Extension.kt create mode 100644 presentation/src/main/res/drawable/icon_check_circle_mono.xml diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt index 51eb02ff..838e17b5 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/main/MainScreen.kt @@ -20,7 +20,7 @@ import com.everymeal.presentation.ui.bottom.navigateBottomNavigationScreen import com.everymeal.presentation.ui.detail.DetailListScreen import com.everymeal.presentation.ui.home.HomeScreen import com.everymeal.presentation.ui.mypage.MyPageScreen -import com.everymeal.presentation.ui.mypage.WithDrawScreen +import com.everymeal.presentation.ui.withdraw.WithDrawScreen import com.everymeal.presentation.ui.restaurant.DetailRestaurantScreen import com.everymeal.presentation.ui.review.search.ReviewSearchScreen import com.everymeal.presentation.ui.search.SearchScreen diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/mypage/MyPageScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/mypage/MyPageScreen.kt index 973edd00..3d596191 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/mypage/MyPageScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/mypage/MyPageScreen.kt @@ -36,6 +36,7 @@ import com.everymeal.presentation.ui.theme.Gray400 import com.everymeal.presentation.ui.theme.Gray600 import com.everymeal.presentation.ui.theme.Gray800 import com.everymeal.presentation.ui.theme.Gray900 +import com.everymeal.presentation.util.noRippleClickable @Composable @@ -231,7 +232,7 @@ fun MyTabMenu( modifier = modifier .fillMaxWidth() .padding(top = 24.dp) - .clickable(onClick = onClick) + .noRippleClickable(onClick = onClick) .padding(vertical = 3.dp) ) { Row ( diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt deleted file mode 100644 index 1830914c..00000000 --- a/presentation/src/main/java/com/everymeal/presentation/ui/mypage/WithDrawScreen.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.everymeal.presentation.ui.mypage - -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import com.everymeal.presentation.ui.save.SaveTopBar - -@Composable -fun WithDrawScreen( - onBackClick: () -> Unit = {} -) { - Scaffold( - topBar = { - SaveTopBar( - title = "탈퇴하기", - onBackClick = onBackClick - ) - } - ) { innerPadding -> - LazyColumn( - modifier = Modifier.padding(innerPadding) - ) { - - } - } -} - -@Preview -@Composable -fun WithDrawScreenPreview() { - WithDrawScreen() -} \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawContract.kt b/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawContract.kt new file mode 100644 index 00000000..8a9d35a9 --- /dev/null +++ b/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawContract.kt @@ -0,0 +1,29 @@ +package com.everymeal.presentation.ui.withdraw + +import com.everymeal.presentation.base.LoadState +import com.everymeal.presentation.base.ViewEvent +import com.everymeal.presentation.base.ViewSideEffect +import com.everymeal.presentation.base.ViewState + +class WithDrawContract { + data class WithDrawState( + val uiState: LoadState = LoadState.LOADING, + val selectedReason: WithDrawReasonType? = null + ) : ViewState + + sealed class WithDrawEvent : ViewEvent { + data class WithDrawReasonSelected(val reason: WithDrawReasonType) : WithDrawEvent() + } + + sealed class WithDrawEffect : ViewSideEffect { + + } +} + +enum class WithDrawReasonType(val reason : String) { + NOT_USE("앱을 잘 쓰지 않아요"), + INCONVENIENT("사용성이 불편해요"), + ERROR("오류가 자주 발생해요"), + CHANGE_SCHOOL("학교가 바뀌었어요"), + ETC("기타") +} \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawScreen.kt new file mode 100644 index 00000000..4223e6cf --- /dev/null +++ b/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawScreen.kt @@ -0,0 +1,123 @@ +package com.everymeal.presentation.ui.withdraw + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.everymeal.presentation.R +import com.everymeal.presentation.ui.save.SaveTopBar +import com.everymeal.presentation.ui.theme.EveryMealTypography +import com.everymeal.presentation.ui.theme.Gray100 +import com.everymeal.presentation.ui.theme.Gray300 +import com.everymeal.presentation.ui.theme.Gray400 +import com.everymeal.presentation.ui.theme.Gray700 +import com.everymeal.presentation.ui.theme.Gray800 +import com.everymeal.presentation.ui.theme.Gray900 +import com.everymeal.presentation.ui.theme.Main100 +import com.everymeal.presentation.util.noRippleClickable + +@Composable +fun WithDrawScreen( + viewModel: WithDrawViewModel = hiltViewModel(), + onBackClick: () -> Unit = {} +) { + val viewState by viewModel.viewState.collectAsState() + + Scaffold( + topBar = { + SaveTopBar( + title = "탈퇴하기", + onBackClick = onBackClick + ) + } + ) { innerPadding -> + LazyColumn( + modifier = Modifier + .padding(innerPadding) + .fillMaxSize() + .padding(horizontal = 20.dp) + ) { + item { + Spacer(modifier = Modifier.padding(top = 40.dp)) + Text( + text = "에브리밀을 정말 떠나시겠어요?", + style = EveryMealTypography.Heading1, + color = Gray900 + ) + Spacer(modifier = Modifier.padding(top = 6.dp)) + Text( + text = "탈퇴 이유를 알려주시면 큰 도움이 돼요", + style = EveryMealTypography.Body2, + color = Gray700 + ) + } + + item { + Spacer(modifier = Modifier.padding(top = 36.dp)) + WithDrawReason(viewModel, viewState, WithDrawReasonType.NOT_USE) + WithDrawReason(viewModel, viewState, WithDrawReasonType.INCONVENIENT) + WithDrawReason(viewModel, viewState, WithDrawReasonType.ERROR) + WithDrawReason(viewModel, viewState, WithDrawReasonType.CHANGE_SCHOOL) + WithDrawReason(viewModel, viewState, WithDrawReasonType.ETC) + } + } + } +} + +@Composable +fun WithDrawReason( + viewModel : WithDrawViewModel = hiltViewModel(), + viewState : WithDrawContract.WithDrawState, + withDrawReasonType : WithDrawReasonType, +) { + val isSelected = viewState.selectedReason == withDrawReasonType + + Row( + modifier = Modifier + .border(1.dp, if(isSelected) Main100 else Gray300, RoundedCornerShape(10.dp)) + .fillMaxWidth() + .noRippleClickable { + viewModel.setEvent(WithDrawContract.WithDrawEvent.WithDrawReasonSelected(withDrawReasonType)) + } + .padding(vertical = 18.dp, horizontal = 16.dp) + ) { + Text( + text = withDrawReasonType.reason, + style = EveryMealTypography.Subtitle3, + color = Gray800 + ) + Spacer(modifier = Modifier.weight(1f)) + Image( + imageVector = ImageVector.vectorResource(id = R.drawable.icon_check_circle_mono), + contentDescription = null, + colorFilter = if(isSelected) ColorFilter.tint(Main100) else ColorFilter.tint(Gray400), + ) + } + Spacer(modifier = Modifier.padding(bottom = 12.dp)) +} + +@Preview +@Composable +fun WithDrawScreenPreview() { + WithDrawScreen() +} \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawViewModel.kt b/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawViewModel.kt new file mode 100644 index 00000000..fb3c9083 --- /dev/null +++ b/presentation/src/main/java/com/everymeal/presentation/ui/withdraw/WithDrawViewModel.kt @@ -0,0 +1,23 @@ +package com.everymeal.presentation.ui.withdraw + +import com.everymeal.presentation.base.BaseViewModel +import com.everymeal.presentation.ui.mypage.MyPageContract +import javax.inject.Inject + +class WithDrawViewModel @Inject constructor( + +) : BaseViewModel( + WithDrawContract.WithDrawState() +) { + override fun handleEvents(event: WithDrawContract.WithDrawEvent) { + when(event) { + is WithDrawContract.WithDrawEvent.WithDrawReasonSelected -> { + updateState { + copy( + selectedReason = event.reason + ) + } + } + } + } +} diff --git a/presentation/src/main/java/com/everymeal/presentation/util/Extension.kt b/presentation/src/main/java/com/everymeal/presentation/util/Extension.kt new file mode 100644 index 00000000..d6c6a666 --- /dev/null +++ b/presentation/src/main/java/com/everymeal/presentation/util/Extension.kt @@ -0,0 +1,19 @@ +package com.everymeal.presentation.util + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed + +fun Modifier.noRippleClickable( + enabled: Boolean = true, + onClick: () -> Unit = {}, +): Modifier = composed { + clickable( + enabled = enabled, + indication = null, + interactionSource = remember { MutableInteractionSource() }) { + onClick() + } +} \ No newline at end of file diff --git a/presentation/src/main/res/drawable/icon_check_circle_mono.xml b/presentation/src/main/res/drawable/icon_check_circle_mono.xml new file mode 100644 index 00000000..c6fa47de --- /dev/null +++ b/presentation/src/main/res/drawable/icon_check_circle_mono.xml @@ -0,0 +1,10 @@ + + + From e1fd2639ce313a0784fdbc1b730d1cc06ae92076 Mon Sep 17 00:00:00 2001 From: sgsk88 Date: Mon, 5 Feb 2024 21:47:12 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[feature/withdraw]=20=ED=99=88=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EB=A6=AC=EB=B7=B0=20=EC=A1=B0=ED=9A=8C=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datasource/review/ReviewDataSource.kt | 11 +- .../datasource/review/ReviewDataSourceImpl.kt | 28 +++-- .../data/model/review/ReviewListResponse.kt | 113 +++++++++++------- .../review/DefaultReviewRepository.kt | 25 ++-- .../data/service/review/StoreReviewApi.kt | 18 +-- .../model/review/GetStoreReviewEntity.kt | 19 +++ .../repository/review/ReviewRepository.kt | 9 +- .../usecase/review/GetHomeReviewUseCase.kt | 19 +++ .../components/EveryMealReviewItem.kt | 71 +++++------ .../presentation/ui/home/HomeContract.kt | 4 +- .../presentation/ui/home/HomeScreen.kt | 41 ++----- .../presentation/ui/home/HomeViewModel.kt | 26 +++- 12 files changed, 224 insertions(+), 160 deletions(-) create mode 100644 domain/src/main/java/com/everymeal/domain/model/review/GetStoreReviewEntity.kt create mode 100644 domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt index 327428b2..589f9ab4 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt @@ -4,10 +4,13 @@ import com.everymeal.data.model.review.ReviewListResponse import com.everymeal.data.model.review.StoreReviewRequest interface ReviewDataSource { - suspend fun getReviewList( - cursorIdx: Int, - mealIdx: Int, - pageSize: Int, + + suspend fun getStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int? ): Result suspend fun postReview(storeReviewRequest: StoreReviewRequest): Result diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt index 3aca7eb3..13de912f 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt @@ -9,19 +9,21 @@ import javax.inject.Inject class ReviewDataSourceImpl @Inject constructor( private val storeReviewApi: StoreReviewApi, ) : ReviewDataSource { - - override suspend fun getReviewList( - cursorIdx: Int, - mealIdx: Int, - pageSize: Int, - ): Result = - unwrapRunCatching { - storeReviewApi.getStoreReviewsWithId( - cursorIdx, - mealIdx, - pageSize, - ) - } + override suspend fun getStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int? + ): Result { + return unwrapRunCatching { storeReviewApi.getStoresReviews( + offset = 0, + limit = 3, + order = order, + group = group, + grade = grade, + ) } + } override suspend fun postReview( storeReviewRequest: StoreReviewRequest, diff --git a/data/src/main/java/com/everymeal/data/model/review/ReviewListResponse.kt b/data/src/main/java/com/everymeal/data/model/review/ReviewListResponse.kt index e4861abe..28356058 100644 --- a/data/src/main/java/com/everymeal/data/model/review/ReviewListResponse.kt +++ b/data/src/main/java/com/everymeal/data/model/review/ReviewListResponse.kt @@ -1,54 +1,75 @@ package com.everymeal.data.model.review -import com.everymeal.domain.model.review.Review -import kotlinx.serialization.SerialName +import com.everymeal.domain.model.review.GetStoreReviewEntity +import com.everymeal.domain.model.review.StoreReviewEntity import kotlinx.serialization.Serializable @Serializable data class ReviewListResponse( - @SerialName("reviewPagingList") - val reviewPagingList: List? = null, - @SerialName("reviewTotalCnt") - val reviewTotalCnt: Int? = null -) { - @Serializable - data class ReviewPaging( - @SerialName("content") - val content: String? = null, - @SerialName("grade") - val grade: Int? = null, - @SerialName("imageList") - val imageList: List? = null, - @SerialName("mealCategory") - val mealCategory: String? = null, - @SerialName("mealType") - val mealType: String? = null, - @SerialName("restaurantName") - val restaurantName: String? = null, - @SerialName("reviewIdx") - val reviewIdx: Int? = null, - @SerialName("reviewMarksCnt") - val reviewMarksCnt: Int? = null - ) { - fun toReviewDetail(): Review.ReviewDetail { - return Review.ReviewDetail( - content = content ?: "", - grade = grade ?: 0, - imageList = imageList ?: listOf(), - mealCategory = mealCategory ?: "", - mealType = mealType ?: "", - restaurantName = restaurantName ?: "", - reviewIdx = reviewIdx ?: 0, - reviewMarksCnt = reviewMarksCnt ?: 0 - ) - } - } - - fun toReview(): Review { - return Review( - reviewPagingList = reviewPagingList?.map { it.toReviewDetail() } ?: listOf(), - reviewTotalCnt = reviewTotalCnt ?: 0 - ) - } + val content: List, + val pageable: Pageable, + val totalPages: Int, + val totalElements: Int, + val last: Boolean, + val size: Int, + val number: Int, + val sort: Sort, + val numberOfElements: Int, + val first: Boolean, + val empty: Boolean, +) + +@Serializable +data class ReviewResponse( + val reviewIdx: Int, + val content: String, + val grade: Int, + val createdAt: String, + val formattedCreatedAt: String, + val nickName: String, + val profileImageUrl: String, + val reviewMarksCnt: Int, + val images: List?, + val storeIdx: Int, + val storeName: String, +) + +@Serializable +data class Pageable( + val sort: Sort, + val offset: Int, + val pageNumber: Int, + val pageSize: Int, + val paged: Boolean, + val unpaged: Boolean, +) + +@Serializable +data class Sort( + val empty: Boolean, + val sorted: Boolean, + val unsorted: Boolean, +) + +fun ReviewResponse.toStoreReviewEntity(): StoreReviewEntity { + return StoreReviewEntity( + reviewIdx = this.reviewIdx, + content = this.content, + grade = this.grade, + createdAt = this.createdAt, + formattedCreatedAt = this.formattedCreatedAt, + nickName = this.nickName, + profileImageUrl = this.profileImageUrl, + reviewMarksCnt = this.reviewMarksCnt, + images = this.images, + storeIdx = this.storeIdx, + storeName = this.storeName, + ) +} + +fun ReviewListResponse.toStoreReviewEntityList(): GetStoreReviewEntity { + return GetStoreReviewEntity( + data = this.content.map { it.toStoreReviewEntity() } + ) } diff --git a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt index 6abb844c..b4a39aad 100644 --- a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt +++ b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt @@ -2,6 +2,8 @@ package com.everymeal.data.repository.review import com.everymeal.data.datasource.review.ReviewDataSource import com.everymeal.data.model.review.toReviewRequest +import com.everymeal.data.model.review.toStoreReviewEntityList +import com.everymeal.domain.model.review.GetStoreReviewEntity import com.everymeal.domain.model.review.Review import com.everymeal.domain.model.review.UserReview import com.everymeal.domain.repository.review.ReviewRepository @@ -10,14 +12,21 @@ import javax.inject.Inject class DefaultReviewRepository @Inject constructor( private val reviewDataSource: ReviewDataSource, ) : ReviewRepository { - override suspend fun getReviewList( - cursorIdx: Int, - mealIdx: Int, - pageSize: Int, - ): Result = - reviewDataSource.getReviewList(cursorIdx, mealIdx, pageSize).map { - it.toReview() - } + override suspend fun getStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int? + ): Result { + return reviewDataSource.getStoreReviews( + offset, + limit, + order, + group, + grade, + ).map { it.toStoreReviewEntityList() } + } override suspend fun postReview( userReview: UserReview, diff --git a/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt b/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt index 06100a94..bf46b8bd 100644 --- a/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt +++ b/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt @@ -9,20 +9,20 @@ import retrofit2.http.POST import retrofit2.http.Query interface StoreReviewApi { - @GET("/api/v1/stores/{index}/reviews") - suspend fun getStoreReviewsWithId( - @Query("index") index: Int, - @Query("offset") offset: Int, - @Query("limit") limit: Int, - ): BaseResponse +// @GET("/api/v1/stores/{index}/reviews") +// suspend fun getStoreReviewsWithId( +// @Query("index") index: Int, +// @Query("offset") offset: Int, +// @Query("limit") limit: Int, +// ): BaseResponse @GET("/api/v1/stores/reviews") suspend fun getStoresReviews( @Query("offset") offset: Int, @Query("limit") limit: Int, - @Query("order") order: String, - @Query("group") group: String, - @Query("grade") grade: Int, + @Query("order") order: String?, + @Query("group") group: String?, + @Query("grade") grade: Int?, ): BaseResponse @POST("/api/v1/reviews/store") diff --git a/domain/src/main/java/com/everymeal/domain/model/review/GetStoreReviewEntity.kt b/domain/src/main/java/com/everymeal/domain/model/review/GetStoreReviewEntity.kt new file mode 100644 index 00000000..cf102efd --- /dev/null +++ b/domain/src/main/java/com/everymeal/domain/model/review/GetStoreReviewEntity.kt @@ -0,0 +1,19 @@ +package com.everymeal.domain.model.review + +data class GetStoreReviewEntity( + val data: List +) + +data class StoreReviewEntity( + val reviewIdx: Int, + val content: String, + val grade: Int, + val createdAt: String, + val formattedCreatedAt: String, + val nickName: String, + val profileImageUrl: String, + val reviewMarksCnt: Int, + val images: List?, + val storeIdx: Int, + val storeName: String, +) \ No newline at end of file diff --git a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt index d999da28..0562f44b 100644 --- a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt +++ b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt @@ -1,9 +1,16 @@ package com.everymeal.domain.repository.review +import com.everymeal.domain.model.review.GetStoreReviewEntity import com.everymeal.domain.model.review.Review import com.everymeal.domain.model.review.UserReview interface ReviewRepository { - suspend fun getReviewList(cursorIdx: Int, mealIdx: Int, pageSize: Int): Result + suspend fun getStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int? + ): Result suspend fun postReview(userReview: UserReview): Result } diff --git a/domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt b/domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt new file mode 100644 index 00000000..d4e08dc1 --- /dev/null +++ b/domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt @@ -0,0 +1,19 @@ +package com.everymeal.domain.usecase.review + +import com.everymeal.domain.model.review.GetStoreReviewEntity +import com.everymeal.domain.repository.review.ReviewRepository +import javax.inject.Inject + +class GetHomeReviewUseCase @Inject constructor( + private val reviewRepository: ReviewRepository +) { + suspend operator fun invoke( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int? + ) : Result { + return reviewRepository.getStoreReviews(offset, limit, order, group, grade) + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt b/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt index 2d6dd172..ad10742a 100644 --- a/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt +++ b/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt @@ -27,6 +27,8 @@ 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.sp +import coil.compose.AsyncImage +import com.everymeal.domain.model.review.StoreReviewEntity import com.everymeal.presentation.R import com.everymeal.presentation.ui.home.Review import com.everymeal.presentation.ui.theme.Gray300 @@ -37,8 +39,8 @@ import com.everymeal.presentation.util.Utils @Composable fun EveryMealReviewItem( - review: Review, - onDetailRestaurantClick: () -> Unit, + review: StoreReviewEntity, + onDetailRestaurantClick: (Int) -> Unit, ) { Column( modifier = Modifier @@ -57,15 +59,15 @@ fun EveryMealReviewItem( } @Composable -fun ReviewTitle(review: Review) { +fun ReviewTitle(review: StoreReviewEntity) { Row( modifier = Modifier.fillMaxWidth(), ) { - Image( + AsyncImage( modifier = Modifier .size(40.dp) .align(alignment = Alignment.CenterVertically), - painter = painterResource(id = review.profileImage), + model = review.profileImageUrl, contentDescription = stringResource(id = R.string.home_review_profile_image_description) ) Spacer(modifier = Modifier.padding(end = 8.dp)) @@ -75,7 +77,7 @@ fun ReviewTitle(review: Review) { .align(alignment = Alignment.CenterVertically) ) { Text( - text = review.name, + text = review.nickName, fontSize = 12.sp, fontWeight = FontWeight.SemiBold, color = Gray800, @@ -86,7 +88,7 @@ fun ReviewTitle(review: Review) { .padding(top = 4.dp), verticalAlignment = Alignment.CenterVertically, ) { - items(review.rating) { + items(review.grade) { Image( modifier = Modifier .size(12.dp) @@ -98,7 +100,7 @@ fun ReviewTitle(review: Review) { item { Spacer(modifier = Modifier.padding(end = 4.dp)) Text( - text = Utils.getTimeAgo(review.reviewDate), + text = Utils.getTimeAgo(review.createdAt), fontSize = 12.sp, color = Gray600, ) @@ -116,7 +118,7 @@ fun ReviewTitle(review: Review) { } @Composable -fun ReviewContent(review: Review) { +fun ReviewContent(review: StoreReviewEntity) { Row( modifier = Modifier.fillMaxWidth(), ) { @@ -130,18 +132,20 @@ fun ReviewContent(review: Review) { overflow = TextOverflow.Ellipsis ) Spacer(modifier = Modifier.padding(end = 10.dp)) - Image( - modifier = Modifier - .size(64.dp) - .align(alignment = Alignment.CenterVertically), - painter = painterResource(id = review.image[0]), - contentDescription = stringResource(id = R.string.home_review_image) - ) + review.images?.let { + AsyncImage( + modifier = Modifier + .size(64.dp) + .align(alignment = Alignment.CenterVertically), + model = it[0], + contentDescription = stringResource(id = R.string.home_review_image) + ) + } } } @Composable -fun ReviewGoodCount(review: Review) { +fun ReviewGoodCount(review: StoreReviewEntity) { Row( modifier = Modifier .fillMaxWidth(), @@ -155,7 +159,7 @@ fun ReviewGoodCount(review: Review) { ) Spacer(modifier = Modifier.padding(end = 2.dp)) Text( - text = review.loveCount.toString(), + text = review.reviewMarksCnt.toString(), fontSize = 12.sp, color = Gray600, ) @@ -164,14 +168,14 @@ fun ReviewGoodCount(review: Review) { @Composable fun ReviewDetailRestaurant( - review: Review, - onDetailRestaurantClick: () -> Unit + review: StoreReviewEntity, + onDetailRestaurantClick: (Int) -> Unit ) { Row( modifier = Modifier .clip(RoundedCornerShape(8.dp)) .fillMaxWidth() - .clickable { onDetailRestaurantClick() } + .clickable { onDetailRestaurantClick(review.storeIdx) } .background(Gray300), verticalAlignment = Alignment.CenterVertically, ) { @@ -185,7 +189,7 @@ fun ReviewDetailRestaurant( Text( modifier = Modifier .weight(1f), - text = review.restaurantName, + text = review.storeName, fontSize = 14.sp, fontWeight = FontWeight.SemiBold, color = Gray700, @@ -198,25 +202,4 @@ fun ReviewDetailRestaurant( contentDescription = stringResource(id = R.string.home_review_detail_restaurant) ) } -} - -@Preview -@Composable -fun ReviewDetailRestaurantPreview() { - ReviewDetailRestaurant( - review = Review( - name = "슈니", - profileImage = R.drawable.profile_ex_image, - loveCount = 100, - image = listOf( - 0, - 1, - ), - rating = 3, - reviewDate = "2023-08-29T09:58:47.604732", - content = "매장 안쪽으로 가면 너무 감성있는 곳이 나와요. 그리고 분위기도 너무 좋고 맛도 너무 완벽해요. 이런 카페는 정말 처음인 것 같아요. 알바생도 너무 아름답습니다.. 여기 계속 찾을 것 같아요. 정말 항상 감사드려요.", - restaurantName = "왕가주방", - ), - onDetailRestaurantClick = { }, - ) -} +} \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt index 43a90fa0..f2eeb10f 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt @@ -1,6 +1,7 @@ package com.everymeal.presentation.ui.home import com.everymeal.domain.model.restaurant.RestaurantDataEntity +import com.everymeal.domain.model.review.StoreReviewEntity import com.everymeal.presentation.base.LoadState import com.everymeal.presentation.base.ViewEvent import com.everymeal.presentation.base.ViewSideEffect @@ -11,7 +12,8 @@ class HomeContract { val uiState: LoadState = LoadState.LOADING, val detailListScreenType: DetailListScreenType = DetailListScreenType.RECOMMEND, val bottomSheetState: Boolean = false, - val restaurantData: List = emptyList() + val restaurantData: List = emptyList(), + val reviewData: List = emptyList() ) : ViewState sealed class HomeEvent : ViewEvent { diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt index c54a6f5f..6dd97304 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt @@ -80,35 +80,6 @@ fun HomeScreen( } } - val reviewTestItem = listOf( - Review( - name = "슈니", - profileImage = R.drawable.profile_ex_image, - loveCount = 100, - image = listOf( - R.drawable.review_ex_1, - R.drawable.review_ex_1, - ), - rating = 5, - reviewDate = "2023-08-29T09:58:47.604732", - content = "매장 안쪽으로 가면 너무 감성있는 곳이 나와요. 그리고 분위기도 너무 좋고 맛도 너무 완벽해요. 이런 카페는 정말 처음인 것 같아요. 알바생도 너무 아름답습니다.. 여기 계속 찾을 것 같아요. 정말 항상 감사드려요.", - restaurantName = "왕가주방", - ), - Review( - name = "슈니", - profileImage = R.drawable.profile_ex_image, - loveCount = 100, - image = listOf( - R.drawable.review_ex_1, - R.drawable.review_ex_1, - ), - rating = 5, - reviewDate = "2023-08-20T09:58:47.604732", - content = "맛있어요", - restaurantName = "왕가주방", - ), - ) - val homeViewState by homeViewModel.viewState.collectAsState() if (homeViewState.bottomSheetState) { @@ -202,13 +173,17 @@ fun HomeScreen( LazyColumnTitle(stringResource(R.string.home_top_good_review)) Spacer(modifier = Modifier.padding(8.dp)) } - items(reviewTestItem.size) { index -> - val item = reviewTestItem[index] + items(homeViewState.reviewData.size) { index -> + val item = homeViewState.reviewData[index] EveryMealReviewItem(item) { - + homeViewModel.setEvent( + HomeContract.HomeEvent.OnClickDetailRestaurant( + it + ) + ) } Spacer(modifier = Modifier.padding(10.dp)) - if (index != reviewTestItem.size - 1) { + if (index != homeViewState.reviewData.size - 1) { Divider( modifier = Modifier .padding(horizontal = 20.dp), diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt index a0117795..860b5168 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt @@ -1,9 +1,11 @@ package com.everymeal.presentation.ui.home +import android.util.Log import androidx.lifecycle.viewModelScope import com.everymeal.domain.usecase.local.GetUniversityIndexUseCase import com.everymeal.domain.usecase.restaurant.GetHomeRestaurantUseCase import com.everymeal.domain.usecase.restaurant.GetUnivRestaurantUseCase +import com.everymeal.domain.usecase.review.GetHomeReviewUseCase import com.everymeal.presentation.base.BaseViewModel import com.everymeal.presentation.base.LoadState import com.everymeal.presentation.ui.home.HomeContract.HomeEffect @@ -37,7 +39,8 @@ data class Restaurant( @HiltViewModel class HomeViewModel @Inject constructor( private val getHomeRestaurantUseCase: GetHomeRestaurantUseCase, - private val getUniversityIndexUseCase: GetUniversityIndexUseCase + private val getUniversityIndexUseCase: GetUniversityIndexUseCase, + private val getHomeReviewUseCase: GetHomeReviewUseCase ): BaseViewModel( HomeState() ) { @@ -46,6 +49,7 @@ class HomeViewModel @Inject constructor( when (event) { is HomeEvent.InitHomeScreen -> { getUnivRestaurant() + getHomeReview() } is HomeEvent.OnClickDetailList -> { sendEffect({ HomeEffect.NavigateToDetailListScreen(event.detailListScreenType) }) @@ -87,4 +91,24 @@ class HomeViewModel @Inject constructor( } } } + + private fun getHomeReview() { + viewModelScope.launch { + getHomeReviewUseCase( + offset = 0, + limit = 3, + order = "name", + group = null, + grade = null + ).onSuccess { + updateState { + copy( + reviewData = it.data + ) + } + }.onFailure { + Log.d("gg1234", "gg") + } + } + } } From 271a06a86bf8b1cba5da81a465b5dbe5b567e9ff Mon Sep 17 00:00:00 2001 From: sgsk88 Date: Wed, 7 Feb 2024 23:43:11 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[feature/withdraw]=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=BA=A0=ED=8D=BC=EC=8A=A4=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datasource/review/ReviewDataSource.kt | 3 ++- .../datasource/review/ReviewDataSourceImpl.kt | 4 +++- .../review/DefaultReviewRepository.kt | 4 +++- .../data/service/review/StoreReviewApi.kt | 1 + .../repository/review/ReviewRepository.kt | 3 ++- .../usecase/review/GetHomeReviewUseCase.kt | 5 ++-- .../components/EveryMealReviewItem.kt | 2 -- .../presentation/ui/home/HomeViewModel.kt | 23 ++----------------- 8 files changed, 16 insertions(+), 29 deletions(-) diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt index 589f9ab4..294b525a 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt @@ -10,7 +10,8 @@ interface ReviewDataSource { limit: Int, order: String?, group: String?, - grade: Int? + grade: Int?, + campusIdx: Int, ): Result suspend fun postReview(storeReviewRequest: StoreReviewRequest): Result diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt index 13de912f..f3a84666 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt @@ -14,7 +14,8 @@ class ReviewDataSourceImpl @Inject constructor( limit: Int, order: String?, group: String?, - grade: Int? + grade: Int?, + campusIdx: Int ): Result { return unwrapRunCatching { storeReviewApi.getStoresReviews( offset = 0, @@ -22,6 +23,7 @@ class ReviewDataSourceImpl @Inject constructor( order = order, group = group, grade = grade, + campusIdx = campusIdx ) } } diff --git a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt index b4a39aad..10e8207f 100644 --- a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt +++ b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt @@ -17,7 +17,8 @@ class DefaultReviewRepository @Inject constructor( limit: Int, order: String?, group: String?, - grade: Int? + grade: Int?, + campusIdx: Int, ): Result { return reviewDataSource.getStoreReviews( offset, @@ -25,6 +26,7 @@ class DefaultReviewRepository @Inject constructor( order, group, grade, + campusIdx ).map { it.toStoreReviewEntityList() } } diff --git a/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt b/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt index bf46b8bd..5150662a 100644 --- a/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt +++ b/data/src/main/java/com/everymeal/data/service/review/StoreReviewApi.kt @@ -23,6 +23,7 @@ interface StoreReviewApi { @Query("order") order: String?, @Query("group") group: String?, @Query("grade") grade: Int?, + @Query("campusIdx") campusIdx: Int, ): BaseResponse @POST("/api/v1/reviews/store") diff --git a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt index 0562f44b..4c24e892 100644 --- a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt +++ b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt @@ -10,7 +10,8 @@ interface ReviewRepository { limit: Int, order: String?, group: String?, - grade: Int? + grade: Int?, + campusIdx: Int, ): Result suspend fun postReview(userReview: UserReview): Result } diff --git a/domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt b/domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt index d4e08dc1..80e140a7 100644 --- a/domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt +++ b/domain/src/main/java/com/everymeal/domain/usecase/review/GetHomeReviewUseCase.kt @@ -12,8 +12,9 @@ class GetHomeReviewUseCase @Inject constructor( limit: Int, order: String?, group: String?, - grade: Int? + grade: Int?, + campusIdx: Int ) : Result { - return reviewRepository.getStoreReviews(offset, limit, order, group, grade) + return reviewRepository.getStoreReviews(offset, limit, order, group, grade, campusIdx) } } \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt b/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt index ad10742a..f8e0e1a5 100644 --- a/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt +++ b/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt @@ -24,13 +24,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.font.FontWeight 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.sp import coil.compose.AsyncImage import com.everymeal.domain.model.review.StoreReviewEntity import com.everymeal.presentation.R -import com.everymeal.presentation.ui.home.Review import com.everymeal.presentation.ui.theme.Gray300 import com.everymeal.presentation.ui.theme.Gray600 import com.everymeal.presentation.ui.theme.Gray700 diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt index 860b5168..a0cafadf 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeViewModel.kt @@ -16,26 +16,6 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import javax.inject.Inject -data class Review( - val name: String, - val profileImage: Int, - val loveCount: Int, - val image: List, - val rating: Int, - val reviewDate: String, - val content: String, - val restaurantName: String, -) - -data class Restaurant( - val name: String, - val category: String, - val image: List, - val rating: Double, - val reviewCount: Int, - val loveCount: Int, -) - @HiltViewModel class HomeViewModel @Inject constructor( private val getHomeRestaurantUseCase: GetHomeRestaurantUseCase, @@ -99,7 +79,8 @@ class HomeViewModel @Inject constructor( limit = 3, order = "name", group = null, - grade = null + grade = null, + campusIdx = getUniversityIndexUseCase().first().toInt() ).onSuccess { updateState { copy( From 549925a0d55364b1780ec8d9e54e5a65d1d6f9a9 Mon Sep 17 00:00:00 2001 From: sgsk88 Date: Thu, 8 Feb 2024 00:54:49 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[feature/withdraw]=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=95=20=EA=B0=81=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EC=85=8B=ED=8C=85=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datasource/review/ReviewDataSource.kt | 13 +++++++++ .../datasource/review/ReviewDataSourceImpl.kt | 14 ++++++++++ .../review/DefaultReviewRepository.kt | 27 +++++++++++++++++++ .../repository/review/ReviewRepository.kt | 12 +++++++++ .../components/EveryMealReviewItem.kt | 8 ++++-- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt index 294b525a..a1a773ad 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt @@ -1,10 +1,23 @@ package com.everymeal.data.datasource.review +import androidx.paging.PagingData import com.everymeal.data.model.review.ReviewListResponse +import com.everymeal.data.model.review.ReviewResponse import com.everymeal.data.model.review.StoreReviewRequest +import com.everymeal.domain.model.review.GetStoreReviewEntity +import kotlinx.coroutines.flow.Flow interface ReviewDataSource { + suspend fun getPagingStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int?, + campusIdx: Int, + ): Flow> + suspend fun getStoreReviews( offset: Int, limit: Int, diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt index f3a84666..b9d0e00a 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt @@ -1,14 +1,28 @@ package com.everymeal.data.datasource.review +import androidx.paging.PagingData import com.everymeal.data.model.review.ReviewListResponse +import com.everymeal.data.model.review.ReviewResponse import com.everymeal.data.model.review.StoreReviewRequest import com.everymeal.data.model.unwrapRunCatching import com.everymeal.data.service.review.StoreReviewApi +import kotlinx.coroutines.flow.Flow import javax.inject.Inject class ReviewDataSourceImpl @Inject constructor( private val storeReviewApi: StoreReviewApi, ) : ReviewDataSource { + override suspend fun getPagingStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int?, + campusIdx: Int + ): Flow> { + throw NotImplementedError() + } + override suspend fun getStoreReviews( offset: Int, limit: Int, diff --git a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt index 10e8207f..2127a4ac 100644 --- a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt +++ b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt @@ -1,17 +1,44 @@ package com.everymeal.data.repository.review +import androidx.paging.PagingData +import androidx.paging.map import com.everymeal.data.datasource.review.ReviewDataSource +import com.everymeal.data.model.restaruant.toRestaurant import com.everymeal.data.model.review.toReviewRequest +import com.everymeal.data.model.review.toStoreReviewEntity import com.everymeal.data.model.review.toStoreReviewEntityList import com.everymeal.domain.model.review.GetStoreReviewEntity import com.everymeal.domain.model.review.Review +import com.everymeal.domain.model.review.StoreReviewEntity import com.everymeal.domain.model.review.UserReview import com.everymeal.domain.repository.review.ReviewRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map import javax.inject.Inject class DefaultReviewRepository @Inject constructor( private val reviewDataSource: ReviewDataSource, ) : ReviewRepository { + override suspend fun getPagingStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int?, + campusIdx: Int + ): Flow> { + return reviewDataSource.getPagingStoreReviews( + offset, + limit, + order, + group, + grade, + campusIdx + ).map { pagingData -> + pagingData.map { it.toStoreReviewEntity() } + } + } + override suspend fun getStoreReviews( offset: Int, limit: Int, diff --git a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt index 4c24e892..6dd5bae1 100644 --- a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt +++ b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt @@ -1,10 +1,22 @@ package com.everymeal.domain.repository.review +import androidx.paging.PagingData import com.everymeal.domain.model.review.GetStoreReviewEntity import com.everymeal.domain.model.review.Review +import com.everymeal.domain.model.review.StoreReviewEntity import com.everymeal.domain.model.review.UserReview +import kotlinx.coroutines.flow.Flow interface ReviewRepository { + suspend fun getPagingStoreReviews( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int?, + campusIdx: Int, + ): Flow> + suspend fun getStoreReviews( offset: Int, limit: Int, diff --git a/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt b/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt index f8e0e1a5..04fc5ac5 100644 --- a/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt +++ b/presentation/src/main/java/com/everymeal/presentation/components/EveryMealReviewItem.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -19,6 +20,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale.Companion.Crop import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource @@ -121,8 +123,7 @@ fun ReviewContent(review: StoreReviewEntity) { modifier = Modifier.fillMaxWidth(), ) { Text( - modifier = Modifier - .weight(1f), + modifier = Modifier.weight(1f), text = review.content, fontSize = 14.sp, color = Gray800, @@ -134,8 +135,11 @@ fun ReviewContent(review: StoreReviewEntity) { AsyncImage( modifier = Modifier .size(64.dp) + .aspectRatio(1f) + .clip(RoundedCornerShape(8.dp)) .align(alignment = Alignment.CenterVertically), model = it[0], + contentScale = Crop, contentDescription = stringResource(id = R.string.home_review_image) ) } From d902932cdc7f82222a5329bb0bd2f1a8813b1c38 Mon Sep 17 00:00:00 2001 From: SsongSik Date: Thu, 8 Feb 2024 14:19:03 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[feature/withdraw]=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=95=20data,=20domain=20layer=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datasource/review/ReviewDataSourceImpl.kt | 13 ++++- .../datasource/review/ReviewPagingSource.kt | 53 +++++++++++++++++++ .../usecase/review/GetStoreReviewUseCase.kt | 22 ++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 data/src/main/java/com/everymeal/data/datasource/review/ReviewPagingSource.kt create mode 100644 domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt index b9d0e00a..4d7b0112 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt @@ -1,6 +1,9 @@ package com.everymeal.data.datasource.review +import androidx.paging.Pager +import androidx.paging.PagingConfig import androidx.paging.PagingData +import com.everymeal.data.datasource.restaurant.PAGING_SIZE import com.everymeal.data.model.review.ReviewListResponse import com.everymeal.data.model.review.ReviewResponse import com.everymeal.data.model.review.StoreReviewRequest @@ -20,7 +23,15 @@ class ReviewDataSourceImpl @Inject constructor( grade: Int?, campusIdx: Int ): Flow> { - throw NotImplementedError() + val pagingSourceFactory = { ReviewPagingSource(storeReviewApi, order, group, grade, campusIdx) } + return Pager( + config = PagingConfig( + initialLoadSize = PAGING_SIZE, + pageSize = PAGING_SIZE, + enablePlaceholders = false, + ), + pagingSourceFactory = pagingSourceFactory + ).flow } override suspend fun getStoreReviews( diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewPagingSource.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewPagingSource.kt new file mode 100644 index 00000000..99337d6d --- /dev/null +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewPagingSource.kt @@ -0,0 +1,53 @@ +package com.everymeal.data.datasource.review + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.everymeal.data.datasource.restaurant.PAGING_SIZE +import com.everymeal.data.datasource.restaurant.STARTING_PAGE_INDEX +import com.everymeal.data.model.restaruant.RestaurantResponse +import com.everymeal.data.model.review.ReviewResponse +import com.everymeal.data.service.restaurant.RestaurantApi +import com.everymeal.data.service.review.StoreReviewApi +import retrofit2.HttpException +import java.io.IOException + +class ReviewPagingSource ( + private val storeReviewApi: StoreReviewApi, + private val order: String?, + private val group: String?, + private val grade: Int?, + private val campusIdx: Int +) : PagingSource() { + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition?.let { anchorPosition -> + state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1) + ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1) + } + } + + override suspend fun load(params: LoadParams): LoadResult { + val position = params.key ?: STARTING_PAGE_INDEX + + return try { + val response = storeReviewApi.getStoresReviews( + campusIdx = campusIdx, + order = order, + group = group, + grade = grade, + offset = position, + limit = PAGING_SIZE + ) + val restaurants = response.data.content + LoadResult.Page( + data = restaurants, + prevKey = if (position == STARTING_PAGE_INDEX) null else position - 1, + nextKey = if (restaurants.isEmpty()) null else position + 1 + ) + } catch (exception: IOException) { + LoadResult.Error(exception) + } catch (exception: HttpException) { + LoadResult.Error(exception) + } + } + +} \ No newline at end of file diff --git a/domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt b/domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt new file mode 100644 index 00000000..41c597bd --- /dev/null +++ b/domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt @@ -0,0 +1,22 @@ +package com.everymeal.domain.usecase.review + +import androidx.paging.PagingData +import com.everymeal.domain.model.review.StoreReviewEntity +import com.everymeal.domain.repository.review.ReviewRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetStoreReviewUseCase @Inject constructor( + private val reviewRepository: ReviewRepository +) { + suspend operator fun invoke( + offset: Int, + limit: Int, + order: String?, + group: String?, + grade: Int?, + campusIdx: Int + ) : Flow> { + return reviewRepository.getPagingStoreReviews(offset, limit, order, group, grade, campusIdx) + } +} \ No newline at end of file From 8d08a69b1def4ced4a4bb65781a4ffd17364359e Mon Sep 17 00:00:00 2001 From: SsongSik Date: Thu, 8 Feb 2024 15:04:58 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[feature/withdraw]=20=EC=8B=9D=EB=8B=B9?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=99=94=EB=A9=B4=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datasource/review/ReviewDataSource.kt | 2 - .../datasource/review/ReviewDataSourceImpl.kt | 2 - .../review/DefaultReviewRepository.kt | 4 -- .../repository/review/ReviewRepository.kt | 2 - .../usecase/review/GetStoreReviewUseCase.kt | 4 +- .../ui/detail/DetailListContract.kt | 3 +- .../ui/detail/DetailListScreen.kt | 20 ++++++- .../ui/detail/DetailListViewModel.kt | 57 +++++++++++++++++-- .../presentation/ui/home/HomeContract.kt | 3 + .../presentation/ui/home/HomeScreen.kt | 2 +- 10 files changed, 77 insertions(+), 22 deletions(-) diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt index a1a773ad..938758b9 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSource.kt @@ -10,8 +10,6 @@ import kotlinx.coroutines.flow.Flow interface ReviewDataSource { suspend fun getPagingStoreReviews( - offset: Int, - limit: Int, order: String?, group: String?, grade: Int?, diff --git a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt index 4d7b0112..3024f42f 100644 --- a/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt +++ b/data/src/main/java/com/everymeal/data/datasource/review/ReviewDataSourceImpl.kt @@ -16,8 +16,6 @@ class ReviewDataSourceImpl @Inject constructor( private val storeReviewApi: StoreReviewApi, ) : ReviewDataSource { override suspend fun getPagingStoreReviews( - offset: Int, - limit: Int, order: String?, group: String?, grade: Int?, diff --git a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt index 2127a4ac..fb69353e 100644 --- a/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt +++ b/data/src/main/java/com/everymeal/data/repository/review/DefaultReviewRepository.kt @@ -20,16 +20,12 @@ class DefaultReviewRepository @Inject constructor( private val reviewDataSource: ReviewDataSource, ) : ReviewRepository { override suspend fun getPagingStoreReviews( - offset: Int, - limit: Int, order: String?, group: String?, grade: Int?, campusIdx: Int ): Flow> { return reviewDataSource.getPagingStoreReviews( - offset, - limit, order, group, grade, diff --git a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt index 6dd5bae1..7002216f 100644 --- a/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt +++ b/domain/src/main/java/com/everymeal/domain/repository/review/ReviewRepository.kt @@ -9,8 +9,6 @@ import kotlinx.coroutines.flow.Flow interface ReviewRepository { suspend fun getPagingStoreReviews( - offset: Int, - limit: Int, order: String?, group: String?, grade: Int?, diff --git a/domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt b/domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt index 41c597bd..8700264d 100644 --- a/domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt +++ b/domain/src/main/java/com/everymeal/domain/usecase/review/GetStoreReviewUseCase.kt @@ -10,13 +10,11 @@ class GetStoreReviewUseCase @Inject constructor( private val reviewRepository: ReviewRepository ) { suspend operator fun invoke( - offset: Int, - limit: Int, order: String?, group: String?, grade: Int?, campusIdx: Int ) : Flow> { - return reviewRepository.getPagingStoreReviews(offset, limit, order, group, grade, campusIdx) + return reviewRepository.getPagingStoreReviews(order, group, grade, campusIdx) } } \ No newline at end of file diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListContract.kt b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListContract.kt index c9b606d0..ea9b4a5c 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListContract.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListContract.kt @@ -16,10 +16,11 @@ class DetailContract { val reportCategoryType: ReportCategoryType = ReportCategoryType.NONE, val restaurantCategoryType: RestaurantCategoryType = RestaurantCategoryType.NONE, val rating: Int = 0, + val isReviewScreen: Boolean = false ) : ViewState sealed class DetailEvent : ViewEvent { - object InitDetailScreen : DetailEvent() + data class InitDetailScreen(val isReviewScreen: Boolean = false) : DetailEvent() data class SortBottomSheetStateChange(val sortBottomSheetState: Boolean) : DetailEvent() data class MealRatingBottomSheetStateChange(val mealRatingBottomSheetState: Boolean) : DetailEvent() data class ReportBottomSheetStateChange(val reportBottomSheetState: Boolean) : DetailEvent() diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListScreen.kt index 53776f89..597d6e2b 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListScreen.kt @@ -31,11 +31,13 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import com.everymeal.domain.model.restaurant.RestaurantDataEntity +import com.everymeal.domain.model.review.StoreReviewEntity import com.everymeal.presentation.R import com.everymeal.presentation.components.EveryMealCategoryRatingBottomSheetDialog import com.everymeal.presentation.components.EveryMealDetailReportBottomSheetDialog import com.everymeal.presentation.components.EveryMealReportBottomSheetDialog import com.everymeal.presentation.components.EveryMealRestaurantItem +import com.everymeal.presentation.components.EveryMealReviewItem import com.everymeal.presentation.components.EveryMealSortCategoryBottomSheetDialog import com.everymeal.presentation.ui.save.SaveTopBar import com.everymeal.presentation.ui.theme.Grey2 @@ -55,8 +57,11 @@ fun DetailListScreen( val pagingRestaurantList: LazyPagingItems = detailListViewModel.restaurantItems.collectAsLazyPagingItems() + val pagingReviewList: LazyPagingItems = + detailListViewModel.restaurantReviews.collectAsLazyPagingItems() + LaunchedEffect(Unit) { - detailListViewModel.setEvent(DetailContract.DetailEvent.InitDetailScreen) + detailListViewModel.setEvent(DetailContract.DetailEvent.InitDetailScreen(title == "리뷰")) } LaunchedEffect(key1 = detailListViewModel.effect) { @@ -258,6 +263,19 @@ fun DetailListScreen( Spacer(modifier = Modifier.padding(16.dp)) } } + + items(pagingReviewList.itemCount) { index -> + val item = pagingReviewList[index] + item?.let { + EveryMealReviewItem( + review = it, + onDetailRestaurantClick = { restaurantId -> + detailListViewModel.setEvent(DetailContract.DetailEvent.OnRestaurantDetailClick(restaurantId)) + } + ) + Spacer(modifier = Modifier.padding(16.dp)) + } + } } } } diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt index 8bf0e46f..43287aec 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt @@ -4,8 +4,10 @@ import androidx.lifecycle.viewModelScope import androidx.paging.PagingData import androidx.paging.cachedIn import com.everymeal.domain.model.restaurant.RestaurantDataEntity +import com.everymeal.domain.model.review.StoreReviewEntity import com.everymeal.domain.usecase.local.GetUniversityIndexUseCase import com.everymeal.domain.usecase.restaurant.GetUnivRestaurantUseCase +import com.everymeal.domain.usecase.review.GetStoreReviewUseCase import com.everymeal.presentation.base.BaseViewModel import com.everymeal.presentation.ui.detail.DetailContract.DetailEvent import com.everymeal.presentation.ui.detail.DetailContract.DetailState @@ -21,23 +23,38 @@ import javax.inject.Inject @HiltViewModel class DetailListViewModel @Inject constructor( private val getUnivRestaurantUseCase: GetUnivRestaurantUseCase, - private val getUniversityIndexUseCase: GetUniversityIndexUseCase + private val getUniversityIndexUseCase: GetUniversityIndexUseCase, + private val getStoreReviewUseCase: GetStoreReviewUseCase ): BaseViewModel( DetailState() ) { private val _restaurantItems : MutableStateFlow> = MutableStateFlow(value = PagingData.empty()) val restaurantItems : StateFlow> = _restaurantItems.asStateFlow() + private val _restaurantReviews : MutableStateFlow> = MutableStateFlow(value = PagingData.empty()) + val restaurantReviews : StateFlow> = _restaurantReviews.asStateFlow() + override fun handleEvents(event: DetailEvent) { when (event) { is DetailEvent.InitDetailScreen -> { - getRestaurantList() + reflectUpdateState( + isReviewScreen = event.isReviewScreen + ) + if(event.isReviewScreen) { + getReviewList() + } else { + getRestaurantList() + } } is DetailEvent.OnClickDetailListCategoryType -> { reflectUpdateState( detailSortCategoryType = event.detailSortCategoryType ) - getRestaurantList() + if(viewState.value.isReviewScreen) { + getReviewList() + } else { + getRestaurantList() + } } is DetailEvent.SortBottomSheetStateChange -> { reflectUpdateState( @@ -48,7 +65,11 @@ class DetailListViewModel @Inject constructor( reflectUpdateState( mealRatingBottomSheetState = event.mealRatingBottomSheetState ) - getRestaurantList() + if(viewState.value.isReviewScreen) { + getReviewList() + } else { + getRestaurantList() + } } is DetailEvent.ReportBottomSheetStateChange -> { reflectUpdateState( @@ -79,13 +100,21 @@ class DetailListViewModel @Inject constructor( reflectUpdateState( restaurantCategoryType = RestaurantCategoryType.NONE ) - getRestaurantList() + if(viewState.value.isReviewScreen) { + getReviewList() + } else { + getRestaurantList() + } } is DetailEvent.OnDeleteClickRating -> { reflectUpdateState( rating = 0 ) - getRestaurantList() + if(viewState.value.isReviewScreen) { + getReviewList() + } else { + getRestaurantList() + } } is DetailEvent.OnRestaurantDetailClick -> { sendEffect({ DetailEffect.OnRestaurantClickEffect(event.restaurantId) }) @@ -93,6 +122,20 @@ class DetailListViewModel @Inject constructor( } } + private fun getReviewList() { + viewModelScope.launch { + getStoreReviewUseCase( + order = viewState.value.detailSortCategoryType.sort(), + group = viewState.value.restaurantCategoryType.sort(), + grade = if(viewState.value.rating == 0) null else viewState.value.rating, + campusIdx = getUniversityIndexUseCase().first().toInt() + ).cachedIn(viewModelScope) + .collect { + _restaurantReviews.emit(it) + } + } + } + private fun getRestaurantList() { viewModelScope.launch { getUnivRestaurantUseCase( @@ -116,6 +159,7 @@ class DetailListViewModel @Inject constructor( reportCategoryType: ReportCategoryType = viewState.value.reportCategoryType, rating: Int = viewState.value.rating, restaurantCategoryType: RestaurantCategoryType = viewState.value.restaurantCategoryType, + isReviewScreen: Boolean = viewState.value.isReviewScreen ) { updateState { copy( @@ -127,6 +171,7 @@ class DetailListViewModel @Inject constructor( reportCategoryType = reportCategoryType, rating = rating, restaurantCategoryType = restaurantCategoryType, + isReviewScreen = isReviewScreen ) } } diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt index f2eeb10f..01ea35da 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeContract.kt @@ -34,6 +34,7 @@ enum class DetailListScreenType { RESTAURANT, CAFE, DRINK, + REVIEW } fun String.DetailListScreenType(): DetailListScreenType { @@ -42,6 +43,7 @@ fun String.DetailListScreenType(): DetailListScreenType { "밥집" -> DetailListScreenType.RESTAURANT "카페" -> DetailListScreenType.CAFE "술집" -> DetailListScreenType.DRINK + "리뷰" -> DetailListScreenType.REVIEW else -> DetailListScreenType.RECOMMEND } } @@ -52,5 +54,6 @@ fun DetailListScreenType.title(): String { DetailListScreenType.RESTAURANT -> "밥집" DetailListScreenType.CAFE -> "카페" DetailListScreenType.DRINK -> "술집" + DetailListScreenType.REVIEW -> "리뷰" } } diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt index 6dd97304..fd086101 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/home/HomeScreen.kt @@ -196,7 +196,7 @@ fun HomeScreen( EveryMealLineButton( text = stringResource(R.string.home_restaurant_review_button_text), onClick = { - + homeViewModel.setEvent(HomeContract.HomeEvent.OnClickDetailList("리뷰".DetailListScreenType())) }, ) } From 80466950f8ae12363539277ca35f8ce97cd49920 Mon Sep 17 00:00:00 2001 From: SsongSik Date: Thu, 8 Feb 2024 15:37:20 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[feature/withdraw]=20=EC=8B=9D=EB=8B=B9?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=99=94=EB=A9=B4=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=ED=99=94=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/detail/DetailListViewModel.kt | 38 +++++++------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt index 43287aec..0fbda5e2 100644 --- a/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt +++ b/presentation/src/main/java/com/everymeal/presentation/ui/detail/DetailListViewModel.kt @@ -40,21 +40,13 @@ class DetailListViewModel @Inject constructor( reflectUpdateState( isReviewScreen = event.isReviewScreen ) - if(event.isReviewScreen) { - getReviewList() - } else { - getRestaurantList() - } + fetchListBasedOnType(event.isReviewScreen) } is DetailEvent.OnClickDetailListCategoryType -> { reflectUpdateState( detailSortCategoryType = event.detailSortCategoryType ) - if(viewState.value.isReviewScreen) { - getReviewList() - } else { - getRestaurantList() - } + fetchListBasedOnType(viewState.value.isReviewScreen) } is DetailEvent.SortBottomSheetStateChange -> { reflectUpdateState( @@ -65,11 +57,7 @@ class DetailListViewModel @Inject constructor( reflectUpdateState( mealRatingBottomSheetState = event.mealRatingBottomSheetState ) - if(viewState.value.isReviewScreen) { - getReviewList() - } else { - getRestaurantList() - } + fetchListBasedOnType(viewState.value.isReviewScreen) } is DetailEvent.ReportBottomSheetStateChange -> { reflectUpdateState( @@ -100,21 +88,13 @@ class DetailListViewModel @Inject constructor( reflectUpdateState( restaurantCategoryType = RestaurantCategoryType.NONE ) - if(viewState.value.isReviewScreen) { - getReviewList() - } else { - getRestaurantList() - } + fetchListBasedOnType(viewState.value.isReviewScreen) } is DetailEvent.OnDeleteClickRating -> { reflectUpdateState( rating = 0 ) - if(viewState.value.isReviewScreen) { - getReviewList() - } else { - getRestaurantList() - } + fetchListBasedOnType(viewState.value.isReviewScreen) } is DetailEvent.OnRestaurantDetailClick -> { sendEffect({ DetailEffect.OnRestaurantClickEffect(event.restaurantId) }) @@ -122,6 +102,14 @@ class DetailListViewModel @Inject constructor( } } + private fun fetchListBasedOnType(isReviewScreen: Boolean) { + if(isReviewScreen) { + getReviewList() + } else { + getRestaurantList() + } + } + private fun getReviewList() { viewModelScope.launch { getStoreReviewUseCase(