Conversation
Walkthrough색상 값 수정, 게이지 단계(gaugeStep) 계산 및 UI 전파, 게이지 타입 이미지 필드 논-널 전환, 레이아웃/정렬·modifier 조정, 홈 내 캘린더 네비게이션 분기 추가 등이 포함된 변경입니다. Changes
Sequence Diagram(s)(생성 조건에 부합하지 않아 생략됨) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 1 | ❌ 4❌ Failed checks (1 warning, 3 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
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/cherrish/android/presentation/home/component/ChallengeSection.kt (1)
96-103: gauges 비어있는 경우 예외 가능성 있습니다.
gauges.lastIndex가 -1일 때coerceIn이 예외를 던집니다. 비어있는 리스트가 들어올 수 있다면 방어 로직이 필요합니다.🛡️ 제안 수정
- val safeStep = currentStep.coerceIn(0, gauges.lastIndex) + val safeStep = if (gauges.isNotEmpty()) { + currentStep.coerceIn(0, gauges.lastIndex) + } else { + 0 + }
🤖 Fix all issues with AI agents
In `@app/src/main/java/com/cherrish/android/presentation/home/HomeViewModel.kt`:
- Around line 43-59: The current code clamps selectedIndex to at least 1
(safeIndex) but leaves currentStep using the raw response.cherryLevel, causing
UI mismatch when level == 0; inside the _uiState.update ->
UiState.Success(HomeUiState(...)) block, compute a single clamped value (e.g.,
safeLevel) from response.cherryLevel using coerceIn(1,
CherrishGaugeType.entries.lastIndex) and use that same safeLevel for both
currentStep and selectedIndex (replace references to level/currentStep or
safeIndex accordingly) so both fields share the identical safe range.
🧹 Nitpick comments (3)
app/src/main/java/com/cherrish/android/presentation/mypage/component/MyPageHeader.kt (1)
34-40:contentScale추가를 권장합니다.
size와clip(CircleShape)를 함께 사용할 때, 원본 이미지의 비율이 1:1이 아닌 경우 원형 영역을 제대로 채우지 못할 수 있습니다.ContentScale.Crop을 추가하면 이미지가 원형 영역을 완전히 채우도록 보장할 수 있습니다.♻️ 권장 수정 사항
+import androidx.compose.ui.layout.ContentScaleImage( painter = painterResource(id = profileIcon), contentDescription = null, modifier = Modifier .size(48.dp) - .clip(CircleShape) + .clip(CircleShape), + contentScale = ContentScale.Crop )app/src/main/java/com/cherrish/android/presentation/splash/SplashViewModel.kt (1)
20-30: 임시 코드 정리 필요자동 로그인이 임시 삭제된 상태에서 몇 가지 정리가 필요합니다:
tokenManager.getId()호출 결과(id)가 사용되지 않아 불필요한 연산입니다- 주석 처리된 코드는 추후 복원 시점이 명확하지 않으면 삭제하는 것이 좋습니다
임시 변경이라면 TODO 주석을 추가하여 복원 시점을 명시하는 것을 권장합니다.
♻️ 제안: TODO 추가 또는 불필요 코드 제거
fun isAutoLoginCheck() { viewModelScope.launch { - val id = tokenManager.getId() _sideEffect.emit( + // TODO: 자동 로그인 기능 복원 예정 (이슈 `#XXX`) SplashSideEffect.NavigateToOnboarding -// if (id != null) { -// SplashSideEffect.NavigateToHome -// } else { -// SplashSideEffect.NavigateToOnboarding -// } ) } }app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt (1)
100-110: stepForUi 매핑 로직 개선
firstOrNull과 fallback 패턴을 사용한 안전한 처리가 좋습니다. 다만cherryLevel0과 1이 모두 1로 매핑되는 이유가 명확하지 않아 추후 유지보수 시 혼란을 줄 수 있습니다.간단한 주석을 추가하면 의도가 더 명확해집니다.
💡 제안: 매핑 의도 주석 추가
private fun ChallengeMissionProgressResponseModel.toUiState(): ChallengeMissionProgressUiState { + // cherryLevel 0은 초기 상태이므로 UI에서는 level 1로 표시 val stepForUi = when (cherryLevel) { 0, 1 -> 1 else -> cherryLevel }
| val level = response.cherryLevel | ||
| val safeIndex = level.coerceIn( | ||
| 1, | ||
| CherrishGaugeType.entries.lastIndex | ||
| ) | ||
| _uiState.update { | ||
| UiState.Success( | ||
| HomeUiState( | ||
| currentStep = response.cherryLevel, | ||
| currentStep = level, | ||
| gauges = CherrishGaugeType.entries.toImmutableList(), | ||
| challengeRate = response.challengeRate, | ||
| challengeName = response.challengeName, | ||
| todayDate = response.toTodayDateString(), | ||
| plans = response.recentProcedures.toImmutableList(), | ||
| upcomingPlans = response.upcomingProcedures.toImmutableList(), | ||
| selectedIndex = (response.cherryLevel - 1) | ||
| .coerceIn(0, CherrishGaugeType.entries.size - 1) | ||
| selectedIndex = safeIndex | ||
| ) |
There was a problem hiding this comment.
LEVEL0 포함 시 상태 불일치 가능성 있습니다.
현재 safeIndex가 최소 1로 고정되어 level=0일 때 selectedIndex가 1로 치우치고, currentStep은 0으로 남아 UI 상태가 어긋날 수 있습니다. 둘 다 같은 안전 범위를 공유하도록 정리하는 게 안전합니다.
🔧 제안 수정
- val level = response.cherryLevel
- val safeIndex = level.coerceIn(
- 1,
- CherrishGaugeType.entries.lastIndex
- )
+ val level = response.cherryLevel
+ val safeLevel = level.coerceIn(
+ 0,
+ CherrishGaugeType.entries.lastIndex
+ )
...
- currentStep = level,
+ currentStep = safeLevel,
...
- selectedIndex = safeIndex
+ selectedIndex = safeLevel🤖 Prompt for AI Agents
In `@app/src/main/java/com/cherrish/android/presentation/home/HomeViewModel.kt`
around lines 43 - 59, The current code clamps selectedIndex to at least 1
(safeIndex) but leaves currentStep using the raw response.cherryLevel, causing
UI mismatch when level == 0; inside the _uiState.update ->
UiState.Success(HomeUiState(...)) block, compute a single clamped value (e.g.,
safeLevel) from response.cherryLevel using coerceIn(1,
CherrishGaugeType.entries.lastIndex) and use that same safeLevel for both
currentStep and selectedIndex (replace references to level/currentStep or
safeIndex accordingly) so both fields share the identical safe range.
There was a problem hiding this comment.
Actionable comments posted: 2
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/cherrish/android/presentation/home/component/ChallengeSection.kt (1)
209-221: Preview 함수 이름이 실제 동작과 불일치합니다.
Preview_ChallengeSection_NoChallenge라는 이름이지만challengeName = "아침 루틴"이 설정되어 있어 실제로는 챌린지가 있는 상태(hasChallenge = true)를 보여줍니다. NoChallenge 상태를 미리보기하려면challengeName = null또는challengeName = ""로 설정해야 합니다.🐛 NoChallenge 상태를 올바르게 미리보기하는 수정 제안
`@Preview`(showBackground = true) `@Composable` private fun Preview_ChallengeSection_NoChallenge() { CherrishTheme { ChallengeSection( - imageRes = R.drawable.img_challenge_lv2, + imageRes = null, currentStep = 0, gauges = CherrishGaugeType.entries.toImmutableList(), onChallengeStartClick = {}, - challengeName = "아침 루틴" + challengeName = null ) } }
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt`:
- Around line 101-110: The bug is that stepForCherry uses the raw cherryLevel
while gaugeStep is clamped, causing mismatched UI; change stepForCherry to base
itself on the clamped gaugeStep (use gaugeStep instead of cherryLevel) so both
gaugeStep and CherryType lookup (CherryType.entries.firstOrNull { it.step ==
stepForCherry } ?: CherryType.MONGRONG) use the same bounded value; ensure the
comparison uses the same numeric range and types as gaugeStep to avoid falling
back to MONGRONG unexpectedly.
In
`@app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt`:
- Around line 141-144: The currentStep coming from HomeViewModel (set from
response.cherryLevel) is not clamped and can produce incorrect states in
CherrishGaugeBar (its isActive logic uses gauge.step <= currentStep); fix this
by bounding currentStep before passing it into ChallengeSection/CherrishGaugeBar
(e.g., use currentStep.coerceIn(1, gauges.size) or equivalent) — update the code
that sets or forwards currentStep (HomeViewModel assignment and the
ChallengeSection invocation where currentStep is passed) so the value is
validated like safeIndex/StepProgressBar does.
🧹 Nitpick comments (1)
app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt (1)
76-81:NoChallenge에currentStep파라미터 전달 방식 검토 필요.
NoChallenge가 항상currentStep = 0으로 호출되므로,NoChallenge컴포저블에서currentStep파라미터를 제거하고 내부에서 0을 직접 사용하는 것이 더 명확할 수 있습니다. 또는 향후 확장성을 위해 의도적으로 유지하는 것이라면 현재 상태도 괜찮습니다.
| val gaugeStep = cherryLevel.coerceIn(0, 4) | ||
|
|
||
| val stepForCherry = when (cherryLevel) { | ||
| 0, 1 -> 1 | ||
| else -> cherryLevel | ||
| } | ||
|
|
||
| val cherryType = CherryType.entries.firstOrNull { it.step == stepForCherry } | ||
| ?: CherryType.MONGRONG | ||
|
|
There was a problem hiding this comment.
게이지 단계와 체리 타입 계산이 서로 불일치할 수 있습니다.
gaugeStep는 클램프되지만 stepForCherry는 원본 cherryLevel을 사용합니다. 범위를 벗어난 값이 오면 게이지는 최대인데 체리 타입은 기본값(MONGRONG)으로 떨어져 UI가 엇갈릴 수 있어요. 동일한 기준(클램프된 값)으로 정렬하는 편이 안전합니다.
🛠️ 제안 수정
- val gaugeStep = cherryLevel.coerceIn(0, 4)
-
- val stepForCherry = when (cherryLevel) {
+ val gaugeStep = cherryLevel.coerceIn(0, 4)
+
+ val stepForCherry = when (gaugeStep) {
0, 1 -> 1
- else -> cherryLevel
+ else -> gaugeStep
}🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt`
around lines 101 - 110, The bug is that stepForCherry uses the raw cherryLevel
while gaugeStep is clamped, causing mismatched UI; change stepForCherry to base
itself on the clamped gaugeStep (use gaugeStep instead of cherryLevel) so both
gaugeStep and CherryType lookup (CherryType.entries.firstOrNull { it.step ==
stepForCherry } ?: CherryType.MONGRONG) use the same bounded value; ensure the
comparison uses the same numeric range and types as gaugeStep to avoid falling
back to MONGRONG unexpectedly.
| CherrishGaugeBar( | ||
| currentStep = safeStep, | ||
| currentStep = currentStep, | ||
| gauges = gauges | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find CherrishGaugeBar implementation
fd -e kt | xargs grep -l "fun CherrishGaugeBar" | head -5Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 169
🏁 Script executed:
# Find ChallengeSection.kt and examine the context around lines 141-144
fd "ChallengeSection.kt" -e ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 160
🏁 Script executed:
# Search for safeStep references to understand what was removed
rg "safeStep" -B 2 -A 2Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 2405
🏁 Script executed:
# Examine CherrishGaugeBar implementation
cat -n app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeBar.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 6359
🏁 Script executed:
# Examine Challenge composable around lines 141-144 in ChallengeSection.kt
sed -n '120,155p' app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt | cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 1163
🏁 Script executed:
# Search for Challenge composable function signature and currentStep initialization
sed -n '1,100p' app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt | cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 4374
🏁 Script executed:
# Check CherrishGaugeType to understand step values
fd "CherrishGaugeType" -e kt | head -3Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 156
🏁 Script executed:
# Look at ChallengeSection Challenge composable more thoroughly
sed -n '94,155p' app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt | cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 2119
🏁 Script executed:
# Search for how currentStep is derived in the call hierarchy
rg "Challenge\(" -B 3 -A 3 app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 1018
🏁 Script executed:
# Examine CherrishGaugeType enum
cat -n app/src/main/java/com/cherrish/android/presentation/home/type/CherrishGaugeType.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 662
🏁 Script executed:
# Check ChallengeSection function signature and default values for currentStep
sed -n '38,50p' app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt | cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 551
🏁 Script executed:
# Search for usages of ChallengeSection to see how currentStep is passed
rg "ChallengeSection\(" -B 2 -A 5 --type kt | head -50Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 100
🏁 Script executed:
# Check how currentStep values are generated/passed from ViewModels
rg "currentStep" --type-add 'kt:*.kt' -B 2 -A 2 app/src/main/java/com/cherrish/android/presentation/home | head -80Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 7865
🏁 Script executed:
# Look for usages of ChallengeSection in the codebase
fd -e kt | xargs grep -l "ChallengeSection" | head -5Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 231
🏁 Script executed:
# Examine HomeViewModel to see how currentStep (level) is set
sed -n '1,80p' app/src/main/java/com/cherrish/android/presentation/home/HomeViewModel.kt | cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 3564
🏁 Script executed:
# Check the complete flow - HomeScreen usage of currentStep
sed -n '1,120p' app/src/main/java/com/cherrish/android/presentation/home/HomeScreen.kt | cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 5062
🏁 Script executed:
# Check the git history or PR context - look for recent changes around safeStep
rg "safeStep" -B 5 -A 5 app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeBar.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 56
🏁 Script executed:
# Verify what values currentStep can actually receive at runtime
# Check HomeViewModel more carefully - does response.cherryLevel have validation?
cat -n app/src/main/java/com/cherrish/android/presentation/home/HomeViewModel.kt | grep -A 15 "loadHomeData"Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 921
🏁 Script executed:
# Check if there's any validation at the data layer for cherryLevel
fd -e kt | xargs grep -l "cherryLevel\|cherryLevel" | head -5Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 536
🏁 Script executed:
# Check the HomeResponseModel and HomeResponseDto for cherryLevel definition/validation
cat -n app/src/main/java/com/cherrish/android/data/model/HomeResponseModel.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 2592
🏁 Script executed:
# Also check the DTO
cat -n app/src/main/java/com/cherrish/android/data/remote/dto/response/HomeResponseDto.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 1466
🏁 Script executed:
# Final verification: Check if there's any validation in Challenge composable for currentStep
sed -n '94,110p' app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt | cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 653
currentStep 경계 검증 부족으로 인한 런타임 오류 가능성
HomeViewModel에서 currentStep이 백엔드 응답값(response.cherryLevel)으로 직접 설정되며, 경계 검증 없이 ChallengeSection → Challenge → CherrishGaugeBar로 전달됩니다. CherrishGaugeBar의 isActive 로직(line 54: gauge.step <= currentStep)이 경계값을 처리하지 않으면:
currentStep ≤ 0: 모든 게이지가 비활성currentStep > 4: 모든 게이지가 활성 (의도하지 않은 상태)
HomeViewModel 라인 44-46에서 safeIndex는 경계 처리되지만 currentStep은 처리되지 않습니다. StepProgressBar.kt와 유사하게 currentStep.coerceIn(1, gauges.size) 또는 동등한 검증이 필요합니다.
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/home/component/ChallengeSection.kt`
around lines 141 - 144, The currentStep coming from HomeViewModel (set from
response.cherryLevel) is not clamped and can produce incorrect states in
CherrishGaugeBar (its isActive logic uses gauge.step <= currentStep); fix this
by bounding currentStep before passing it into ChallengeSection/CherrishGaugeBar
(e.g., use currentStep.coerceIn(1, gauges.size) or equivalent) — update the code
that sets or forwards currentStep (HomeViewModel assignment and the
ChallengeSection invocation where currentStep is passed) so the value is
validated like safeIndex/StepProgressBar does.
|
잘하셨어요 |
Related issue 🛠
Work Description ✏️
Screenshot 📸
Uncompleted Tasks 😅
To Reviewers 📢
Summary by CodeRabbit
Style
New Features
Bug Fixes
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.