Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,24 @@ import coil.request.ImageRequest
import com.paw.key.R
import com.paw.key.core.designsystem.theme.PawKeyTheme
import com.paw.key.core.designsystem.theme.Gray100
import com.paw.key.core.util.noRippleClickable
import com.paw.key.domain.model.entity.walklist.CategoryTop3Entity
import kotlinx.serialization.json.JsonNull.content

@Composable
fun CourseDetail(
title : String,
petName : String,
date : String,
location : String,
isLike : Boolean,
content : String,
onClickLike: (Boolean) -> Unit,
petProfileImage : String,
routeMapImageUrl : String,
categorySummary : List<String>,
categoryTop3 : List<CategoryTop3Entity>,
totalReviewCount : Int,
walkingImageUrls : List<String>,

content: String,
onImageClick: (String) -> Unit,
modifier: Modifier = Modifier
) {
Expand Down Expand Up @@ -110,16 +111,18 @@ fun CourseDetail(
)

Icon(
imageVector = if (isLiked.value) {
ImageVector.vectorResource(id = R.drawable.ic_eye_linear_gray_valid)
} else {
ImageVector.vectorResource(id = R.drawable.ic_eye_linear_gray_invalid)
},
imageVector = if (isLiked.value)
ImageVector.vectorResource(id = R.drawable.ic_heart_filled)
else
ImageVector.vectorResource(id = R.drawable.ic_heart_default),
contentDescription = "좋아요",
tint = Color.Unspecified,
modifier = Modifier.clickable {
isLiked.value = !isLiked.value
}
modifier = Modifier
.size(24.dp)
.noRippleClickable {
isLiked.value = !isLiked.value // 로컬 상태 먼저 변경
onClickLike(!isLiked.value) // 변경된 값을 넘김
}
)
}

Expand Down Expand Up @@ -324,43 +327,22 @@ fun CourseDetailPreview() {
petName = "핑구",
date = "2025/06/30",
location = "홍대입구역",
isLike = true,
content = "산책로가 깨끗하고 벚꽃이 예뻐요!",
onClickLike = {},
petProfileImage = "https://pawkey-server.com/image/profile.png",
routeMapImageUrl = "https://pawkey-server.com/image/map.png",
categoryTop3 = listOf(
CategoryTop3Entity(
rank = 1,
optionText = "산책로가 어쩌구 저꾸",
percentage = 42,
categoryName = "산책로가 어쩌구 저꾸",
categoryOptionId = 1,
categoryId = 2
),
CategoryTop3Entity(
rank = 2,
optionText = "산책로가 어쩌구 저꾸",
percentage = 37,
categoryName = "산책로가 어쩌구 저꾸",
categoryOptionId = 1,
categoryId = 2
),
CategoryTop3Entity(
rank = 3,
optionText = "산책로가 어쩌구 저꾸",
percentage = 35,
categoryName = "산책로가 어쩌구 저꾸",
categoryOptionId = 1,
categoryId = 2
)
CategoryTop3Entity(rank = 1, optionText = "산책로가 어쩌구 저꾸", percentage = 42, categoryName = "", categoryOptionId = 1, categoryId = 2),
CategoryTop3Entity(rank = 2, optionText = "풍경이 예뻐요", percentage = 37, categoryName = "", categoryOptionId = 1, categoryId = 2),
CategoryTop3Entity(rank = 3, optionText = "깨끗해요", percentage = 35, categoryName = "", categoryOptionId = 1, categoryId = 2)
),
totalReviewCount = 42,
walkingImageUrls = listOf(
"https://pawkey-server.com/image/walk1.jpg",
"https://pawkey-server.com/image/walk2.jpg"
),
categorySummary = listOf("안전", "편리성"),
onImageClick = {},
content = "산책로가 깨끗하고 벚꽃이 예뻐요!",
onImageClick = {}
)
}
}
8 changes: 8 additions & 0 deletions app/src/main/java/com/paw/key/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.paw.key.data.di

import com.paw.key.data.repositoryimpl.ArchivedListRepositoryImpl
import com.paw.key.data.repositoryimpl.DummyRepositoryImpl
import com.paw.key.data.repositoryimpl.LikeRepositoryImpl
import com.paw.key.data.repositoryimpl.PetProfileRepositoryImpl
import com.paw.key.data.repositoryimpl.onboarding.OnboardingInfoRepositoryImpl
import com.paw.key.data.repositoryimpl.onboarding.OnboardingRegionRepositoryImpl
Expand All @@ -19,6 +20,7 @@ import com.paw.key.data.repositoryimpl.walklist.WalkListDetailRepositoryImpl
import com.paw.key.data.repositoryimpl.walkreview.WalkReviewRepositoryImpl
import com.paw.key.domain.repository.ArchivedListRepository
import com.paw.key.domain.repository.DummyRepository
import com.paw.key.domain.repository.LikeRepository
import com.paw.key.domain.repository.onboarding.OnboardingInfoRepository
import com.paw.key.domain.repository.onboarding.OnboardingRegionRepository
import com.paw.key.domain.repository.onboarding.OnboardingRepository
Expand Down Expand Up @@ -124,6 +126,12 @@ interface RepositoryModule {
impl: ArchivedListRepositoryImpl
): ArchivedListRepository

@Binds
@Singleton
fun bindLikeRepository(
impl: LikeRepositoryImpl
): LikeRepository

@Binds
@Singleton
fun bindWalkReviewRepository(
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/paw/key/data/di/ServiceModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.paw.key.data.di

import com.paw.key.data.service.ArchivedListService
import com.paw.key.data.service.DummyService
import com.paw.key.data.service.LikeService
import com.paw.key.data.service.PetProfileService
import com.paw.key.data.service.onboarding.OnboardingInfoService
import com.paw.key.data.service.onboarding.OnboardingPetsService
Expand Down Expand Up @@ -89,6 +90,11 @@ object ServiceModule {
fun provideArchivedListService(retrofit: Retrofit): ArchivedListService =
retrofit.create()

@Provides
@Singleton
fun provideLikeService(retrofit: Retrofit): LikeService =
retrofit.create()

@Provides
@Singleton
fun provideWalkReviewService(retrofit: Retrofit): WalkReviewService =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ data class ArchivedDto(
val descriptionTags: List<String>
) {
fun toEntity() = ArchivedListEntity(
postId = postId.toLong(),
postId = postId,
createdAt = createdAt,
isLiked = isLike,
title = title,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.paw.key.data.repositoryimpl

import com.paw.key.data.remote.datasource.LikeDataSource
import com.paw.key.domain.repository.LikeRepository
import javax.inject.Inject

class LikeRepositoryImpl @Inject constructor(
private val dataSource: LikeDataSource
) : LikeRepository {

override suspend fun likeCourse(userId: Int, courseId: Int): Result<Unit> {
return try {
dataSource.likeCourse(userId, courseId)
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
}

override suspend fun unlikeCourse(userId: Int, courseId: Int): Result<Unit> {
return try {
dataSource.unlikeCourse(userId, courseId)
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
}
}
1 change: 1 addition & 0 deletions app/src/main/java/com/paw/key/data/service/LikeService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import retrofit2.http.POST
import retrofit2.http.Path

interface LikeService {

@POST("/api/v1/likes/{courseId}")
suspend fun likeCourse(
@Header("X-USER-ID") userId: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ data class ArchivedListPostsEntity(
)

data class ArchivedListEntity(
val postId: Long,
val postId: Int,
val createdAt: String,
val isLiked: Boolean,
val title: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,14 @@ package com.paw.key.presentation.ui.course.entire.tab.map.List
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
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.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand All @@ -41,7 +31,8 @@ import com.paw.key.presentation.ui.course.entire.tab.map.List.viewmodel.TapListV
private fun PreviewTabListScreen() {
PawKeyTheme {
TabListScreen(
navigateToDetail = {}
navigateToDetail = {},
onClickLike = { _, _ -> }
)
}
}
Expand All @@ -55,7 +46,10 @@ fun TapListRoute(
TabListScreen(
modifier = modifier,
navigateToDetail = navigateToDetail,
viewModel = viewModel
viewModel = viewModel,
onClickLike = { postId, isLiked ->
viewModel.toggleLike(postId = postId, isLiked = isLiked)
}
)
}

Expand All @@ -64,13 +58,13 @@ fun TabListScreen(
navigateToDetail: () -> Unit,
modifier: Modifier = Modifier,
viewModel: TapListViewModel = hiltViewModel(),
onClickLike: (postId: Int, isLiked: Boolean) -> Unit
) {
var showBottomSheet by remember { mutableStateOf(false) }
val listState by viewModel.state.collectAsStateWithLifecycle()

Column(
modifier = modifier
.fillMaxSize()
modifier = modifier.fillMaxSize()
) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
Expand All @@ -84,10 +78,9 @@ fun TabListScreen(
imageVector = ImageVector.vectorResource(R.drawable.ic_course_optin_filter),
contentDescription = "filter",
tint = Color.Unspecified,
modifier = Modifier
.noRippleClickable {
showBottomSheet = true
}
modifier = Modifier.noRippleClickable {
showBottomSheet = true
}
)
OptionChip(
text = if (viewModel.isFilterApplied()) "필터 적용됨" else "선택한 옵션이 없어요",
Expand All @@ -101,10 +94,6 @@ fun TabListScreen(
.background(PawKeyTheme.colors.white2)
.padding(bottom = 36.dp)
) {

// Todo : 나중에 서버용 리스트로 변경

// 로딩 상태 표시
if (listState.isLoading) {
item {
Box(
Expand Down Expand Up @@ -134,6 +123,7 @@ fun TabListScreen(
isLiked = post.isLike,
onClickLike = { isLiked ->
viewModel.toggleLike(post.postId, isLiked)

},
onClickItem = { navigateToDetail() }
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,20 @@ class TapListViewModel @Inject constructor(
fun isFilterApplied(): Boolean {
return isAllOptionsSelected()
}

fun toggleLike(postId: Int, isLiked: Boolean) {
viewModelScope.launch {
_state.update { state ->
val updatedPosts = state.postsResult?.posts?.map {
if (it.postId == postId) it.copy(isLike = isLiked) else it
} ?: emptyList()

val updatedPostsResult = state.postsResult?.copy(posts = updatedPosts)

state.copy(
postsResult = updatedPostsResult
)
}
}
}
}
Loading