[API] 모임방 참여 이후 활동들 api 연결#70
Conversation
|
Caution Review failedThe pull request is closed. Walkthrough이 변경 사항은 모임방(그룹룸) 상세 정보 및 독서메이트(룸 유저) API 연동, 관련 데이터 모델 및 서비스, 뷰모델, UI 컴포넌트, 네비게이션 구조를 전반적으로 도입 및 리팩터링합니다. 기존 목(mock) 데이터 구조는 삭제되고, 실제 서버 데이터를 바탕으로 동적 UI 상태 관리와 화면 전환이 구현되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as GroupRoomScreen
participant VM as GroupRoomViewModel
participant Repo as RoomsRepository
participant API as RoomsService
UI->>VM: fetchRoomsPlaying(roomId)
VM->>Repo: getRoomsPlaying(roomId)
Repo->>API: getRoomsPlaying(roomId)
API-->>Repo: BaseResponse<RoomsPlayingResponse>
Repo-->>VM: Result<RoomsPlayingResponse>
VM-->>UI: GroupRoomUiState.Success(roomsPlaying)
sequenceDiagram
participant UI as GroupRoomMatesScreen
participant VM as GroupRoomMatesViewModel
participant Repo as RoomsRepository
participant API as RoomsService
UI->>VM: fetchUsers(roomId)
VM->>Repo: getRoomsUsers(roomId)
Repo->>API: getRoomsUsers(roomId)
API-->>Repo: BaseResponse<RoomsUsersResponse>
Repo-->>VM: Result<RoomsUsersResponse>
VM-->>UI: GroupRoomMatesUiState.Success(users)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes해당 변경 사항 중 명확하게 요구 사항과 무관한 기능적 코드 변경은 발견되지 않았습니다. Possibly related PRs
Suggested reviewers
Poem
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 14
🔭 Outside diff range comments (1)
app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt (1)
57-106: 하드코딩된 목 데이터를 개선해야 합니다.
mySubscriptions리스트가 하드코딩되어 있고 모든 항목이 동일한roleColor를 사용합니다.다음 개선사항을 고려해보세요:
- 목 데이터를 별도 파일로 분리
- 다양한 장르 색상 사용으로 더 현실적인 데이터 구성
- 매개변수로 전달받아 동적으로 처리
@Composable fun FeedScreen( navController: NavController? = null, nickname: String = "", userRole: String = "", feeds: List<FeedItem> = emptyList(), totalFeedCount: Int = 0, selectedTabIndex: Int = 0, - followerProfileImageUrls: List<String> = emptyList() + followerProfileImageUrls: List<String> = emptyList(), + subscriptions: List<MySubscriptionData> = emptyList() ) { - val mySubscriptions = listOf( - // 하드코딩된 데이터들... - ) + val mySubscriptions = subscriptions.ifEmpty { + // 기본 목 데이터 또는 빈 리스트 + }
♻️ Duplicate comments (1)
app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt (1)
26-43: null 응답 처리 개선 필요
GroupRoomMatesViewModel과 동일한 null 처리 문제가 있습니다.roomsRepository.getRoomsPlaying(roomId = roomId) .onSuccess { roomsPlaying -> if (roomsPlaying != null) { _uiState.value = GroupRoomUiState.Success(roomsPlaying) + } else { + _uiState.value = GroupRoomUiState.Error( + "방 정보를 찾을 수 없습니다." + ) } }
🧹 Nitpick comments (9)
app/src/main/java/com/texthip/thip/ui/common/cards/CardNote.kt (1)
88-88: 타입 변환 로직을 간소화할 수 있습니다.현재
(percentage / 100f).toFloat()로 변환하고 있는데,percentage가 이미Double이므로 더 간단하게 표현할 수 있습니다.다음과 같이 간소화를 제안합니다:
- .fillMaxWidth(fraction = (percentage / 100f).toFloat()) + .fillMaxWidth(fraction = (percentage / 100).toFloat())app/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.kt (1)
36-36: TODO 주석을 해결해야 합니다.서버에서 색상 정보를 받아오는 것으로 변경하는 TODO가 남아있습니다.
이 TODO를 처리하는 새로운 이슈를 생성하거나 구현을 도와드릴까요?
app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt (1)
12-27:getOrThrow()사용 패턴을 검토해보세요.
runCatching블록 내에서getOrThrow()를 사용하는 것은 예외를 던진 후 즉시 잡는 패턴입니다.다음 중 하나를 고려해보세요:
옵션 1: getOrThrow() 제거
suspend fun getRoomsPlaying(roomId: Int) = runCatching { - roomsService.getRoomsPlaying(roomId = roomId).handleBaseResponse().getOrThrow() + roomsService.getRoomsPlaying(roomId = roomId).handleBaseResponse().getOrElse { throw it } }옵션 2: runCatching 제거 (handleBaseResponse가 이미 Result를 반환하는 경우)
-suspend fun getRoomsPlaying(roomId: Int) = runCatching { - roomsService.getRoomsPlaying(roomId = roomId).handleBaseResponse().getOrThrow() -} +suspend fun getRoomsPlaying(roomId: Int) = + roomsService.getRoomsPlaying(roomId = roomId).handleBaseResponse()app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt (1)
22-22: 주석 처리된 코드를 제거하세요.더 이상 사용하지 않는 주석 처리된 파라미터 라인을 제거하는 것이 좋습니다.
-// data: GroupRoomBodyDataapp/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt (1)
58-59: 주석 처리된 코드를 제거하세요사용하지 않는 주석 코드는 제거해야 합니다.
-// profileImage: Painter? = null, profileImage: String,app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (2)
79-82: TODO: 에러 메시지 스타일링 구현 필요에러 메시지에 적절한 스타일을 적용해야 합니다.
에러 화면 디자인 구현이 필요하시면 도움을 드릴 수 있습니다. 새 이슈를 생성할까요?
102-111: 이미지 URL 판별 로직 개선 제안현재 "_image" 접미사로 로컬/원격 이미지를 구분하는 방식은 취약합니다. 서버 응답에서 명시적으로 타입을 구분하는 것이 좋습니다.
향후 서버 응답에
imageType: "local" | "remote"필드를 추가하거나, 별도의 필드로 구분하는 것을 고려하세요.app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomHeader.kt (2)
32-42: 파라미터 구조 개선이 잘 되었습니다.개별 파라미터로 변경하여 유연성이 향상되었습니다. TODO 주석에 따라 서버에서 색상 정보가 추가되면 기본값을 제거해주세요.
119-121: 메이트 섹션 네비게이션이 구현되었습니다.클릭 가능한 영역이 적절히 설정되었습니다. Line 143의 참여자 목록 네비게이션 TODO도 향후 구현이 필요합니다.
Also applies to: 143-143
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
app/src/main/res/drawable/img_art.pngis excluded by!**/*.pngapp/src/main/res/drawable/img_humanities.pngis excluded by!**/*.pngapp/src/main/res/drawable/img_literature.pngis excluded by!**/*.pngapp/src/main/res/drawable/img_science_it.pngis excluded by!**/*.pngapp/src/main/res/drawable/img_social_science.pngis excluded by!**/*.png
📒 Files selected for processing (38)
app/src/main/java/com/texthip/thip/data/di/ServiceModule.kt(1 hunks)app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt(1 hunks)app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsUsersResponse.kt(1 hunks)app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt(1 hunks)app/src/main/java/com/texthip/thip/data/service/RoomsService.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/common/cards/CardNote.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/common/cards/CardVote.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/common/header/ProfileBarFeed.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt(2 hunks)app/src/main/java/com/texthip/thip/ui/group/note/component/CommentItem.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/group/note/component/VoteCommentCard.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomHeader.kt(8 hunks)app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomMatesList.kt(2 hunks)app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomBodyData.kt(0 hunks)app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomHeaderData.kt(0 hunks)app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomMateData.kt(0 hunks)app/src/main/java/com/texthip/thip/ui/group/room/mock/VoteData.kt(0 hunks)app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomMatesScreen.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomMatesViewModel.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/mypage/component/RoleCard.kt(2 hunks)app/src/main/java/com/texthip/thip/ui/mypage/component/SavedFeedCard.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageEditScreen.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/navigator/extensions/GroupNavigationExtensions.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/navigator/routes/GroupRoutes.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/signin/screen/SignupGenreScreen.kt(2 hunks)app/src/main/java/com/texthip/thip/ui/theme/Color.kt(3 hunks)app/src/main/java/com/texthip/thip/utils/type/GenreBackgroundImage.kt(1 hunks)app/src/main/java/com/texthip/thip/utils/type/GenreColor.kt(1 hunks)
💤 Files with no reviewable changes (4)
- app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomHeaderData.kt
- app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomMateData.kt
- app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomBodyData.kt
- app/src/main/java/com/texthip/thip/ui/group/room/mock/VoteData.kt
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/myPage/groupPage/GroupPageScreen.kt:34-37
Timestamp: 2025-07-01T07:19:01.239Z
Learning: GroupPageScreen의 MyPageViewModel은 임시 ViewModel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다.
📚 Learning: the user rbqks529 prefers to extract hardcoded ui strings to stringresource files (strings.xml) rath...
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt:108-112
Timestamp: 2025-07-01T07:19:10.981Z
Learning: The user rbqks529 prefers to extract hardcoded UI strings to StringResource files (strings.xml) rather than keeping them inline in Compose components, which is a good practice for maintainability and localization in Android development.
Applied to files:
app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageEditScreen.ktapp/src/main/java/com/texthip/thip/ui/group/note/component/VoteCommentCard.ktapp/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.ktapp/src/main/java/com/texthip/thip/ui/signin/screen/SignupGenreScreen.ktapp/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.ktapp/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.ktapp/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt
📚 Learning: grouppagescreen의 mypageviewmodel은 임시 viewmodel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다....
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/myPage/groupPage/GroupPageScreen.kt:34-37
Timestamp: 2025-07-01T07:19:01.239Z
Learning: GroupPageScreen의 MyPageViewModel은 임시 ViewModel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다.
Applied to files:
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomMatesScreen.ktapp/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.ktapp/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomMatesViewModel.ktapp/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.ktapp/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt
🧬 Code Graph Analysis (2)
app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomMatesList.kt (1)
app/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.kt (1)
ProfileBar(29-111)
app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt (2)
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (1)
GroupRoomScreen(48-85)app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomMatesScreen.kt (1)
GroupRoomMatesScreen(29-66)
🔇 Additional comments (30)
app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt (1)
35-35: 배경색 리팩터링 확인 완료
colors.DarkGrey02컬러로의 교체가 디자인 시스템 변경 사항과 일치합니다. 다른 영향 범위도 없으므로 그대로 진행해도 되겠습니다.app/src/main/java/com/texthip/thip/ui/group/note/component/CommentItem.kt (1)
46-46: 장르 색상 상수 업데이트 적절
colors.SocialScience사용으로 테마 통일성이 높아졌습니다. 추가 수정 사항 없이 승인합니다.app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt (1)
57-57: 장르 색상 변경 확인
colors.SocialScience적용이 다른 컴포넌트와 일관됩니다. 문제 없습니다.app/src/main/java/com/texthip/thip/ui/common/header/ProfileBarFeed.kt (1)
91-91: 프리뷰 컬러 교체 OK프리뷰에서도 동일한 색상 값을 사용하도록 맞춘 점 확인했습니다.
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt (1)
282-283: 장르 텍스트 색상 변경 적합
colors.SocialScience로의 교체가 테마 표준화와 일관성을 유지합니다. 추가 조치 없이 승인합니다.app/src/main/java/com/texthip/thip/ui/mypage/component/RoleCard.kt (1)
35-35: 테마 색상 리팩터링 승인
Pink에서Art로의 색상 명명 변경이 깔끔하게 적용되었습니다. 도메인 특화된 색상 명명은 코드의 가독성과 유지보수성을 향상시킵니다.Also applies to: 132-132
app/src/main/java/com/texthip/thip/ui/navigator/routes/GroupRoutes.kt (1)
25-26: 독서메이트 네비게이션 라우트 추가 승인PR 목표에 부합하는
RoomMates라우트가 추가되었습니다. 기존 라우트 패턴과 일관성을 유지하며roomId파라미터를 통해 적절한 식별자를 전달합니다.app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageEditScreen.kt (1)
41-66: 컬러 테마 리팩터링이 잘 적용되었습니다.기존의 일반적인 색상명(
NeonGreen,Lavendar등)을 도메인별로 더 의미있는 색상명(Literature,ScienceIt,SocialScience등)으로 변경한 것이 좋습니다. 코드의 가독성과 유지보수성이 향상되었습니다.app/src/main/java/com/texthip/thip/ui/navigator/extensions/GroupNavigationExtensions.kt (1)
58-61: 독서메이트 네비게이션 함수가 올바르게 구현되었습니다.기존 네비게이션 확장 함수들과 일관된 패턴을 따르며,
roomId파라미터를 통해 특정 방의 독서메이트 정보로 이동할 수 있도록 적절히 구현되었습니다.app/src/main/java/com/texthip/thip/ui/signin/screen/SignupGenreScreen.kt (1)
43-68: 컬러 테마 업데이트와 코드 정리가 잘 이루어졌습니다.MypageEditScreen과 동일하게 도메인별 색상명으로 일관되게 변경되었으며, 사용하지 않는 import들도 적절히 정리되었습니다.
app/src/main/java/com/texthip/thip/data/di/ServiceModule.kt (1)
14-17: RoomsService 의존성 주입이 올바르게 구현되었습니다.모임방 관련 API 연동을 위한
RoomsService프로바이더가 적절한 Dagger Hilt 패턴으로 구현되었습니다. 싱글톤 스코프로 설정하여 메모리 효율성을 고려한 것도 좋습니다.app/src/main/java/com/texthip/thip/ui/common/cards/CardNote.kt (1)
30-30: percentage 타입 변경이 적절합니다.API 응답에서 더 정확한 백분율 값을 지원하기 위해
Double타입으로 변경한 것이 좋습니다.app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsUsersResponse.kt (1)
5-17: 데이터 모델 구조가 잘 정의되었습니다.API 응답을 위한 데이터 클래스들이 적절하게 구성되어 있습니다:
@Serializable어노테이션으로 직렬화 지원- 명확한 속성 타입 정의 (Int, String)
- 일관된 네이밍 컨벤션 준수
app/src/main/java/com/texthip/thip/utils/type/GenreBackgroundImage.kt (1)
1-22: 코드 구조가 명확하고 구현이 적절합니다.enum class 설계와 companion object의
fromServerValue함수 구현이 깔끔합니다. 서버 데이터의 언더스코어 접두사를 파싱하여 장르를 매칭시키는 로직과 기본값 처리가 적절합니다.app/src/main/java/com/texthip/thip/data/service/RoomsService.kt (1)
9-19: 서비스 인터페이스 구조가 적절합니다.Retrofit 어노테이션 사용과 suspend 함수 정의, BaseResponse 래핑이 일관성 있게 구현되었습니다.
app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt (1)
20-28: 파라미터 구조 개선이 적절합니다.mock 데이터 클래스에서 실제 서버 데이터 모델로의 전환이 잘 구현되었습니다.
app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomMatesList.kt (2)
34-35: 색상 하드코딩 이슈가 TODO로 표시되어 있습니다.서버에서 색상 정보를 제공할 때까지 임시로 하드코딩된 색상을 사용하고 있습니다. 이후 서버 응답에 색상 필드가 추가되면 업데이트가 필요합니다.
서버 API 스펙에서 색상 필드 추가 계획을 확인해보세요.
18-21: 데이터 모델 전환이 적절합니다.
RoomsUsersResponse와onUserClick콜백 추가로 실제 서버 데이터를 사용하는 구조로 잘 개선되었습니다.app/src/main/java/com/texthip/thip/ui/common/cards/CardVote.kt (2)
87-110: 투표 아이템 렌더링 구현이 적절합니다.
voteItems를 반복하여 각 아이템을 개별적으로 렌더링하는 방식으로 잘 구현되었습니다. UI 구조도 명확합니다.
32-35: 파라미터와 콜백 구조가 개선되었습니다.
List<CurrentVote>타입으로 변경하고onVoteClick콜백을 추가하여 실제 데이터 모델과 상호작용이 가능하도록 잘 구현되었습니다.app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt (1)
5-14: 명시적 import 사용이 좋습니다와일드카드 import를 명시적 import로 변경한 것은 좋은 개선입니다.
app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt (1)
20-20: Also applies to: 26-26, 33-33, 35-35app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomMatesViewModel.kt (1)
13-26: ViewModel 구조가 잘 설계되었습니다sealed interface를 사용한 UI 상태 관리와 StateFlow 활용이 적절합니다.
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (1)
48-85: 화면 구조가 잘 설계되었습니다ViewModel과 UI 상태 관리가 적절하게 구현되었습니다.
app/src/main/java/com/texthip/thip/ui/theme/Color.kt (2)
16-25: 색상 이름 변경이 적절합니다!학술 분야별 카테고리에 맞는 명확한 이름으로 변경되어 코드 가독성이 향상되었습니다.
55-64: 데이터 클래스 속성이 올바르게 업데이트되었습니다.새로운 색상 이름과 일치하도록 속성이 적절히 변경되었습니다.
app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt (1)
3-35: API 응답 모델이 잘 구성되었습니다.데이터 클래스들이 API 응답 구조에 맞게 적절히 정의되었고, Kotlin serialization을 올바르게 사용하고 있습니다.
app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomHeader.kt (1)
43-44: GenreColor 열거형 활용이 적절합니다.문자열을 색상으로 동적 변환하는 로직이 깔끔하게 구현되었습니다.
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomMatesScreen.kt (2)
30-66: ViewModel 통합이 훌륭하게 구현되었습니다!MVVM 패턴이 올바르게 적용되었고, 생명주기를 고려한 상태 수집이 적절합니다. LaunchedEffect로 초기 데이터 로딩도 잘 처리되었습니다.
Line 62의 에러 메시지 스타일링 TODO는 향후 UX 개선 시 처리하시면 됩니다.
68-94: UI 컨텐츠 분리가 잘 되었습니다.상태 관리와 UI 렌더링이 명확히 분리되어 있어 유지보수가 용이합니다.
app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt
Show resolved
Hide resolved
app/src/main/java/com/texthip/thip/data/service/RoomsService.kt
Outdated
Show resolved
Hide resolved
| // if (profileImage != null) { | ||
| AsyncImage( | ||
| model = profileImage, | ||
| contentDescription = "프로필 이미지", | ||
| modifier = Modifier | ||
| .size(36.dp) | ||
| .clip(CircleShape) | ||
| ) | ||
| // } else { | ||
| // Box( | ||
| // modifier = Modifier | ||
| // .size(36.dp) | ||
| // .clip(CircleShape) | ||
| // .background(Grey) | ||
| // ) | ||
| // } |
There was a problem hiding this comment.
이미지 로딩 실패 시 대체 UI가 누락되었습니다.
주석 처리된 placeholder Box가 제거되면서 이미지 로딩에 실패했을 때 보여줄 대체 UI가 없습니다.
AsyncImage에 placeholder와 error 매개변수를 추가하세요:
AsyncImage(
model = profileImage,
contentDescription = "프로필 이미지",
+ placeholder = painterResource(R.drawable.ic_profile_placeholder),
+ error = painterResource(R.drawable.ic_profile_placeholder),
modifier = Modifier
.size(36.dp)
.clip(CircleShape)
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // if (profileImage != null) { | |
| AsyncImage( | |
| model = profileImage, | |
| contentDescription = "프로필 이미지", | |
| modifier = Modifier | |
| .size(36.dp) | |
| .clip(CircleShape) | |
| ) | |
| // } else { | |
| // Box( | |
| // modifier = Modifier | |
| // .size(36.dp) | |
| // .clip(CircleShape) | |
| // .background(Grey) | |
| // ) | |
| // } | |
| // if (profileImage != null) { | |
| AsyncImage( | |
| model = profileImage, | |
| contentDescription = "프로필 이미지", | |
| placeholder = painterResource(R.drawable.ic_profile_placeholder), | |
| error = painterResource(R.drawable.ic_profile_placeholder), | |
| modifier = Modifier | |
| .size(36.dp) | |
| .clip(CircleShape) | |
| ) | |
| // } else { | |
| // Box( | |
| // modifier = Modifier | |
| // .size(36.dp) | |
| // .clip(CircleShape) | |
| // .background(Grey) | |
| // ) | |
| // } |
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.kt between
lines 48 and 63, the placeholder Box UI for when the profile image is null or
fails to load has been removed, leaving no fallback UI. To fix this, add the
placeholder and error parameters to the AsyncImage composable, providing
appropriate UI elements or colors to display while loading or on error, ensuring
a consistent fallback is shown if the image cannot be loaded.
| ProfileBar( | ||
| modifier = Modifier.padding(0.dp), | ||
| profileImage = painterResource(R.drawable.character_literature), | ||
| profileImage = "https://example.com/image1.jpg", |
There was a problem hiding this comment.
🛠️ Refactor suggestion
하드코딩된 URL 대신 실제 데이터 사용 권장
ProfileBar에 하드코딩된 URL을 전달하고 있습니다. data.profileImageUrl 속성을 사용해야 합니다.
다음과 같이 수정하세요:
- profileImage = "https://example.com/image1.jpg",
+ profileImage = data.profileImageUrl,🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/group/note/component/TextCommentCard.kt
at line 51, replace the hardcoded profileImage URL
"https://example.com/image1.jpg" with the actual data source by using
data.profileImageUrl to dynamically provide the profile image URL.
app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt
Outdated
Show resolved
Hide resolved
| GroupRoomScreen( | ||
| // roomId = roomId, | ||
| roomId = 1, | ||
| onBackClick = { | ||
| navigateBack() | ||
| }, | ||
| onNavigateToMates = { | ||
| navController.navigateToGroupRoomMates(roomId) | ||
| }, | ||
| ) |
There was a problem hiding this comment.
하드코딩된 roomId를 제거하고 실제 route 파라미터를 사용하세요
현재 roomId = 1로 하드코딩되어 있어 모든 방이 동일한 데이터를 표시하게 됩니다. 또한 주석 처리된 코드도 제거해야 합니다.
GroupRoomScreen(
-// roomId = roomId,
- roomId = 1,
+ roomId = roomId,
onBackClick = {
navigateBack()
},
onNavigateToMates = {
navController.navigateToGroupRoomMates(roomId)
},
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| GroupRoomScreen( | |
| // roomId = roomId, | |
| roomId = 1, | |
| onBackClick = { | |
| navigateBack() | |
| }, | |
| onNavigateToMates = { | |
| navController.navigateToGroupRoomMates(roomId) | |
| }, | |
| ) | |
| GroupRoomScreen( | |
| roomId = roomId, | |
| onBackClick = { | |
| navigateBack() | |
| }, | |
| onNavigateToMates = { | |
| navController.navigateToGroupRoomMates(roomId) | |
| }, | |
| ) |
🤖 Prompt for AI Agents
In
app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt
around lines 245 to 254, replace the hardcoded roomId value of 1 with the actual
route parameter that provides the roomId dynamically. Remove the commented-out
line setting roomId to avoid confusion. Ensure that the roomId passed to
GroupRoomScreen and navController.navigateToGroupRoomMates uses the correct
variable from the navigation arguments or route parameters.
| GroupRoomMatesScreen( | ||
| // roomId = roomId, | ||
| roomId = 1, | ||
| onBackClick = { | ||
| navigateBack() | ||
| }, | ||
| onUserClick = { | ||
| // 네비게이션 로직 (예: 유저 프로필로 이동) | ||
| } | ||
| ) |
There was a problem hiding this comment.
하드코딩된 roomId를 제거하고 TODO를 구현하세요
roomId = 1로 하드코딩되어 있으며, onUserClick 콜백이 구현되지 않았습니다.
GroupRoomMatesScreen(
-// roomId = roomId,
- roomId = 1,
+ roomId = roomId,
onBackClick = {
navigateBack()
},
onUserClick = {
- // 네비게이션 로직 (예: 유저 프로필로 이동)
+ // TODO: 유저 프로필로 이동 구현
}
)유저 프로필 네비게이션 구현이 필요하시면 도움을 드릴 수 있습니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| GroupRoomMatesScreen( | |
| // roomId = roomId, | |
| roomId = 1, | |
| onBackClick = { | |
| navigateBack() | |
| }, | |
| onUserClick = { | |
| // 네비게이션 로직 (예: 유저 프로필로 이동) | |
| } | |
| ) | |
| GroupRoomMatesScreen( | |
| roomId = roomId, | |
| onBackClick = { | |
| navigateBack() | |
| }, | |
| onUserClick = { | |
| // TODO: 유저 프로필로 이동 구현 | |
| } | |
| ) |
🤖 Prompt for AI Agents
In
app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt
between lines 262 and 271, remove the hardcoded roomId value of 1 and replace it
with the appropriate dynamic roomId variable or parameter. Additionally,
implement the onUserClick callback to handle navigation to the user's profile
screen, adding the necessary navigation logic inside the lambda.
| enum class GenreColor( | ||
| val colorProvider: @Composable () -> Color | ||
| ) { | ||
| RED({ colors.Art }), | ||
| BLUE({ colors.Humanities }), | ||
| GREEN({ colors.Literature }), | ||
| YELLOW({ colors.SocialScience }), | ||
| PURPLE({ colors.ScienceIt }); | ||
|
|
||
|
|
||
| companion object { | ||
| fun fromString(colorString: String?): GenreColor { | ||
| return entries.find { it.name.equals(colorString, ignoreCase = true) } | ||
| ?: RED | ||
| } | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
🛠️ Refactor suggestion
enum 이름과 색상 매핑이 직관적이지 않습니다.
현재 구현에서 RED가 colors.Art에, BLUE가 colors.Humanities에 매핑되는 것이 직관적이지 않습니다. 개발자가 혼동할 수 있습니다.
다음 중 하나를 고려해보세요:
- enum 이름을 도메인에 맞게 변경 (예:
ART,HUMANITIES,LITERATURE) - 매핑 관계를 문서화하는 주석 추가
enum class GenreColor(
val colorProvider: @Composable () -> Color
) {
+ // 서버에서 "RED" 문자열이 전달되면 Art 테마 색상으로 매핑
- RED({ colors.Art }),
- BLUE({ colors.Humanities }),
- GREEN({ colors.Literature }),
- YELLOW({ colors.SocialScience }),
- PURPLE({ colors.ScienceIt });
+ RED({ colors.Art }), // 예술
+ BLUE({ colors.Humanities }), // 인문학
+ GREEN({ colors.Literature }), // 문학
+ YELLOW({ colors.SocialScience }), // 사회과학
+ PURPLE({ colors.ScienceIt }); // 과학/IT📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| enum class GenreColor( | |
| val colorProvider: @Composable () -> Color | |
| ) { | |
| RED({ colors.Art }), | |
| BLUE({ colors.Humanities }), | |
| GREEN({ colors.Literature }), | |
| YELLOW({ colors.SocialScience }), | |
| PURPLE({ colors.ScienceIt }); | |
| companion object { | |
| fun fromString(colorString: String?): GenreColor { | |
| return entries.find { it.name.equals(colorString, ignoreCase = true) } | |
| ?: RED | |
| } | |
| } | |
| } | |
| enum class GenreColor( | |
| val colorProvider: @Composable () -> Color | |
| ) { | |
| // 서버에서 "RED" 문자열이 전달되면 Art 테마 색상으로 매핑 | |
| RED({ colors.Art }), // 예술 | |
| BLUE({ colors.Humanities }), // 인문학 | |
| GREEN({ colors.Literature }), // 문학 | |
| YELLOW({ colors.SocialScience }), // 사회과학 | |
| PURPLE({ colors.ScienceIt }); // 과학/IT | |
| companion object { | |
| fun fromString(colorString: String?): GenreColor { | |
| return entries.find { it.name.equals(colorString, ignoreCase = true) } | |
| ?: RED | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/utils/type/GenreColor.kt lines 7 to 23,
the enum names like RED, BLUE do not intuitively match their mapped colors such
as colors.Art and colors.Humanities, which can confuse developers. To fix this,
rename the enum constants to domain-relevant names like ART, HUMANITIES,
LITERATURE, SOCIAL_SCIENCE, SCIENCE_IT to clearly reflect their associated
colors, or alternatively add clear comments explaining the mapping between enum
names and colors for better clarity.
| val uiState by viewModel.uiState.collectAsStateWithLifecycle() | ||
|
|
||
| // 화면이 처음 그려질 때 데이터 로딩 실행 | ||
| LaunchedEffect(key1 = Unit) { | ||
| viewModel.fetchUsers(roomId) | ||
| } | ||
|
|
||
| // UI 상태에 따라 다른 화면을 보여줌 | ||
| when (val state = uiState) { | ||
| is GroupRoomMatesUiState.Loading -> { | ||
| Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { | ||
| CircularProgressIndicator() | ||
| } | ||
| } | ||
|
|
||
| is GroupRoomMatesUiState.Success -> { | ||
| // 성공 시, 실제 데이터를 화면에 표시 | ||
| GroupRoomMatesContent( | ||
| data = state.users, | ||
| onBackClick = onBackClick, | ||
| onUserClick = onUserClick | ||
| ) | ||
| } | ||
|
|
||
| is GroupRoomMatesUiState.Error -> { | ||
| Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { | ||
| Text(text = state.message, color = colors.White) // TODO: 에러 메시지 스타일링 | ||
| } | ||
| } | ||
| } |
| fun ProfileBar( | ||
| modifier: Modifier = Modifier, | ||
| profileImage: Painter?, | ||
| // profileImage: Painter?, |
There was a problem hiding this comment.
주석이 남아있는 이유가 따로 있을까용?
string으로 받을텐데 지워도 되지 않나여??
| // } else { | ||
| // Box( | ||
| // modifier = Modifier | ||
| // .size(36.dp) | ||
| // .clip(CircleShape) | ||
| // .background(Grey) | ||
| // ) | ||
| // } |
There was a problem hiding this comment.
이미지 null인 경우 예외처리를 주석처리 하신 것 같은데 서버측 설계가 어떤지 모르겠지만, 프로필 이미지를 null로 보내주는 경우가 아예 없는게 맞나유? 사용자가 프로필이미지를 삭제하는 경우라던지.. 그런 상황에서는 null이 아니라 기본 이미지로 채워서 보내주는 거라면 예외처리 따로 안 해도 되겠네용!
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt (1)
79-83: 에러 상태에 대한 UX 보완 필요에러 화면이 단순 텍스트만 노출되고 재시도 버튼이 없습니다.
네트워크 오류가 빈번할 수 있으므로 “다시 시도” 액션을 제공해 사용자 흐름을 끊지 않도록 개선을 검토해 주세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt(1 hunks)app/src/main/java/com/texthip/thip/data/service/RoomsService.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/common/cards/CardVote.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomMatesList.kt(2 hunks)app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt(4 hunks)app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- app/src/main/java/com/texthip/thip/ui/common/header/ProfileBar.kt
- app/src/main/java/com/texthip/thip/ui/common/cards/CardVote.kt
- app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomMatesList.kt
- app/src/main/java/com/texthip/thip/data/service/RoomsService.kt
- app/src/main/java/com/texthip/thip/ui/group/room/component/GroupRoomBody.kt
- app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt
- app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsPlayingResponse.kt
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/myPage/groupPage/GroupPageScreen.kt:34-37
Timestamp: 2025-07-01T07:19:01.239Z
Learning: GroupPageScreen의 MyPageViewModel은 임시 ViewModel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다.
📚 Learning: 2025-07-01T07:19:01.239Z
Learnt from: rbqks529
PR: THIP-TextHip/THIP-Android#30
File: app/src/main/java/com/texthip/thip/ui/myPage/groupPage/GroupPageScreen.kt:34-37
Timestamp: 2025-07-01T07:19:01.239Z
Learning: GroupPageScreen의 MyPageViewModel은 임시 ViewModel로, 현재는 프로토타입 단계이므로 오류 처리 등의 추가 기능은 나중에 구현 예정입니다.
Applied to files:
app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt
| // 화면이 처음 그려질 때 데이터 로딩 실행 | ||
| LaunchedEffect(key1 = Unit) { | ||
| viewModel.fetchRoomsPlaying(roomId) | ||
| } |
There was a problem hiding this comment.
LaunchedEffect의 key를 Unit 대신 roomId로 교체 필요
현재 LaunchedEffect(key1 = Unit)로 지정되어 있어 동일 Composable 인스턴스에서 roomId가 바뀌어도 데이터 재조회가 실행되지 않습니다.
방 재입장·딥링크 시 ID 변경이 가능하므로 다음과 같이 수정해 주세요.
-LaunchedEffect(key1 = Unit) {
- viewModel.fetchRoomsPlaying(roomId)
-}
+LaunchedEffect(roomId) {
+ viewModel.fetchRoomsPlaying(roomId)
+}🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt
around lines 57 to 60, replace the LaunchedEffect key from Unit to roomId to
ensure that when roomId changes, the data reloads correctly. Change
LaunchedEffect(key1 = Unit) to LaunchedEffect(key1 = roomId) so that the effect
re-triggers on roomId updates, handling room re-entries or deep link changes
properly.
| val imageModel = remember(roomDetails.roomImageUrl) { | ||
| // 서버에서 받은 문자열이 "_image"로 끝나면 Enum에서 로컬 리소스를 찾음 | ||
| if (roomDetails.roomImageUrl.endsWith("_image")) { | ||
| GenreBackgroundImage.fromServerValue(roomDetails.roomImageUrl).imageResId | ||
| } | ||
| // 그렇지 않으면 URL로 그대로 사용 | ||
| else { | ||
| roomDetails.roomImageUrl | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
장르 이미지 변환 시 안전 장치 추가 권장
GenreBackgroundImage.fromServerValue(roomDetails.roomImageUrl).imageResId 호출은
매핑에 실패하면 NullPointerException을 유발할 수 있습니다.
예상치 못한 값에도 안전하게 동작하도록 ?: 연산자로 기본 이미지를 지정하거나
runCatching으로 예외를 흡수하는 방식을 고려해 주세요.
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt
around lines 102 to 111, the call to
GenreBackgroundImage.fromServerValue(roomDetails.roomImageUrl).imageResId can
throw a NullPointerException if the mapping fails. To fix this, add a safe
fallback by using the Elvis operator (?:) to provide a default image resource ID
or wrap the call in runCatching to catch exceptions and return a default image
in case of failure, ensuring the app handles unexpected values safely.
| verticalAlignment = Alignment.CenterVertically, | ||
| ) { | ||
| Text( | ||
| text = "${index + 1}. ${item.itemName}", |
| @Serializable | ||
| data class RoomsPlayingResponse( | ||
| val isHost: Boolean, | ||
| val roomId: Int, |
There was a problem hiding this comment.
pk 값에 대한 대응을 한다면 Int 대신 Long 이 어떨까요 ??
➕ 이슈 링크
🔎 작업 내용
📸 스크린샷
2025-08-08.12.37.27.mov
😢 해결하지 못한 과제
[] TASK
📢 리뷰어들에게
Summary by CodeRabbit
신규 기능
UI/UX 개선
버그 수정 및 스타일
구조 개선