Skip to content

[FEAT/#35] 챌린지 뷰 컴포넌트 구현#41

Closed
hyeminililo wants to merge 24 commits intodevelopfrom
feat/#35-challenge-view
Closed

[FEAT/#35] 챌린지 뷰 컴포넌트 구현#41
hyeminililo wants to merge 24 commits intodevelopfrom
feat/#35-challenge-view

Conversation

@hyeminililo
Copy link
Copy Markdown
Contributor

@hyeminililo hyeminililo commented Jan 12, 2026

Related issue 🛠

Work Description ✏️

  • 챌린지 루틴 선택 온보딩 화면 UI 구현
  • 루틴 카테고리 선택 영역을 Grid 기반으로 구성
  • 단일 선택 로직을 ViewModel에서 관리하도록 분리
  • 선택 상태에 따라 다음 버튼 활성화가 가능하도록 구조 설계
  • 컴포넌트는 stateless하게 구성

Screenshot 📸

  • 선택 온보딩 top
image
  • 선택 온보딩 body
image
  • 선택 온보딩 bottom
image

Uncompleted Tasks 😅

  • N/A

To Reviewers 📢

ViewModel은 컴포넌트 PR 완료 후, 조립과 함께 ViewModel을 같이 구현할 예정입니당 3개의 컴폰넌트 모두 다 프리뷰 있으니까, 편히 봐주세용 !! 피드백도 조하요 ~~ ! !

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 챌린지 루틴 온보딩 기능이 추가되었습니다. 스킨, 라이프, 바디, 웰니스 4가지 카테고리의 루틴과 미션을 그리드 레이아웃에서 선택할 수 있습니다.
  • 스타일

    • UI 컴포넌트의 코드 포맷팅이 개선되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@hyeminililo hyeminililo self-assigned this Jan 12, 2026
@hyeminililo hyeminililo requested a review from a team as a code owner January 12, 2026 15:17
@hyeminililo hyeminililo added FEAT✨ 새로운 기능 구현 혜민🍒 혜민 담당 labels Jan 12, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 12, 2026

Walkthrough

챌린지 루틴 온보딩 기능을 위한 새로운 Compose UI 컴포넌트와 데이터 모델을 추가합니다. 2열 그리드 레이아웃으로 루틴과 미션 항목을 렌더링하며, 기존 컴포넌트의 형식을 일부 수정합니다.

Changes

코호트 / 파일 변경 내용
새로운 데이터 모델
app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutine*.kt, ChallengeRoutineItem.kt
ChallengeRoutineItem 인터페이스(id, title, category, isSelected) 추가. ChallengeRoutineModelChallengeRoutineMissionModel 데이터 클래스로 구현. ChallengeRoutineCategory 열거형(SKIN, LIFE, BODY, WELLNESS) 추가
새로운 UI 컴포넌트
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
헤더 텍스트, 스페이서, LazyVerticalGrid를 포함한 새로운 공개 Composable 함수 추가. 2열 그리드에서 항목 유형에 따라 CherrishSelectionChip 또는 CherrishMissionCard 렌더링. 클릭 이벤트 처리 및 두 개의 프리뷰 포함
기존 컴포넌트 형식 업데이트
app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt, app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeChecklist.kt
프리뷰의 Modifier 호출을 한 줄로 정리. RoundedCornerShape의 위치 인자를 명명된 파라미터 size로 변경. spacedBy에 명명된 파라미터 추가. 프리뷰 상태에서 mutableStateOf(false)value = false로 업데이트

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sohee6989
  • usuuhyn
  • nhyeonii
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 '[FEAT/#35] 챌린지 뷰 컴포넌트 구현'으로 challenge view component 구현이라는 주요 변경사항을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명은 템플릿 구조를 모두 포함하고 있으며, 관련 issue, 작업 설명, 스크린샷, 미완료 작업, 리뷰어 메모를 완전히 기재했습니다.
Linked Issues check ✅ Passed PR에서 구현된 ChallengeRoutineOnboardingBody 컴포넌트, 모델 클래스들(ChallengeRoutineItem, ChallengeRoutineModel, ChallengeRoutineMissionModel, ChallengeRoutineCategory)은 issue #35의 '루틴 챌린지 선택 뷰' 요구사항을 만족합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항은 ChallengeRoutineOnboardingBody 컴포넌트와 관련 모델 구현에 집중되어 있으며, issue #35의 루틴 챌린지 선택 뷰 구현 범위 내에 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeChecklist.kt:
- Line 53: The RoundedCornerShape call in ChallengeChecklist's shape parameter
uses inconsistent spacing ("size= 10.dp"); update the argument to use standard
spacing ("size = 10.dp") by editing the shape = RoundedCornerShape(...)
expression (look for RoundedCornerShape and the size argument) to ensure the
code reads size = 10.dp.

In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt:
- Around line 8-15: The ChallengeRoutineBottom composable currently hardcodes
CherrishButton's onClick and enabled state; update ChallengeRoutineBottom to
accept onClick: () -> Unit and enabled: Boolean (with sensible defaults) as
parameters and pass them through to CherrishButton (retain modifier param), so
the parent can control button enablement and click handling; reference the
ChallengeRoutineBottom function and CherrishButton's enabled and onClick
parameters when making the change.

In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineHeader.kt:
- Around line 9-16: ChallengeRoutineHeader ignores its modifier and hardcodes
empty click handlers; update the function signature to accept and forward the
modifier and expose onBackClick and onCloseClick as parameters (e.g., fun
ChallengeRoutineHeader(modifier: Modifier = Modifier, onBackClick: () -> Unit,
onCloseClick: () -> Unit)) and then pass the received modifier and handlers into
BackAndCloseTopAppBar (replace Modifier with the incoming modifier and replace
{} with onBackClick/onCloseClick) so parent composables and the ViewModel can
supply behavior.

In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt:
- Around line 48-61: ChallengeRoutineCategoryChip declares a modifier parameter
but never passes it down, preventing parent composables from applying layout
modifiers; update ChallengeRoutineCategoryChip so the modifier is forwarded into
the CherrishSelectionChip call (e.g., pass modifier = modifier to
CherrishSelectionChip) while keeping the existing onClick and isSelected
behavior.

In
@app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt:
- Around line 3-8: The enum ChallengeRoutineCategory has a trailing space in the
BODY label and inconsistent spacing before the opening brace; remove the
trailing whitespace from the BODY label value ("체형 관리 ") and normalize the enum
declaration spacing so the brace follows the enum header consistently (look for
ChallengeRoutineCategory and the BODY entry to update).
🧹 Nitpick comments (3)
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt (1)

9-9: 코드 스타일 일관성 개선

함수 선언부의 공백이 일관되지 않습니다. Kotlin 컨벤션에 맞게 수정하는 것을 권장합니다.

♻️ 포맷팅 수정
-fun ChallengeRoutineBottom (modifier :Modifier = Modifier){
+fun ChallengeRoutineBottom(modifier: Modifier = Modifier) {
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (2)

25-46: 상태 호이스팅 패턴이 잘 적용되었습니다.

selectedCategoryonCategoryClick을 파라미터로 받아 stateless 컴포저블로 구현한 점이 좋습니다. 단방향 데이터 흐름 패턴을 잘 따르고 있습니다.

다만, 하드코딩된 문자열(line 33)은 향후 다국어 지원을 위해 strings.xml 리소스로 분리하는 것을 권장합니다.


70-86: itemskey 파라미터 추가를 권장합니다.

LazyVerticalGriditemskey를 지정하면 아이템 순서 변경이나 추가/삭제 시 불필요한 recomposition을 방지할 수 있습니다. ChallengeRoutineCategory가 enum이므로 안정적인 key를 제공할 수 있습니다.

♻️ 수정 제안
     LazyVerticalGrid(
         columns = GridCells.Fixed(count = 2),
         horizontalArrangement = Arrangement.spacedBy(space = 12.dp),
         verticalArrangement = Arrangement.spacedBy(space = 12.dp),
         modifier = modifier
     ) {
-        items(items = categories) { category ->
-
+        items(
+            items = categories,
+            key = { it.name }
+        ) { category ->
             ChallengeRoutineCategoryChip(
                 category = category,
                 isSelected = selectedCategory == category,
                 onClick = onCategoryClick
             )
-
         }
     }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f85b7b9 and 74bec37.

📒 Files selected for processing (7)
  • .kotlin/sessions/kotlin-compiler-2012687974255034637.salive
  • app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeChecklist.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineHeader.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: - Jetpack Compose 구조, 상태 관리, recomposition 최적화에 집중

  • ViewModel, UiState, 단방향 데이터 흐름 패턴 검토
  • 불필요한 recomposition 가능성, remember/derivedStateOf 적절한 사용 확인
  • 네이밍 컨벤션, 가독성, Google 권장 Android 아키텍처 준수 여부

Files:

  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineHeader.kt
  • app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeChecklist.kt
🧠 Learnings (1)
📚 Learning: 2026-01-09T08:25:52.533Z
Learnt from: nhyeonii
Repo: TEAM-Cherrish/Cherrish-Android PR: 14
File: app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelction.kt:1-1
Timestamp: 2026-01-09T08:25:52.533Z
Learning: Enforce that the Kotlin file name under the design system chip package matches the main Jetpack Compose function name defined in that file. For example, CherrishBasicChip.kt should declare a top-level composable function named CherrishBasicChip. If the file name and main composable name do not align, flag for refactor. This improves consistency and discovery across the Android codebase (TEAM-Cherrish/Cherrish-Android).

Applied to files:

  • app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt
🧬 Code graph analysis (3)
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineHeader.kt (1)
app/src/main/java/com/cherrish/android/core/designsystem/component/topappbar/BackAndCloseTopAppBar.kt (1)
  • BackAndCloseTopAppBar (15-46)
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt (1)
app/src/main/java/com/cherrish/android/core/designsystem/component/button/CherrishButton.kt (1)
  • CherrishButton (27-79)
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (2)
app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt (1)
  • CherrishSelectionChip (18-42)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
⏰ 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). (2)
  • GitHub Check: PR Lint Check
  • GitHub Check: PR Build Check
🔇 Additional comments (3)
app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt (1)

44-57: LGTM!

포맷팅 변경만 포함되어 있으며, 기능적 변경 없이 코드 가독성이 유지됩니다. 파일명과 주요 Composable 함수명(CherrishSelectionChip)이 일치하여 명명 규칙을 잘 준수하고 있습니다.

app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeChecklist.kt (1)

46-57: 명명된 파라미터 사용 개선

RoundedCornerShape, spacedBy, mutableStateOf에 명명된 파라미터를 사용하여 코드 가독성이 향상되었습니다.

Also applies to: 78-81, 103-106

app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (1)

88-117: 프리뷰 구현이 적절합니다.

CherrishTheme으로 감싸고 remember + mutableStateOf를 사용하여 인터랙티브한 프리뷰를 제공하는 패턴이 잘 적용되었습니다.

Comment on lines +8 to +15
@Composable
fun ChallengeRoutineBottom (modifier :Modifier = Modifier){
CherrishButton(
text = "다음",
onClick = {},
modifier = modifier
)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

버튼 활성화 상태와 클릭 핸들러를 외부에서 제어할 수 있도록 파라미터를 노출해야 합니다.

PR 목표에 따르면 "선택 상태에 따라 다음 버튼이 활성화"되어야 합니다. 현재 구현에서는 enabledonClick이 하드코딩되어 있어 상위 컴포저블에서 버튼 상태를 제어할 수 없습니다.

CherrishButtonenabled 파라미터를 지원하므로(관련 코드 스니펫 참조), 이를 노출하는 것이 좋습니다.

🔧 수정 제안
 @Composable
-fun ChallengeRoutineBottom (modifier :Modifier = Modifier){
+fun ChallengeRoutineBottom(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true
+) {
     CherrishButton(
         text = "다음",
-        onClick = {},
-        modifier = modifier
+        onClick = onClick,
+        modifier = modifier,
+        enabled = enabled
     )
 }
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt
around lines 8 - 15, The ChallengeRoutineBottom composable currently hardcodes
CherrishButton's onClick and enabled state; update ChallengeRoutineBottom to
accept onClick: () -> Unit and enabled: Boolean (with sensible defaults) as
parameters and pass them through to CherrishButton (retain modifier param), so
the parent can control button enablement and click handling; reference the
ChallengeRoutineBottom function and CherrishButton's enabled and onClick
parameters when making the change.

Comment on lines +9 to +16
fun ChallengeRoutineHeader(modifier: Modifier = Modifier) {
BackAndCloseTopAppBar(
title = "루틴 챌린지 선택",
onBackClick = {},
onCloseClick = {},
modifier = Modifier

)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

전달받은 modifier 파라미터가 사용되지 않습니다.

modifier 파라미터를 받지만, BackAndCloseTopAppBar에 새로운 Modifier를 전달하고 있습니다. 이는 상위 컴포저블에서 레이아웃 수정자를 적용할 수 없게 만듭니다. Compose의 modifier 체이닝 컨벤션을 위반합니다.

또한, onBackClickonCloseClick이 빈 람다로 되어 있어 실제 사용 시 상위에서 주입받아야 합니다. PR 설명에 따르면 ViewModel 통합 후 구성될 예정이므로, 이 핸들러들을 파라미터로 노출하는 것을 권장합니다.

🔧 수정 제안
 @Composable
-fun ChallengeRoutineHeader(modifier: Modifier = Modifier) {
+fun ChallengeRoutineHeader(
+    onBackClick: () -> Unit,
+    onCloseClick: () -> Unit,
+    modifier: Modifier = Modifier
+) {
     BackAndCloseTopAppBar(
         title = "루틴 챌린지 선택",
-        onBackClick = {},
-        onCloseClick = {},
-        modifier = Modifier
-
+        onBackClick = onBackClick,
+        onCloseClick = onCloseClick,
+        modifier = modifier
     )
 }
📝 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.

Suggested change
fun ChallengeRoutineHeader(modifier: Modifier = Modifier) {
BackAndCloseTopAppBar(
title = "루틴 챌린지 선택",
onBackClick = {},
onCloseClick = {},
modifier = Modifier
)
@Composable
fun ChallengeRoutineHeader(
onBackClick: () -> Unit,
onCloseClick: () -> Unit,
modifier: Modifier = Modifier
) {
BackAndCloseTopAppBar(
title = "루틴 챌린지 선택",
onBackClick = onBackClick,
onCloseClick = onCloseClick,
modifier = modifier
)
}
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineHeader.kt
around lines 9 - 16, ChallengeRoutineHeader ignores its modifier and hardcodes
empty click handlers; update the function signature to accept and forward the
modifier and expose onBackClick and onCloseClick as parameters (e.g., fun
ChallengeRoutineHeader(modifier: Modifier = Modifier, onBackClick: () -> Unit,
onCloseClick: () -> Unit)) and then pass the received modifier and handlers into
BackAndCloseTopAppBar (replace Modifier with the incoming modifier and replace
{} with onBackClick/onCloseClick) so parent composables and the ViewModel can
supply behavior.

Comment on lines +48 to +61
@Composable
private fun ChallengeRoutineCategoryChip(
category: ChallengeRoutineCategory,
isSelected: Boolean,
onClick: (ChallengeRoutineCategory) -> Unit,
modifier: Modifier = Modifier
) {
CherrishSelectionChip(
text = category.label,
onClick = { onClick(category) },
isSelected = isSelected
)

}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

modifier 파라미터가 사용되지 않고 있습니다.

modifier 파라미터를 선언했지만 CherrishSelectionChip에 전달하지 않아 부모 컴포저블에서 레이아웃 수정자를 적용할 수 없습니다.

🔧 수정 제안
 @Composable
 private fun ChallengeRoutineCategoryChip(
     category: ChallengeRoutineCategory,
     isSelected: Boolean,
     onClick: (ChallengeRoutineCategory) -> Unit,
     modifier: Modifier = Modifier
 ) {
     CherrishSelectionChip(
         text = category.label,
         onClick = { onClick(category) },
-        isSelected = isSelected
+        isSelected = isSelected,
+        modifier = modifier
     )
-
 }
📝 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.

Suggested change
@Composable
private fun ChallengeRoutineCategoryChip(
category: ChallengeRoutineCategory,
isSelected: Boolean,
onClick: (ChallengeRoutineCategory) -> Unit,
modifier: Modifier = Modifier
) {
CherrishSelectionChip(
text = category.label,
onClick = { onClick(category) },
isSelected = isSelected
)
}
@Composable
private fun ChallengeRoutineCategoryChip(
category: ChallengeRoutineCategory,
isSelected: Boolean,
onClick: (ChallengeRoutineCategory) -> Unit,
modifier: Modifier = Modifier
) {
CherrishSelectionChip(
text = category.label,
onClick = { onClick(category) },
isSelected = isSelected,
modifier = modifier
)
}
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
around lines 48 - 61, ChallengeRoutineCategoryChip declares a modifier parameter
but never passes it down, preventing parent composables from applying layout
modifiers; update ChallengeRoutineCategoryChip so the modifier is forwarded into
the CherrishSelectionChip call (e.g., pass modifier = modifier to
CherrishSelectionChip) while keeping the existing onClick and isSelected
behavior.

Comment on lines +3 to +8
enum class ChallengeRoutineCategory(val label: String){
SKIN (label = "피부 컨디션"),
LIFE (label = "생활 습관"),
BODY (label = "체형 관리 "),
WELLNESS (label = "웰니스 ∙ 마음 챙김"),
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

레이블에 불필요한 공백이 포함되어 있습니다.

BODY의 레이블 "체형 관리 "에 후행 공백이 있습니다. UI에서 정렬 문제나 비교 로직에서 예상치 못한 동작을 유발할 수 있습니다. 또한 클래스 선언부에 중괄호 앞 공백을 추가하면 코드 스타일 일관성이 향상됩니다.

🔧 수정 제안
-enum class ChallengeRoutineCategory(val label: String){
-    SKIN (label = "피부 컨디션"),
-    LIFE (label = "생활 습관"),
-    BODY (label = "체형 관리 "),
-    WELLNESS (label = "웰니스 ∙ 마음 챙김"),
+enum class ChallengeRoutineCategory(val label: String) {
+    SKIN(label = "피부 컨디션"),
+    LIFE(label = "생활 습관"),
+    BODY(label = "체형 관리"),
+    WELLNESS(label = "웰니스 ∙ 마음 챙김"),
}
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt
around lines 3 - 8, The enum ChallengeRoutineCategory has a trailing space in
the BODY label and inconsistent spacing before the opening brace; remove the
trailing whitespace from the BODY label value ("체형 관리 ") and normalize the enum
declaration spacing so the brace follows the enum header consistently (look for
ChallengeRoutineCategory and the BODY entry to update).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

래빗씨 굿굿 ~~

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hyeminililo 감사합니다! 😊 수정이 필요하실 때 언제든지 적용해 주시면 됩니다.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt:
- Line 6: Remove the trailing space from the enum label for BODY in
ChallengeRoutineCategory: locate the BODY entry (symbol: BODY) in the
ChallengeRoutineCategory enum and change its label string from "체형 관리 " to "체형
관리" so the stored/displayed label has no trailing whitespace.
🧹 Nitpick comments (1)
app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt (1)

3-8: 하드코딩된 문자열 대신 문자열 리소스 사용을 고려해 보세요.

현재 한국어 레이블이 직접 하드코딩되어 있습니다. 향후 다국어 지원이나 유지보수를 고려한다면, strings.xml 리소스를 활용하는 것이 Android 권장 패턴입니다.

단, 한국어 전용 앱으로 유지할 예정이라면 현재 구조도 무방합니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74bec37 and 501a84f.

📒 Files selected for processing (5)
  • app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeChecklist.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeChecklist.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineBottom.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: - Jetpack Compose 구조, 상태 관리, recomposition 최적화에 집중

  • ViewModel, UiState, 단방향 데이터 흐름 패턴 검토
  • 불필요한 recomposition 가능성, remember/derivedStateOf 적절한 사용 확인
  • 네이밍 컨벤션, 가독성, Google 권장 Android 아키텍처 준수 여부

Files:

  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt
  • app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt
🧠 Learnings (1)
📚 Learning: 2026-01-09T08:25:52.533Z
Learnt from: nhyeonii
Repo: TEAM-Cherrish/Cherrish-Android PR: 14
File: app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelction.kt:1-1
Timestamp: 2026-01-09T08:25:52.533Z
Learning: Enforce that the Kotlin file name under the design system chip package matches the main Jetpack Compose function name defined in that file. For example, CherrishBasicChip.kt should declare a top-level composable function named CherrishBasicChip. If the file name and main composable name do not align, flag for refactor. This improves consistency and discovery across the Android codebase (TEAM-Cherrish/Cherrish-Android).

Applied to files:

  • app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt
⏰ 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). (2)
  • GitHub Check: PR Lint Check
  • GitHub Check: PR Build Check
🔇 Additional comments (1)
app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt (1)

44-57: LGTM!

Preview 함수에서 modifier 파라미터를 한 줄로 정리한 포맷팅 변경입니다. 컴포넌트가 stateless하게 잘 설계되어 있고, 파일명(CherrishSelectionChip.kt)과 메인 Composable 함수명(CherrishSelectionChip)이 일치하여 컨벤션을 잘 따르고 있습니다. 학습된 내용 기반으로 확인했습니다.

ChallengeRoutinBottom 내에 있는 컴포넌트와 CherrishButton을 바로 사용하도록 리팩토링
ChallengeRoutinHeader 내에 있는 컴포넌트와 CherrishTopAppbar를 바로 사용하도록 리팩토링
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/challenge/ChallengeScreen.kt (1)

21-26: ViewModel 미사용 및 paddingValues 미적용

ChallengeRouteViewModel이 이미 구현되어 있지만 ChallengeRoute에서 사용되지 않고 있습니다. 또한 paddingValues가 전달되지만 ChallengeScreen에서 적용되지 않습니다.

PR 설명에 따르면 단방향 데이터 흐름을 위해 ViewModel로 상태 관리를 위임한다고 했으므로, ViewModel 연동을 권장합니다.

♻️ ViewModel 연동 및 paddingValues 적용 예시
+import androidx.lifecycle.viewmodel.compose.viewModel
+
 @Composable
 fun ChallengeRoute(
-    paddingValues: PaddingValues
+    paddingValues: PaddingValues,
+    viewModel: ChallengeRouteViewModel = viewModel()
 ) {
-    ChallengeScreen(paddingValues = paddingValues)
+    val selectedCategory by viewModel.selectedCategory.collectAsStateWithLifecycle()
+    
+    ChallengeScreen(
+        paddingValues = paddingValues,
+        selectedCategory = selectedCategory,
+        onCategoryClick = viewModel::onCategoryClick
+    )
 }
🤖 Fix all issues with AI agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt:
- Around line 52-55: The "Next" CherrishButton isn't wired to the selection
state: make the button's enabled property depend on the selection (e.g., use
selectedCategory or selectedCategories state) so it is disabled when nothing is
selected and enabled when a selection exists; update the CherrishButton
invocation in ChallengeScreen (reference CherrishButton and
selectedCategory/selectedCategories) to pass enabled = (selectedCategory != null
/ selectedCategories.isNotEmpty()) and keep the existing onClick behavior only
when enabled (or guard the click handler by the same condition).
🧹 Nitpick comments (3)
app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeViewModel.kt (1)

8-11: 파일명과 클래스명 불일치 및 asStateFlow() 사용 권장

파일명 ChallengeViewModel.kt와 클래스명 ChallengeRouteViewModel이 일치하지 않습니다. 일관성을 위해 둘 중 하나를 수정하는 것이 좋습니다.

또한, _selectedCategoryStateFlow로 노출할 때 asStateFlow()를 사용하면 실수로 캐스팅하여 수정하는 것을 방지할 수 있습니다.

♻️ 권장 수정안
+import kotlinx.coroutines.flow.asStateFlow
+
 class ChallengeRouteViewModel : ViewModel() {
     private val _selectedCategory =
         MutableStateFlow<ChallengeRoutineCategory?>(null)
-    val selectedCategory: StateFlow<ChallengeRoutineCategory?> = _selectedCategory
+    val selectedCategory: StateFlow<ChallengeRoutineCategory?> = _selectedCategory.asStateFlow()
app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt (2)

33-35: 로컬 상태 대신 상태 호이스팅 패턴 적용 권장

현재 ChallengeScreen 내부에서 로컬 상태를 관리하고 있습니다. Stateless 컴포넌트 원칙에 따라 상태를 파라미터로 받아 처리하면 테스트 용이성과 재사용성이 향상됩니다.

♻️ 상태 호이스팅 적용 예시
 @Composable
 private fun ChallengeScreen(
     paddingValues: PaddingValues,
+    selectedCategory: ChallengeRoutineCategory?,
+    onCategoryClick: (ChallengeRoutineCategory) -> Unit,
     modifier: Modifier = Modifier
 ) {
-    var selectedCategory by remember {
-        mutableStateOf<ChallengeRoutineCategory?>(value = null)
-    }

59-63: Preview에 테마 래퍼 추가 권장

CherrishTheme으로 감싸지 않으면 Preview에서 커스텀 테마 색상과 타이포그래피가 적용되지 않을 수 있습니다.

♻️ 테마 래퍼 추가
 @Preview
 @Composable
 private fun ChallengeScreenPreview() {
-    ChallengeScreen(paddingValues = PaddingValues(26.dp))
+    CherrishTheme {
+        ChallengeScreen(paddingValues = PaddingValues(26.dp))
+    }
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 501a84f and 4d0d3d7.

📒 Files selected for processing (2)
  • app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeViewModel.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: - Jetpack Compose 구조, 상태 관리, recomposition 최적화에 집중

  • ViewModel, UiState, 단방향 데이터 흐름 패턴 검토
  • 불필요한 recomposition 가능성, remember/derivedStateOf 적절한 사용 확인
  • 네이밍 컨벤션, 가독성, Google 권장 Android 아키텍처 준수 여부

Files:

  • app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeViewModel.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt (3)
app/src/main/java/com/cherrish/android/core/designsystem/component/topappbar/CherrishBasicTopAppBar.kt (1)
  • CherrishBasicTopAppBar (17-54)
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (1)
  • ChallengeRoutineOnboardingBody (24-45)
app/src/main/java/com/cherrish/android/core/designsystem/component/button/CherrishButton.kt (1)
  • CherrishButton (27-79)
⏰ 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). (2)
  • GitHub Check: PR Build Check
  • GitHub Check: PR Lint Check
🔇 Additional comments (1)
app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeViewModel.kt (1)

13-15: 토글 선택 해제 기능 고려

현재 동일한 카테고리를 다시 클릭해도 선택이 해제되지 않습니다. UX 요구사항에 따라 선택 해제 기능이 필요할 수 있습니다.

선택 해제 기능이 필요하다면 다음과 같이 수정할 수 있습니다:

♻️ 토글 기능 추가 예시
 fun onCategoryClick(category: ChallengeRoutineCategory) {
-    _selectedCategory.value = category
+    _selectedCategory.value = if (_selectedCategory.value == category) null else category
 }

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt:
- Around line 52-55: The Next button in ChallengeScreen is not tied to the
selection state; update the CherrishButton call so its enabled parameter
reflects the current selection (e.g., use selectedCategory or whatever selection
state variable is used in ChallengeScreen), e.g., enabled = selectedCategory !=
null (or selectedCategory.isNotEmpty() for strings, or
selectedItems.isNotEmpty() for collections) and keep the existing onClick logic;
ensure you reference the selectedCategory state variable in ChallengeScreen to
drive the button enabled/disabled state.
- Around line 30-39: The ChallengeScreen composable currently ignores the
paddingValues parameter causing layout overlap with system bars; update the root
container Modifier (the Column using modifier) to incorporate paddingValues
(e.g., combine or chain the existing .padding(start = 26.dp, bottom = 64.dp, end
= 26.dp) with paddingValues) so the incoming Scaffold inner padding is applied;
locate the ChallengeScreen function and modify the Column's modifier (and any
parent modifier passed in) to include paddingValues before/alongside the
existing paddings.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d0d3d7 and 5cc0327.

📒 Files selected for processing (2)
  • app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineCategory.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: - Jetpack Compose 구조, 상태 관리, recomposition 최적화에 집중

  • ViewModel, UiState, 단방향 데이터 흐름 패턴 검토
  • 불필요한 recomposition 가능성, remember/derivedStateOf 적절한 사용 확인
  • 네이밍 컨벤션, 가독성, Google 권장 Android 아키텍처 준수 여부

Files:

  • app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt (3)
app/src/main/java/com/cherrish/android/core/designsystem/component/topappbar/CherrishBasicTopAppBar.kt (1)
  • CherrishBasicTopAppBar (17-54)
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (1)
  • ChallengeRoutineOnboardingBody (24-45)
app/src/main/java/com/cherrish/android/core/designsystem/component/button/CherrishButton.kt (1)
  • CherrishButton (27-79)
⏰ 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). (2)
  • GitHub Check: PR Build Check
  • GitHub Check: PR Lint Check
🔇 Additional comments (1)
app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt (1)

59-63: Preview 구현 확인

Preview 함수가 추가되어 컴포넌트를 시각적으로 확인할 수 있습니다. 위의 paddingValues 적용 문제가 수정되면 Preview도 정상적으로 동작할 것입니다.

Comment on lines +30 to +39
paddingValues: PaddingValues,
modifier: Modifier = Modifier
) {
Text(
"Challenge",
modifier = modifier.padding(paddingValues)
)
var selectedCategory by remember {
mutableStateOf<ChallengeRoutineCategory?>(value = null)
}

Column(
modifier = modifier
.padding(start = 26.dp, bottom = 64.dp, end = 26.dp)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

paddingValues 파라미터가 사용되지 않음

paddingValues가 함수 파라미터로 전달되지만 실제로 적용되지 않고 있습니다. Scaffold와 함께 사용될 때 시스템 바(상태바, 네비게이션 바)와의 레이아웃 충돌이 발생할 수 있습니다.

🐛 paddingValues 적용 수정 제안
 @Composable
 private fun ChallengeScreen(
     paddingValues: PaddingValues,
     modifier: Modifier = Modifier
 ) {
     var selectedCategory by remember {
         mutableStateOf<ChallengeRoutineCategory?>(value = null)
     }

     Column(
         modifier = modifier
+            .padding(paddingValues)
             .padding(start = 26.dp, bottom = 64.dp, end = 26.dp)
     ) {
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt
around lines 30 - 39, The ChallengeScreen composable currently ignores the
paddingValues parameter causing layout overlap with system bars; update the root
container Modifier (the Column using modifier) to incorporate paddingValues
(e.g., combine or chain the existing .padding(start = 26.dp, bottom = 64.dp, end
= 26.dp) with paddingValues) so the incoming Scaffold inner padding is applied;
locate the ChallengeScreen function and modify the Column's modifier (and any
parent modifier passed in) to include paddingValues before/alongside the
existing paddings.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 #27 요기 pr에도 질문 나왓던거죠 ~~ !! 래빗이도 잘 짚어줫네요 ㅎㅎㅎ 반영해서 수정해주세요 ~~

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nhyeonii 감사합니다! 네, 동일한 이슈가 이전 PR에서도 발견되었군요. paddingValues를 적용하지 않으면 Scaffold의 시스템 바와 겹칠 수 있으니 꼭 반영이 필요합니다.

제안드린 대로 Column의 modifier에 .padding(paddingValues)를 먼저 추가하고, 그 다음에 추가 패딩을 적용하면 됩니다. 🙂


✏️ Learnings added
Learnt from: nhyeonii
Repo: TEAM-Cherrish/Cherrish-Android PR: 41
File: app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt:30-39
Timestamp: 2026-01-12T19:49:27.085Z
Learning: In the Cherrish-Android codebase, Screen composables that receive a `paddingValues: PaddingValues` parameter from Scaffold must apply it to their root container's modifier (e.g., `.padding(paddingValues)`) before applying additional padding, to avoid layout overlap with system bars.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵넵 !! 감사합니당 :)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +52 to +55
CherrishButton(
text = "다음",
onClick = {}
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

버튼 활성화 상태가 선택 상태와 연동되지 않음

PR 목표에 "다음 버튼이 선택 상태에 따라 활성화될 수 있도록 구조 설계"라고 명시되어 있습니다. CherrishButtonenabled 파라미터를 selectedCategory에 따라 설정해야 합니다.

🐛 버튼 활성화 로직 추가 제안
         CherrishButton(
             text = "다음",
-            onClick = {}
+            onClick = {},
+            enabled = selectedCategory != null
         )
📝 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.

Suggested change
CherrishButton(
text = "다음",
onClick = {}
)
CherrishButton(
text = "다음",
onClick = {},
enabled = selectedCategory != null
)
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt
around lines 52 - 55, The Next button in ChallengeScreen is not tied to the
selection state; update the CherrishButton call so its enabled parameter
reflects the current selection (e.g., use selectedCategory or whatever selection
state variable is used in ChallengeScreen), e.g., enabled = selectedCategory !=
null (or selectedCategory.isNotEmpty() for strings, or
selectedItems.isNotEmpty() for collections) and keep the existing onClick logic;
ensure you reference the selectedCategory state variable in ChallengeScreen to
drive the button enabled/disabled state.

Copy link
Copy Markdown
Contributor

@nhyeonii nhyeonii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

직접 이야기하면서 나누어보앗던 얘기들 기억하면서 리팩토링 해보면 참 좋을 거 가트요 ㅎㅎㅎ 너무 잘해주고 잇고 질문도 열심히 해주는 모습 기특합니다 🫳🫳🫳🫳 좀만 더 화이팅 ~ !!!!

"Challenge",
modifier = modifier.padding(paddingValues)
)
var selectedCategory by remember {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 : 이거 UiState로 상태관리 올려주세용옹 ~~ 이렇게 스크린에 작성해주면 요 선택된 아이들의 관리가 힘들답니다 ㅎㅎㅎ

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵넵 기반으로 리팩토링 진행해보도록 하겠습니다 ~!!

Comment on lines +30 to +39
paddingValues: PaddingValues,
modifier: Modifier = Modifier
) {
Text(
"Challenge",
modifier = modifier.padding(paddingValues)
)
var selectedCategory by remember {
mutableStateOf<ChallengeRoutineCategory?>(value = null)
}

Column(
modifier = modifier
.padding(start = 26.dp, bottom = 64.dp, end = 26.dp)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 #27 요기 pr에도 질문 나왓던거죠 ~~ !! 래빗이도 잘 짚어줫네요 ㅎㅎㅎ 반영해서 수정해주세요 ~~


ChallengeRoutineOnboardingBody(
selectedCategory = selectedCategory,
onCategoryClick = { selectedCategory = it }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 : 얘도 상태 호이스팅 필요하겟죠잉 ?!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 끌어올리겠습니당 ~~!!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호.. 스크린 구현할 때 상태 호이스팅에 유의해야겟군요? ㅎ호호이


CherrishButton(
text = "다음",
onClick = {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 : onClick 상태 호이스팅 해주세요 ~~ 그리고 버튼이 활성화 되는 시기가 언제인지도 처리해줘야하겟죵 !?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 네네 !! 리팩토링 진행할게요 !!

Comment on lines +4 to +7
SKIN(label = "피부 컨디션"),
LIFE(label = "생활 습관"),
BODY(label = "체형 관리"),
WELLNESS(label = "웰니스 ∙ 마음 챙김")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

P1 : 지금 서버에서 요런식으로 내려주고 있는데 이거 enum class 보다는 data class로 작성해주면 어떨까요 ?!?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니당 !!! 서버 API 꼭 확인하겠습니다아 ,,, 🤭

onCategoryClick: (ChallengeRoutineCategory) -> Unit,
modifier: Modifier = Modifier
) {
Column(modifier = modifier) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 : 요거 .fillMaxWidth() 속성 줘야할거 가트요 ~~

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 !!!

Comment on lines +31 to +44
Text(
text = "지금 나에게 가장 필요한 \n관리 루틴을 선택해주세요.",
color = CherrishTheme.colors.gray1000,
style = CherrishTheme.typography.title1SB18
)

Spacer(modifier = Modifier.height(height = 40.dp))

ChallengeRoutineSelectionChipGroup(
categories = ChallengeRoutineCategory.entries,
selectedCategory = selectedCategory,
onCategoryClick = onCategoryClick
)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image image

P1 : 요거 Title + Description(nullable) + LazyGrid 이게 계속 반복적으로 뷰마다 사용되고 있죠잉 ! 그렇다면 이렇게 하나하나 화면을 따로따로 만들어주기 보다는 Title + Description(nullable) + LazyGrid 이거 자체를 컴포넌트로 뺴는건 어떨까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 좋을 것 같아요 ~!~~!!@


@Composable
private fun ChallengeRoutineSelectionChipGroup(
categories: List<ChallengeRoutineCategory>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
categories: List<ChallengeRoutineCategory>,
categories: immutableList<ChallengeRoutineCategory>,

P1 : 요거 List 보다는 immutableList 사용해주세요!! immutableLIst의 장점은 무엇일까용ㅇ이 ~?!!?!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

immutableList는 한 번 정하면 값이 변하지 않는 불변 값이니 타입 안정성이 보장된다 ,,! ! 그리고 리소스를 보장할 수 있다가 맞을까요 ??

verticalArrangement = Arrangement.spacedBy(space = 12.dp),
modifier = modifier
) {
items(items = categories) { category ->
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 : key 값 지정해주는거 어떨까용 ?!?!?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 좋습니다 !!!

Copy link
Copy Markdown
Contributor

@usuuhyn usuuhyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니당 !! 👍😻😻


ChallengeRoutineOnboardingBody(
selectedCategory = selectedCategory,
onCategoryClick = { selectedCategory = it }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호.. 스크린 구현할 때 상태 호이스팅에 유의해야겟군요? ㅎ호호이

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt:
- Around line 119-127: The compile error comes from calling item.copy(...) on
ChallengeRoutineItem (an interface) inside the ChallengeRoutineOnboardingBody
onItemClick handler; replace that call with a polymorphic copy method on the
interface (e.g., add fun copyWithSelection(isSelected: Boolean):
ChallengeRoutineItem to the ChallengeRoutineItem interface and implement it in
concrete classes) and then update the mapping to use
item.copyWithSelection(item.id == clickedItem.id); alternatively, if all items
are concrete data classes, cast to the concrete type before using copy, but the
preferred fix is to add and call copyWithSelection on ChallengeRoutineItem and
implement it in the implementations.
🧹 Nitpick comments (4)
app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineItem.kt (1)

3-8: 인터페이스 설계가 적절합니다.

다형성을 활용한 ChallengeRoutineItem 인터페이스 설계가 잘 되어 있습니다. ChallengeRoutineModelChallengeRoutineMissionModel이 공통 인터페이스를 구현하여 ChallengeRoutineOnboardingBody에서 유연하게 처리할 수 있습니다.

선택 사항: category 타입을 String 대신 ChallengeRoutineCategory enum으로 변경하면 타입 안전성을 높일 수 있습니다.

♻️ 타입 안전성 개선 제안
+import com.cherrish.android.presentation.challenge.model.ChallengeRoutineCategory
+
 interface ChallengeRoutineItem {
     val id : Int
     val title : String
-    val category: String
+    val category: ChallengeRoutineCategory
     val isSelected: Boolean
 }
app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineMissionModel.kt (1)

3-9: 들여쓰기가 일관되지 않습니다.

subTitle 프로퍼티의 들여쓰기가 다른 프로퍼티들과 일치하지 않습니다.

♻️ 들여쓰기 수정
 data class ChallengeRoutineMissionModel(
-   override val id: Int,
-   override val title : String,
- val subTitle: String,
-   override val category : String,
-   override val isSelected: Boolean = false
+    override val id: Int,
+    override val title: String,
+    val subTitle: String,
+    override val category: String,
+    override val isSelected: Boolean = false
 ) : ChallengeRoutineItem
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (2)

51-70: when 표현식에 else 분기 누락

새로운 ChallengeRoutineItem 구현체가 추가될 경우를 대비해 else 분기를 추가하는 것이 좋습니다. 또한 ChallengeRoutineMissionModelsubTitle이 UI에 표시되지 않습니다.

♻️ else 분기 및 subTitle 활용 제안
             items(items) { item ->
                 when (item) {
                     is ChallengeRoutineModel -> {
                         CherrishSelectionChip(
                             text = item.title,
                             isSelected = item.isSelected,
                             onClick = { onItemClick(item) }
                         )
                     }

                     is ChallengeRoutineMissionModel -> {
                         CherrishMissionCard(
-                            text = item.title,
+                            text = "${item.subTitle}\n${item.title}",
                             isSelected = item.isSelected,
                             onClick = { onItemClick(item) }
                         )
                     }
+
+                    else -> {
+                        // 알 수 없는 아이템 타입 처리
+                    }
                 }
             }

45-51: items()key 파라미터 추가 권장

리스트 아이템 변경 시 효율적인 recomposition을 위해 key 파라미터를 추가하세요. 코딩 가이드라인에서 불필요한 recomposition 최적화를 권장합니다.

♻️ key 파라미터 추가
         LazyVerticalGrid(
             columns = GridCells.Fixed(2),
             horizontalArrangement = Arrangement.spacedBy(12.dp),
             verticalArrangement = Arrangement.spacedBy(12.dp),
             modifier = Modifier.fillMaxHeight()
         ) {
-            items(items) { item ->
+            items(items, key = { it.id }) { item ->
                 when (item) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5cc0327 and fc3804a.

📒 Files selected for processing (5)
  • .kotlin/sessions/kotlin-compiler-2276212971756165281.salive
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineItem.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineMissionModel.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineModel.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: - Jetpack Compose 구조, 상태 관리, recomposition 최적화에 집중

  • ViewModel, UiState, 단방향 데이터 흐름 패턴 검토
  • 불필요한 recomposition 가능성, remember/derivedStateOf 적절한 사용 확인
  • 네이밍 컨벤션, 가독성, Google 권장 Android 아키텍처 준수 여부

Files:

  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineModel.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineItem.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineMissionModel.kt
🧠 Learnings (1)
📚 Learning: 2026-01-12T19:49:27.085Z
Learnt from: nhyeonii
Repo: TEAM-Cherrish/Cherrish-Android PR: 41
File: app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt:30-39
Timestamp: 2026-01-12T19:49:27.085Z
Learning: When a Jetpack Compose screen composable receives a Scaffold paddingValues: PaddingValues parameter (commonly from Scaffold), apply it to the root container's modifier first (e.g., .padding(paddingValues)) before applying any additional padding. This ensures content respects system bars (status/navigation) and avoids layout overlap. This pattern should be followed across presentation screens under app/src/main/java/com/cherrish/android/presentation/ to maintain consistent insets handling.

Applied to files:

  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineModel.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineItem.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
  • app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineMissionModel.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (3)
app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionChip.kt (1)
  • CherrishSelectionChip (18-42)
app/src/main/java/com/cherrish/android/core/designsystem/component/chip/CherrishSelectionMissionChip.kt (1)
  • CherrishMissionCard (27-70)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
⏰ 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). (2)
  • GitHub Check: PR Lint Check
  • GitHub Check: PR Build Check
🔇 Additional comments (2)
app/src/main/java/com/cherrish/android/presentation/challenge/model/ChallengeRoutineModel.kt (1)

3-8: LGTM!

data class 구현이 적절하며, copy() 함수를 통해 Compose에서 불변 상태 업데이트가 가능합니다. isSelected의 기본값 설정도 적절합니다.

app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt (1)

30-35: Stateless 컴포넌트 설계가 좋습니다.

PR 설명에 언급된 대로 컴포넌트가 상태를 직접 관리하지 않고 itemsonItemClick을 통해 외부에서 상태를 제어할 수 있도록 설계되어 있습니다. 단방향 데이터 흐름 패턴을 잘 따르고 있습니다.

Comment on lines +119 to +127
ChallengeRoutineOnboardingBody(
items = routineItems,
onItemClick = { clickedItem ->
routineItems = routineItems.map { item ->
item.copy(
isSelected = item.id == clickedItem.id
)
}
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

컴파일 오류: ChallengeRoutineItem 인터페이스에서 copy() 호출 불가

ChallengeRoutineItem은 인터페이스이므로 copy() 메서드가 없습니다. Preview에서 item.copy()를 호출하면 컴파일 오류가 발생합니다.

🐛 수정 제안
         ChallengeRoutineOnboardingBody(
             items = routineItems,
             onItemClick = { clickedItem ->
                 routineItems = routineItems.map { item ->
-                    item.copy(
-                        isSelected = item.id == clickedItem.id
-                    )
+                    if (item is ChallengeRoutineModel) {
+                        item.copy(isSelected = item.id == clickedItem.id)
+                    } else {
+                        item
+                    }
                 }
             },
             modifier = Modifier.padding(26.dp)
         )

또는 ChallengeRoutineItem 인터페이스에 copyWithSelection 메서드를 추가하는 방법도 있습니다:

interface ChallengeRoutineItem {
    // ... existing properties
    fun copyWithSelection(isSelected: Boolean): ChallengeRoutineItem
}
📝 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.

Suggested change
ChallengeRoutineOnboardingBody(
items = routineItems,
onItemClick = { clickedItem ->
routineItems = routineItems.map { item ->
item.copy(
isSelected = item.id == clickedItem.id
)
}
},
ChallengeRoutineOnboardingBody(
items = routineItems,
onItemClick = { clickedItem ->
routineItems = routineItems.map { item ->
if (item is ChallengeRoutineModel) {
item.copy(isSelected = item.id == clickedItem.id)
} else {
item
}
}
},
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeRoutineOnboardingBody.kt
around lines 119 - 127, The compile error comes from calling item.copy(...) on
ChallengeRoutineItem (an interface) inside the ChallengeRoutineOnboardingBody
onItemClick handler; replace that call with a polymorphic copy method on the
interface (e.g., add fun copyWithSelection(isSelected: Boolean):
ChallengeRoutineItem to the ChallengeRoutineItem interface and implement it in
concrete classes) and then update the mapping to use
item.copyWithSelection(item.id == clickedItem.id); alternatively, if all items
are concrete data classes, cast to the concrete type before using copy, but the
preferred fix is to add and call copyWithSelection on ChallengeRoutineItem and
implement it in the implementations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FEAT✨ 새로운 기능 구현 혜민🍒 혜민 담당

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 챌린지 뷰 컴포넌트 구현

3 participants