From f047a5b8fe092a3652fbefbde08cb30e257d6b0f Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Thu, 22 Aug 2024 01:08:52 +0900 Subject: [PATCH 01/15] =?UTF-8?q?[fix/#110]=20=EA=B3=B5=EA=B0=90=EC=88=9C?= =?UTF-8?q?=20=ED=95=84=ED=84=B0=EB=A7=81=20=ED=94=8C=EB=9E=98=EA=B7=B8=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20true=20=ED=95=A0=EB=8B=B9=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewfinder/viewmodel/StadiumDetailViewModel.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt index 63610275..b357b12f 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt @@ -80,8 +80,11 @@ class StadiumDetailViewModel @Inject constructor( } fun updateSort(sortBy: String) { - _reviewFilter.value = _reviewFilter.value.copy(sortBy = sortBy) - getBlockReviews(query = _reviewFilter.value) + if (_reviewFilter.value.sortBy != sortBy) { + reset = true + _reviewFilter.value = _reviewFilter.value.copy(sortBy = sortBy) + getBlockReviews(query = _reviewFilter.value) + } } fun updateRequestPathVariable(stadiumId: Int, blockCode: String) { From 02ea0002b7c7cacd3550aa15a006aab9ffecda72 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Thu, 22 Aug 2024 20:22:41 +0900 Subject: [PATCH 02/15] =?UTF-8?q?[fix/#110]=20cursor=20null=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt index b357b12f..756dd081 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt @@ -82,7 +82,7 @@ class StadiumDetailViewModel @Inject constructor( fun updateSort(sortBy: String) { if (_reviewFilter.value.sortBy != sortBy) { reset = true - _reviewFilter.value = _reviewFilter.value.copy(sortBy = sortBy) + _reviewFilter.value = _reviewFilter.value.copy(sortBy = sortBy, cursor = null) getBlockReviews(query = _reviewFilter.value) } } From 0dfd9596db19a272df9482e952c5fbb64061055e Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Thu, 22 Aug 2024 20:27:05 +0900 Subject: [PATCH 03/15] =?UTF-8?q?[fix/#110]=20reset=20=ED=94=8C=EB=9E=98?= =?UTF-8?q?=EA=B7=B8=20=EB=B3=80=EC=88=98=20=EA=B0=92=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt index 756dd081..50627d91 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt @@ -111,6 +111,7 @@ class StadiumDetailViewModel @Inject constructor( (_detailUiState.value as StadiumDetailUiState.ReviewsData) if (reset) { + reset = false _detailUiState.value = reviewsData.copy( reviews = blockReviews.reviews, hasNext = blockReviews.hasNext, From 10d47b8640c463504ef8196a563484de445f0da5 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 13:07:56 +0900 Subject: [PATCH 04/15] =?UTF-8?q?[fix/#110]=20DTO=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewfinder/ResponseBlockReviewDto.kt | 56 +++++++------------ .../viewfinder/ResponseBlockReview.kt | 18 ++---- .../util/StadiumUxWritingUtils.kt | 30 ++++++---- .../uistate/StadiumDetailUiState.kt | 2 +- 4 files changed, 47 insertions(+), 59 deletions(-) diff --git a/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt b/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt index 537e237f..b110c069 100644 --- a/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt +++ b/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt @@ -13,7 +13,7 @@ data class ResponseBlockReviewDto( @SerialName("reviews") val reviews: List, @SerialName("topReviewImages") - val topReviewImages: List, + val topReviewImages: List, @SerialName("totalElements") val totalElements: Long, @SerialName("nextCursor") @@ -56,7 +56,7 @@ data class ResponseBlockReviewDto( @SerialName("block") val block: ResponseReviewBlockDto, @SerialName("row") - val row: ResponseReviewRowDto, + val row: ResponseReviewRowDto?, @SerialName("seat") val seat: ResponseReviewSeatDto?, @SerialName("dateTime") @@ -67,8 +67,13 @@ data class ResponseBlockReviewDto( val images: List, @SerialName("keywords") val keywords: List, - - ) { + @SerialName("likesCount") + val likesCount: Long, + @SerialName("scrapsCount") + val scrapsCount: Long, + @SerialName("reviewType") + val reviewType: String?, + ) { @Serializable data class ResponseReviewImageDto( @SerialName("id") @@ -126,9 +131,9 @@ data class ResponseBlockReviewDto( @Serializable data class ResponseReviewRowDto( @SerialName("id") - val id: Int, + val id: Int?, @SerialName("number") - val number: Int, + val number: Int?, ) @Serializable @@ -140,20 +145,6 @@ data class ResponseBlockReviewDto( ) } - @Serializable - data class ResponseTopReviewImagesDto( - @SerialName("url") - val url: String, - @SerialName("reviewId") - val reviewId: Int, - @SerialName("blockCode") - val blockCode: String, - @SerialName("rowNumber") - val rowNumber: Int, - @SerialName("seatNumber") - val seatNumber: Int?, - ) - @Serializable data class ResponseReviewFilterDto( @SerialName("rowNumber") @@ -171,7 +162,7 @@ fun ResponseBlockReviewDto.toBlockReviewResponse() = ResponseBlockReview( location = location?.toLocationResponse() ?: ResponseBlockReview.ResponseLocation(), keywords = keywords.map { it.toKeywordResponse() }, reviews = reviews.map { it.toReviewResponse() }, - topReviewImages = topReviewImages.map { it.toTopReviewImagesResponse() }, + topReviewImages = topReviewImages.map { it.toReviewResponse() }, totalElements = totalElements, nextCursor = nextCursor ?: "", hasNext = hasNext, @@ -185,15 +176,6 @@ fun ResponseBlockReviewDto.ResponseKeywordDto.toKeywordResponse() = isPositive = isPositive ) -fun ResponseBlockReviewDto.ResponseTopReviewImagesDto.toTopReviewImagesResponse() = - ResponseBlockReview.ResponseTopReviewImages( - url = url, - reviewId = reviewId, - blockCode = blockCode, - rowNumber = rowNumber, - seatNumber = seatNumber ?: 0 - ) - fun ResponseBlockReviewDto.ResponseReviewFilterDto.toReviewFilterResponse() = ResponseBlockReview.ResponseReviewFilter( rowNumber = rowNumber ?: 0, @@ -209,12 +191,16 @@ fun ResponseBlockReviewDto.ResponseReviewDto.toReviewResponse() = stadium = stadium.toReviewStadiumResponse(), section = section.toReviewSectionResponse(), block = block.toReviewBlockResponse(), - row = row.toReviewRowResponse(), - seat = seat?.toReviewSeatResponse() ?: ResponseBlockReview.ResponseReview.ResponseReviewSeat(), + row = row?.toReviewRowResponse() ?: ResponseBlockReview.ResponseReview.ResponseReviewRow(), + seat = seat?.toReviewSeatResponse() + ?: ResponseBlockReview.ResponseReview.ResponseReviewSeat(), dateTime = dateTime, content = content ?: "", images = images.map { it.toReviewImageResponse() }, - keywords = keywords.map { it.toReviewKeywordResponse() } + keywords = keywords.map { it.toReviewKeywordResponse() }, + likesCount = likesCount, + scrapsCount = scrapsCount, + reviewType = reviewType ?: "" ) fun ResponseBlockReviewDto.ResponseLocationDto.toLocationResponse() = @@ -263,8 +249,8 @@ fun ResponseBlockReviewDto.ResponseReviewDto.ResponseReviewBlockDto.toReviewBloc fun ResponseBlockReviewDto.ResponseReviewDto.ResponseReviewRowDto.toReviewRowResponse() = ResponseBlockReview.ResponseReview.ResponseReviewRow( - id = id, - number = number + id = id ?: 0, + number = number ?: 0 ) fun ResponseBlockReviewDto.ResponseReviewDto.ResponseReviewSeatDto.toReviewSeatResponse() = diff --git a/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt b/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt index 40504f0c..2108760f 100644 --- a/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt +++ b/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt @@ -31,7 +31,7 @@ data class ResponseBlockReview( val location: ResponseLocation = ResponseLocation(), val keywords: List = emptyList(), val reviews: List = emptyList(), - val topReviewImages: List = emptyList(), + val topReviewImages: List = emptyList(), val totalElements: Long = 0, val nextCursor: String = "", val hasNext: Boolean = false, @@ -61,8 +61,10 @@ data class ResponseBlockReview( val content: String = "", val images: List = emptyList(), val keywords: List = emptyList(), - - ) { + val likesCount: Long, + val scrapsCount: Long, + val reviewType: String, + ) { data class ResponseReviewImage( val id: Int, val url: String = "", @@ -97,7 +99,7 @@ data class ResponseBlockReview( ) data class ResponseReviewRow( - val id: Int, + val id: Int = 0, val number: Int = 0, ) @@ -116,14 +118,6 @@ data class ResponseBlockReview( } } - data class ResponseTopReviewImages( - val url: String = "", - val reviewId: Int, - val blockCode: String = "", - val rowNumber: Int = 0, - val seatNumber: Int = 0, - ) - data class ResponseReviewFilter( val rowNumber: Int = 0, val seatNumber: Int = 0, diff --git a/presentation/src/main/java/com/dpm/presentation/util/StadiumUxWritingUtils.kt b/presentation/src/main/java/com/dpm/presentation/util/StadiumUxWritingUtils.kt index 4b89d50e..15a796be 100644 --- a/presentation/src/main/java/com/dpm/presentation/util/StadiumUxWritingUtils.kt +++ b/presentation/src/main/java/com/dpm/presentation/util/StadiumUxWritingUtils.kt @@ -3,6 +3,7 @@ package com.dpm.presentation.util import com.dpm.domain.entity.response.viewfinder.BASE import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview import com.dpm.domain.entity.response.viewfinder.base +import com.dpm.presentation.viewfinder.uistate.StadiumDetailUiState /** * @UX_Writing : 야구장 구장 화면에서 블록 클릭 후, 블록 별 리뷰 화면의 [n루]•[구역]•[블록] @@ -96,16 +97,23 @@ fun ResponseBlockReview.ResponseReview.toBlockContent(): String { return numberString } -fun ResponseBlockReview.ResponseTopReviewImages.toBlockContent(): String { - var numberString = "" - if (blockCode.isNotEmpty()) { - numberString += if (blockCode in listOf("exciting1", "exciting3", "premium")) { - "" - } else { - "${blockCode}블록 " - } + +/** + * @UX_Writing : 카카오 공유하기 제목 -> 서울 잠실 야구장 1루 네이비석 101블록 3열 12번 좌석시야 + * @author : 조관희 + */ +fun StadiumDetailUiState.ReviewsData.kakaoShareSeatFeedTitle( + index: Int +): String { + val base = when (stadiumContent.stadiumName.base(stadiumContent.blockCode)) { + BASE.Base1 -> "1루" + BASE.Base3 -> "3루" + else -> "" } - if (rowNumber > 0) numberString += "${rowNumber}열 " - if (seatNumber > 0) numberString += "${seatNumber}번" - return numberString + val section = base + stadiumContent.sectionName + val block = if (stadiumContent.blockCode in listOf("exciting1", "exciting3", "premium")) "" else "${stadiumContent.blockCode}블록" + val column = if (reviews[index].row.number == 0) "" else "${reviews[index].row.number}열" + val seatNumber = if (reviews[index].seat.seatNumber == 0) "" else "${reviews[index].seat.seatNumber}번" + + return "${stadiumContent.stadiumName} $section $block $column $seatNumber 좌석시야" } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/uistate/StadiumDetailUiState.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/uistate/StadiumDetailUiState.kt index 7d5d7edb..21cbffde 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/uistate/StadiumDetailUiState.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/uistate/StadiumDetailUiState.kt @@ -4,7 +4,7 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview sealed class StadiumDetailUiState { data class ReviewsData( - val topReviewImages: List, + val topReviewImages: List, val stadiumContent: ResponseBlockReview.ResponseLocation, val keywords: List, val total: Long, From e45397b5c408c05d83db8503cb7c290c57058b23 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 13:10:16 +0900 Subject: [PATCH 05/15] =?UTF-8?q?[feat/#110]=20=EC=B9=B4=EC=B9=B4=EC=98=A4?= =?UTF-8?q?=20=EA=B3=B5=EC=9C=A0=ED=95=98=EA=B8=B0=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B2=84=ED=8A=BC=20UI=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dpm/presentation/util/KakaoUtils.kt | 22 +++ .../viewfinder/StadiumDetailActivity.kt | 25 ++- .../StadiumDetailPictureFragment.kt | 17 +- .../viewfinder/compose/LikeButton.kt | 13 +- .../viewfinder/compose/ReviewContentBottom.kt | 22 ++- .../viewfinder/compose/StadiumDetailScreen.kt | 50 ++++- .../compose/StadiumHeaderContent.kt | 162 ++++++++++++--- .../compose/StadiumPictureViewPager.kt | 92 +++++++-- .../compose/StadiumReviewContent.kt | 23 ++- .../detailpicture/DetailCotentLayer.kt | 5 +- .../DetailReviewInteractionItems.kt | 33 +++- .../detailpicture/DetailViewPagerLayer.kt | 16 +- .../StadiumDetailPictureScreen.kt | 187 +++++++++++++----- .../StadiumDetailPictureViewPager.kt | 134 ++++++++----- .../StadiumDetailReviewViewPager.kt | 40 ++-- 15 files changed, 641 insertions(+), 200 deletions(-) diff --git a/presentation/src/main/java/com/dpm/presentation/util/KakaoUtils.kt b/presentation/src/main/java/com/dpm/presentation/util/KakaoUtils.kt index d76090d4..d31873de 100644 --- a/presentation/src/main/java/com/dpm/presentation/util/KakaoUtils.kt +++ b/presentation/src/main/java/com/dpm/presentation/util/KakaoUtils.kt @@ -32,6 +32,28 @@ val mockDefaultFeed = FeedTemplate( ) ) +fun seatFeed( + title: String, + description: String, + imageUrl: String, + queryParams: Map +) = FeedTemplate( + content = Content( + title = title, + description = description, + imageUrl = imageUrl, + link = Link() + ), + buttons = listOf( + Button( + title = "SPOT! 앱에서 열기", + link = Link( + androidExecutionParams = queryParams + ) + ) + ) +) + class KakaoUtils() { fun share( context: Context, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt index f04f1b04..d120e7f4 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt @@ -13,6 +13,8 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview import com.depromeet.presentation.R import com.depromeet.presentation.databinding.ActivityStadiumDetailBinding import com.dpm.presentation.home.HomeActivity +import com.dpm.presentation.util.KakaoUtils +import com.dpm.presentation.util.seatFeed import com.dpm.presentation.util.toEmptyBlock import com.dpm.presentation.viewfinder.compose.StadiumDetailScreen import com.dpm.presentation.viewfinder.dialog.ReportDialog @@ -29,6 +31,8 @@ class StadiumDetailActivity : BaseActivity({ const val REVIEW_ID = "review_id" const val REVIEW_INDEX = "review_index" const val REVIEW_TITLE_WITH_STADIUM = "review_title_with_stadium" + const val REVIEW_TYPE = "review_type" + const val STADIUM_HEADER = "stadium_header" const val STADIUM_REVIEW_CONTENT = "stadium_review_content" } @@ -57,8 +61,8 @@ class StadiumDetailActivity : BaseActivity({ StadiumDetailScreen( emptyBlockName = toEmptyBlock(viewModel.stadiumId, viewModel.blockCode), viewModel = viewModel, - onClickReviewPicture = { reviewContent, index, title -> - startToStadiumDetailPictureFragment(reviewContent, index, title) + onClickReviewPicture = { id, index, title -> + startToStadiumDetailPictureFragment(id, index, title, DetailReviewEntryPoint.MAIN_REVIEW) }, onClickSelectSeat = { StadiumSelectSeatDialog.apply { @@ -86,7 +90,12 @@ class StadiumDetailActivity : BaseActivity({ }, onRefresh = { viewModel.getBlockReviews() - } + }, + onClickTopImage = { id, index, title -> + startToStadiumDetailPictureFragment(id, index, title, DetailReviewEntryPoint.TOP_REVIEW) + }, + onClickLike = {}, + onClickScrap = {} ) } } @@ -121,15 +130,17 @@ class StadiumDetailActivity : BaseActivity({ } private fun startToStadiumDetailPictureFragment( - reviewContent: ResponseBlockReview.ResponseReview, + id: Long, index: Int, - title: String + title: String, + type: DetailReviewEntryPoint ) { val fragment = StadiumDetailPictureFragment.newInstance().apply { arguments = bundleOf( - REVIEW_ID to reviewContent.id, + REVIEW_ID to id, REVIEW_INDEX to index, - REVIEW_TITLE_WITH_STADIUM to title + REVIEW_TITLE_WITH_STADIUM to title, + REVIEW_TYPE to type.name, ) } diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt index 957d0025..df4d98ed 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt @@ -22,6 +22,10 @@ import com.dpm.presentation.viewfinder.dialog.ReportDialog import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel import dagger.hilt.android.AndroidEntryPoint +enum class DetailReviewEntryPoint { + TOP_REVIEW, MAIN_REVIEW +} + @AndroidEntryPoint class StadiumDetailPictureFragment : BindingFragment( R.layout.fragment_stadium_detail_picture, FragmentStadiumDetailPictureBinding::inflate @@ -51,13 +55,14 @@ class StadiumDetailPictureFragment : BindingFragment + getReviewExtra { reviewId, reviewIndex, title, type -> binding.spotAppbar.setText(title) binding.cvReviewContent.setContent { MaterialTheme { StadiumDetailPictureScreen( reviewId = reviewId, reviewIndex = reviewIndex, + type = type, stadiumDetailViewModel = stadiumDetailViewModel, ) } @@ -93,11 +98,12 @@ class StadiumDetailPictureFragment : BindingFragment Unit) { + private fun getReviewExtra(callback: (id: Long, index: Int, title: String, type: String) -> Unit) { val reviewId = arguments?.getLong(StadiumDetailActivity.REVIEW_ID) ?: return val reviewIndex = arguments?.getInt(StadiumDetailActivity.REVIEW_INDEX) ?: return val title = arguments?.getString(StadiumDetailActivity.REVIEW_TITLE_WITH_STADIUM) ?: return - callback(reviewId, reviewIndex, title) + val type = arguments?.getString(StadiumDetailActivity.REVIEW_TYPE) ?: return + callback(reviewId, reviewIndex, title, type) } private fun removeFragment() { @@ -145,7 +151,10 @@ class StadiumDetailPictureFragment : BindingFragment Unit ) { Row( modifier = modifier @@ -42,7 +44,7 @@ fun LikeButton( vertical = 8.dp ) .noRippleClickable { - + onClick() }, horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically @@ -61,7 +63,7 @@ fun LikeButton( ) Spacer(modifier = Modifier.width(4.dp)) Text( - text = 12.toString(), + text = likeCount.toString(), style = SpotTheme.typography.label09, color = SpotTheme.colors.foregroundDisabled ) @@ -71,5 +73,8 @@ fun LikeButton( @Preview @Composable private fun LikeButtonPreview() { - LikeButton() + LikeButton( + likeCount = 1, + onClick = {} + ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt index 32df4b19..e82abb3a 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt @@ -18,17 +18,24 @@ import com.depromeet.designsystem.R @Composable fun ReviewContentBottom( - modifier: Modifier = Modifier + likeCount: Long, + modifier: Modifier = Modifier, + onClickLike: () -> Unit, + onClickScrap: () -> Unit, + onClickShare: () -> Unit ) { Row( modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - LikeButton() + LikeButton( + likeCount = likeCount, + onClick = onClickLike + ) Row { IconButton( - onClick = { } + onClick = onClickScrap ) { Icon( painter = painterResource( @@ -39,7 +46,7 @@ fun ReviewContentBottom( } Spacer(modifier = Modifier.width(6.dp)) IconButton( - onClick = { } + onClick = onClickShare ) { Icon( painter = painterResource( @@ -55,5 +62,10 @@ fun ReviewContentBottom( @Preview @Composable private fun ReviewContentBottomPreview() { - ReviewContentBottom() + ReviewContentBottom( + likeCount = 0, + onClickLike = {}, + onClickScrap = {}, + onClickShare = {} + ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt index ad8f3af5..f9f8c296 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt @@ -1,6 +1,7 @@ package com.dpm.presentation.viewfinder.compose import android.content.Context +import android.util.Log import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -19,15 +20,22 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat.startActivity import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import com.dpm.domain.entity.response.viewfinder.BASE import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview +import com.dpm.domain.entity.response.viewfinder.base import com.dpm.presentation.mapper.toKeyword +import com.dpm.presentation.util.KakaoUtils +import com.dpm.presentation.util.kakaoShareSeatFeedTitle +import com.dpm.presentation.util.seatFeed import com.dpm.presentation.util.stadiumBlock import com.dpm.presentation.util.toTitle import com.dpm.presentation.viewfinder.StadiumDetailActivity import com.dpm.presentation.viewfinder.uistate.StadiumDetailUiState import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel +import timber.log.Timber @OptIn(ExperimentalFoundationApi::class) @Composable @@ -36,11 +44,14 @@ fun StadiumDetailScreen( context: Context = LocalContext.current, modifier: Modifier = Modifier, viewModel: StadiumDetailViewModel = viewModel(), - onClickReviewPicture: (reviewContent: ResponseBlockReview.ResponseReview, index: Int, title: String) -> Unit, + onClickReviewPicture: (id: Long, index: Int, title: String) -> Unit, + onClickTopImage: (id: Long, index: Int, title: String) -> Unit, onClickSelectSeat: () -> Unit, onClickFilterMonthly: () -> Unit, onClickReport: () -> Unit, onClickGoBack: () -> Unit, + onClickLike: () -> Unit, + onClickScrap: () -> Unit, onRefresh: () -> Unit ) { var isMore by remember { mutableStateOf(false) } @@ -108,7 +119,10 @@ fun StadiumDetailScreen( keywords = uiState.keywords.map { it.toKeyword() }, onChangeIsMore = { isMore = it }, onClickSelectSeat = onClickSelectSeat, - onCancelSeat = viewModel::clearSeat + onCancelSeat = viewModel::clearSeat, + onClickTopImage = { id, index -> + onClickTopImage(id, index, uiState.stadiumContent.toTitle()) + } ) Spacer(modifier = Modifier.height(30.dp)) } @@ -141,12 +155,35 @@ fun StadiumDetailScreen( reviewContent = uiState.reviews[index], onClick = { reviewContent, index -> onClickReviewPicture( - reviewContent, + reviewContent.id, index, uiState.stadiumContent.toTitle() ) }, - onClickReport = onClickReport + onClickReport = onClickReport, + onClickLike = onClickLike, + onClickScrap = onClickScrap, + onClickShare = { + KakaoUtils().share( + context, + seatFeed( + title = uiState.kakaoShareSeatFeedTitle(index), + description = "출처 : ${uiState.reviews[index].member.nickname}", + imageUrl = uiState.reviews[index].images.firstOrNull()?.url + ?: "", + queryParams = mapOf( + "stadiumId" to viewModel.stadiumId.toString(), + "blockCode" to viewModel.blockCode + ) + ), + onSuccess = { sharingIntent -> + context.startActivity(sharingIntent) + }, + onFailure = { + Timber.e("error : ${it.message}") + } + ) + } ) Spacer(modifier = Modifier.height(40.dp)) } @@ -168,7 +205,10 @@ private fun StadiumDetailScreenPreview() { onClickFilterMonthly = {}, onClickReport = {}, onClickGoBack = {}, - onRefresh = {} + onRefresh = {}, + onClickTopImage = { _, _, _ -> }, + onClickLike = {}, + onClickScrap = {}, ) } } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt index fdc7aec0..959b67f4 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt @@ -30,10 +30,11 @@ fun StadiumHeaderContent( stadiumTitle: String, keywords: List, reviewFilter: RequestBlockReviewQuery, - topReviewImages: List, + topReviewImages: List, modifier: Modifier = Modifier, onChangeIsMore: (Boolean) -> Unit, onClickSelectSeat: () -> Unit, + onClickTopImage:(id: Long, index: Int) -> Unit, onCancelSeat: () -> Unit ) { Column( @@ -43,7 +44,8 @@ fun StadiumHeaderContent( StadiumPictureViewPager( context = context, topReviewImages = topReviewImages, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + onClick = onClickTopImage ) Spacer(modifier = Modifier.height(20.dp)) StadiumAreaText( @@ -84,24 +86,72 @@ fun StadiumHeaderContent( @Preview(showBackground = true) @Composable private fun StadiumHeaderContentPreview() { + val review = ResponseBlockReview.ResponseReview( + id = 1, + dateTime = "2023-03-01T19:00:00", + content = "asdfsdfsafsfda", + images = listOf( + ResponseBlockReview.ResponseReview.ResponseReviewImage( + id = 1, + url = "https://picsum.photos/200/300" + ), + ResponseBlockReview.ResponseReview.ResponseReviewImage( + id = 1, + url = "https://picsum.photos/200/300" + ), + ), + member = ResponseBlockReview.ResponseReview.ResponseReviewMember( + "https://picsum.photos/200/300", + nickname = "엘지의 왕자", + level = 0 + ), + stadium = ResponseBlockReview.ResponseReview.ResponseReviewStadium( + id = 1, + name = "서울 잠실 야구장" + ), + section = ResponseBlockReview.ResponseReview.ResponseReviewSection( + id = 1, + name = "오렌지석", + alias = "응원석" + ), + block = ResponseBlockReview.ResponseReview.ResponseReviewBlock( + id = 1, + code = "207" + ), + row = ResponseBlockReview.ResponseReview.ResponseReviewRow( + id = 1, + number = 1 + ), + seat = ResponseBlockReview.ResponseReview.ResponseReviewSeat( + id = 1, + seatNumber = 12 + ), + keywords = listOf( + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ), + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ), + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ) + ), + likesCount = 1, + scrapsCount = 0, + reviewType = "" + ) StadiumHeaderContent( context = LocalContext.current, isMore = false, topReviewImages = listOf( - ResponseBlockReview.ResponseTopReviewImages( - url = "", - reviewId = 1, - blockCode = "207", - rowNumber = 1, - seatNumber = 12 - ), - ResponseBlockReview.ResponseTopReviewImages( - url = "", - reviewId = 1, - blockCode = "207", - rowNumber = 1, - seatNumber = 12 - ), + review, review ), reviewFilter = RequestBlockReviewQuery( rowNumber = null, @@ -121,6 +171,7 @@ private fun StadiumHeaderContentPreview() { ), onChangeIsMore = {}, onClickSelectSeat = {}, + onClickTopImage = {_,_ ->}, onCancelSeat = {} ) } @@ -128,25 +179,73 @@ private fun StadiumHeaderContentPreview() { @Preview(showBackground = true) @Composable private fun StadiumHeaderContentIsMorePreview() { + val review = ResponseBlockReview.ResponseReview( + id = 1, + dateTime = "2023-03-01T19:00:00", + content = "asdfsdfsafsfda", + images = listOf( + ResponseBlockReview.ResponseReview.ResponseReviewImage( + id = 1, + url = "https://picsum.photos/200/300" + ), + ResponseBlockReview.ResponseReview.ResponseReviewImage( + id = 1, + url = "https://picsum.photos/200/300" + ), + ), + member = ResponseBlockReview.ResponseReview.ResponseReviewMember( + "https://picsum.photos/200/300", + nickname = "엘지의 왕자", + level = 0 + ), + stadium = ResponseBlockReview.ResponseReview.ResponseReviewStadium( + id = 1, + name = "서울 잠실 야구장" + ), + section = ResponseBlockReview.ResponseReview.ResponseReviewSection( + id = 1, + name = "오렌지석", + alias = "응원석" + ), + block = ResponseBlockReview.ResponseReview.ResponseReviewBlock( + id = 1, + code = "207" + ), + row = ResponseBlockReview.ResponseReview.ResponseReviewRow( + id = 1, + number = 1 + ), + seat = ResponseBlockReview.ResponseReview.ResponseReviewSeat( + id = 1, + seatNumber = 12 + ), + keywords = listOf( + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ), + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ), + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ) + ), + likesCount = 1, + scrapsCount = 0, + reviewType = "" + ) StadiumHeaderContent( context = LocalContext.current, isMore = true, topReviewImages = listOf( - ResponseBlockReview.ResponseTopReviewImages( - url = "", - reviewId = 1, - blockCode = "207", - rowNumber = 1, - seatNumber = 12 - - ), - ResponseBlockReview.ResponseTopReviewImages( - url = "", - reviewId = 1, - blockCode = "207", - rowNumber = 1, - seatNumber = 12 - ), + review, + review, ), reviewFilter = RequestBlockReviewQuery( rowNumber = 1, @@ -167,6 +266,7 @@ private fun StadiumHeaderContentIsMorePreview() { ), onChangeIsMore = {}, onClickSelectSeat = {}, + onClickTopImage = {_,_ ->}, onCancelSeat = {} ) } diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt index 0198eb79..f8a559d3 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt @@ -29,14 +29,16 @@ import coil.compose.AsyncImage import coil.request.ImageRequest import com.dpm.designsystem.compose.ui.SpotTheme import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview +import com.dpm.presentation.extension.noRippleClickable import com.dpm.presentation.util.toBlockContent @OptIn(ExperimentalFoundationApi::class) @Composable fun StadiumPictureViewPager( context: Context, - topReviewImages: List, - modifier: Modifier = Modifier + topReviewImages: List, + modifier: Modifier = Modifier, + onClick: (id: Long, index: Int) -> Unit ) { val pagerState = rememberPagerState(pageCount = { topReviewImages.size }) @@ -51,7 +53,7 @@ fun StadiumPictureViewPager( ) { page -> AsyncImage( model = ImageRequest.Builder(context) - .data(topReviewImages.getOrNull(page)?.url) + .data(topReviewImages.getOrNull(page)?.images?.getOrNull(0)?.url) .crossfade(true) .build(), contentDescription = null, @@ -66,7 +68,10 @@ fun StadiumPictureViewPager( ), modifier = Modifier .fillMaxWidth() - .clip(RectangleShape), + .clip(RectangleShape) + .noRippleClickable { + onClick(topReviewImages[page].id, page) + }, ) } @@ -121,24 +126,73 @@ fun StadiumPictureViewPager( @Preview @Composable private fun StadiumPictureViewPagerPreview() { + val review = ResponseBlockReview.ResponseReview( + id = 1, + dateTime = "2023-03-01T19:00:00", + content = "asdfsdfsafsfda", + images = listOf( + ResponseBlockReview.ResponseReview.ResponseReviewImage( + id = 1, + url = "https://picsum.photos/200/300" + ), + ResponseBlockReview.ResponseReview.ResponseReviewImage( + id = 1, + url = "https://picsum.photos/200/300" + ), + ), + member = ResponseBlockReview.ResponseReview.ResponseReviewMember( + "https://picsum.photos/200/300", + nickname = "엘지의 왕자", + level = 0 + ), + stadium = ResponseBlockReview.ResponseReview.ResponseReviewStadium( + id = 1, + name = "서울 잠실 야구장" + ), + section = ResponseBlockReview.ResponseReview.ResponseReviewSection( + id = 1, + name = "오렌지석", + alias = "응원석" + ), + block = ResponseBlockReview.ResponseReview.ResponseReviewBlock( + id = 1, + code = "207" + ), + row = ResponseBlockReview.ResponseReview.ResponseReviewRow( + id = 1, + number = 1 + ), + seat = ResponseBlockReview.ResponseReview.ResponseReviewSeat( + id = 1, + seatNumber = 12 + ), + keywords = listOf( + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ), + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ), + ResponseBlockReview.ResponseReview.ResponseReviewKeyword( + id = 1, + content = "", + isPositive = false + ) + ), + likesCount = 1, + scrapsCount = 0, + reviewType = "" + ) StadiumPictureViewPager( context = LocalContext.current, topReviewImages = listOf( - ResponseBlockReview.ResponseTopReviewImages( - url = "", - reviewId = 1, - blockCode = "207", - rowNumber = 1, - seatNumber = 12 - ), - ResponseBlockReview.ResponseTopReviewImages( - url = "", - reviewId = 1, - blockCode = "207", - rowNumber = 1, - seatNumber = 12 - ), + review, review ), - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + onClick = {_,_ ->} ) } diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt index 45c6a706..7ae2b99b 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt @@ -39,9 +39,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import coil.request.ImageRequest +import com.depromeet.presentation.R import com.dpm.designsystem.compose.ui.SpotTheme import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview -import com.depromeet.presentation.R import com.dpm.presentation.extension.noRippleClickable import com.dpm.presentation.mapper.toKeyword import com.dpm.presentation.util.toBlockContent @@ -56,7 +56,10 @@ fun StadiumReviewContent( reviewContent: ResponseBlockReview.ResponseReview, modifier: Modifier = Modifier, onClick: (reviewContent: ResponseBlockReview.ResponseReview, index: Int) -> Unit, - onClickReport: () -> Unit + onClickReport: () -> Unit, + onClickLike: () -> Unit, + onClickScrap: () -> Unit, + onClickShare: () -> Unit ) { val minimumLineLength = 3 var showMoreButtonState by remember { @@ -240,7 +243,11 @@ fun StadiumReviewContent( ) Spacer(modifier = Modifier.height(12.dp)) ReviewContentBottom( - modifier = Modifier.padding(start = 32.dp, end = 16.dp) + likeCount = reviewContent.likesCount, + modifier = Modifier.padding(start = 32.dp, end = 16.dp), + onClickLike = onClickLike, + onClickScrap = onClickScrap, + onClickShare = onClickShare ) } } @@ -311,10 +318,16 @@ private fun StadiumReviewContentPreview() { content = "", isPositive = false ) - ) + ), + likesCount = 1, + scrapsCount = 0, + reviewType = "" ), onClick = { _, _ -> }, - onClickReport = {} + onClickReport = {}, + onClickLike = {}, + onClickScrap = {}, + onClickShare ={} ) } diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt index 15c891ea..044f02b2 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt @@ -262,7 +262,10 @@ private fun DetailContentLayerPreview() { ResponseBlockReview.ResponseReview.ResponseReviewKeyword( id = 2, content = "싫어요", isPositive = false ) - ) + ), + likesCount = 1, + scrapsCount = 1, + reviewType = "" ) DetailContentLayer( context = LocalContext.current, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt index b2a4ff8a..95b92c41 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt @@ -2,6 +2,8 @@ package com.dpm.presentation.viewfinder.compose.detailpicture import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape @@ -21,7 +23,11 @@ import com.dpm.presentation.extension.noRippleClickable @Composable fun DetailReviewInteractionItems( - modifier: Modifier = Modifier + likeCount: Long, + modifier: Modifier = Modifier, + onClickLike: () -> Unit, + onClickScrap: () -> Unit, + onClickShare: () -> Unit ) { Column( modifier = modifier @@ -35,32 +41,34 @@ fun DetailReviewInteractionItems( ), horizontalAlignment = Alignment.CenterHorizontally ) { - IconButton(onClick = { /*TODO*/ }) { + IconButton(onClick = onClickLike) { Icon( painter = painterResource(id = R.drawable.ic_like_inactive), contentDescription = null, tint = Color.Unspecified, - modifier = Modifier.size(30.dp) + modifier = Modifier.size(24.dp) ) } Text( - text = 10.toString(), + text = likeCount.toString(), style = SpotTheme.typography.label10, color = SpotTheme.colors.foregroundWhite ) - IconButton(onClick = { /*TODO*/ }) { + Spacer(modifier = Modifier.height(5.dp)) + IconButton(onClick = onClickScrap) { Icon( painter = painterResource(id = R.drawable.ic_scrap), contentDescription = null, - tint = Color.Unspecified, - modifier = Modifier.size(23.dp) + tint = SpotTheme.colors.foregroundWhite, + modifier = Modifier.size(24.dp) ) } - IconButton(onClick = { /*TODO*/ }) { + Spacer(modifier = Modifier.height(5.dp)) + IconButton(onClick = onClickShare) { Icon( painter = painterResource(id = R.drawable.ic_share), contentDescription = null, - tint = Color.Unspecified, + tint = SpotTheme.colors.foregroundWhite, ) } } @@ -69,5 +77,10 @@ fun DetailReviewInteractionItems( @Preview @Composable private fun DetailReviewInteractionItemsPreview() { - DetailReviewInteractionItems() + DetailReviewInteractionItems( + likeCount = 1, + onClickLike = {}, + onClickScrap = {}, + onClickShare = {} + ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt index 79ae4518..19239508 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt @@ -19,10 +19,14 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview @Composable fun DetailViewPagerLayer( context: Context, + likeCount: Long, isDimmed: Boolean, verticalPagerState: PagerState, pictures: List, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + onClickLike: () -> Unit, + onClickScrap: () -> Unit, + onClickShare: () -> Unit ) { Column( modifier = modifier @@ -34,7 +38,11 @@ fun DetailViewPagerLayer( StadiumDetailPictureViewPager( context = context, pictures = pictures, + likeCount = likeCount, verticalPagerState = verticalPagerState, + onClickLike = onClickLike, + onClickScrap = onClickScrap, + onClickShare = onClickShare ) } } @@ -63,7 +71,11 @@ private fun DetailViewPagerLayerPreview() { DetailViewPagerLayer( context = LocalContext.current, isDimmed = true, + likeCount = 1, pictures = pictures, - verticalPagerState = pagerState + verticalPagerState = pagerState, + onClickLike = { }, + onClickScrap = { }, + onClickShare = { } ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt index c90f6a12..53dd4d39 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt @@ -16,6 +16,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import com.dpm.presentation.util.KakaoUtils +import com.dpm.presentation.util.kakaoShareSeatFeedTitle +import com.dpm.presentation.util.seatFeed +import com.dpm.presentation.viewfinder.DetailReviewEntryPoint +import com.dpm.presentation.viewfinder.StadiumDetailActivity import com.dpm.presentation.viewfinder.uistate.StadiumDetailUiState import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel @@ -26,78 +31,168 @@ fun StadiumDetailPictureScreen( stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), reviewId: Long, reviewIndex: Int, + type: String, modifier: Modifier = Modifier ) { val reviews = stadiumDetailViewModel.detailUiState.collectAsStateWithLifecycle() val bottomPadding by stadiumDetailViewModel.bottomPadding.collectAsStateWithLifecycle() - reviews.value.let { uiState -> - when (uiState) { - is StadiumDetailUiState.ReviewsData -> { - val visited = remember { - mutableStateListOf( - *List(uiState.reviews.size) { false }.toTypedArray() - ) - } + when(type) { + DetailReviewEntryPoint.TOP_REVIEW.name -> { + reviews.value.let { uiState -> + when (uiState) { + is StadiumDetailUiState.ReviewsData -> { + val initPage by remember { + mutableStateOf(uiState.topReviewImages.indexOfFirst { it.id == reviewId }) + } - if (uiState.reviews.size - visited.size > 0) { - visited.addAll(List(uiState.reviews.size - visited.size) { false }) - } + val pagerState = rememberPagerState( + pageCount = { uiState.topReviewImages.size }, + initialPage = initPage + ) - val initPage by remember { - mutableStateOf(uiState.reviews.indexOfFirst { it.id == reviewId }) - } + var pageIndex by remember { + mutableStateOf(0) + } - val pagerState = rememberPagerState( - pageCount = { uiState.reviews.size }, - initialPage = initPage - ) + LaunchedEffect(key1 = pagerState) { + snapshotFlow { pagerState.currentPage }.collect { + pageIndex = it + } + } - var pageIndex by remember { - mutableStateOf(0) + StadiumDetailReviewViewPager( + context = context, + reviews = uiState.topReviewImages, + position = reviewIndex, + pagerState = pagerState, + pageIndex = pageIndex, + bottomPadding = bottomPadding, + modifier = modifier, + onClickShare = { imagePosition -> + KakaoUtils().share( + context, + seatFeed( + title = uiState.kakaoShareSeatFeedTitle(pageIndex), + description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", + imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, + queryParams = mapOf( + "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), + "blockCode" to stadiumDetailViewModel.blockCode + ) + ), + onSuccess = { sharingIntent -> + context.startActivity(sharingIntent) + } + ) + } + ) + } + else -> Unit } + } + } + DetailReviewEntryPoint.MAIN_REVIEW.name -> { + reviews.value.let { uiState -> + when (uiState) { + is StadiumDetailUiState.ReviewsData -> { + val visited = remember { + mutableStateListOf( + *List(uiState.reviews.size) { false }.toTypedArray() + ) + } - LaunchedEffect(key1 = pagerState) { - snapshotFlow { pagerState.currentPage }.collect { - pageIndex = it - stadiumDetailViewModel.updateCurrentIndex(it) - if (visited[it]) return@collect + if (uiState.reviews.size - visited.size > 0) { + visited.addAll(List(uiState.reviews.size - visited.size) { false }) + } - if (it == initPage) { - visited[it] = true + val initPage by remember { + mutableStateOf(uiState.reviews.indexOfFirst { it.id == reviewId }) } - if (!visited[it]) { - visited[it] = true + val pagerState = rememberPagerState( + pageCount = { uiState.reviews.size }, + initialPage = initPage + ) + + var pageIndex by remember { + mutableStateOf(0) + } + + LaunchedEffect(key1 = pagerState) { + snapshotFlow { pagerState.currentPage }.collect { + pageIndex = it + stadiumDetailViewModel.updateCurrentIndex(it) + if (visited[it]) return@collect + + if (it == initPage) { + visited[it] = true + } + + if (!visited[it]) { + visited[it] = true + } + } } + + StadiumDetailReviewViewPager( + context = context, + reviews = uiState.reviews, + visited = visited, + position = reviewIndex, + hasNext = uiState.hasNext, + pagerState = pagerState, + pageIndex = pageIndex, + bottomPadding = bottomPadding, + modifier = modifier, + onLoadPaging = stadiumDetailViewModel::getBlockReviews, + onClickShare = { imagePosition -> + KakaoUtils().share( + context, + seatFeed( + title = uiState.kakaoShareSeatFeedTitle(pageIndex), + description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", + imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, + queryParams = mapOf( + "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), + "blockCode" to stadiumDetailViewModel.blockCode + ) + ), + onSuccess = { sharingIntent -> + context.startActivity(sharingIntent) + } + ) + } + ) } - } - StadiumDetailReviewViewPager( - context = context, - reviews = uiState.reviews, - visited = visited, - position = reviewIndex, - pageState = uiState.hasNext, - pagerState = pagerState, - pageIndex = pageIndex, - bottomPadding = bottomPadding, - modifier = modifier, - onLoadPaging = stadiumDetailViewModel::getBlockReviews, - ) + else -> Unit + } } - - else -> Unit } } + + +} + +@Preview +@Composable +private fun StadiumDetailPictureScreenMainPreview() { + StadiumDetailPictureScreen( + context = LocalContext.current, + reviewId = 1, + reviewIndex = 0, + type = DetailReviewEntryPoint.MAIN_REVIEW.name + ) } @Preview @Composable -private fun StadiumDetailPictureScreenPreview() { +private fun StadiumDetailPictureScreenTopPreview() { StadiumDetailPictureScreen( context = LocalContext.current, reviewId = 1, - reviewIndex = 0 + reviewIndex = 0, + type = DetailReviewEntryPoint.TOP_REVIEW.name ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt index 156ee923..408e64db 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt @@ -1,6 +1,7 @@ package com.dpm.presentation.viewfinder.compose.detailpicture import android.content.Context +import android.util.Log import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -8,6 +9,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column 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.height import androidx.compose.foundation.layout.heightIn @@ -20,6 +22,10 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -39,68 +45,92 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview @Composable fun StadiumDetailPictureViewPager( context: Context, + likeCount: Long, verticalPagerState: PagerState, pictures: List, modifier: Modifier = Modifier, + onClickLike: () -> Unit, + onClickScrap: () -> Unit, + onClickShare: () -> Unit ) { - Column( + Box( modifier = modifier, - horizontalAlignment = Alignment.CenterHorizontally + contentAlignment = Alignment.Center ) { - HorizontalPager( - modifier = Modifier, - state = verticalPagerState, - ) { page -> - AsyncImage( - model = ImageRequest.Builder(context) - .data(pictures.getOrNull(page)?.url) - .crossfade(true) - .build(), - contentScale = ContentScale.FillWidth, - contentDescription = null, - placeholder = ColorPainter(Color.LightGray), - modifier = Modifier - .fillMaxWidth() - .heightIn(max = ((context.resources.displayMetrics.heightPixels / context.resources.displayMetrics.density) * 0.58).dp) - .clip(RectangleShape), - - ) - } - Spacer(modifier = Modifier.height(8.dp)) - Row( - Modifier - .wrapContentHeight() - .fillMaxWidth(), - horizontalArrangement = Arrangement.Center + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally ) { - repeat(verticalPagerState.pageCount) { iteration -> - if (verticalPagerState.currentPage == iteration) { - Box( - modifier = Modifier - .padding(end = 4.dp) - .clip(RoundedCornerShape(8.dp)) - .background( - color = SpotTheme.colors.actionEnabled - ) - .size( - height = 6.dp, - width = 15.dp - ) - ) - } else { - Box( - modifier = Modifier - .padding(end = 4.dp) - .clip(CircleShape) - .background( - color = SpotTheme.colors.backgroundPrimary - ) - .size(6.dp) + HorizontalPager( + modifier = Modifier, + state = verticalPagerState, + ) { page -> + AsyncImage( + model = ImageRequest.Builder(context) + .data(pictures.getOrNull(page)?.url) + .crossfade(true) + .build(), + contentScale = ContentScale.FillWidth, + contentDescription = null, + placeholder = ColorPainter(Color.LightGray), + modifier = Modifier + .fillMaxWidth() + .heightIn(max = ((context.resources.displayMetrics.heightPixels / context.resources.displayMetrics.density) * 0.58).dp) + .clip(RectangleShape), + ) + } + Spacer(modifier = Modifier.height(8.dp)) + Row( + Modifier + .wrapContentHeight() + .fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + repeat(verticalPagerState.pageCount) { iteration -> + if (verticalPagerState.currentPage == iteration) { + Box( + modifier = Modifier + .padding(end = 4.dp) + .clip(RoundedCornerShape(8.dp)) + .background( + color = SpotTheme.colors.actionEnabled + ) + .size( + height = 6.dp, + width = 15.dp + ) + ) + } else { + Box( + modifier = Modifier + .padding(end = 4.dp) + .clip(CircleShape) + .background( + color = SpotTheme.colors.backgroundPrimary + ) + .size(6.dp) + ) + } } } } + Box( + modifier = Modifier + .fillMaxWidth() + .padding(end = 12.dp), + contentAlignment = Alignment.CenterEnd + ) { + DetailReviewInteractionItems( + likeCount = likeCount, + onClickLike = onClickLike, + onClickScrap = onClickScrap, + onClickShare = onClickShare + ) + } } + + } @OptIn(ExperimentalFoundationApi::class) @@ -112,6 +142,7 @@ private fun StadiumDetailPictureViewPagerPreview() { } StadiumDetailPictureViewPager( context = LocalContext.current, + likeCount = 1, verticalPagerState = pagerState, pictures = listOf( ResponseBlockReview.ResponseReview.ResponseReviewImage( @@ -124,5 +155,8 @@ private fun StadiumDetailPictureViewPagerPreview() { id = 1, url = "" ) ), + onClickLike = { }, + onClickScrap = { }, + onClickShare = { } ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt index c7d07af0..1ac76b0d 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt @@ -1,7 +1,6 @@ package com.dpm.presentation.viewfinder.compose.detailpicture import android.content.Context -import android.util.Log import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -26,16 +25,17 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview fun StadiumDetailReviewViewPager( context: Context, position: Int, - pageState: Boolean, + hasNext: Boolean = false, pagerState: PagerState, pageIndex: Int, bottomPadding: Float, reviews: List, - visited: List, + visited: List = emptyList(), modifier: Modifier = Modifier, - onLoadPaging: () -> Unit, + onLoadPaging: () -> Unit = {}, + onClickShare: (imagePosition: Int) -> Unit = {} ) { - if (pageIndex == reviews.size - 1 && pageState) { + if (pageIndex == reviews.size - 1 && hasNext) { onLoadPaging() } @@ -63,8 +63,10 @@ fun StadiumDetailReviewViewPager( ) LaunchedEffect(key1 = Unit) { - if (!visited[page]) { - verticalPagerState.scrollToPage(0) + if (visited.isNotEmpty()) { + if (!visited[page]) { + verticalPagerState.scrollToPage(0) + } } } @@ -80,8 +82,18 @@ fun StadiumDetailReviewViewPager( DetailViewPagerLayer( context = context, isDimmed = isDimmed, + likeCount = reviews[page].likesCount, pictures = reviews[page].images, verticalPagerState = verticalPagerState, + onClickLike = { + // TODO : 좋아요 클릭 + }, + onClickScrap = { + // TODO : 스크랩 클릭 + }, + onClickShare = { + onClickShare(verticalPagerState.currentPage) + } ) DetailContentLayer( context = context, @@ -151,7 +163,10 @@ private fun StadiumDetailReviewViewPagerPreview() { ResponseBlockReview.ResponseReview.ResponseReviewKeyword( id = 2, content = "싫어요", isPositive = false ) - ) + ), + likesCount = 0, + scrapsCount = 0, + reviewType = "" ) ) val pagerState = rememberPagerState( @@ -162,7 +177,7 @@ private fun StadiumDetailReviewViewPagerPreview() { reviews = reviews, visited = emptyList(), position = 1, - pageState = false, + hasNext = false, pagerState = pagerState, pageIndex = 0, bottomPadding = 0f, @@ -229,7 +244,10 @@ private fun StadiumDetailReviewViewPagerMorePreview() { ResponseBlockReview.ResponseReview.ResponseReviewKeyword( id = 2, content = "싫어요", isPositive = false ) - ) + ), + likesCount = 0, + scrapsCount = 0, + reviewType = "" ) ) val pagerState = rememberPagerState( @@ -240,7 +258,7 @@ private fun StadiumDetailReviewViewPagerMorePreview() { reviews = reviews, visited = emptyList(), position = 1, - pageState = false, + hasNext = false, pagerState = pagerState, pageIndex = 0, bottomPadding = 0f, From d49ea9bb28717e3485956bc3fc4fe2ed60172d91 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 19:07:11 +0900 Subject: [PATCH 06/15] =?UTF-8?q?[feat/#110]=20=EB=A6=AC=EC=86=8C=EC=8A=A4?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/rect_body_subtitle_fill_60.xml | 6 ++++++ presentation/src/main/res/values/strings.xml | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 core/designsystem/src/main/res/drawable/rect_body_subtitle_fill_60.xml diff --git a/core/designsystem/src/main/res/drawable/rect_body_subtitle_fill_60.xml b/core/designsystem/src/main/res/drawable/rect_body_subtitle_fill_60.xml new file mode 100644 index 00000000..155fb747 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/rect_body_subtitle_fill_60.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 0e9b5d6c..4b7760be 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -89,7 +89,9 @@ 꾸준히 다른 구장에 대한 정보가 추가될 예정이에요 화면을 손가락으로 확대하여\n구역을 더 크게 보세요! 현재 잠실야구장만 이용할 수 있어요! + 스크랩이 완료되었어요! ""잠실야구장 보기"" + ""스크랩으로 이동"" 다른 블록에서 새로운 시야를 찾아보세요! 열과 번을 선택해 빠르게 자리를 찾아보세요⚡ From 096471808966ea1df492e1ec790917280db5cd64 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 19:07:41 +0900 Subject: [PATCH 07/15] =?UTF-8?q?[feat/#110]=20SpotSnackBar=20=EB=B0=B1?= =?UTF-8?q?=EA=B7=B8=EB=9D=BC=EC=9A=B4=EB=93=9C=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/dpm/designsystem/SpotSnackBar.kt | 8 +++++--- core/designsystem/src/main/res/layout/spot_snackbar.xml | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt b/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt index 1f857428..45aaea22 100644 --- a/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt +++ b/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt @@ -4,18 +4,20 @@ import android.graphics.Paint import android.view.LayoutInflater import android.view.View import androidx.core.content.ContextCompat +import com.depromeet.designsystem.R import com.depromeet.designsystem.databinding.SpotSnackbarBinding import com.google.android.material.snackbar.Snackbar class SpotSnackBar( view: View, + private val snackBarBackground: Int, private val message: String, private val endMessage: String, private val onClick: () -> Unit ) { companion object { - fun make(view: View, message: String = "", endMessage: String = "", onClick: () -> Unit) = - SpotSnackBar(view, message, endMessage, onClick) + fun make(view: View, background: Int = R.drawable.rect_transfer_black_03_fill_60, message: String = "", endMessage: String = "", onClick: () -> Unit) = + SpotSnackBar(view = view, snackBarBackground = background, message= message, endMessage = endMessage, onClick = onClick) } private val context = view.context @@ -33,7 +35,7 @@ class SpotSnackBar( with(snackbarLayout) { removeAllViews() setPadding(0, 0, 0, 0) - setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)) + setBackgroundResource(snackBarBackground) addView(snackbarBinding.root, 0) } with(snackbarBinding) { diff --git a/core/designsystem/src/main/res/layout/spot_snackbar.xml b/core/designsystem/src/main/res/layout/spot_snackbar.xml index 4781c3b9..54b742c4 100644 --- a/core/designsystem/src/main/res/layout/spot_snackbar.xml +++ b/core/designsystem/src/main/res/layout/spot_snackbar.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/rect_transfer_black_03_fill_60"> + tools:background="@drawable/rect_transfer_black_03_fill_60"> Date: Sat, 24 Aug 2024 19:08:28 +0900 Subject: [PATCH 08/15] =?UTF-8?q?[feat/#110]=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?,=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20api=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dpm/data/datasource/ViewfinderDataSource.kt | 2 ++ .../datasource/remote/ViewfinderDataSourceImpl.kt | 8 ++++++++ .../java/com/dpm/data/remote/ViewfinderService.kt | 12 ++++++++++++ .../dpm/data/repository/ViewfinderRepositoryImpl.kt | 12 ++++++++++++ 4 files changed, 34 insertions(+) diff --git a/data/src/main/java/com/dpm/data/datasource/ViewfinderDataSource.kt b/data/src/main/java/com/dpm/data/datasource/ViewfinderDataSource.kt index 1d804959..8b3c5039 100644 --- a/data/src/main/java/com/dpm/data/datasource/ViewfinderDataSource.kt +++ b/data/src/main/java/com/dpm/data/datasource/ViewfinderDataSource.kt @@ -15,4 +15,6 @@ interface ViewfinderDataSource { queryParam: RequestBlockReviewQueryDto ): ResponseBlockReviewDto suspend fun getBlockRow(stadiumId: Int, blockCode: String): ResponseBlockRowDto + suspend fun updateScrap(reviewId: Int) + suspend fun updateLike(reviewId: Int) } \ No newline at end of file diff --git a/data/src/main/java/com/dpm/data/datasource/remote/ViewfinderDataSourceImpl.kt b/data/src/main/java/com/dpm/data/datasource/remote/ViewfinderDataSourceImpl.kt index d4d35dc4..dbf295e4 100644 --- a/data/src/main/java/com/dpm/data/datasource/remote/ViewfinderDataSourceImpl.kt +++ b/data/src/main/java/com/dpm/data/datasource/remote/ViewfinderDataSourceImpl.kt @@ -41,4 +41,12 @@ class ViewfinderDataSourceImpl @Inject constructor( override suspend fun getBlockRow(stadiumId: Int, blockCode: String): ResponseBlockRowDto { return viewfinderService.getBlockRow(stadiumId, blockCode) } + + override suspend fun updateScrap(reviewId: Int) { + viewfinderService.postScrap(reviewId) + } + + override suspend fun updateLike(reviewId: Int) { + viewfinderService.postLike(reviewId) + } } \ No newline at end of file diff --git a/data/src/main/java/com/dpm/data/remote/ViewfinderService.kt b/data/src/main/java/com/dpm/data/remote/ViewfinderService.kt index 1e0107e0..f28b2d38 100644 --- a/data/src/main/java/com/dpm/data/remote/ViewfinderService.kt +++ b/data/src/main/java/com/dpm/data/remote/ViewfinderService.kt @@ -5,6 +5,7 @@ import com.dpm.data.model.response.viewfinder.ResponseBlockRowDto import com.dpm.data.model.response.viewfinder.ResponseStadiumDto import com.dpm.data.model.response.viewfinder.ResponseStadiumsDto import retrofit2.http.GET +import retrofit2.http.POST import retrofit2.http.Path import retrofit2.http.Query @@ -35,4 +36,15 @@ interface ViewfinderService { @Path("stadiumId") stadiumId: Int, @Path("blockCode") blockCode: String ): ResponseBlockRowDto + + @POST("/api/v1/reviews/{reviewId}/scrap") + suspend fun postScrap( + @Path("reviewId") reviewId: Int + ) + + + @POST("/api/v1/reviews/{reviewId}/like") + suspend fun postLike( + @Path("reviewId") reviewId: Int + ) } \ No newline at end of file diff --git a/data/src/main/java/com/dpm/data/repository/ViewfinderRepositoryImpl.kt b/data/src/main/java/com/dpm/data/repository/ViewfinderRepositoryImpl.kt index 16e0edb0..3475ea2f 100644 --- a/data/src/main/java/com/dpm/data/repository/ViewfinderRepositoryImpl.kt +++ b/data/src/main/java/com/dpm/data/repository/ViewfinderRepositoryImpl.kt @@ -48,4 +48,16 @@ class ViewfinderRepositoryImpl @Inject constructor( viewfinderDataSource.getBlockRow(stadiumId, blockCode).toBlockRowResponse() } } + + override suspend fun updateScrap(reviewId: Int): Result { + return runCatching { + viewfinderDataSource.updateScrap(reviewId) + } + } + + override suspend fun updateLike(reviewId: Int): Result { + return runCatching { + viewfinderDataSource.updateLike(reviewId) + } + } } \ No newline at end of file From 3f29fc982495f7163cb8cf2b08d00e389c3ef91b Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 19:10:35 +0900 Subject: [PATCH 09/15] =?UTF-8?q?[feat/#110]=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?,=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=B0=8F=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewfinder/ResponseBlockReviewDto.kt | 2 + .../viewfinder/ResponseBlockReview.kt | 2 + .../domain/repository/ViewfinderRepository.kt | 2 + .../viewfinder/compose/LikeButton.kt | 12 +- .../viewfinder/compose/ReviewContentBottom.kt | 11 +- .../viewfinder/compose/StadiumDetailScreen.kt | 5 +- .../compose/StadiumHeaderContent.kt | 4 + .../compose/StadiumPictureViewPager.kt | 2 + .../compose/StadiumReviewContent.kt | 20 ++- .../detailpicture/DetailCotentLayer.kt | 2 + .../DetailReviewInteractionItems.kt | 23 ++- .../detailpicture/DetailViewPagerLayer.kt | 3 + .../StadiumDetailPictureScreen.kt | 170 +++--------------- .../StadiumDetailPictureViewPager.kt | 3 + .../StadiumDetailReviewViewPager.kt | 11 +- .../main/StadiumDetailPictureTopScreen.kt | 104 +++++++++++ .../top/StadiumDetailPictureMainScreen.kt | 127 +++++++++++++ .../viewmodel/StadiumDetailViewModel.kt | 69 +++++++ 18 files changed, 405 insertions(+), 167 deletions(-) create mode 100644 presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt create mode 100644 presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt diff --git a/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt b/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt index b110c069..42993643 100644 --- a/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt +++ b/data/src/main/java/com/dpm/data/model/response/viewfinder/ResponseBlockReviewDto.kt @@ -198,6 +198,8 @@ fun ResponseBlockReviewDto.ResponseReviewDto.toReviewResponse() = content = content ?: "", images = images.map { it.toReviewImageResponse() }, keywords = keywords.map { it.toReviewKeywordResponse() }, + isLike = false, + isScrap = false, likesCount = likesCount, scrapsCount = scrapsCount, reviewType = reviewType ?: "" diff --git a/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt b/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt index 2108760f..c5e4e5e5 100644 --- a/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt +++ b/domain/src/main/java/com/dpm/domain/entity/response/viewfinder/ResponseBlockReview.kt @@ -61,6 +61,8 @@ data class ResponseBlockReview( val content: String = "", val images: List = emptyList(), val keywords: List = emptyList(), + val isLike: Boolean, + val isScrap: Boolean, val likesCount: Long, val scrapsCount: Long, val reviewType: String, diff --git a/domain/src/main/java/com/dpm/domain/repository/ViewfinderRepository.kt b/domain/src/main/java/com/dpm/domain/repository/ViewfinderRepository.kt index 589d2003..e8fff763 100644 --- a/domain/src/main/java/com/dpm/domain/repository/ViewfinderRepository.kt +++ b/domain/src/main/java/com/dpm/domain/repository/ViewfinderRepository.kt @@ -11,4 +11,6 @@ interface ViewfinderRepository { suspend fun getStadium(id : Int) : Result suspend fun getBlockReviews(stadiumId:Int, blockCode: String, query: RequestBlockReviewQuery): Result suspend fun getBlockRow(stadiumId: Int, blockCode: String): Result + suspend fun updateScrap(reviewId: Int): Result + suspend fun updateLike(reviewId: Int): Result } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/LikeButton.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/LikeButton.kt index 099a13ef..7825911b 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/LikeButton.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/LikeButton.kt @@ -24,7 +24,8 @@ import com.dpm.presentation.extension.noRippleClickable @Composable fun LikeButton( - likeCount : Long, + isLike: Boolean, + likeCount: Long, modifier: Modifier = Modifier, onClick: () -> Unit ) { @@ -36,7 +37,7 @@ fun LikeButton( ) .border( width = 1.dp, - color = SpotTheme.colors.strokeTertiary, + color = if (isLike) SpotTheme.colors.actionEnabled else SpotTheme.colors.strokeTertiary, shape = RoundedCornerShape(72.dp) ) .padding( @@ -50,7 +51,9 @@ fun LikeButton( verticalAlignment = Alignment.CenterVertically ) { Icon( - painter = painterResource(id = R.drawable.ic_like_inactive), + painter = painterResource( + id = if (isLike) R.drawable.ic_like_active else R.drawable.ic_like_inactive + ), contentDescription = null, modifier = Modifier.size(24.dp), tint = Color.Unspecified @@ -65,7 +68,7 @@ fun LikeButton( Text( text = likeCount.toString(), style = SpotTheme.typography.label09, - color = SpotTheme.colors.foregroundDisabled + color = if (isLike) SpotTheme.colors.actionEnabled else SpotTheme.colors.strokeTertiary ) } } @@ -74,6 +77,7 @@ fun LikeButton( @Composable private fun LikeButtonPreview() { LikeButton( + isLike = true, likeCount = 1, onClick = {} ) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt index e82abb3a..2dee03a1 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt @@ -8,6 +8,10 @@ import androidx.compose.foundation.layout.width import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -18,6 +22,8 @@ import com.depromeet.designsystem.R @Composable fun ReviewContentBottom( + isLike: Boolean, + isScrap: Boolean, likeCount: Long, modifier: Modifier = Modifier, onClickLike: () -> Unit, @@ -30,6 +36,7 @@ fun ReviewContentBottom( verticalAlignment = Alignment.CenterVertically ) { LikeButton( + isLike = isLike, likeCount = likeCount, onClick = onClickLike ) @@ -39,7 +46,7 @@ fun ReviewContentBottom( ) { Icon( painter = painterResource( - id = R.drawable.ic_scrap_inactive_button + id = if (isScrap) R.drawable.ic_scrap_active_button else R.drawable.ic_scrap_inactive_button ), contentDescription = null, tint = Color.Unspecified ) @@ -63,6 +70,8 @@ fun ReviewContentBottom( @Composable private fun ReviewContentBottomPreview() { ReviewContentBottom( + isLike = false, + isScrap = true, likeCount = 0, onClickLike = {}, onClickScrap = {}, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt index f9f8c296..03ac4e87 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt @@ -61,6 +61,7 @@ fun StadiumDetailScreen( val detailUiState by viewModel.detailUiState.collectAsStateWithLifecycle() val currentIndex by viewModel.currentIndex.collectAsStateWithLifecycle() + LaunchedEffect(key1 = scrollState) { verticalScrollState.scrollToItem(0) viewModel.updateScrollState(false) @@ -161,8 +162,8 @@ fun StadiumDetailScreen( ) }, onClickReport = onClickReport, - onClickLike = onClickLike, - onClickScrap = onClickScrap, + onClickLike = viewModel::updateLike, + onClickScrap = viewModel::updateScrap, onClickShare = { KakaoUtils().share( context, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt index 959b67f4..02d8d144 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumHeaderContent.kt @@ -143,6 +143,8 @@ private fun StadiumHeaderContentPreview() { isPositive = false ) ), + isLike = false, + isScrap = false, likesCount = 1, scrapsCount = 0, reviewType = "" @@ -236,6 +238,8 @@ private fun StadiumHeaderContentIsMorePreview() { isPositive = false ) ), + isLike = false, + isScrap = false, likesCount = 1, scrapsCount = 0, reviewType = "" diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt index f8a559d3..c655c07e 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumPictureViewPager.kt @@ -183,6 +183,8 @@ private fun StadiumPictureViewPagerPreview() { isPositive = false ) ), + isLike = true, + isScrap = true, likesCount = 1, scrapsCount = 0, reviewType = "" diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt index 7ae2b99b..13619585 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt @@ -57,8 +57,8 @@ fun StadiumReviewContent( modifier: Modifier = Modifier, onClick: (reviewContent: ResponseBlockReview.ResponseReview, index: Int) -> Unit, onClickReport: () -> Unit, - onClickLike: () -> Unit, - onClickScrap: () -> Unit, + onClickLike: (id: Long) -> Unit = {}, + onClickScrap: (id: Long) -> Unit = {}, onClickShare: () -> Unit ) { val minimumLineLength = 3 @@ -243,10 +243,16 @@ fun StadiumReviewContent( ) Spacer(modifier = Modifier.height(12.dp)) ReviewContentBottom( + isLike = reviewContent.isLike, + isScrap = reviewContent.isScrap, likeCount = reviewContent.likesCount, modifier = Modifier.padding(start = 32.dp, end = 16.dp), - onClickLike = onClickLike, - onClickScrap = onClickScrap, + onClickLike = { + onClickLike(reviewContent.id) + }, + onClickScrap = { + onClickScrap(reviewContent.id) + }, onClickShare = onClickShare ) } @@ -319,15 +325,15 @@ private fun StadiumReviewContentPreview() { isPositive = false ) ), + isLike = false, + isScrap = false, likesCount = 1, scrapsCount = 0, reviewType = "" ), onClick = { _, _ -> }, onClickReport = {}, - onClickLike = {}, - onClickScrap = {}, - onClickShare ={} + onClickShare = {} ) } diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt index 044f02b2..83004774 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailCotentLayer.kt @@ -263,6 +263,8 @@ private fun DetailContentLayerPreview() { id = 2, content = "싫어요", isPositive = false ) ), + isLike = false, + isScrap = false, likesCount = 1, scrapsCount = 1, reviewType = "" diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt index 95b92c41..9c65cd8c 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailReviewInteractionItems.kt @@ -19,10 +19,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.depromeet.designsystem.R import com.dpm.designsystem.compose.ui.SpotTheme -import com.dpm.presentation.extension.noRippleClickable @Composable fun DetailReviewInteractionItems( + isLike: Boolean, likeCount: Long, modifier: Modifier = Modifier, onClickLike: () -> Unit, @@ -43,7 +43,7 @@ fun DetailReviewInteractionItems( ) { IconButton(onClick = onClickLike) { Icon( - painter = painterResource(id = R.drawable.ic_like_inactive), + painter = painterResource(id = if (isLike) R.drawable.ic_like_active else R.drawable.ic_like_inactive), contentDescription = null, tint = Color.Unspecified, modifier = Modifier.size(24.dp) @@ -52,10 +52,12 @@ fun DetailReviewInteractionItems( Text( text = likeCount.toString(), style = SpotTheme.typography.label10, - color = SpotTheme.colors.foregroundWhite + color = if (isLike) SpotTheme.colors.actionEnabled else SpotTheme.colors.foregroundWhite ) Spacer(modifier = Modifier.height(5.dp)) - IconButton(onClick = onClickScrap) { + IconButton(onClick = { + onClickScrap() + }) { Icon( painter = painterResource(id = R.drawable.ic_scrap), contentDescription = null, @@ -74,10 +76,23 @@ fun DetailReviewInteractionItems( } } +@Preview +@Composable +private fun DetailReviewInteractionItemsLikePreview() { + DetailReviewInteractionItems( + isLike = true, + likeCount = 1, + onClickLike = {}, + onClickScrap = {}, + onClickShare = {} + ) +} + @Preview @Composable private fun DetailReviewInteractionItemsPreview() { DetailReviewInteractionItems( + isLike = false, likeCount = 1, onClickLike = {}, onClickScrap = {}, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt index 19239508..3886d003 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt @@ -19,6 +19,7 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview @Composable fun DetailViewPagerLayer( context: Context, + isLike: Boolean, likeCount: Long, isDimmed: Boolean, verticalPagerState: PagerState, @@ -36,6 +37,7 @@ fun DetailViewPagerLayer( horizontalAlignment = Alignment.CenterHorizontally ) { StadiumDetailPictureViewPager( + isLike = isLike, context = context, pictures = pictures, likeCount = likeCount, @@ -71,6 +73,7 @@ private fun DetailViewPagerLayerPreview() { DetailViewPagerLayer( context = LocalContext.current, isDimmed = true, + isLike = true, likeCount = 1, pictures = pictures, verticalPagerState = pagerState, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt index 53dd4d39..8f4ea89a 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt @@ -1,30 +1,17 @@ package com.dpm.presentation.viewfinder.compose.detailpicture import android.content.Context -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateListOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import com.dpm.presentation.util.KakaoUtils -import com.dpm.presentation.util.kakaoShareSeatFeedTitle -import com.dpm.presentation.util.seatFeed import com.dpm.presentation.viewfinder.DetailReviewEntryPoint -import com.dpm.presentation.viewfinder.StadiumDetailActivity -import com.dpm.presentation.viewfinder.uistate.StadiumDetailUiState +import com.dpm.presentation.viewfinder.compose.detailpicture.main.StadiumDetailPictureTopScreen +import com.dpm.presentation.viewfinder.compose.detailpicture.top.StadiumDetailPictureMainScreen import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel -@OptIn(ExperimentalFoundationApi::class) @Composable fun StadiumDetailPictureScreen( context: Context = LocalContext.current, @@ -32,147 +19,36 @@ fun StadiumDetailPictureScreen( reviewId: Long, reviewIndex: Int, type: String, - modifier: Modifier = Modifier + onClickScrap: (id: Long) -> Unit = {} ) { val reviews = stadiumDetailViewModel.detailUiState.collectAsStateWithLifecycle() val bottomPadding by stadiumDetailViewModel.bottomPadding.collectAsStateWithLifecycle() - when(type) { + when (type) { DetailReviewEntryPoint.TOP_REVIEW.name -> { - reviews.value.let { uiState -> - when (uiState) { - is StadiumDetailUiState.ReviewsData -> { - val initPage by remember { - mutableStateOf(uiState.topReviewImages.indexOfFirst { it.id == reviewId }) - } - - val pagerState = rememberPagerState( - pageCount = { uiState.topReviewImages.size }, - initialPage = initPage - ) - - var pageIndex by remember { - mutableStateOf(0) - } - - LaunchedEffect(key1 = pagerState) { - snapshotFlow { pagerState.currentPage }.collect { - pageIndex = it - } - } - - StadiumDetailReviewViewPager( - context = context, - reviews = uiState.topReviewImages, - position = reviewIndex, - pagerState = pagerState, - pageIndex = pageIndex, - bottomPadding = bottomPadding, - modifier = modifier, - onClickShare = { imagePosition -> - KakaoUtils().share( - context, - seatFeed( - title = uiState.kakaoShareSeatFeedTitle(pageIndex), - description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", - imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, - queryParams = mapOf( - "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), - "blockCode" to stadiumDetailViewModel.blockCode - ) - ), - onSuccess = { sharingIntent -> - context.startActivity(sharingIntent) - } - ) - } - ) - } - else -> Unit - } - } + StadiumDetailPictureTopScreen( + context = context, + reviews = reviews.value, + reviewId = reviewId, + reviewIndex = reviewIndex, + bottomPadding = bottomPadding, + stadiumDetailViewModel = stadiumDetailViewModel, + onClickScrap = onClickScrap + ) } - DetailReviewEntryPoint.MAIN_REVIEW.name -> { - reviews.value.let { uiState -> - when (uiState) { - is StadiumDetailUiState.ReviewsData -> { - val visited = remember { - mutableStateListOf( - *List(uiState.reviews.size) { false }.toTypedArray() - ) - } - - if (uiState.reviews.size - visited.size > 0) { - visited.addAll(List(uiState.reviews.size - visited.size) { false }) - } - - val initPage by remember { - mutableStateOf(uiState.reviews.indexOfFirst { it.id == reviewId }) - } - - val pagerState = rememberPagerState( - pageCount = { uiState.reviews.size }, - initialPage = initPage - ) - var pageIndex by remember { - mutableStateOf(0) - } - - LaunchedEffect(key1 = pagerState) { - snapshotFlow { pagerState.currentPage }.collect { - pageIndex = it - stadiumDetailViewModel.updateCurrentIndex(it) - if (visited[it]) return@collect - - if (it == initPage) { - visited[it] = true - } - - if (!visited[it]) { - visited[it] = true - } - } - } - - StadiumDetailReviewViewPager( - context = context, - reviews = uiState.reviews, - visited = visited, - position = reviewIndex, - hasNext = uiState.hasNext, - pagerState = pagerState, - pageIndex = pageIndex, - bottomPadding = bottomPadding, - modifier = modifier, - onLoadPaging = stadiumDetailViewModel::getBlockReviews, - onClickShare = { imagePosition -> - KakaoUtils().share( - context, - seatFeed( - title = uiState.kakaoShareSeatFeedTitle(pageIndex), - description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", - imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, - queryParams = mapOf( - "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), - "blockCode" to stadiumDetailViewModel.blockCode - ) - ), - onSuccess = { sharingIntent -> - context.startActivity(sharingIntent) - } - ) - } - ) - } - - else -> Unit - } - } + DetailReviewEntryPoint.MAIN_REVIEW.name -> { + StadiumDetailPictureMainScreen( + context = context, + reviews = reviews.value, + reviewId = reviewId, + reviewIndex = reviewIndex, + bottomPadding = bottomPadding, + stadiumDetailViewModel = stadiumDetailViewModel, + onClickScrap = onClickScrap + ) } } - - } @Preview diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt index 408e64db..cb3f210e 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt @@ -45,6 +45,7 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview @Composable fun StadiumDetailPictureViewPager( context: Context, + isLike: Boolean, likeCount: Long, verticalPagerState: PagerState, pictures: List, @@ -122,6 +123,7 @@ fun StadiumDetailPictureViewPager( contentAlignment = Alignment.CenterEnd ) { DetailReviewInteractionItems( + isLike = isLike, likeCount = likeCount, onClickLike = onClickLike, onClickScrap = onClickScrap, @@ -142,6 +144,7 @@ private fun StadiumDetailPictureViewPagerPreview() { } StadiumDetailPictureViewPager( context = LocalContext.current, + isLike = true, likeCount = 1, verticalPagerState = pagerState, pictures = listOf( diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt index 1ac76b0d..572e362c 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt @@ -33,6 +33,8 @@ fun StadiumDetailReviewViewPager( visited: List = emptyList(), modifier: Modifier = Modifier, onLoadPaging: () -> Unit = {}, + onClickLike: (id:Long) -> Unit = {}, + onClickScrap: (id:Long) -> Unit = {}, onClickShare: (imagePosition: Int) -> Unit = {} ) { if (pageIndex == reviews.size - 1 && hasNext) { @@ -82,14 +84,15 @@ fun StadiumDetailReviewViewPager( DetailViewPagerLayer( context = context, isDimmed = isDimmed, + isLike = reviews[page].isLike, likeCount = reviews[page].likesCount, pictures = reviews[page].images, verticalPagerState = verticalPagerState, onClickLike = { - // TODO : 좋아요 클릭 + onClickLike(reviews[page].id) }, onClickScrap = { - // TODO : 스크랩 클릭 + onClickScrap(reviews[page].id) }, onClickShare = { onClickShare(verticalPagerState.currentPage) @@ -164,6 +167,8 @@ private fun StadiumDetailReviewViewPagerPreview() { id = 2, content = "싫어요", isPositive = false ) ), + isLike = false, + isScrap = false, likesCount = 0, scrapsCount = 0, reviewType = "" @@ -245,6 +250,8 @@ private fun StadiumDetailReviewViewPagerMorePreview() { id = 2, content = "싫어요", isPositive = false ) ), + isLike = false, + isScrap = false, likesCount = 0, scrapsCount = 0, reviewType = "" diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt new file mode 100644 index 00000000..ba255518 --- /dev/null +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt @@ -0,0 +1,104 @@ +package com.dpm.presentation.viewfinder.compose.detailpicture.main + +import android.content.Context +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.viewmodel.compose.viewModel +import com.dpm.presentation.util.KakaoUtils +import com.dpm.presentation.util.kakaoShareSeatFeedTitle +import com.dpm.presentation.util.seatFeed +import com.dpm.presentation.viewfinder.DetailReviewEntryPoint +import com.dpm.presentation.viewfinder.compose.detailpicture.StadiumDetailReviewViewPager +import com.dpm.presentation.viewfinder.uistate.StadiumDetailUiState +import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun StadiumDetailPictureTopScreen( + context: Context, + reviewId: Long, + reviewIndex: Int, + bottomPadding: Float, + reviews: StadiumDetailUiState, + modifier: Modifier = Modifier, + stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), + onClickScrap: (id: Long) -> Unit = {} +) { + reviews.let { uiState -> + when (uiState) { + is StadiumDetailUiState.ReviewsData -> { + val initPage by remember { + mutableStateOf(uiState.topReviewImages.indexOfFirst { it.id == reviewId }) + } + + val pagerState = rememberPagerState( + pageCount = { uiState.topReviewImages.size }, + initialPage = initPage + ) + + var pageIndex by remember { + mutableStateOf(0) + } + + LaunchedEffect(key1 = pagerState) { + snapshotFlow { pagerState.currentPage }.collect { + pageIndex = it + } + } + + StadiumDetailReviewViewPager( + context = context, + reviews = uiState.topReviewImages, + position = reviewIndex, + pagerState = pagerState, + pageIndex = pageIndex, + bottomPadding = bottomPadding, + modifier = modifier, + onClickLike = stadiumDetailViewModel::updateLike, + onClickScrap = onClickScrap, + onClickShare = { imagePosition -> + KakaoUtils().share( + context, + seatFeed( + title = uiState.kakaoShareSeatFeedTitle(pageIndex), + description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", + imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, + queryParams = mapOf( + "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), + "blockCode" to stadiumDetailViewModel.blockCode + ) + ), + onSuccess = { sharingIntent -> + context.startActivity(sharingIntent) + } + ) + } + ) + } + + else -> Unit + } + } +} + +@Preview +@Composable +private fun StadiumDetailPictureTopScreenPreview() { + StadiumDetailPictureTopScreen( + context = LocalContext.current, + reviewId = 1, + reviewIndex = 0, + bottomPadding = 0f, + reviews = StadiumDetailUiState.Empty, + ) +} \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt new file mode 100644 index 00000000..f44db35d --- /dev/null +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt @@ -0,0 +1,127 @@ +package com.dpm.presentation.viewfinder.compose.detailpicture.top + +import android.content.Context +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.viewmodel.compose.viewModel +import com.dpm.presentation.util.KakaoUtils +import com.dpm.presentation.util.kakaoShareSeatFeedTitle +import com.dpm.presentation.util.seatFeed +import com.dpm.presentation.viewfinder.compose.detailpicture.StadiumDetailReviewViewPager +import com.dpm.presentation.viewfinder.uistate.StadiumDetailUiState +import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun StadiumDetailPictureMainScreen( + context: Context, + reviewId: Long, + reviewIndex: Int, + bottomPadding: Float, + reviews: StadiumDetailUiState, + modifier: Modifier = Modifier, + stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), + onClickScrap: (id: Long) -> Unit = {} +) { + reviews.let { uiState -> + when (uiState) { + is StadiumDetailUiState.ReviewsData -> { + val visited = remember { + mutableStateListOf( + *List(uiState.reviews.size) { false }.toTypedArray() + ) + } + + if (uiState.reviews.size - visited.size > 0) { + visited.addAll(List(uiState.reviews.size - visited.size) { false }) + } + + val initPage by remember { + mutableStateOf(uiState.reviews.indexOfFirst { it.id == reviewId }) + } + + val pagerState = rememberPagerState( + pageCount = { uiState.reviews.size }, + initialPage = initPage + ) + + var pageIndex by remember { + mutableStateOf(0) + } + + LaunchedEffect(key1 = pagerState) { + snapshotFlow { pagerState.currentPage }.collect { + pageIndex = it + stadiumDetailViewModel.updateCurrentIndex(it) + if (visited[it]) return@collect + + if (it == initPage) { + visited[it] = true + } + + if (!visited[it]) { + visited[it] = true + } + } + } + + StadiumDetailReviewViewPager( + context = context, + reviews = uiState.reviews, + visited = visited, + position = reviewIndex, + hasNext = uiState.hasNext, + pagerState = pagerState, + pageIndex = pageIndex, + bottomPadding = bottomPadding, + modifier = modifier, + onLoadPaging = stadiumDetailViewModel::getBlockReviews, + onClickLike = stadiumDetailViewModel::updateLike, + onClickScrap = onClickScrap, + onClickShare = { imagePosition -> + KakaoUtils().share( + context, + seatFeed( + title = uiState.kakaoShareSeatFeedTitle(pageIndex), + description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", + imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, + queryParams = mapOf( + "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), + "blockCode" to stadiumDetailViewModel.blockCode + ) + ), + onSuccess = { sharingIntent -> + context.startActivity(sharingIntent) + } + ) + } + ) + } + + else -> Unit + } + } +} + +@Preview +@Composable +private fun StadiumDetailPictureMainScreenPreview() { + StadiumDetailPictureMainScreen( + context = LocalContext.current, + reviewId = 1, + reviewIndex = 0, + bottomPadding = 0f, + reviews = StadiumDetailUiState.Empty, + ) +} \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt index 50627d91..965fb723 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/viewmodel/StadiumDetailViewModel.kt @@ -64,6 +64,66 @@ class StadiumDetailViewModel @Inject constructor( _scrollState.value = state } + fun updateLike(id: Long) { + viewModelScope.launch { + viewfinderRepository.updateLike(id.toInt()) + _detailUiState.value = when (val currentState = _detailUiState.value) { + is StadiumDetailUiState.ReviewsData -> { + val updatedReviews = currentState.reviews.map { review -> + if (review.id == id) { + if (review.isLike) { + review.copy( + isLike = !review.isLike, + likesCount = review.likesCount - 1 + ) + } else { + review.copy( + isLike = !review.isLike, + likesCount = review.likesCount + 1 + ) + } + } else { + review + } + } + currentState.copy(reviews = updatedReviews) + } + + else -> currentState + } + } + } + + fun updateScrap(id: Long) { + viewModelScope.launch { + viewfinderRepository.updateScrap(id.toInt()) + _detailUiState.value = when (val currentState = _detailUiState.value) { + is StadiumDetailUiState.ReviewsData -> { + val updatedReviews = currentState.reviews.map { review -> + if (review.id == id) { + if (review.isScrap) { + review.copy( + isScrap = !review.isScrap, + scrapsCount = review.scrapsCount - 1 + ) + } else { + review.copy( + isScrap = !review.isScrap, + scrapsCount = review.scrapsCount + 1 + ) + } + } else { + review + } + } + currentState.copy(reviews = updatedReviews) + } + + else -> currentState + } + } + } + fun updateMonth(month: Int?) { if (month != _reviewFilter.value.month) { reset = true @@ -157,6 +217,15 @@ class StadiumDetailViewModel @Inject constructor( } } + fun checkScrap(id: Long): Boolean { + (_detailUiState.value as StadiumDetailUiState.ReviewsData).reviews.map { review -> + if (review.id == id && review.isScrap) { + return true + } + } + return false + } + fun handleColumNumber( column: Int, number: Int, From 539ce93a0f20489130e22113aef259ddbaa28f0a Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 19:11:08 +0900 Subject: [PATCH 10/15] =?UTF-8?q?[feat/#110]=20=EC=8A=A4=ED=81=AC=EB=9E=A9?= =?UTF-8?q?=20=EC=8A=A4=EB=82=B5=EB=B0=94=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StadiumDetailPictureFragment.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt index df4d98ed..964a18e7 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt @@ -13,9 +13,10 @@ import androidx.core.view.updatePadding import androidx.fragment.app.DialogFragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.commit -import com.dpm.core.base.BindingFragment import com.depromeet.presentation.R import com.depromeet.presentation.databinding.FragmentStadiumDetailPictureBinding +import com.dpm.core.base.BindingFragment +import com.dpm.designsystem.SpotSnackBar import com.dpm.presentation.util.Utils import com.dpm.presentation.viewfinder.compose.detailpicture.StadiumDetailPictureScreen import com.dpm.presentation.viewfinder.dialog.ReportDialog @@ -46,6 +47,7 @@ class StadiumDetailPictureFragment : BindingFragment binding.spotAppbar.setText(title) binding.cvReviewContent.setContent { @@ -64,6 +67,11 @@ class StadiumDetailPictureFragment : BindingFragment + if (stadiumDetailViewModel.checkScrap(id)) { + snackBar.show() + } + } ) } } @@ -98,6 +106,17 @@ class StadiumDetailPictureFragment : BindingFragment Unit) { val reviewId = arguments?.getLong(StadiumDetailActivity.REVIEW_ID) ?: return val reviewIndex = arguments?.getInt(StadiumDetailActivity.REVIEW_INDEX) ?: return @@ -143,6 +162,7 @@ class StadiumDetailPictureFragment : BindingFragment Date: Sat, 24 Aug 2024 20:41:32 +0900 Subject: [PATCH 11/15] =?UTF-8?q?[feat/#110]=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?,=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20=ED=88=B4=ED=8C=81=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dpm/data/preference/SharedPreference.kt | 22 ++++++++++++++++--- .../domain/preference/NetworkPreference.kt | 2 ++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/data/src/main/java/com/dpm/data/preference/SharedPreference.kt b/data/src/main/java/com/dpm/data/preference/SharedPreference.kt index b9567759..61c37b9d 100644 --- a/data/src/main/java/com/dpm/data/preference/SharedPreference.kt +++ b/data/src/main/java/com/dpm/data/preference/SharedPreference.kt @@ -47,7 +47,7 @@ class DefaultSharedPreference @Inject constructor( } override var teamName: String - get() = preferences.getString("teamName","").orEmpty() + get() = preferences.getString("teamName", "").orEmpty() set(value) { preferences.edit(commit = true) { putString("teamName", value) @@ -64,12 +64,12 @@ class DefaultSharedPreference @Inject constructor( get() = preferences.getString("levelTitle", "").orEmpty() set(value) { preferences.edit(commit = true) { - putString("levelTitle",value) + putString("levelTitle", value) } } override var profileImage: String - get() = preferences.getString("profileImage","").orEmpty() + get() = preferences.getString("profileImage", "").orEmpty() set(value) { preferences.edit(commit = true) { putString("profileImage", value) @@ -83,4 +83,20 @@ class DefaultSharedPreference @Inject constructor( putBoolean("isFirstTime", value) } } + + override var isFirstShare: Boolean + get() = preferences.getBoolean("isFirstShare", true) + set(value) { + preferences.edit(commit = true) { + putBoolean("isFirstShare", value) + } + } + + override var isFirstLike: Boolean + get() = preferences.getBoolean("isFirstLike", true) + set(value) { + preferences.edit(commit = true) { + putBoolean("isFirstLike", value) + } + } } diff --git a/domain/src/main/java/com/dpm/domain/preference/NetworkPreference.kt b/domain/src/main/java/com/dpm/domain/preference/NetworkPreference.kt index 20234379..dbedf655 100644 --- a/domain/src/main/java/com/dpm/domain/preference/NetworkPreference.kt +++ b/domain/src/main/java/com/dpm/domain/preference/NetworkPreference.kt @@ -10,5 +10,7 @@ interface SharedPreference { var nickname: String var profileImage : String var isFirstTime: Boolean + var isFirstShare: Boolean + var isFirstLike: Boolean fun clear() } From 0b861e8d789d4b552c5cb961800279bd2f0b7dc6 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 20:43:23 +0900 Subject: [PATCH 12/15] =?UTF-8?q?[feat/#110]=20=EA=B3=B5=EC=9C=A0=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=95=88=EB=82=B4=20=ED=88=B4=ED=8C=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewfinder/StadiumDetailActivity.kt | 11 +++++- .../viewfinder/compose/ReviewContentBottom.kt | 39 +++++++++++++++++++ .../viewfinder/compose/StadiumDetailScreen.kt | 12 ++++-- .../compose/StadiumReviewContent.kt | 16 +++++++- 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt index d120e7f4..8a8c3a59 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailActivity.kt @@ -12,6 +12,7 @@ import com.dpm.core.base.BaseActivity import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview import com.depromeet.presentation.R import com.depromeet.presentation.databinding.ActivityStadiumDetailBinding +import com.dpm.domain.preference.SharedPreference import com.dpm.presentation.home.HomeActivity import com.dpm.presentation.util.KakaoUtils import com.dpm.presentation.util.seatFeed @@ -22,6 +23,7 @@ import com.dpm.presentation.viewfinder.dialog.StadiumFilterMonthsDialog import com.dpm.presentation.viewfinder.dialog.StadiumSelectSeatDialog import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class StadiumDetailActivity : BaseActivity({ @@ -37,6 +39,9 @@ class StadiumDetailActivity : BaseActivity({ const val STADIUM_REVIEW_CONTENT = "stadium_review_content" } + @Inject + lateinit var sharedPreference: SharedPreference + private val viewModel: StadiumDetailViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { @@ -60,6 +65,7 @@ class StadiumDetailActivity : BaseActivity({ MaterialTheme { StadiumDetailScreen( emptyBlockName = toEmptyBlock(viewModel.stadiumId, viewModel.blockCode), + isFirstShare = sharedPreference.isFirstShare, viewModel = viewModel, onClickReviewPicture = { id, index, title -> startToStadiumDetailPictureFragment(id, index, title, DetailReviewEntryPoint.MAIN_REVIEW) @@ -94,8 +100,9 @@ class StadiumDetailActivity : BaseActivity({ onClickTopImage = { id, index, title -> startToStadiumDetailPictureFragment(id, index, title, DetailReviewEntryPoint.TOP_REVIEW) }, - onClickLike = {}, - onClickScrap = {} + onClickShare = { + sharedPreference.isFirstShare = false + } ) } } diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt index 2dee03a1..a8803a39 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/ReviewContentBottom.kt @@ -71,6 +71,45 @@ fun ReviewContentBottom( private fun ReviewContentBottomPreview() { ReviewContentBottom( isLike = false, + isScrap = false, + likeCount = 0, + onClickLike = {}, + onClickScrap = {}, + onClickShare = {} + ) +} + +@Preview +@Composable +private fun ReviewContentBottomLikePreview() { + ReviewContentBottom( + isLike = true, + isScrap = false, + likeCount = 0, + onClickLike = {}, + onClickScrap = {}, + onClickShare = {} + ) +} + +@Preview +@Composable +private fun ReviewContentBottomScrapPreview() { + ReviewContentBottom( + isLike = false, + isScrap = true, + likeCount = 0, + onClickLike = {}, + onClickScrap = {}, + onClickShare = {} + ) +} + +@Preview +@Composable +private fun ReviewContentBottomLikeAndScrapPreview() { + ReviewContentBottom( + isLike = true, isScrap = true, likeCount = 0, onClickLike = {}, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt index 03ac4e87..0c8bbad3 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumDetailScreen.kt @@ -41,6 +41,7 @@ import timber.log.Timber @Composable fun StadiumDetailScreen( emptyBlockName: String, + isFirstShare: Boolean, context: Context = LocalContext.current, modifier: Modifier = Modifier, viewModel: StadiumDetailViewModel = viewModel(), @@ -50,11 +51,11 @@ fun StadiumDetailScreen( onClickFilterMonthly: () -> Unit, onClickReport: () -> Unit, onClickGoBack: () -> Unit, - onClickLike: () -> Unit, - onClickScrap: () -> Unit, + onClickShare:() -> Unit = {}, onRefresh: () -> Unit ) { var isMore by remember { mutableStateOf(false) } + var isFirstShare by remember { mutableStateOf(isFirstShare) } val verticalScrollState = rememberLazyListState() val scrollState by viewModel.scrollState.collectAsStateWithLifecycle() val reviewFilter by viewModel.reviewFilter.collectAsStateWithLifecycle() @@ -153,6 +154,8 @@ fun StadiumDetailScreen( ) { index -> StadiumReviewContent( context = context, + isFirstShare = isFirstShare, + firstReview = uiState.reviews[index] == uiState.reviews.firstOrNull(), reviewContent = uiState.reviews[index], onClick = { reviewContent, index -> onClickReviewPicture( @@ -165,6 +168,8 @@ fun StadiumDetailScreen( onClickLike = viewModel::updateLike, onClickScrap = viewModel::updateScrap, onClickShare = { + onClickShare() + isFirstShare = false KakaoUtils().share( context, seatFeed( @@ -200,6 +205,7 @@ fun StadiumDetailScreen( private fun StadiumDetailScreenPreview() { Box(modifier = Modifier.background(Color.White)) { StadiumDetailScreen( + isFirstShare = true, emptyBlockName = "207", onClickReviewPicture = { _, _, _ -> }, onClickSelectSeat = {}, @@ -208,8 +214,6 @@ private fun StadiumDetailScreenPreview() { onClickGoBack = {}, onRefresh = {}, onClickTopImage = { _, _, _ -> }, - onClickLike = {}, - onClickScrap = {}, ) } } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt index 13619585..0edacde0 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/StadiumReviewContent.kt @@ -53,11 +53,13 @@ private enum class ReviewContentShowMoreState { @Composable fun StadiumReviewContent( context: Context, + isFirstShare: Boolean, + firstReview: Boolean, reviewContent: ResponseBlockReview.ResponseReview, modifier: Modifier = Modifier, onClick: (reviewContent: ResponseBlockReview.ResponseReview, index: Int) -> Unit, onClickReport: () -> Unit, - onClickLike: (id: Long) -> Unit = {}, + onClickLike: (id: Long) -> Unit = {}, onClickScrap: (id: Long) -> Unit = {}, onClickShare: () -> Unit ) { @@ -255,6 +257,16 @@ fun StadiumReviewContent( }, onClickShare = onClickShare ) + if (firstReview && isFirstShare) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(end = 16.dp), + contentAlignment = Alignment.CenterEnd + ) { + ShareTooltip(bias = 0.875f, content = "카카오톡으로 같이가는 친구에게 공유하기") + } + } } } @@ -268,6 +280,8 @@ private fun StadiumReviewContentPreview() { ) { StadiumReviewContent( context = LocalContext.current, + isFirstShare = false, + firstReview = false, reviewContent = ResponseBlockReview.ResponseReview( id = 1, dateTime = "2023-03-01T19:00:00", From 1ffb6a2089b87fbb51489dc21e8341e15eb6ec66 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 24 Aug 2024 20:43:36 +0900 Subject: [PATCH 13/15] =?UTF-8?q?[feat/#110]=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=20=EC=95=88=EB=82=B4=20=ED=88=B4=ED=8C=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StadiumDetailPictureFragment.kt | 12 +++++++++++ .../detailpicture/DetailViewPagerLayer.kt | 3 +++ .../compose/detailpicture/LikeTooltip.kt | 1 - .../StadiumDetailPictureScreen.kt | 21 ++++++++++++++----- .../StadiumDetailPictureViewPager.kt | 19 +++++++++++------ .../StadiumDetailReviewViewPager.kt | 8 +++++-- .../main/StadiumDetailPictureTopScreen.kt | 18 ++++++++++++++-- .../top/StadiumDetailPictureMainScreen.kt | 18 ++++++++++++++-- 8 files changed, 82 insertions(+), 18 deletions(-) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt index 964a18e7..ccf91b6e 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt @@ -17,11 +17,13 @@ import com.depromeet.presentation.R import com.depromeet.presentation.databinding.FragmentStadiumDetailPictureBinding import com.dpm.core.base.BindingFragment import com.dpm.designsystem.SpotSnackBar +import com.dpm.domain.preference.SharedPreference import com.dpm.presentation.util.Utils import com.dpm.presentation.viewfinder.compose.detailpicture.StadiumDetailPictureScreen import com.dpm.presentation.viewfinder.dialog.ReportDialog import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject enum class DetailReviewEntryPoint { TOP_REVIEW, MAIN_REVIEW @@ -43,6 +45,9 @@ class StadiumDetailPictureFragment : BindingFragment if (stadiumDetailViewModel.checkScrap(id)) { snackBar.show() } + }, + onClickShare = { + sharedPreference.isFirstShare = false } ) } diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt index 3886d003..330843cf 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/DetailViewPagerLayer.kt @@ -21,6 +21,7 @@ fun DetailViewPagerLayer( context: Context, isLike: Boolean, likeCount: Long, + isFirstLike: Boolean, isDimmed: Boolean, verticalPagerState: PagerState, pictures: List, @@ -40,6 +41,7 @@ fun DetailViewPagerLayer( isLike = isLike, context = context, pictures = pictures, + isFirstLike = isFirstLike, likeCount = likeCount, verticalPagerState = verticalPagerState, onClickLike = onClickLike, @@ -74,6 +76,7 @@ private fun DetailViewPagerLayerPreview() { context = LocalContext.current, isDimmed = true, isLike = true, + isFirstLike = true, likeCount = 1, pictures = pictures, verticalPagerState = pagerState, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/LikeTooltip.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/LikeTooltip.kt index e260c7dd..53ce9dad 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/LikeTooltip.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/LikeTooltip.kt @@ -64,7 +64,6 @@ fun LikeTooltip( Canvas( modifier = Modifier .height(triangleHeight) - .offset(y = tooltipHeight.dp) ) { val trianglePath = Path().apply { moveTo(tooltipWidth * bias, triangleHeight.toPx()) // 삼각형 꼭짓점 diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt index 8f4ea89a..6cc72d8f 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt @@ -14,12 +14,15 @@ import com.dpm.presentation.viewfinder.viewmodel.StadiumDetailViewModel @Composable fun StadiumDetailPictureScreen( - context: Context = LocalContext.current, - stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), reviewId: Long, reviewIndex: Int, type: String, - onClickScrap: (id: Long) -> Unit = {} + isFirstLike: Boolean, + context: Context = LocalContext.current, + stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), + onClickLike:() -> Unit = {}, + onClickScrap: (id: Long) -> Unit = {}, + onClickShare: () -> Unit = {} ) { val reviews = stadiumDetailViewModel.detailUiState.collectAsStateWithLifecycle() val bottomPadding by stadiumDetailViewModel.bottomPadding.collectAsStateWithLifecycle() @@ -32,8 +35,11 @@ fun StadiumDetailPictureScreen( reviewId = reviewId, reviewIndex = reviewIndex, bottomPadding = bottomPadding, + isFirstLike = isFirstLike, stadiumDetailViewModel = stadiumDetailViewModel, - onClickScrap = onClickScrap + onClickLike = onClickLike, + onClickScrap = onClickScrap, + onClickShare = onClickShare ) } @@ -44,8 +50,11 @@ fun StadiumDetailPictureScreen( reviewId = reviewId, reviewIndex = reviewIndex, bottomPadding = bottomPadding, + isFirstLike = isFirstLike, stadiumDetailViewModel = stadiumDetailViewModel, - onClickScrap = onClickScrap + onClickLike = onClickLike, + onClickScrap = onClickScrap, + onClickShare = onClickShare ) } } @@ -55,6 +64,7 @@ fun StadiumDetailPictureScreen( @Composable private fun StadiumDetailPictureScreenMainPreview() { StadiumDetailPictureScreen( + isFirstLike = true, context = LocalContext.current, reviewId = 1, reviewIndex = 0, @@ -66,6 +76,7 @@ private fun StadiumDetailPictureScreenMainPreview() { @Composable private fun StadiumDetailPictureScreenTopPreview() { StadiumDetailPictureScreen( + isFirstLike = true, context = LocalContext.current, reviewId = 1, reviewIndex = 0, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt index cb3f210e..2fd6218a 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureViewPager.kt @@ -1,7 +1,6 @@ package com.dpm.presentation.viewfinder.compose.detailpicture import android.content.Context -import android.util.Log import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -9,10 +8,10 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column 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.height import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight @@ -22,10 +21,6 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -46,6 +41,7 @@ import com.dpm.domain.entity.response.viewfinder.ResponseBlockReview fun StadiumDetailPictureViewPager( context: Context, isLike: Boolean, + isFirstLike: Boolean, likeCount: Long, verticalPagerState: PagerState, pictures: List, @@ -116,6 +112,7 @@ fun StadiumDetailPictureViewPager( } } } + Box( modifier = Modifier .fillMaxWidth() @@ -129,6 +126,15 @@ fun StadiumDetailPictureViewPager( onClickScrap = onClickScrap, onClickShare = onClickShare ) + if (isFirstLike) { + LikeTooltip( + modifier = Modifier + .align(Alignment.TopEnd) + .offset(y = (-32).dp), + bias = 0.8f, + content = "유용했다면, 도움돼요를 눌러주세요!", + ) + } } } @@ -146,6 +152,7 @@ private fun StadiumDetailPictureViewPagerPreview() { context = LocalContext.current, isLike = true, likeCount = 1, + isFirstLike = true, verticalPagerState = pagerState, pictures = listOf( ResponseBlockReview.ResponseReview.ResponseReviewImage( diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt index 572e362c..5b85794a 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailReviewViewPager.kt @@ -26,6 +26,7 @@ fun StadiumDetailReviewViewPager( context: Context, position: Int, hasNext: Boolean = false, + isFirstLike: Boolean, pagerState: PagerState, pageIndex: Int, bottomPadding: Float, @@ -33,8 +34,8 @@ fun StadiumDetailReviewViewPager( visited: List = emptyList(), modifier: Modifier = Modifier, onLoadPaging: () -> Unit = {}, - onClickLike: (id:Long) -> Unit = {}, - onClickScrap: (id:Long) -> Unit = {}, + onClickLike: (id: Long) -> Unit = {}, + onClickScrap: (id: Long) -> Unit = {}, onClickShare: (imagePosition: Int) -> Unit = {} ) { if (pageIndex == reviews.size - 1 && hasNext) { @@ -85,6 +86,7 @@ fun StadiumDetailReviewViewPager( context = context, isDimmed = isDimmed, isLike = reviews[page].isLike, + isFirstLike = isFirstLike, likeCount = reviews[page].likesCount, pictures = reviews[page].images, verticalPagerState = verticalPagerState, @@ -180,6 +182,7 @@ private fun StadiumDetailReviewViewPagerPreview() { StadiumDetailReviewViewPager( context = LocalContext.current, reviews = reviews, + isFirstLike = true, visited = emptyList(), position = 1, hasNext = false, @@ -265,6 +268,7 @@ private fun StadiumDetailReviewViewPagerMorePreview() { reviews = reviews, visited = emptyList(), position = 1, + isFirstLike = true, hasNext = false, pagerState = pagerState, pageIndex = 0, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt index ba255518..62703aff 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt @@ -29,10 +29,13 @@ fun StadiumDetailPictureTopScreen( reviewId: Long, reviewIndex: Int, bottomPadding: Float, + isFirstLike: Boolean, reviews: StadiumDetailUiState, modifier: Modifier = Modifier, stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), - onClickScrap: (id: Long) -> Unit = {} + onClickLike: () -> Unit = {}, + onClickScrap: (id: Long) -> Unit = {}, + onClickShare: () -> Unit = {} ) { reviews.let { uiState -> when (uiState) { @@ -46,6 +49,10 @@ fun StadiumDetailPictureTopScreen( initialPage = initPage ) + var isFirstLikeState by remember { + mutableStateOf(isFirstLike) + } + var pageIndex by remember { mutableStateOf(0) } @@ -60,13 +67,19 @@ fun StadiumDetailPictureTopScreen( context = context, reviews = uiState.topReviewImages, position = reviewIndex, + isFirstLike = isFirstLikeState, pagerState = pagerState, pageIndex = pageIndex, bottomPadding = bottomPadding, modifier = modifier, - onClickLike = stadiumDetailViewModel::updateLike, + onClickLike = { id -> + onClickLike() + isFirstLikeState = false + stadiumDetailViewModel.updateLike(id) + }, onClickScrap = onClickScrap, onClickShare = { imagePosition -> + onClickShare() KakaoUtils().share( context, seatFeed( @@ -99,6 +112,7 @@ private fun StadiumDetailPictureTopScreenPreview() { reviewId = 1, reviewIndex = 0, bottomPadding = 0f, + isFirstLike = false, reviews = StadiumDetailUiState.Empty, ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt index f44db35d..b3b68068 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt @@ -29,10 +29,13 @@ fun StadiumDetailPictureMainScreen( reviewId: Long, reviewIndex: Int, bottomPadding: Float, + isFirstLike: Boolean, reviews: StadiumDetailUiState, modifier: Modifier = Modifier, stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), - onClickScrap: (id: Long) -> Unit = {} + onClickLike: () -> Unit = {}, + onClickScrap: (id: Long) -> Unit = {}, + onClickShare: () -> Unit = {} ) { reviews.let { uiState -> when (uiState) { @@ -60,6 +63,10 @@ fun StadiumDetailPictureMainScreen( mutableStateOf(0) } + var isFirstLikeState by remember { + mutableStateOf(isFirstLike) + } + LaunchedEffect(key1 = pagerState) { snapshotFlow { pagerState.currentPage }.collect { pageIndex = it @@ -81,15 +88,21 @@ fun StadiumDetailPictureMainScreen( reviews = uiState.reviews, visited = visited, position = reviewIndex, + isFirstLike = isFirstLikeState, hasNext = uiState.hasNext, pagerState = pagerState, pageIndex = pageIndex, bottomPadding = bottomPadding, modifier = modifier, onLoadPaging = stadiumDetailViewModel::getBlockReviews, - onClickLike = stadiumDetailViewModel::updateLike, + onClickLike = { id -> + onClickLike() + isFirstLikeState = false + stadiumDetailViewModel.updateLike(id) + }, onClickScrap = onClickScrap, onClickShare = { imagePosition -> + onClickShare() KakaoUtils().share( context, seatFeed( @@ -122,6 +135,7 @@ private fun StadiumDetailPictureMainScreenPreview() { reviewId = 1, reviewIndex = 0, bottomPadding = 0f, + isFirstLike = false, reviews = StadiumDetailUiState.Empty, ) } \ No newline at end of file From d51594bbffd8939eb7590053dd52b29d7854765e Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 25 Aug 2024 00:28:42 +0900 Subject: [PATCH 14/15] =?UTF-8?q?[fix/#110]=20let=20=EC=8A=A4=EC=BD=94?= =?UTF-8?q?=ED=94=84=20=ED=95=A8=EC=88=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StadiumDetailPictureScreen.kt | 4 +- .../main/StadiumDetailPictureTopScreen.kt | 114 +++++++------- .../top/StadiumDetailPictureMainScreen.kt | 149 +++++++++--------- 3 files changed, 131 insertions(+), 136 deletions(-) diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt index 6cc72d8f..5c87b121 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/StadiumDetailPictureScreen.kt @@ -31,7 +31,7 @@ fun StadiumDetailPictureScreen( DetailReviewEntryPoint.TOP_REVIEW.name -> { StadiumDetailPictureTopScreen( context = context, - reviews = reviews.value, + uiState = reviews.value, reviewId = reviewId, reviewIndex = reviewIndex, bottomPadding = bottomPadding, @@ -46,7 +46,7 @@ fun StadiumDetailPictureScreen( DetailReviewEntryPoint.MAIN_REVIEW.name -> { StadiumDetailPictureMainScreen( context = context, - reviews = reviews.value, + uiState = reviews.value, reviewId = reviewId, reviewIndex = reviewIndex, bottomPadding = bottomPadding, diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt index 62703aff..1d7baaa0 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/main/StadiumDetailPictureTopScreen.kt @@ -30,77 +30,75 @@ fun StadiumDetailPictureTopScreen( reviewIndex: Int, bottomPadding: Float, isFirstLike: Boolean, - reviews: StadiumDetailUiState, + uiState: StadiumDetailUiState, modifier: Modifier = Modifier, stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), onClickLike: () -> Unit = {}, onClickScrap: (id: Long) -> Unit = {}, onClickShare: () -> Unit = {} ) { - reviews.let { uiState -> - when (uiState) { - is StadiumDetailUiState.ReviewsData -> { - val initPage by remember { - mutableStateOf(uiState.topReviewImages.indexOfFirst { it.id == reviewId }) - } + when (uiState) { + is StadiumDetailUiState.ReviewsData -> { + val initPage by remember { + mutableStateOf(uiState.topReviewImages.indexOfFirst { it.id == reviewId }) + } - val pagerState = rememberPagerState( - pageCount = { uiState.topReviewImages.size }, - initialPage = initPage - ) + val pagerState = rememberPagerState( + pageCount = { uiState.topReviewImages.size }, + initialPage = initPage + ) - var isFirstLikeState by remember { - mutableStateOf(isFirstLike) - } + var isFirstLikeState by remember { + mutableStateOf(isFirstLike) + } - var pageIndex by remember { - mutableStateOf(0) - } + var pageIndex by remember { + mutableStateOf(0) + } - LaunchedEffect(key1 = pagerState) { - snapshotFlow { pagerState.currentPage }.collect { - pageIndex = it - } + LaunchedEffect(key1 = pagerState) { + snapshotFlow { pagerState.currentPage }.collect { + pageIndex = it } - - StadiumDetailReviewViewPager( - context = context, - reviews = uiState.topReviewImages, - position = reviewIndex, - isFirstLike = isFirstLikeState, - pagerState = pagerState, - pageIndex = pageIndex, - bottomPadding = bottomPadding, - modifier = modifier, - onClickLike = { id -> - onClickLike() - isFirstLikeState = false - stadiumDetailViewModel.updateLike(id) - }, - onClickScrap = onClickScrap, - onClickShare = { imagePosition -> - onClickShare() - KakaoUtils().share( - context, - seatFeed( - title = uiState.kakaoShareSeatFeedTitle(pageIndex), - description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", - imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, - queryParams = mapOf( - "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), - "blockCode" to stadiumDetailViewModel.blockCode - ) - ), - onSuccess = { sharingIntent -> - context.startActivity(sharingIntent) - } - ) - } - ) } - else -> Unit + StadiumDetailReviewViewPager( + context = context, + reviews = uiState.topReviewImages, + position = reviewIndex, + isFirstLike = isFirstLikeState, + pagerState = pagerState, + pageIndex = pageIndex, + bottomPadding = bottomPadding, + modifier = modifier, + onClickLike = { id -> + onClickLike() + isFirstLikeState = false + stadiumDetailViewModel.updateLike(id) + }, + onClickScrap = onClickScrap, + onClickShare = { imagePosition -> + onClickShare() + KakaoUtils().share( + context, + seatFeed( + title = uiState.kakaoShareSeatFeedTitle(pageIndex), + description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", + imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, + queryParams = mapOf( + "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), + "blockCode" to stadiumDetailViewModel.blockCode + ) + ), + onSuccess = { sharingIntent -> + context.startActivity(sharingIntent) + } + ) + } + ) } + + else -> Unit } } @@ -113,6 +111,6 @@ private fun StadiumDetailPictureTopScreenPreview() { reviewIndex = 0, bottomPadding = 0f, isFirstLike = false, - reviews = StadiumDetailUiState.Empty, + uiState = StadiumDetailUiState.Empty, ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt index b3b68068..c6e6c345 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/compose/detailpicture/top/StadiumDetailPictureMainScreen.kt @@ -30,100 +30,97 @@ fun StadiumDetailPictureMainScreen( reviewIndex: Int, bottomPadding: Float, isFirstLike: Boolean, - reviews: StadiumDetailUiState, + uiState: StadiumDetailUiState, modifier: Modifier = Modifier, stadiumDetailViewModel: StadiumDetailViewModel = viewModel(), onClickLike: () -> Unit = {}, onClickScrap: (id: Long) -> Unit = {}, onClickShare: () -> Unit = {} ) { - reviews.let { uiState -> - when (uiState) { - is StadiumDetailUiState.ReviewsData -> { - val visited = remember { - mutableStateListOf( - *List(uiState.reviews.size) { false }.toTypedArray() - ) - } - - if (uiState.reviews.size - visited.size > 0) { - visited.addAll(List(uiState.reviews.size - visited.size) { false }) - } + when(uiState) { + is StadiumDetailUiState.ReviewsData -> { + val visited = remember { + mutableStateListOf( + *List(uiState.reviews.size) { false }.toTypedArray() + ) + } - val initPage by remember { - mutableStateOf(uiState.reviews.indexOfFirst { it.id == reviewId }) - } + if (uiState.reviews.size - visited.size > 0) { + visited.addAll(List(uiState.reviews.size - visited.size) { false }) + } - val pagerState = rememberPagerState( - pageCount = { uiState.reviews.size }, - initialPage = initPage - ) + val initPage by remember { + mutableStateOf(uiState.reviews.indexOfFirst { it.id == reviewId }) + } - var pageIndex by remember { - mutableStateOf(0) - } + val pagerState = rememberPagerState( + pageCount = { uiState.reviews.size }, + initialPage = initPage + ) - var isFirstLikeState by remember { - mutableStateOf(isFirstLike) - } + var pageIndex by remember { + mutableStateOf(0) + } - LaunchedEffect(key1 = pagerState) { - snapshotFlow { pagerState.currentPage }.collect { - pageIndex = it - stadiumDetailViewModel.updateCurrentIndex(it) - if (visited[it]) return@collect + var isFirstLikeState by remember { + mutableStateOf(isFirstLike) + } - if (it == initPage) { - visited[it] = true - } + LaunchedEffect(key1 = pagerState) { + snapshotFlow { pagerState.currentPage }.collect { + pageIndex = it + stadiumDetailViewModel.updateCurrentIndex(it) + if (visited[it]) return@collect - if (!visited[it]) { - visited[it] = true - } + if (it == initPage) { + visited[it] = true } - } - StadiumDetailReviewViewPager( - context = context, - reviews = uiState.reviews, - visited = visited, - position = reviewIndex, - isFirstLike = isFirstLikeState, - hasNext = uiState.hasNext, - pagerState = pagerState, - pageIndex = pageIndex, - bottomPadding = bottomPadding, - modifier = modifier, - onLoadPaging = stadiumDetailViewModel::getBlockReviews, - onClickLike = { id -> - onClickLike() - isFirstLikeState = false - stadiumDetailViewModel.updateLike(id) - }, - onClickScrap = onClickScrap, - onClickShare = { imagePosition -> - onClickShare() - KakaoUtils().share( - context, - seatFeed( - title = uiState.kakaoShareSeatFeedTitle(pageIndex), - description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", - imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, - queryParams = mapOf( - "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), - "blockCode" to stadiumDetailViewModel.blockCode - ) - ), - onSuccess = { sharingIntent -> - context.startActivity(sharingIntent) - } - ) + if (!visited[it]) { + visited[it] = true } - ) + } } - else -> Unit + StadiumDetailReviewViewPager( + context = context, + reviews = uiState.reviews, + visited = visited, + position = reviewIndex, + isFirstLike = isFirstLikeState, + hasNext = uiState.hasNext, + pagerState = pagerState, + pageIndex = pageIndex, + bottomPadding = bottomPadding, + modifier = modifier, + onLoadPaging = stadiumDetailViewModel::getBlockReviews, + onClickLike = { id -> + onClickLike() + isFirstLikeState = false + stadiumDetailViewModel.updateLike(id) + }, + onClickScrap = onClickScrap, + onClickShare = { imagePosition -> + onClickShare() + KakaoUtils().share( + context, + seatFeed( + title = uiState.kakaoShareSeatFeedTitle(pageIndex), + description = "출처 : ${uiState.reviews[pageIndex].member.nickname}", + imageUrl = uiState.reviews[pageIndex].images[imagePosition].url, + queryParams = mapOf( + "stadiumId" to stadiumDetailViewModel.stadiumId.toString(), + "blockCode" to stadiumDetailViewModel.blockCode + ) + ), + onSuccess = { sharingIntent -> + context.startActivity(sharingIntent) + } + ) + } + ) } + else -> Unit } } @@ -136,6 +133,6 @@ private fun StadiumDetailPictureMainScreenPreview() { reviewIndex = 0, bottomPadding = 0f, isFirstLike = false, - reviews = StadiumDetailUiState.Empty, + uiState = StadiumDetailUiState.Empty, ) } \ No newline at end of file From 8ecb2dbd40c6f17f85307cf98747db62f917a065 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 25 Aug 2024 00:55:03 +0900 Subject: [PATCH 15/15] =?UTF-8?q?[feat/#110]=20SpotSnackBar=20bottom=20pad?= =?UTF-8?q?ding=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dpm/designsystem/SpotSnackBar.kt | 22 +++++-- .../src/main/res/layout/spot_snackbar.xml | 58 +++++++++++-------- .../StadiumDetailPictureFragment.kt | 11 ++-- 3 files changed, 59 insertions(+), 32 deletions(-) diff --git a/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt b/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt index 45aaea22..84a5feda 100644 --- a/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt +++ b/core/designsystem/src/main/java/com/dpm/designsystem/SpotSnackBar.kt @@ -2,22 +2,26 @@ package com.dpm.designsystem import android.graphics.Paint import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import androidx.core.content.ContextCompat import com.depromeet.designsystem.R import com.depromeet.designsystem.databinding.SpotSnackbarBinding +import com.dpm.designsystem.extension.dpToPx import com.google.android.material.snackbar.Snackbar + class SpotSnackBar( view: View, private val snackBarBackground: Int, private val message: String, + private val marginBottom: Int, private val endMessage: String, private val onClick: () -> Unit ) { companion object { - fun make(view: View, background: Int = R.drawable.rect_transfer_black_03_fill_60, message: String = "", endMessage: String = "", onClick: () -> Unit) = - SpotSnackBar(view = view, snackBarBackground = background, message= message, endMessage = endMessage, onClick = onClick) + fun make(view: View, background: Int = R.drawable.rect_transfer_black_03_fill_60, marginBottom: Int = 0, message: String = "", endMessage: String = "", onClick: () -> Unit) = + SpotSnackBar(view = view, snackBarBackground = background, marginBottom = marginBottom, message= message, endMessage = endMessage, onClick = onClick) } private val context = view.context @@ -34,14 +38,24 @@ class SpotSnackBar( private fun initView() { with(snackbarLayout) { removeAllViews() - setPadding(0, 0, 0, 0) - setBackgroundResource(snackBarBackground) + setPadding(0, 0, 0, marginBottom.dpToPx(context)) + setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)) addView(snackbarBinding.root, 0) + + setOnTouchListener { v, event -> + if (event.action == MotionEvent.ACTION_UP) { + v.performClick() + true + } else { + false + } + } } with(snackbarBinding) { tvDescription.text = message tvTrigger.paintFlags = Paint.UNDERLINE_TEXT_FLAG tvTrigger.text = endMessage + clContainer.setBackgroundResource(snackBarBackground) } } diff --git a/core/designsystem/src/main/res/layout/spot_snackbar.xml b/core/designsystem/src/main/res/layout/spot_snackbar.xml index 54b742c4..a0011f5b 100644 --- a/core/designsystem/src/main/res/layout/spot_snackbar.xml +++ b/core/designsystem/src/main/res/layout/spot_snackbar.xml @@ -4,34 +4,44 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - tools:background="@drawable/rect_transfer_black_03_fill_60"> + android:background="@android:color/transparent"> - + tools:background="@drawable/rect_transfer_black_03_fill_60"> - + + + + \ No newline at end of file diff --git a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt index ccf91b6e..9cf51f90 100644 --- a/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt +++ b/presentation/src/main/java/com/dpm/presentation/viewfinder/StadiumDetailPictureFragment.kt @@ -91,6 +91,9 @@ class StadiumDetailPictureFragment : BindingFragment