Conversation
…ail-ui # Conflicts: # app/src/main/res/values/strings.xml
📝 WalkthroughWalkthrough분철팟 상세 UI와 관련 도메인 모델, 네비게이션(콜백→NavController), ViewModel 상태/이펙트, 여러 Compose 컴포넌트, 문자열 리소스 및 반응형 패딩/프로필 이미지 로더 변경을 추가합니다. (기능적 흐름·네비게이션과 UI/상태 연동이 도입됨) Changes
Sequence Diagram(s)sequenceDiagram
participant Nav as NavController
participant Route as PartyDetailRoute
participant VM as PartyDetailViewModel
participant UI as PartyDetailScreen
participant Repo as (Data source)
Nav->>Route: navigateToPartyDetail(partyId)
Route->>VM: savedStateHandle -> toRoute -> partyId
VM->>VM: init { processIntent(LoadPartyDetail) }
VM->>Repo: fetchPartyDetail(partyId) -- (currently returns dummy)
Repo-->>VM: PartyDetail data
VM-->>UI: uiState = Success(PartyDetail)
UI->>UI: render(Header, Content, Participants, Uploader)
UI->>VM: user interaction (OnJoinClick / OnUploaderClick / OnBackClick)
VM-->>Nav: emit Effect (NavigateToJoin / NavigateToProfile / NavigateBack)
Nav->>Nav: perform navigation action
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
| PotiHeaderPage( | ||
| onNavigationClick = onBackClick, | ||
| title = stringResource(R.string.party_detail_title, partyDetail.userSummary.nickname), | ||
| ) |
There was a problem hiding this comment.
p1: 스티키 스티키 하다고 합니다!! by 디쌤
| VerticalDivider( | ||
| thickness = 1.dp, | ||
| color = PotiTheme.colors.gray800, | ||
| modifier = Modifier.height(21.dp), |
There was a problem hiding this comment.
p2: 피그마에 fill로 되어 있어 시스템 텍스트 사이즈에 따라 높이가 달라져야할 것 같은데 Text 높이 재서 넣어주는 건 어때요?? 넘 복잡한강
| style = PotiTheme.typography.title18sb, | ||
| color = PotiTheme.colors.black, | ||
| minLines = 2, | ||
| maxLines = 2, |
There was a problem hiding this comment.
p1: 엇 여기 최대 두 줄 조건 있나욤..? 상세 페이지라 타이틀 다 보여야 할 것 같아요
app/src/main/res/values/strings.xml
Outdated
| <string name="party_detail_uploader">모집자</string> | ||
| <string name="party_detail_participants">참여자</string> | ||
| <string name="party_detail_review_count">%d개의 평가</string> | ||
| <string name="party_detail_participants_count">%1d/%2d</string> |
| PotiIconButton( | ||
| iconRes = R.drawable.ic_arrow_right_lg, | ||
| onClick = { onClick(userSummary.userId) }, | ||
| tint = PotiTheme.colors.gray700, | ||
| ) |
There was a problem hiding this comment.
이거는 버튼이 Row 에 가운데 정렬 되어 있어서 Row 안에 넣고 Screen에서 PartyUploaderInfo 패딩을 좌우 다르게 줬습니당 피그마에 Row 밖에 있다고 꼭 코드 짤 때도 Row 밖에 넣을 필요는 없음!!
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/main/java/com/poti/android/presentation/user/profile/navigation/ProfileNavigation.kt (1)
19-23: 프로필 화면 구현이 누락되어 있습니다.
composable<ProfileRoute.Profile>블록이 비어있어 이 경로로 네비게이션 시 아무것도 표시되지 않습니다. 또한paddingValues파라미터가 전달되지 않고 있습니다.코드베이스의 다른 네비게이션 패턴(
authNavGraph,historyNavGraph,onboardingNavGraph)과 일관성 있게 다음과 같이 구현해주세요:🛠️ 권장 수정안
fun NavGraphBuilder.profileNavGraph( paddingValues: PaddingValues, ) { - composable<ProfileRoute.Profile> { } + composable<ProfileRoute.Profile> { backStackEntry -> + val profile = backStackEntry.toRoute<ProfileRoute.Profile>() + ProfileScreen( + userId = profile.userId, + modifier = Modifier.padding(paddingValues), + ) + } }참고로 현재 코드베이스에서
ProfileScreen컴포저블을 찾을 수 없습니다. 아직 구현 중이거나 다른 파일에 있다면 경로를 확인해주세요. TODO 주석을 추가하는 것도 좋은 방안입니다.
🤖 Fix all issues with AI agents
In `@app/src/main/java/com/poti/android/domain/model/delivery/DeliveryOption.kt`:
- Around line 3-7: Fix the minor comment typo in the DeliveryOption data class:
change the comment for the deliveryId property (currently "바송 방식 ID") to the
correct text "배송 방식 ID" in the DeliveryOption declaration so the comment reads
correctly alongside the deliveryId property.
In
`@app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt`:
- Line 20: The import for hiltViewModel is using the deprecated package; replace
the import statement "androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel"
with "androidx.hilt.navigation.compose.hiltViewModel" so all usages of
hiltViewModel() in PartyDetailScreen.kt reference the modern package; ensure
there are no other deprecated hilt lifecycle imports in the file and run a quick
build to confirm the symbol resolves.
In `@app/src/main/java/com/poti/android/presentation/party/home/HomeScreen.kt`:
- Around line 8-18: HomeRoute declares an unused parameter
onNavigateToGoodsCategory; either remove that parameter from HomeRoute's
signature or forward it to HomeScreen so it's used. If removing, delete
onNavigateToGoodsCategory from HomeRoute's parameter list and any callers; if
keeping, add a corresponding argument to the HomeScreen call (e.g.,
HomeScreen(onClick = onNavigateToPartyDetail, onNavigateToGoodsCategory =
onNavigateToGoodsCategory, modifier = modifier)) and ensure HomeScreen
defines/accepts that parameter. Make the change in the HomeRoute function and
update any affected call sites or HomeScreen signature accordingly.
In `@app/src/main/res/values/strings.xml`:
- Line 36: The string resource party_detail_announcement currently contains
placeholder text ("어쩌구 저쩌구"); replace its value in strings.xml with the
finalized announcement text from product/PM, preserving any intended line breaks
or formatting (use \n for newlines or string resources with <xliff:g> if needed)
and ensure the string name party_detail_announcement remains unchanged so
callers referencing it are unaffected.
♻️ Duplicate comments (1)
app/src/main/java/com/poti/android/presentation/party/detail/component/PartyUploaderInfo.kt (1)
50-54: IconButton 레이아웃 이슈가 아직 남아있는 것 같아요.이전 리뷰에서 지적된 것처럼,
PotiIconButton이 Row의 경계를 벗어나는 문제가 있을 수 있어요.PotiIconButton의 내부 구현을 보면size(48.dp)로 고정되어 있고,padding(12.dp)가 추가로 적용되어 있어서 실제 터치 영역이 의도보다 클 수 있어요.해결 방안으로는:
IconButton대신Icon에 직접clickablemodifier를 적용하거나Row에 적절한 패딩/클리핑을 적용하는 방법을 고려해 보세요.
🧹 Nitpick comments (11)
app/src/main/java/com/poti/android/core/common/extension/IntExt.kt (1)
5-8:DecimalFormat인스턴스 재사용을 고려해 주세요.현재 구현에서는
toMoneyString()이 호출될 때마다 새로운DecimalFormat인스턴스가 생성됩니다. 자주 호출되는 경우 성능에 영향을 줄 수 있으므로, 인스턴스를 캐싱하는 방식을 고려해 보시면 좋겠습니다.♻️ 제안된 개선 코드
package com.poti.android.core.common.extension import java.text.DecimalFormat +private val moneyFormat = DecimalFormat("#,###") + fun Int.toMoneyString(): String { - val decimalFormat = DecimalFormat("#,###") - return decimalFormat.format(this) + return moneyFormat.format(this) }참고:
DecimalFormat은 스레드 안전하지 않으므로, 멀티스레드 환경에서 사용될 가능성이 있다면ThreadLocal을 사용하거나 현재 방식을 유지하는 것이 안전합니다.app/src/main/java/com/poti/android/domain/model/party/Participant.kt (1)
3-9: Domain 모델 구현이 깔끔합니다.Domain 레이어의 순수성이 잘 유지되어 있고,
data class와val프로퍼티로 불변성이 보장되어 있습니다.다만,
selectedMembers: List<String>은 Compose에서 State로 사용될 때 불필요한 리컴포지션을 유발할 수 있습니다. 이 모델이 UI State에서 직접 사용된다면,@Immutable어노테이션 추가를 권장드립니다.♻️ 선택적 개선안
package com.poti.android.domain.model.party +import androidx.compose.runtime.Immutable + +@Immutable data class Participant( val userId: Long, // 참여자 유저 ID val nickname: String, // 참여자 닉네임 val profileImage: String?, // 참여자 프로필 이미지 (없으면 null) val rating: Double, // 참여자 평점 val selectedMembers: List<String>, // 선점한 멤버 목록 )app/src/main/java/com/poti/android/presentation/party/detail/component/PartyUploaderInfo.kt (1)
41-47: rating 표시 형식 확인이 필요해요.
userSummary.rating.toString()으로 Double 값을 그대로 문자열로 변환하고 있는데, 예를 들어4.5가4.5로 표시되지만4.0이4.0으로 표시될 거예요. 만약 소수점 한 자리로 통일하거나 특정 포맷이 필요하다면String.format("%.1f", rating)등의 포맷팅을 고려해 주세요.♻️ 포맷팅 적용 예시
PotiProfileSummary( profileImageUrl = userSummary.profileImage, nickname = userSummary.nickname, sizeType = PotiProfileSummarySize.LARGE, - rating = userSummary.rating.toString(), + rating = String.format("%.1f", userSummary.rating), reviewText = stringResource(R.string.party_detail_review_count, userSummary.reviewCount), modifier = Modifier.weight(1f), )app/src/main/java/com/poti/android/presentation/party/detail/component/PartyParticipantsInfo.kt (1)
24-26: 컴포저블 파라미터 최적화를 고려해 보세요.현재
PartyDetail전체를 파라미터로 받고 있지만, 실제로 사용하는 필드는participants,currentCount,totalCount뿐입니다. Compose의 리컴포지션 최적화를 위해 필요한 필드만 개별 파라미터로 받는 것이 권장됩니다.♻️ 리팩토링 제안
`@Composable` fun PartyParticipantsInfo( - partyDetail: PartyDetail, + participants: List<Participant>, + currentCount: Int, + totalCount: Int, modifier: Modifier = Modifier, ) {이렇게 하면
PartyDetail의 다른 필드가 변경되어도 이 컴포저블이 불필요하게 리컴포지션되지 않습니다. 또한,Participant가 일반data class이므로@Immutable또는@Stable어노테이션 적용도 검토해 주세요.app/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailContent.kt (2)
31-40:remember를 사용하여 계산 결과를 캐싱하는 것을 권장드립니다.
textHeightDp계산이 리컴포지션마다 반복될 수 있습니다.density와textStyle이 변경될 때만 재계산되도록remember로 감싸주시면 좋겠습니다.♻️ 리팩토링 제안
val density = LocalDensity.current val textStyle = PotiTheme.typography.body14m - val textHeightDp = with(density) { + val textHeightDp = remember(density, textStyle) { + with(density) { - if (textStyle.lineHeight.isSp) { - textStyle.lineHeight.toDp() - } else { - textStyle.fontSize.toDp() + if (textStyle.lineHeight.isSp) { + textStyle.lineHeight.toDp() + } else { + textStyle.fontSize.toDp() + } } }코딩 가이드라인에 따라 계산 비용이 있는 로직은
remember로 감싸는 것이 권장됩니다.
27-29: 컴포저블 파라미터 최적화를 고려해 보세요.
PartyParticipantsInfo와 마찬가지로,PartyDetail전체 대신 필요한 필드(content,deadline,deliveryOptions)만 받으면 리컴포지션 범위를 줄일 수 있습니다. 일관성 있는 설계를 위해 검토해 주세요.app/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailHeaderInfo.kt (2)
33-48: Column에Modifier.weight(1f)추가를 권장드려요.
Row에서Arrangement.SpaceBetween을 사용하고 있지만, 왼쪽Column에weight(1f)가 없으면 긴 텍스트가 오른쪽 하트 아이콘을 밀어낼 수 있어요. 레이아웃 안정성을 위해 수정을 고려해 주세요.♻️ 제안하는 수정 사항
Row( modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, ) { - Column { + Column(modifier = Modifier.weight(1f)) { Text( text = partyDetail.artist,
24-28:PartyDetail타입의 안정성(Stability) 검토가 필요해요.
PartyDetail은List타입의 프로퍼티들(images,deliveryOptions,participants)을 포함하고 있어서, Compose 컴파일러가 이를 불안정(unstable)한 타입으로 인식할 수 있어요. 이로 인해 불필요한 리컴포지션이 발생할 수 있으니,PartyDetaildata class에@Immutable어노테이션 추가를 고려해 주세요.app/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.kt (1)
37-37:popBackStack반환값 처리에 대해 알려드려요.
navController::popBackStack은Boolean을 반환하지만,onPopBackStack은() -> Unit타입이에요. Kotlin에서는 반환값이 무시되어 동작에는 문제가 없지만, 백스택이 비어있을 때의 처리가 필요하다면 별도 래퍼 함수 사용을 고려해 주세요.app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt (2)
94-98:onLikeClick콜백이 비어있어요.좋아요 기능의 콜백이 빈 람다로 되어 있어요. 추후 ViewModel과 연결하여 좋아요 Intent를 처리해야 할 것 같아요. 현재 UI 구현 단계라면 TODO 주석을 남겨주시면 추적이 용이해요.
TODO 주석 추가나 ViewModel 연결 코드 생성을 도와드릴까요?
97-137: 반복되는 padding 값을 상수로 추출하면 좋을 것 같아요.
screenWidthDp(16.dp)가 여러 곳에서 반복 사용되고 있어요. 유지보수성을 위해 상수로 추출하는 것을 고려해 주세요.♻️ 제안하는 수정 사항
`@Composable` private fun PartyDetailScreen( // ... ) { val horizontalPadding = screenWidthDp(16.dp) // 사용 예시 PartyDetailHeaderInfo( partyDetail = partyDetail, onLikeClick = {}, modifier = Modifier.padding(horizontal = horizontalPadding, vertical = 20.dp), ) // ... }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (26)
app/src/main/java/com/poti/android/core/common/extension/IntExt.ktapp/src/main/java/com/poti/android/core/designsystem/component/display/PotiProfileSummary.ktapp/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiBottomButton.ktapp/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPage.ktapp/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPrimary.ktapp/src/main/java/com/poti/android/domain/model/delivery/DeliveryOption.ktapp/src/main/java/com/poti/android/domain/model/party/Participant.ktapp/src/main/java/com/poti/android/domain/model/party/PartyDetail.ktapp/src/main/java/com/poti/android/domain/model/party/PartyImage.ktapp/src/main/java/com/poti/android/domain/model/user/UserSummary.ktapp/src/main/java/com/poti/android/domain/type/PartyStatusType.ktapp/src/main/java/com/poti/android/presentation/main/PotiNavHost.ktapp/src/main/java/com/poti/android/presentation/party/PartyNavigation.ktapp/src/main/java/com/poti/android/presentation/party/detail/DummyPartyDetailData.ktapp/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.ktapp/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailContent.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailHeaderInfo.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyParticipantsInfo.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyUploaderInfo.ktapp/src/main/java/com/poti/android/presentation/party/detail/model/Contracts.ktapp/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.ktapp/src/main/java/com/poti/android/presentation/party/home/HomeScreen.ktapp/src/main/java/com/poti/android/presentation/party/home/navigation/HomeNavigation.ktapp/src/main/java/com/poti/android/presentation/user/profile/navigation/ProfileNavigation.ktapp/src/main/res/values/strings.xml
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt
⚙️ CodeRabbit configuration file
**/*.kt: 코드를 리뷰할 때 다음 Kotlin 및 Jetpack Compose 모범 사례를 중점적으로 확인:
Jetpack Compose 성능 및 UI 최적화:
- Recomposition 방지: 불필요한 리컴포지션을 유발하는 코드를 지적해줘. 특히
LazyColumn등 리스트에서key파라미터가 누락되었는지 확인해줘.- 스마트한 계산: 계산 비용이 높은 로직은
remember나derivedStateOf로 감싸져 있는지 확인해줘.- 안정성(Stability): List나 일반 클래스를 State로 사용할 때, 불필요한 리컴포지션을 막기 위해
@Immutable이나@Stable어노테이션 사용을 제안해줘.- Modifier 규칙:
Modifier는 항상 컴포저블 함수의 첫 번째 선택적 파라미터로 받아야 하며, 재사용성을 위해 외부에서 주입받아야 해.- 리소스 사용: 하드코딩된 값(색상, 크기, 문자열) 대신
Theme,Dimens,strings.xml리소스를 사용하는지 체크해줘.- 접근성 예외: Icon이나 Image 컴포저블의
contentDescription이null인 경우는 장식용(Decorative) 이미지로 간주하고 지적하지 마.MVI (Model-View-Intent) 아키텍처 및 상태 관리:
- 단방향 데이터 흐름(UDF): UI는 상태를 직접 변경할 수 없고, 반드시
Intent(또는 Event)를 통해 ViewModel로 요청을 보내야 해.- 불변 상태(Immutable State):
UiState는 반드시data class+val프로퍼티로 구성되어야 하며, 상태 업데이트 시.copy()를 사용해야 해.- Side Effect 분리: 네비게이션, Toast 같은 일회성 이벤트는 UiState가 아닌
Channel이나SharedFlow로 처리하여 화면 회전 시 재발생하지 않도록 해야 해.- 안전한 수집: UI에서 Flow 수집 시
collectAsStateWithLifecycle()을 사용하여 생명주기를 준수하는지 확인해줘.- 상태 노출:
ViewModel내부에서StateFlow나SharedFlow를 올바르게 노출하고 있는지 확인해줘.- 호이스팅(Hoisting): 상태나 UI 이벤트 처리가 적절하게 호이스팅되었는지 확인해줘. UI 로직과 비즈니스 로직을 분리하고, UI가 로직을 직접 수행하지 않도록 확인해줘.
Clean Architecture (Dependency Rule) 준수:
- Domain 순수성: Domain 레이어(
domain패키지)는 절대로 안드로이드 의존성(android.*,R클래스 등)을 가져서는 안 돼. 순수 Kotlin 코드인지 엄격히 확인해줘.- 데이터 노출 금지: Data 레이어의 DTO(
@Entity,@SerializedName)가 UI나 Domain 레이어로 바로 노출되면 안 돼. 반드시 Mapper를 통해 변환했는지 확인해줘.- 계층 간 의존성:
UI -> Domain <- Data방향이 올바른지, UI가 Data 레이어를 직접 참조하고 있진 않은지 감시해줘.Kotlin & Coroutines 안전성:
- Scope 사용:
GlobalScope사용을 금지하고,viewModelScope나lifecycleScope사용을 권장해줘.- Dispatcher 주입:
Dispatchers.IO등을 하드코딩하지 말고, 테스트 용이성을 위해 생성자를 통해 주입(Injection)받도록 제안해줘.- 예외 처리: Coroutine 실행 시
runCatching이나CoroutineExceptionHandler등을 통해 예외 처리가 누락되지 않았는지 확인해줘.- Null-Safety: 불필요한
!!연산자 사용을 지적...
Files:
app/src/main/java/com/poti/android/core/common/extension/IntExt.ktapp/src/main/java/com/poti/android/presentation/party/PartyNavigation.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyParticipantsInfo.ktapp/src/main/java/com/poti/android/domain/model/party/Participant.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailHeaderInfo.ktapp/src/main/java/com/poti/android/domain/type/PartyStatusType.ktapp/src/main/java/com/poti/android/domain/model/party/PartyDetail.ktapp/src/main/java/com/poti/android/core/designsystem/component/display/PotiProfileSummary.ktapp/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.ktapp/src/main/java/com/poti/android/presentation/main/PotiNavHost.ktapp/src/main/java/com/poti/android/presentation/user/profile/navigation/ProfileNavigation.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailContent.ktapp/src/main/java/com/poti/android/presentation/party/home/HomeScreen.ktapp/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPrimary.ktapp/src/main/java/com/poti/android/domain/model/user/UserSummary.ktapp/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiBottomButton.ktapp/src/main/java/com/poti/android/presentation/party/detail/model/Contracts.ktapp/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.ktapp/src/main/java/com/poti/android/domain/model/delivery/DeliveryOption.ktapp/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPage.ktapp/src/main/java/com/poti/android/presentation/party/home/navigation/HomeNavigation.ktapp/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.ktapp/src/main/java/com/poti/android/domain/model/party/PartyImage.ktapp/src/main/java/com/poti/android/presentation/party/detail/DummyPartyDetailData.ktapp/src/main/java/com/poti/android/presentation/party/detail/component/PartyUploaderInfo.kt
🧬 Code graph analysis (10)
app/src/main/java/com/poti/android/presentation/party/PartyNavigation.kt (3)
app/src/main/java/com/poti/android/presentation/party/home/navigation/HomeNavigation.kt (1)
homeNavGraph(24-35)app/src/main/java/com/poti/android/presentation/party/goodsfilter/navigation/GoodsNavigation.kt (1)
goodsFilterNavGraph(34-47)app/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.kt (1)
partyDetailNavGraph(31-48)
app/src/main/java/com/poti/android/presentation/party/detail/component/PartyParticipantsInfo.kt (3)
app/src/main/java/com/poti/android/core/designsystem/component/display/PotiProfileSummary.kt (1)
PotiProfileSummary(33-93)app/src/main/java/com/poti/android/core/designsystem/component/display/PotiPrimaryTag.kt (1)
PotiPrimaryTag(42-61)app/src/main/java/com/poti/android/core/designsystem/theme/Theme.kt (1)
PotiTheme(48-71)
app/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailHeaderInfo.kt (2)
app/src/main/java/com/poti/android/core/designsystem/component/button/PotiIconButton.kt (1)
PotiIconButton(19-35)app/src/main/java/com/poti/android/core/designsystem/theme/Theme.kt (1)
PotiTheme(48-71)
app/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailContent.kt (1)
app/src/main/java/com/poti/android/core/designsystem/theme/Theme.kt (1)
PotiTheme(48-71)
app/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPrimary.kt (1)
app/src/main/java/com/poti/android/core/common/util/DimensionUtil.kt (1)
screenWidthDp(20-26)
app/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiBottomButton.kt (1)
app/src/main/java/com/poti/android/core/common/util/DimensionUtil.kt (1)
screenWidthDp(20-26)
app/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.kt (2)
app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt (1)
PartyDetailRoute(35-50)app/src/main/java/com/poti/android/presentation/party/detail/PartyJoinScreen.kt (1)
PartyJoinRoute(6-8)
app/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPage.kt (1)
app/src/main/java/com/poti/android/core/common/util/DimensionUtil.kt (1)
screenWidthDp(20-26)
app/src/main/java/com/poti/android/presentation/party/home/navigation/HomeNavigation.kt (1)
app/src/main/java/com/poti/android/presentation/party/home/HomeScreen.kt (1)
HomeRoute(8-18)
app/src/main/java/com/poti/android/presentation/party/detail/component/PartyUploaderInfo.kt (3)
app/src/main/java/com/poti/android/core/designsystem/component/display/PotiProfileSummary.kt (1)
PotiProfileSummary(33-93)app/src/main/java/com/poti/android/core/designsystem/component/button/PotiIconButton.kt (1)
PotiIconButton(19-35)app/src/main/java/com/poti/android/core/designsystem/theme/Theme.kt (1)
PotiTheme(48-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: PR CI Check (Lint & Build)
🔇 Additional comments (25)
app/src/main/java/com/poti/android/presentation/user/profile/navigation/ProfileNavigation.kt (2)
10-13: LGTM! Type-safe Navigation 패턴이 잘 적용되었습니다.
@Serializable과data class를 활용한 Type-safe Navigation은 Modern Android Development에서 권장하는 방식입니다.userId를 route 파라미터로 전달하는 구조가 적절합니다.
15-17: LGTM! NavController 확장 함수가 깔끔하게 구현되었습니다.Navigation 로직을 확장 함수로 캡슐화하여 호출부에서 route 구조를 알 필요 없이 사용할 수 있도록 한 점이 좋습니다.
app/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPage.kt (1)
16-31: LGTM! 반응형 패딩 적용이 잘 되었습니다.
screenWidthDp를 사용하여 화면 너비에 따른 반응형 수평 패딩을 적용한 부분이PotiBottomButton,PotiHeaderPrimary등 다른 디자인 시스템 컴포넌트들과 일관성 있게 구현되었습니다. Modern Android Development 권장 사항에 따라 다양한 화면 크기를 지원하는 좋은 접근 방식입니다.app/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiBottomButton.kt (1)
12-28: LGTM! 반응형 수평 패딩 적용이 일관되게 구현되었습니다.
screenWidthDp(16.dp)를 사용하여 다양한 화면 크기에서 적절한 여백을 제공하는 반응형 레이아웃이 적용되었습니다. 다른 네비게이션 컴포넌트들과 동일한 패턴을 따르고 있어 일관성이 좋습니다.app/src/main/java/com/poti/android/core/designsystem/component/navigation/PotiHeaderPrimary.kt (1)
21-37: LGTM! 반응형 패딩이 잘 적용되었습니다.헤더의 시작(20.dp)과 끝(4.dp) 패딩에
screenWidthDp를 적용하여 다양한 화면 크기에서 적절한 레이아웃을 유지하도록 구현되었습니다.PotiHeaderPage,PotiBottomButton과 일관된 반응형 패딩 전략을 따르고 있어 디자인 시스템의 통일성이 유지됩니다.app/src/main/java/com/poti/android/presentation/party/home/navigation/HomeNavigation.kt (1)
24-34: NavController 기반 네비게이션 전환이 잘 되어 있습니다.콜백 기반에서
NavController기반으로 전환하면서 메서드 레퍼런스(navController::navigateToPartyDetail)를 활용한 점이 깔끔합니다. 이 패턴은 Modern Android Development에서 권장하는 방식이며, 네비게이션 로직을 일관되게 관리할 수 있게 해줍니다.app/src/main/java/com/poti/android/domain/type/PartyStatusType.kt (1)
1-10: Domain 타입 정의가 적절합니다.
PartyStatusTypeenum이 순수 Kotlin으로 작성되어 Domain 레이어의 순수성이 잘 유지되어 있습니다. 각 상태에 대한 한글 주석도 비즈니스 로직 이해에 도움이 됩니다.app/src/main/java/com/poti/android/core/designsystem/component/display/PotiProfileSummary.kt (1)
47-56: AsyncImage로의 전환이 적절합니다.
SubcomposeAsyncImage에서AsyncImage로 단순화하면서placeholder와error처리가 깔끔하게 구현되어 있습니다.profileImageUrl을 nullable로 변경한 것도 프로필 이미지가 없는 경우를 적절히 처리할 수 있게 해줍니다.app/src/main/java/com/poti/android/domain/model/user/UserSummary.kt (1)
3-9: LGTM! 깔끔한 도메인 모델이에요.순수 Kotlin으로 작성된 불변(immutable)
data class로, Clean Architecture의 Domain 레이어 원칙을 잘 준수하고 있어요.profileImage의 nullable 처리도 적절하게 되어 있네요.app/src/main/java/com/poti/android/domain/model/party/PartyImage.kt (1)
3-6: LGTM! 단순하고 명확한 도메인 모델이에요.이미지 메타데이터를 담는 불변
data class로, 안드로이드 의존성 없이 순수 Kotlin으로 잘 구현되어 있어요.app/src/main/java/com/poti/android/presentation/party/PartyNavigation.kt (1)
18-39: NavController 기반 네비게이션으로의 전환, 좋아요!콜백 기반에서
NavController직접 전달 방식으로 변경하신 것은 Modern Android Development의 권장 패턴과 일치해요. 코드 가독성과 일관성이 향상되었네요.참고로,
goodsFilterNavGraph와partyCreateNavGraph는 현재navController를 받지 않고 있는데, 향후 해당 화면들에서 네비게이션이 필요해지면 동일한 패턴으로 확장하시면 될 것 같아요.app/src/main/java/com/poti/android/presentation/main/PotiNavHost.kt (1)
32-35: LGTM! 네비게이션 호출 방식이 잘 업데이트되었어요.
partyNavGraph에NavController를 직접 전달하는 방식으로 깔끔하게 변경되었네요.navigator.navController를 통해 접근하는 것도 적절해요.app/src/main/java/com/poti/android/presentation/party/detail/component/PartyUploaderInfo.kt (1)
22-27: Composable 시그니처가 잘 구성되었어요.필수 파라미터(
userSummary,onClick) 다음에Modifier를 선택적 파라미터로 배치한 것은 Compose 컨벤션에 맞아요.Modifier가 첫 번째 선택적 파라미터로 올바르게 위치해 있네요.app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.kt (1)
12-13: LGTM! MVI 패턴에 맞는 상태 노출 방식입니다.
MutableStateFlow를 private으로 선언하고asStateFlow()로 불변 StateFlow를 노출하는 패턴이 올바르게 적용되어 있습니다. Modern Android Development 권장 사항에 부합합니다.다만, 가독성을 위해
uiState에 명시적 타입을 추가하는 것도 고려해 보실 수 있습니다:val uiState: StateFlow<PartyDetailUiState> = _uiState.asStateFlow()app/src/main/java/com/poti/android/presentation/party/detail/DummyPartyDetailData.kt (2)
54-75: 중복된 userId 확인이 필요합니다.
participants리스트에서userId = 1을 가진Participant가 두 개 존재합니다 (Lines 55-61, 62-68). 한 사용자가 여러 멤버를 선택한 경우를 표현하려는 의도라면,selectedMembers리스트에 여러 멤버를 담는 것이 더 적절할 수 있습니다.Participant( userId = 1, nickname = "참여자1", profileImage = null, rating = 4.5, selectedMembers = listOf("원영", "이서"), // 한 Participant에 여러 멤버 ),더미 데이터라 큰 문제는 아니지만, 실제 데이터 구조와 일치하는지 확인해 주세요.
10-79: Preview/테스트용 더미 데이터 구성이 잘 되어 있습니다.
PartyDetail모델의 모든 필드를 포함하여 다양한 시나리오를 테스트할 수 있도록 구성되어 있습니다. 프리뷰 작성 시 유용하게 활용될 것입니다.app/src/main/java/com/poti/android/presentation/party/detail/component/PartyParticipantsInfo.kt (1)
48-68: 참여자 목록 렌더링 로직이 잘 구현되어 있습니다.중첩된
forEach를 사용하여 각 참여자의selectedMembers를 개별 행으로 표시하는 로직이 명확합니다.Column내에서 사용되므로LazyColumn의key파라미터 이슈는 해당되지 않습니다.app/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailContent.kt (1)
81-100: 배송 옵션 FlowRow 구현이 잘 되어 있습니다.
FlowRow와IntrinsicSize.Min을 활용하여 동적인 레이아웃을 구현하셨고,forEachIndexed를 통해 마지막 항목 이후에는 구분선을 표시하지 않는 로직도 적절합니다.toMoneyString()확장 함수를 활용한 금액 포맷팅도 좋습니다.app/src/main/java/com/poti/android/presentation/party/detail/model/Contracts.kt (2)
8-10: MVI 패턴의 UiState가 올바르게 구현되어 있습니다.
data class와val프로퍼티를 사용하여 불변 상태를 보장하고,ApiState<PartyDetail>을 통해 Loading/Success/Error 상태를 표현할 수 있는 구조입니다. Modern Android Development의 상태 관리 권장 사항을 잘 따르고 있습니다.향후 기능 확장 시 추가적인 UI 상태(예:
isRefreshing,errorMessage등)가 필요하다면 이data class에 필드를 추가하시면 됩니다.
1-2: 파일명 규칙 예외 처리가 적용되어 있습니다.
@file:Suppress("ktlint:standard:filename")으로 파일명과 클래스명 불일치 경고를 억제하고 있습니다.Contracts.kt에 여러 계약(UiState, Intent, SideEffect 등)을 함께 정의하려는 의도로 보입니다.향후
PartyDetailIntent나PartyDetailSideEffect등이 추가될 예정이라면 현재 구조가 적절합니다. 단일 클래스만 유지된다면 파일명을PartyDetailUiState.kt로 변경하는 것도 고려해 주세요.app/src/main/java/com/poti/android/presentation/party/detail/component/PartyDetailHeaderInfo.kt (1)
42-48: 제목 텍스트에maxLines설정이 필요해 보여요.
minLines = 2만 설정되어 있고maxLines가 없어서, 긴 제목의 경우 텍스트가 무한정 확장될 수 있어요. 기존 리뷰 코멘트에서도 언급된 것처럼, 상세 페이지에서는 타이틀을 다 보여줘야 할 것 같지만, 레이아웃 안정성을 위해 적절한maxLines값을 고려해 주세요.app/src/main/java/com/poti/android/domain/model/party/PartyDetail.kt (1)
7-24: 도메인 모델이 잘 정의되어 있어요!순수 Kotlin으로 작성되어 Android 의존성이 없고, 모든 프로퍼티가
val로 선언되어 불변성을 보장하고 있어요. Clean Architecture의 Domain 순수성 원칙을 잘 준수하고 있네요. 한글 주석도 명확해서 가독성이 좋습니다.app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt (1)
80-92: 이미지 페이저 구현이 적절해요.
HorizontalPager와AsyncImage를 활용한 이미지 갤러리 구현이 잘 되어 있어요.aspectRatio로 일관된 비율을 유지하고 있네요.app/src/main/res/values/strings.xml (1)
25-37: PartyDetail 관련 문자열 리소스가 잘 정리되어 있어요!섹션별 주석으로 구분되어 있고, 포맷 문자열도 positional argument(
%1$s,%2$d)를 적절히 사용하고 있어요. 하드코딩 대신 리소스를 활용하는 좋은 패턴이에요.app/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.kt (1)
36-41: 문제없습니다.onNavigateToProfile콜백 시그니처가 일치해요.
navController::navigateToProfile은fun NavController.navigateToProfile(userId: Long)의 메서드 참조이며, 이것이 콜백으로 전달될 때(Long) -> Unit타입으로 정확히 변환됩니다. 이는PartyDetailRoute의onNavigateToProfile: (Long) -> Unit파라미터 타입과 완벽하게 일치합니다.Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
app/src/main/java/com/poti/android/domain/model/delivery/DeliveryOption.kt
Show resolved
Hide resolved
| import androidx.compose.ui.res.stringResource | ||
| import androidx.compose.ui.tooling.preview.Preview | ||
| import androidx.compose.ui.unit.dp | ||
| import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel |
There was a problem hiding this comment.
hiltViewModel import 경로가 deprecated되었어요.
androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel은 deprecated된 경로예요. Modern Android Development 권장사항에 따라 androidx.hilt.navigation.compose.hiltViewModel을 사용해 주세요.
🔧 제안하는 수정 사항
-import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
+import androidx.hilt.navigation.compose.hiltViewModel📝 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.
| import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel | |
| import androidx.hilt.navigation.compose.hiltViewModel |
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt`
at line 20, The import for hiltViewModel is using the deprecated package;
replace the import statement
"androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel" with
"androidx.hilt.navigation.compose.hiltViewModel" so all usages of
hiltViewModel() in PartyDetailScreen.kt reference the modern package; ensure
there are no other deprecated hilt lifecycle imports in the file and run a quick
build to confirm the symbol resolves.
app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/poti/android/presentation/party/home/HomeScreen.kt
Show resolved
Hide resolved
| <string name="party_detail_participants">참여자</string> | ||
| <string name="party_detail_review_count">%d개의 평가</string> | ||
| <string name="party_detail_participants_count">%1$d/%2$d</string> | ||
| <string name="party_detail_announcement">안내 사항\n어쩌구 저쩌구\n어쩌구 저쩌구\n어쩌구 저쩌구\n</string> |
There was a problem hiding this comment.
안내 사항 문자열이 플레이스홀더 텍스트로 되어 있어요.
party_detail_announcement가 "어쩌구 저쩌구"로 되어 있는데, 실제 안내 문구로 교체가 필요해 보여요. 기획 확정 후 업데이트해 주세요.
🤖 Prompt for AI Agents
In `@app/src/main/res/values/strings.xml` at line 36, The string resource
party_detail_announcement currently contains placeholder text ("어쩌구 저쩌구");
replace its value in strings.xml with the finalized announcement text from
product/PM, preserving any intended line breaks or formatting (use \n for
newlines or string resources with <xliff:g> if needed) and ensure the string
name party_detail_announcement remains unchanged so callers referencing it are
unaffected.
|
|
||
| data class DeliveryOption( | ||
| val deliveryId: Long, | ||
| val deliveryId: Long, // 바송 방식 ID |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt (1)
22-22:hiltViewModelimport 경로가 deprecated되었어요.
androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel은 deprecated된 경로예요.androidx.hilt.navigation.compose.hiltViewModel을 사용해 주세요.🔧 제안하는 수정 사항
-import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.hilt.navigation.compose.hiltViewModel
🧹 Nitpick comments (3)
app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt (2)
51-59: LaunchedEffect 키 사용을 개선해 주세요.
viewModel.sideEffect를 키로 사용하면 Flow 참조가 변경되지 않아 한 번만 실행되긴 하지만, 의도가 명확하지 않아요.Unit을 키로 사용하는 것이 더 직관적이에요. 이렇게 하면 컴포저블이 처음 컴포지션될 때 한 번 실행되고, 내부에서 Flow를 수집하는 의도가 명확해져요.♻️ 제안하는 수정 사항
- LaunchedEffect(viewModel.sideEffect) { - viewModel.sideEffect.collect { effect -> + LaunchedEffect(Unit) { + viewModel.sideEffect.collect { effect -> when (effect) { PartyDetailEffect.NavigateBack -> onPopBackStack() PartyDetailEffect.NavigateToJoin -> onNavigateToJoin() is PartyDetailEffect.NavigateToProfile -> onNavigateToProfile(effect.userId) } } }
117-121:onLikeClick핸들러가 비어 있어요.좋아요 기능이 아직 구현되지 않은 것 같아요. 추후 구현 예정이시라면 TODO 주석을 남겨주시면 좋을 것 같아요. 필요하시면
PartyDetailIntent에OnLikeClick을 추가하는 것을 도와드릴 수 있어요.app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.kt (1)
36-40: 서버 연결 시 에러 처리 추가가 필요해요.
launchScope에onError콜백이 제공되지 않았어요. 현재는 더미 데이터를 사용하지만, 서버 연결 시 API 호출 실패에 대한 에러 처리가 필요해요.BaseViewModel의launchScope가onError파라미터를 지원하므로 활용해 주세요.♻️ 제안하는 수정 사항 (서버 연결 시)
private fun loadPartyDetail() = launchScope( + onError = { error -> + updateState { copy(partyDetail = ApiState.Error(error)) } + } + ) { updateState { copy(partyDetail = ApiState.Loading) } - // TODO: [지현] 나중에 서버 연결 - updateState { copy(partyDetail = ApiState.Success(dummyPartyDetail)) } + // TODO: [지현] 서버 API 호출 + val result = repository.getPartyDetail(partyId) + updateState { copy(partyDetail = ApiState.Success(result)) } }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/src/main/java/com/poti/android/domain/model/delivery/DeliveryOption.ktapp/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.ktapp/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.ktapp/src/main/java/com/poti/android/presentation/party/detail/model/Contracts.ktapp/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- app/src/main/java/com/poti/android/domain/model/delivery/DeliveryOption.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt
⚙️ CodeRabbit configuration file
**/*.kt: 코드를 리뷰할 때 다음 Kotlin 및 Jetpack Compose 모범 사례를 중점적으로 확인:
Jetpack Compose 성능 및 UI 최적화:
- Recomposition 방지: 불필요한 리컴포지션을 유발하는 코드를 지적해줘. 특히
LazyColumn등 리스트에서key파라미터가 누락되었는지 확인해줘.- 스마트한 계산: 계산 비용이 높은 로직은
remember나derivedStateOf로 감싸져 있는지 확인해줘.- 안정성(Stability): List나 일반 클래스를 State로 사용할 때, 불필요한 리컴포지션을 막기 위해
@Immutable이나@Stable어노테이션 사용을 제안해줘.- Modifier 규칙:
Modifier는 항상 컴포저블 함수의 첫 번째 선택적 파라미터로 받아야 하며, 재사용성을 위해 외부에서 주입받아야 해.- 리소스 사용: 하드코딩된 값(색상, 크기, 문자열) 대신
Theme,Dimens,strings.xml리소스를 사용하는지 체크해줘.- 접근성 예외: Icon이나 Image 컴포저블의
contentDescription이null인 경우는 장식용(Decorative) 이미지로 간주하고 지적하지 마.MVI (Model-View-Intent) 아키텍처 및 상태 관리:
- 단방향 데이터 흐름(UDF): UI는 상태를 직접 변경할 수 없고, 반드시
Intent(또는 Event)를 통해 ViewModel로 요청을 보내야 해.- 불변 상태(Immutable State):
UiState는 반드시data class+val프로퍼티로 구성되어야 하며, 상태 업데이트 시.copy()를 사용해야 해.- Side Effect 분리: 네비게이션, Toast 같은 일회성 이벤트는 UiState가 아닌
Channel이나SharedFlow로 처리하여 화면 회전 시 재발생하지 않도록 해야 해.- 안전한 수집: UI에서 Flow 수집 시
collectAsStateWithLifecycle()을 사용하여 생명주기를 준수하는지 확인해줘.- 상태 노출:
ViewModel내부에서StateFlow나SharedFlow를 올바르게 노출하고 있는지 확인해줘.- 호이스팅(Hoisting): 상태나 UI 이벤트 처리가 적절하게 호이스팅되었는지 확인해줘. UI 로직과 비즈니스 로직을 분리하고, UI가 로직을 직접 수행하지 않도록 확인해줘.
Clean Architecture (Dependency Rule) 준수:
- Domain 순수성: Domain 레이어(
domain패키지)는 절대로 안드로이드 의존성(android.*,R클래스 등)을 가져서는 안 돼. 순수 Kotlin 코드인지 엄격히 확인해줘.- 데이터 노출 금지: Data 레이어의 DTO(
@Entity,@SerializedName)가 UI나 Domain 레이어로 바로 노출되면 안 돼. 반드시 Mapper를 통해 변환했는지 확인해줘.- 계층 간 의존성:
UI -> Domain <- Data방향이 올바른지, UI가 Data 레이어를 직접 참조하고 있진 않은지 감시해줘.Kotlin & Coroutines 안전성:
- Scope 사용:
GlobalScope사용을 금지하고,viewModelScope나lifecycleScope사용을 권장해줘.- Dispatcher 주입:
Dispatchers.IO등을 하드코딩하지 말고, 테스트 용이성을 위해 생성자를 통해 주입(Injection)받도록 제안해줘.- 예외 처리: Coroutine 실행 시
runCatching이나CoroutineExceptionHandler등을 통해 예외 처리가 누락되지 않았는지 확인해줘.- Null-Safety: 불필요한
!!연산자 사용을 지적...
Files:
app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.ktapp/src/main/java/com/poti/android/presentation/party/detail/model/Contracts.ktapp/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.ktapp/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.kt
🧬 Code graph analysis (1)
app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.kt (1)
app/src/main/java/com/poti/android/core/base/BaseViewModel.kt (3)
sendEffect(34-38)launchScope(42-54)updateState(30-32)
🔇 Additional comments (8)
app/src/main/java/com/poti/android/presentation/party/detail/navigation/PartyDetailNavigation.kt (2)
15-21: Route 정의가 깔끔하게 구현되었어요!
PartyDetailRoute.Detail에partyId파라미터를 추가하여 타입 안전한 네비게이션을 구현하셨네요.@Serializable어노테이션을 사용한 것도 Modern Android Development의 Navigation Compose 권장 사항을 잘 따르고 있어요.
31-47: 네비게이션 그래프 구성이 잘 되어 있어요!
navController를 파라미터로 받아서 콜백을 메서드 레퍼런스로 전달하는 패턴이 깔끔해요. MVI 아키텍처의 단방향 데이터 흐름을 잘 준수하고 있어요.app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailScreen.kt (2)
103-115: HorizontalPager와 이미지 로딩 구현이 좋아요!
rememberPagerState를 사용하고 Coil의AsyncImage로 이미지를 로드하는 패턴이 Modern Android Development 권장 사항을 잘 따르고 있어요.ContentScale.Crop으로 이미지 비율도 잘 처리했네요.
75-96: PartyDetailScreen 구조가 잘 설계되었어요!
Modifier를 첫 번째 선택적 파라미터로 배치하고, 콜백들을 통해 상태 호이스팅을 적절히 구현했어요.Scaffold를 활용한topBar와bottomBar구성도 깔끔하네요.app/src/main/java/com/poti/android/presentation/party/detail/PartyDetailViewModel.kt (2)
14-25: ViewModel 구조가 MVI 패턴을 잘 따르고 있어요!
@HiltViewModel과@Inject가 올바르게 적용되었고,SavedStateHandle을 통한 route 인자 추출도 깔끔해요.BaseViewModel을 상속받아 상태 관리와 사이드 이펙트 처리가 일관되게 구현되었네요.
27-34: Intent 처리 로직이 깔끔해요!모든 Intent가
when표현식으로 명확하게 처리되고, 네비게이션 같은 일회성 이벤트는sendEffect를 통해 분리되어 있어요. MVI의 단방향 데이터 흐름을 잘 준수하고 있네요.app/src/main/java/com/poti/android/presentation/party/detail/model/Contracts.kt (2)
10-12: UiState 정의가 MVI 패턴을 잘 따르고 있어요!
data class와val프로퍼티로 불변성을 보장하고 있고,ApiState를 래핑하여 로딩/성공/에러 상태를 표현할 수 있어요. 코딩 가이드라인의 "불변 상태(Immutable State)" 원칙을 잘 준수했네요.
14-30: Intent와 Effect 분리가 잘 되어 있어요!
sealed interface를 사용해 Intent와 Effect를 명확히 정의했어요. 특히 네비게이션 같은 일회성 이벤트를PartyDetailEffect로 분리하여 화면 회전 시 재발생하지 않도록 처리한 점이 좋아요. MVI 아키텍처의 Side Effect 분리 원칙을 잘 따르고 있네요.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| when (val state = uiState.partyDetail) { | ||
| is ApiState.Success -> { | ||
| PartyDetailScreen( | ||
| partyDetail = state.data, | ||
| onBackClick = { viewModel.processIntent(PartyDetailIntent.OnBackClick) }, | ||
| onJoinClick = { viewModel.processIntent(PartyDetailIntent.OnJoinClick) }, | ||
| onUploaderClick = { viewModel.processIntent(PartyDetailIntent.OnUploaderClick(it)) }, | ||
| modifier = modifier, | ||
| ) | ||
| } | ||
| else -> {} | ||
| } |
There was a problem hiding this comment.
Loading과 Error 상태 처리가 누락되었어요.
현재 ApiState.Success만 처리하고 있어서 로딩 중이거나 에러 발생 시 빈 화면이 표시돼요. 사용자 경험을 위해 로딩 인디케이터와 에러 UI를 추가해 주세요.
🔧 제안하는 수정 사항
when (val state = uiState.partyDetail) {
+ is ApiState.Loading -> {
+ // TODO: 로딩 UI 추가 (예: Box with CircularProgressIndicator)
+ }
+ is ApiState.Error -> {
+ // TODO: 에러 UI 추가 (예: 재시도 버튼 포함)
+ }
is ApiState.Success -> {
PartyDetailScreen(
partyDetail = state.data,
onBackClick = { viewModel.processIntent(PartyDetailIntent.OnBackClick) },
onJoinClick = { viewModel.processIntent(PartyDetailIntent.OnJoinClick) },
onUploaderClick = { viewModel.processIntent(PartyDetailIntent.OnUploaderClick(it)) },
modifier = modifier,
)
}
- else -> {}
}* [feat/36] participant-overview implement * [feat/#36] participant-detail implement * [feat/#36] participant dropdown implement * [fix/#36] apply ktlint * [Refactor/#41] 필드 수정 (#42) * [Feat/#41] ShortTextField에 trailingIcon 추가 * [Chore/#41] kdoc 주석 추가 * [Refactor/#41] FieldErrorMessage 삭제 및 필드에 PotiErrorMessage 적용 * [Refactor/#41] trailingIcon 기본값 null로 변경 * [Refactor/#41] 에러메시지 노출 조건 isNotEmpty -> isNotBlank 변경 * [fix/#36] 코드리뷰 반영 * [fix/#36] apply ktlint * [Feat/#35] 분철팟 상세 뷰 UI 구현 (#39) * [feat/#35] 헤더 컴포넌트 구현 * [feat/#35] 분철팟 상세 뷰 UI 구현 * [feat/#35] 분철팟 상세 뷰 UI 구현 * [feat/#35] 이미지 비율 수정 * [feat/#35] 내비게이션 연결 * [feat/#35] 패키지 분리 * [feat/#35] 내비게이션 파라미터 수정 * [feat/#35] 코리 반영 * [feat/#35] 내비 수정 * [feat/#35] 주석 수정 * [feat/#35] 뷰모델 연결 * [feat/#32] card-history implement * [feat/#32] card-history implement * [fix/#32] 코리 반영 * [Feat/#27] 탐색 컴포넌트 구현 (#37) * [Feat/#27] GoodsSmallCard * [Feat/#27] GoodsLargeCard * [Feat/#27] PostsCard * [Refactor/#27] 디자인 수정사항 반영 * [Refactor/#27] string 추출 * [Refactor/#27] 코드 리뷰 반영 * [Feat/#31] 등록 뷰 컴포넌트 (#40) * [Feat/#31] Edit Option Price 컴포넌트 구현 * [Feat/#31] 이미지 관련 버튼 컴포넌트 구현 * [Feat/#31] 힌트 팝업 컴포넌트 구현 * [Chore/#31] klint 적용 * [Rename/#31] Hint.kt -> HintTooltip.kt * [Refactor/#31] Edit Option Price 레이아웃 리팩토링 및 스트링 리소스 추출 * [Fix/#31] 툴팁 위치 계산식 수정 - 중앙 배치 위해 xOffset에 툴팁 폭 포함 * [Chore/#31] 미사용 코드 삭제 * [Chore/#31] klint 적용 * [Feat/#31] 갤러리 이미지 선택 기능 추가 * [Chore/#31] 오탈자 수정 * [Refactor/#31] 이미지 피커 개선 - Row -> LazyRow 변경해 contentPadding 적용 - distinct 추가해 중복 이미지 방지 - 이미지만 선택 가능하도록 조건 추가 * [Refactor/#31] Edit Option Price 개선 - 최대 길이 제한 - 특수문자 입력 제한 - take 대신 반복문 사용해 불필요한 string 객체 생성 방지 - TransformedText 콤마 추가 로직 단순화 * [Chore/#31] klint 적용 * [Refactor/#31] core 확장함수 적용 * [Fix/#31] strings 충돌 이슈 해결 * [fix/#36] 코드 리뷰 반영 * [fix/#36] apply ktlint * [feat/36] participant-overview implement * [fix/#36] fix conflict * [feat/#36] participant dropdown implement * [fix/#36] apply ktlint * [fix/#36] resolve conflict * [fix/#36] apply ktlint * [fix/#36] 코드 리뷰 반영 * [fix/#36] apply ktlint * [fix/#36] 코드 리뷰 반영 * [fix/#36] 코드리뷰 반영 * [fix/#36] 코드 리뷰 반영 * [fix/#36] apply ktlint * [fix/#36] 코드리뷰 반영 * [fix/#36] apply ktlint --------- Co-authored-by: dodo <108921606+doyeon0307@users.noreply.github.com> Co-authored-by: 이지현 <95419701+jyvnee@users.noreply.github.com> Co-authored-by: Yerim Son <119676236+sonyerim@users.noreply.github.com>
* [feat/36] participant-overview implement * [feat/#36] participant-detail implement * [feat/#36] participant dropdown implement * [fix/#36] apply ktlint * [Refactor/#41] 필드 수정 (#42) * [Feat/#41] ShortTextField에 trailingIcon 추가 * [Chore/#41] kdoc 주석 추가 * [Refactor/#41] FieldErrorMessage 삭제 및 필드에 PotiErrorMessage 적용 * [Refactor/#41] trailingIcon 기본값 null로 변경 * [Refactor/#41] 에러메시지 노출 조건 isNotEmpty -> isNotBlank 변경 * [fix/#36] 코드리뷰 반영 * [fix/#36] apply ktlint * [Feat/#35] 분철팟 상세 뷰 UI 구현 (#39) * [feat/#35] 헤더 컴포넌트 구현 * [feat/#35] 분철팟 상세 뷰 UI 구현 * [feat/#35] 분철팟 상세 뷰 UI 구현 * [feat/#35] 이미지 비율 수정 * [feat/#35] 내비게이션 연결 * [feat/#35] 패키지 분리 * [feat/#35] 내비게이션 파라미터 수정 * [feat/#35] 코리 반영 * [feat/#35] 내비 수정 * [feat/#35] 주석 수정 * [feat/#35] 뷰모델 연결 * [feat/#32] card-history implement * [feat/#32] card-history implement * [fix/#32] 코리 반영 * [Feat/#27] 탐색 컴포넌트 구현 (#37) * [Feat/#27] GoodsSmallCard * [Feat/#27] GoodsLargeCard * [Feat/#27] PostsCard * [Refactor/#27] 디자인 수정사항 반영 * [Refactor/#27] string 추출 * [Refactor/#27] 코드 리뷰 반영 * [Feat/#31] 등록 뷰 컴포넌트 (#40) * [Feat/#31] Edit Option Price 컴포넌트 구현 * [Feat/#31] 이미지 관련 버튼 컴포넌트 구현 * [Feat/#31] 힌트 팝업 컴포넌트 구현 * [Chore/#31] klint 적용 * [Rename/#31] Hint.kt -> HintTooltip.kt * [Refactor/#31] Edit Option Price 레이아웃 리팩토링 및 스트링 리소스 추출 * [Fix/#31] 툴팁 위치 계산식 수정 - 중앙 배치 위해 xOffset에 툴팁 폭 포함 * [Chore/#31] 미사용 코드 삭제 * [Chore/#31] klint 적용 * [Feat/#31] 갤러리 이미지 선택 기능 추가 * [Chore/#31] 오탈자 수정 * [Refactor/#31] 이미지 피커 개선 - Row -> LazyRow 변경해 contentPadding 적용 - distinct 추가해 중복 이미지 방지 - 이미지만 선택 가능하도록 조건 추가 * [Refactor/#31] Edit Option Price 개선 - 최대 길이 제한 - 특수문자 입력 제한 - take 대신 반복문 사용해 불필요한 string 객체 생성 방지 - TransformedText 콤마 추가 로직 단순화 * [Chore/#31] klint 적용 * [Refactor/#31] core 확장함수 적용 * [Fix/#31] strings 충돌 이슈 해결 * [fix/#36] 코드 리뷰 반영 * [fix/#36] apply ktlint * [feat/36] participant-overview implement * [fix/#36] fix conflict * [feat/#36] participant dropdown implement * [fix/#36] apply ktlint * [fix/#36] resolve conflict * [fix/#36] apply ktlint * [fix/#36] 코드 리뷰 반영 * [fix/#36] apply ktlint * [fix/#36] 코드 리뷰 반영 * [fix/#36] 코드리뷰 반영 * [fix/#36] 코드 리뷰 반영 * [fix/#36] apply ktlint * [fix/#36] 코드리뷰 반영 * [fix/#36] apply ktlint --------- Co-authored-by: dodo <108921606+doyeon0307@users.noreply.github.com> Co-authored-by: 이지현 <95419701+jyvnee@users.noreply.github.com> Co-authored-by: Yerim Son <119676236+sonyerim@users.noreply.github.com>


Related issue 🛠️
Work Description ✏️
Screenshot 📸
Screen_recording_20260115_051840.mp4
Uncompleted Tasks 😅
N/A
To Reviewers 📢
애뮬 돌려보면 잘 나오는데 녹화하면 개밤티 필터가 씌워져서 나옴!!!!! ㅠㅠ
Summary by CodeRabbit
릴리즈 노트
새로운 기능
개선사항
✏️ Tip: You can customize this high-level summary in your review settings.