From 3e7fc7f6f9a92adb1435132616adb969b872f37b Mon Sep 17 00:00:00 2001 From: JiWoo1261 Date: Thu, 17 Jul 2025 11:02:24 +0900 Subject: [PATCH 1/2] =?UTF-8?q?mod/#121=20:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/designsystem/component/CourseCard.kt | 55 ++++++++++--------- .../dto/response/ArchivedListResponseDto.kt | 8 ++- .../data/dto/response/SavedListResponseDto.kt | 8 ++- .../entity/archivedlist/ArchivedListEntity.kt | 4 +- .../model/entity/savedlist/SavedListEntity.kt | 4 +- .../ui/mypage/ArchivedCourseListScreen.kt | 6 +- .../presentation/ui/mypage/MyPageScreen.kt | 10 +++- .../ui/mypage/PetProfileScreen.kt | 39 ++++++------- .../ui/mypage/viewmodel/MyPageViewModel.kt | 3 +- .../ui/mypage/viewmodel/SavedListViewModel.kt | 2 +- 10 files changed, 80 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/paw/key/core/designsystem/component/CourseCard.kt b/app/src/main/java/com/paw/key/core/designsystem/component/CourseCard.kt index 1abdc3c6..f4266e60 100644 --- a/app/src/main/java/com/paw/key/core/designsystem/component/CourseCard.kt +++ b/app/src/main/java/com/paw/key/core/designsystem/component/CourseCard.kt @@ -34,9 +34,10 @@ fun CourseCard( postId: Int, title: String, createdAt: String, - isLiked: Boolean, + isLiked: Boolean? = null, // 저장한 루트에서만 사용 + isPublic: Boolean? = null, // 기록한 루트에서만 사용 onClickItem: () -> Unit, - onClickLike: (Boolean) -> Unit, + onClickLike: ((Boolean) -> Unit)? = null, // null이면 클릭 불가 petName: String, modifier: Modifier = Modifier, representativeImageUrl: String? = null, @@ -127,21 +128,6 @@ fun CourseCard( .clip(CircleShape), contentScale = ContentScale.Crop ) - } else { - Box( - modifier = Modifier - .size(40.dp) - .clip(CircleShape) - .background(PawKeyTheme.colors.gray200), - contentAlignment = Alignment.Center - ) { - Icon( - imageVector = ImageVector.vectorResource(id = R.drawable.ic_heart_default), - contentDescription = null, - tint = PawKeyTheme.colors.gray400, - modifier = Modifier.size(20.dp) - ) - } } Spacer(modifier = Modifier.width(10.dp)) @@ -170,15 +156,32 @@ fun CourseCard( Spacer(modifier = Modifier.weight(1f)) - Icon( - imageVector = if (isLiked) - ImageVector.vectorResource(id = R.drawable.ic_heart_filled) - else - ImageVector.vectorResource(id = R.drawable.ic_heart_default), - contentDescription = "좋아요", - tint = Color.Unspecified, - modifier = Modifier.clickable { onClickLike(!isLiked) } //클릭하면 외부에 알려줌 - ) + when { + isLiked != null -> { + Icon( + imageVector = if (isLiked) + ImageVector.vectorResource(id = R.drawable.ic_heart_filled) + else + ImageVector.vectorResource(id = R.drawable.ic_heart_default), + contentDescription = "좋아요", + tint = Color.Unspecified, + modifier = Modifier.clickable { + onClickLike?.invoke(!isLiked) + } + ) + } + + isPublic != null -> { + Icon( + imageVector = if (isPublic) + ImageVector.vectorResource(id = R.drawable.ic_eye_filled_valid) + else + ImageVector.vectorResource(id = R.drawable.ic_eye_filled_invalid), + contentDescription = "공개여부", + tint = Color.Unspecified + ) + } + } } } diff --git a/app/src/main/java/com/paw/key/data/dto/response/ArchivedListResponseDto.kt b/app/src/main/java/com/paw/key/data/dto/response/ArchivedListResponseDto.kt index 9e3f4bf9..5e57f361 100644 --- a/app/src/main/java/com/paw/key/data/dto/response/ArchivedListResponseDto.kt +++ b/app/src/main/java/com/paw/key/data/dto/response/ArchivedListResponseDto.kt @@ -24,6 +24,10 @@ data class ArchivedDto( val createdAt: String, @SerialName("isLike") val isLike: Boolean, + @SerialName("isPublic") + val isPublic: Boolean, + @SerialName("isMine") + val isMine: Boolean, @SerialName("title") val title: String, @SerialName("representativeImageUrl") @@ -43,7 +47,9 @@ data class ArchivedDto( representativeImageUrl = representativeImageUrl ?: "", routeId = routeId.toLong(), writer = listOf(writer.toEntity()), - descriptionTags = descriptionTags + descriptionTags = descriptionTags, + isPublic = isPublic, + isMine = isMine ) } diff --git a/app/src/main/java/com/paw/key/data/dto/response/SavedListResponseDto.kt b/app/src/main/java/com/paw/key/data/dto/response/SavedListResponseDto.kt index 8294b16b..0f251a0d 100644 --- a/app/src/main/java/com/paw/key/data/dto/response/SavedListResponseDto.kt +++ b/app/src/main/java/com/paw/key/data/dto/response/SavedListResponseDto.kt @@ -27,6 +27,10 @@ data class SavedDto( val createdAt: String, @SerialName("isLike") val isLike: Boolean, + @SerialName("isPublic") + val isPublic: Boolean, + @SerialName("isMine") + val isMine: Boolean, @SerialName("title") val title: String, @SerialName("representativeImageUrl") @@ -46,7 +50,9 @@ data class SavedDto( representativeImageUrl = representativeImageUrl ?: "", routeId = routeId, writer = writer.toEntity(), - descriptionTags = descriptionTags + descriptionTags = descriptionTags, + isPublic = true, + isMine = true ) } diff --git a/app/src/main/java/com/paw/key/domain/model/entity/archivedlist/ArchivedListEntity.kt b/app/src/main/java/com/paw/key/domain/model/entity/archivedlist/ArchivedListEntity.kt index 7b7db616..0991d661 100644 --- a/app/src/main/java/com/paw/key/domain/model/entity/archivedlist/ArchivedListEntity.kt +++ b/app/src/main/java/com/paw/key/domain/model/entity/archivedlist/ArchivedListEntity.kt @@ -12,7 +12,9 @@ data class ArchivedListEntity( val representativeImageUrl: String, val routeId: Long, val writer: List, - val descriptionTags: List + val descriptionTags: List, + val isPublic: Boolean, + val isMine: Boolean ) data class WriterEntity( diff --git a/app/src/main/java/com/paw/key/domain/model/entity/savedlist/SavedListEntity.kt b/app/src/main/java/com/paw/key/domain/model/entity/savedlist/SavedListEntity.kt index 817a53c5..9c62d099 100644 --- a/app/src/main/java/com/paw/key/domain/model/entity/savedlist/SavedListEntity.kt +++ b/app/src/main/java/com/paw/key/domain/model/entity/savedlist/SavedListEntity.kt @@ -12,7 +12,9 @@ data class SavedListEntity( val representativeImageUrl: String, val routeId: Int, val writer: SavedWriterEntity, - val descriptionTags: List + val descriptionTags: List, + val isPublic: Boolean, + val isMine: Boolean ) data class SavedWriterEntity( val userId: Int, diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/ArchivedCourseListScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/ArchivedCourseListScreen.kt index 002c78ae..d2abbd56 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/ArchivedCourseListScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/ArchivedCourseListScreen.kt @@ -73,10 +73,10 @@ fun ArchivedCourseListScreen( petName = item.writer.first().petName, petProfileImageUrl = item.writer.first().petProfileImageUrl, descriptionTags = item.descriptionTags, - isLiked = item.isLiked, + isLiked = null, + isPublic = item.isPublic, // 눈아이콘만 표시 onClickItem = navigateNext, - onClickLike = {} - + onClickLike = null ) } } diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt index 6094be7c..53c2e1a4 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt @@ -107,7 +107,11 @@ fun MyPageScreen( PetCard( name = state.petName, age = state.petAge, - gender = state.petGender, + gender = if (state.petGender == "M") { + "남아" + } else { + "여아" + }, tags = state.petTags, walkCount = state.walkCount, totalDistance = state.totalDistance, @@ -261,7 +265,7 @@ fun PetCard( ) { Text("산책 횟수", style = PawKeyTheme.typography.caption12Sb1) Text( - walkCount, + text = "${walkCount}회", style = PawKeyTheme.typography.head20Sb, color = PawKeyTheme.colors.green500 ) @@ -358,7 +362,7 @@ private fun MyPageScreenPreview() { petAge = "12세", petGender = "여아", petTags = listOf("조금 느긋해요", "#오토바이소리", "#대형견"), - walkCount = "7회", + walkCount = "7", totalDistance = "14km" ), paddingValues = PaddingValues(), diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/PetProfileScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/PetProfileScreen.kt index 09d178dd..025fa2c2 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/PetProfileScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/PetProfileScreen.kt @@ -62,13 +62,19 @@ fun PetProfileScreen( energyLevel: String, socialLevel: String ) { + // 여기서 바로 가공 + val displayGender = when (gender.uppercase()) { + "M" -> "남아" + "F" -> "여아" + else -> gender + } + Column( modifier = modifier .fillMaxSize() .padding(horizontal = 20.dp) ) { - TopBar(title = "반려견 프로필", - onBackClick = { navigateUp() }) + TopBar(title = "반려견 프로필", onBackClick = navigateUp) Spacer(modifier = Modifier.height(40.dp)) @@ -92,11 +98,9 @@ fun PetProfileScreen( Spacer(modifier = Modifier.height(36.dp)) - // 정보 항목 PetProfileItem(label = "이름", value = name) - PetProfileItem(label = "성별", value = gender) + PetProfileItem(label = "성별", value = displayGender) - // 중성화 여부 (단일 텍스트) Text( text = "중성화했어요", style = PawKeyTheme.typography.caption12Sb2, @@ -107,7 +111,6 @@ fun PetProfileScreen( PetProfileItem(label = "견종", value = breed) PetProfileItem(label = "나이", value = age) - // 성향 Text( text = "성향", style = PawKeyTheme.typography.body14Sb, @@ -158,28 +161,22 @@ fun PetProfileScreen( Spacer(modifier = Modifier.weight(1f)) } } - @Composable fun PetProfileItem( label: String, - value: String, - modifier: Modifier = Modifier + value: String ) { - Column(modifier = modifier.padding(vertical = 8.dp)) { + Column(modifier = Modifier.padding(start = 16.dp, bottom = 8.dp)) { Text( text = label, - style = PawKeyTheme.typography.body14Sb, - modifier = Modifier.padding(start = 16.dp) + style = PawKeyTheme.typography.body14R, + color = PawKeyTheme.colors.gray600 + ) + Text( + text = value, + style = PawKeyTheme.typography.head18Sb, + color = PawKeyTheme.colors.black ) - if (value.isNotEmpty()) { - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = value, - style = PawKeyTheme.typography.head18Sb, - color = PawKeyTheme.colors.green500, - modifier = Modifier.padding(start = 16.dp) - ) - } } } diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt index 112064ec..440461b4 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt @@ -51,7 +51,8 @@ class MyPageViewModel @Inject constructor( petAge = it.first().age.toString(), petGender = it.first().gender, petImageUrl = it.first().imageUrl, - petTags = it.first().traits.map { trait -> trait.category } + petTags = it.first().traits.map { trait -> trait.option}, + walkCount = it.first().walkCount.toString() ) }.onFailure { _sideEffect.emit(MyPageSideEffect.ShowSnackBar("펫 프로필 불러오기 실패")) diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt index 4c23009a..57e77aeb 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt @@ -42,7 +42,7 @@ class SavedListViewModel @Inject constructor( .onSuccess { result -> _state.update { it.copy( - courseList = result.posts + courseList = result.posts.filter { post -> !post.isMine } ) } } From 46c4a457817ba6a2dda2ddbb4b9c6c0b408a80df Mon Sep 17 00:00:00 2001 From: JiWoo1261 Date: Thu, 17 Jul 2025 14:50:41 +0900 Subject: [PATCH 2/2] =?UTF-8?q?mod/#121=20:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20api=20=EC=97=B0=EB=8F=99=20=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/mypage/MyPageScreen.kt | 11 ++-- .../ui/mypage/SavedCourseListScreen.kt | 8 +++ .../ui/mypage/state/MyPageContract.kt | 2 +- .../ui/mypage/viewmodel/MyPageViewModel.kt | 4 +- .../mypage/viewmodel/PetProfileViewModel.kt | 2 +- .../ui/mypage/viewmodel/SavedListViewModel.kt | 54 ++++++++++++++++++- 6 files changed, 72 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt index 53c2e1a4..f7f5d57a 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/MyPageScreen.kt @@ -52,8 +52,13 @@ fun MyPageRoute( LaunchedEffect(Unit) { viewModel.getUserProfiles(userId = userId.first()) - viewModel.getMyPagePetProfiles(userId = userId.first()) + viewModel.getPetProfiles(userId = userId.first()) } +// LaunchedEffect(Unit) { +// val userId = 2 // ← 임시 테스트용 +// viewModel.getUserProfiles(userId = userId) +// viewModel.getPetProfiles(userId = userId) +// } MyPageScreen( state = state.value, @@ -168,7 +173,7 @@ fun PetCard( gender: String, tags: List, image: String, - walkCount: String, + walkCount: Int, totalDistance: String, navigatePetProfile: () -> Unit, modifier: Modifier = Modifier @@ -362,7 +367,7 @@ private fun MyPageScreenPreview() { petAge = "12세", petGender = "여아", petTags = listOf("조금 느긋해요", "#오토바이소리", "#대형견"), - walkCount = "7", + walkCount = 7, totalDistance = "14km" ), paddingValues = PaddingValues(), diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/SavedCourseListScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/SavedCourseListScreen.kt index 74a0617d..3b74f016 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/SavedCourseListScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/SavedCourseListScreen.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -13,8 +14,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.paw.key.core.designsystem.component.CourseCard import com.paw.key.core.designsystem.component.TopBar import com.paw.key.core.designsystem.theme.PawKeyTheme +import com.paw.key.core.util.PreferenceDataStore import com.paw.key.presentation.ui.mypage.state.SavedListState import com.paw.key.presentation.ui.mypage.viewmodel.SavedListViewModel +import kotlinx.coroutines.flow.first @Composable fun SavedCourseRoute( @@ -24,6 +27,11 @@ fun SavedCourseRoute( viewModel: SavedListViewModel = hiltViewModel() ) { val state = viewModel.state.collectAsStateWithLifecycle() + val userId = PreferenceDataStore.getUserId() +// LaunchedEffect(Unit) { +// viewModel.getSavedList(userId = userId.first()) +// } + SavedCourseListScreen( state = state.value, diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/state/MyPageContract.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/state/MyPageContract.kt index 48231563..fd8f4628 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/state/MyPageContract.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/state/MyPageContract.kt @@ -10,7 +10,7 @@ import androidx.compose.runtime.Immutable val petGender: String = "여아", val petImageUrl: String = "", val petTags: List = listOf("조금 느긋해요", "#오토바이소리", "#대형견"), - val walkCount: String = "7회", + val walkCount: Int = 0, val totalDistance: String = "14km" ) diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt index 440461b4..aec2867d 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/MyPageViewModel.kt @@ -42,7 +42,7 @@ class MyPageViewModel @Inject constructor( } } - fun getMyPagePetProfiles(userId: Int) { + fun getPetProfiles(userId: Int) { viewModelScope.launch { petProfileRepository.getPetProfiles(userId) .onSuccess { @@ -52,7 +52,7 @@ class MyPageViewModel @Inject constructor( petGender = it.first().gender, petImageUrl = it.first().imageUrl, petTags = it.first().traits.map { trait -> trait.option}, - walkCount = it.first().walkCount.toString() + walkCount = it.first().walkCount ) }.onFailure { _sideEffect.emit(MyPageSideEffect.ShowSnackBar("펫 프로필 불러오기 실패")) diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/PetProfileViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/PetProfileViewModel.kt index 2c4c8046..6fc953bd 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/PetProfileViewModel.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/PetProfileViewModel.kt @@ -41,7 +41,7 @@ class PetProfileViewModel @Inject constructor( gender = result.first().gender, breed = result.first().breed, age = result.first().age.toString(), - energyLevel = result.first().traits.first().category, + energyLevel = result.first().traits.first().option, socialLevel = result.first().traits.first().option ) } diff --git a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt index 57e77aeb..d0b5a030 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/mypage/viewmodel/SavedListViewModel.kt @@ -42,7 +42,7 @@ class SavedListViewModel @Inject constructor( .onSuccess { result -> _state.update { it.copy( - courseList = result.posts.filter { post -> !post.isMine } + courseList = result.posts ) } } @@ -79,4 +79,54 @@ class SavedListViewModel @Inject constructor( savedListRepository.getSavedList(userId = 2) } } -} \ No newline at end of file +} + +//@HiltViewModel +//class SavedListViewModel @Inject constructor( +// private val savedListRepository: SavedListRepository, +// private val likeRepository: LikeRepository +//) : ViewModel() { +// +// private val _state = MutableStateFlow(SavedListState()) +// val state: StateFlow = _state.asStateFlow() +// +// private val _sideEffect = MutableSharedFlow() +// val sideEffect: MutableSharedFlow = _sideEffect +// +// // ✅ 테스트용 고정 유저 ID +// private val testUserId = 2 +// +// init { +// getSavedList(testUserId) +// } +// +// // ✅ 하드코딩된 userId 사용 +// fun getSavedList(userId: Int) { +// viewModelScope.launch { +// savedListRepository.getSavedList(userId) +// .onSuccess { result -> +// _state.update { +// it.copy(courseList = result.posts) +// } +// } +// .onFailure { e -> +// Log.e("SavedListViewModel", "저장한 게시물 불러오기 실패", e) +// _sideEffect.emit(SavedListSideEffect.ShowSnackBar(e.message ?: "알 수 없는 오류")) +// } +// } +// } +// +// // ✅ 테스트용 좋아요 토글 +// fun toggleLike(postId: Int, isLiked: Boolean) { +// viewModelScope.launch { +// if (isLiked) { +// likeRepository.unlikeCourse(userId = testUserId, postId = postId) +// } else { +// likeRepository.likeCourse(userId = testUserId, postId = postId) +// } +// +// // 갱신 +// getSavedList(testUserId) +// } +// } +//} \ No newline at end of file