Skip to content

[FEAT/#33] 시술 카드 컴포넌트 구현#37

Merged
usuuhyn merged 16 commits intodevelopfrom
feat/#33-treatment-card-component
Jan 13, 2026
Merged

[FEAT/#33] 시술 카드 컴포넌트 구현#37
usuuhyn merged 16 commits intodevelopfrom
feat/#33-treatment-card-component

Conversation

@usuuhyn
Copy link
Copy Markdown
Contributor

@usuuhyn usuuhyn commented Jan 12, 2026

Related issue 🛠

Work Description ✏️

  • 시술 플로우의 시술 카드 컴포넌트를 구현했습니다.

Screenshot 📸

BasicProcedureCard SelectableProcedureCard

Uncompleted Tasks 😅

N/A

To Reviewers 📢

카드 공통 컴포넌트로 재사용할 수 있도록 ProcedureCard를 구현했습니다.
배경/보더 색상과 우측 상단 체크 영역은 모두 파라미터로 열어두어 선택/비선택 상태에 따라 커스터마이징 가능합니다.
프리뷰 코드도 넣어두었으니 함께 확인 부탁드립니다 !!

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 절차 카드 컴포넌트 추가: 제목, 설명, 다운타임 기간을 표시하는 선택 가능한 카드 UI 구현
    • 기본 및 선택 가능한 두 가지 표시 모드 지원
    • 선택 상태에 따른 시각적 피드백 (체크 아이콘) 포함
    • 새로운 아이콘 리소스 추가 (시계, 체크마크)

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

@usuuhyn usuuhyn self-assigned this Jan 12, 2026
@usuuhyn usuuhyn requested a review from a team as a code owner January 12, 2026 11:46
@usuuhyn usuuhyn added the FEAT✨ 새로운 기능 구현 label Jan 12, 2026
@usuuhyn usuuhyn linked an issue Jan 12, 2026 that may be closed by this pull request
@usuuhyn usuuhyn added the 수현🍒 수현 담당 label Jan 12, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 12, 2026

Walkthrough

시술 카드 컴포넌트를 Jetpack Compose로 새로 구현합니다. 선택 가능한 UI 컴포넌트, 토큰 기반 디자인 시스템, 디스플레이 모드 타입, 관련 벡터 드로어블 리소스를 추가합니다.

Changes

Cohort / File(s) Summary
Compose 컴포넌트
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
선택 가능한 시술 카드 컴포넌트 추가. 제목, 설명, 다운타임 기간 범위를 표시하며 Basic/Selectable 두 가지 디스플레이 모드 지원. 체크 아이콘, 시계 아이콘, 클릭 핸들링 및 토큰 기반 색상 테마 포함
디스플레이 모드 및 토큰 시스템
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardDisplayMode.kt, app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.kt
sealed interface 기반 타입 안전 디스플레이 모드 정의 (Basic, Selectable). 색상 및 드로어블 리소스를 관리하는 토큰 모델 및 팩토리 함수 추가
벡터 드로어블 리소스
app/src/main/res/drawable/ic_check_circular.xml, app/src/main/res/drawable/ic_check_circular_green.xml, app/src/main/res/drawable/ic_clock.xml
시술 카드에서 사용할 아이콘 리소스 추가: 회색 체크 원형, 녹색 체크 원형, 시계 아이콘

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • hyeminililo
  • sohee6989
  • 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/#33] 시술 카드 컴포넌트 구현'은 새로운 시술 카드 컴포넌트 구현이라는 주요 변경 사항을 정확히 반영합니다.
Description check ✅ Passed PR 설명이 템플릿의 모든 필수 항목을 포함하고 있습니다. 관련 이슈, 작업 설명, 스크린샷, 미완료 사항, 검토자 요청이 모두 제공되었으며 내용이 충실합니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경이 이슈 #33의 요구사항을 충족합니다. ProcedureCard 컴포넌트가 선택/비선택 상태를 표현하도록 구현되었고, 스타일 파라미터와 체크 표시 기능을 지원합니다.
Out of Scope Changes check ✅ Passed 모든 변경이 ProcedureCard 컴포넌트 구현과 관련된 범위 내에 있습니다. 새로운 컴포넌트, 디스플레이 모드, 토큰 시스템, 아이콘 리소스 등이 모두 시술 카드 구현을 위한 것입니다.

✏️ 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: 1

🤖 Fix all issues with AI agents
In
@app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt:
- Around line 55-69: The resolvedTopRightContent branch currently sets the
Icon's contentDescription to null, breaking accessibility; update the lambda
built in ProcedureCard (resolvedTopRightContent) to provide a meaningful
contentDescription based on isSelected (e.g., use a string like "Selected" vs
"Not selected" or fetch from string resources), ensuring the description is tied
to the same branch that uses selectedCheckIconResId/unselectedCheckIconResId and
preserving tint and imageVector; if topRightContent is provided leave it
untouched.
🧹 Nitpick comments (1)
app/src/main/res/drawable/icon_check_circular_green.xml (1)

1-12: 아이콘 네이밍 컨벤션 불일치

이 파일은 icon_ 접두사를 사용하고 있으나, 동일 PR에서 추가된 다른 아이콘들(ic_check_circular.xml, ic_clock.xml)은 ic_ 접두사를 사용하고 있습니다. 일관성을 위해 ic_check_circular_green.xml로 변경하는 것을 권장합니다.

📜 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 3e43cc6 and 3b40538.

📒 Files selected for processing (4)
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
  • app/src/main/res/drawable/ic_check_circular.xml
  • app/src/main/res/drawable/ic_clock.xml
  • app/src/main/res/drawable/icon_check_circular_green.xml
🧰 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/calendar/procedure/component/ProcedureCard.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (1)
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 (6)
app/src/main/res/drawable/ic_check_circular.xml (1)

1-12: LGTM!

벡터 드로어블 리소스가 올바르게 정의되어 있습니다. 24dp 크기와 회색 원형 배경에 흰색 체크 아이콘이 적절하게 구현되었습니다.

app/src/main/res/drawable/ic_clock.xml (1)

1-19: LGTM!

시계 아이콘이 적절하게 구현되었습니다. stroke 스타일과 round cap/join 설정이 깔끔한 아웃라인 스타일을 제공합니다.

app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (4)

71-78: LGTM!

Modifier 체인 순서가 올바르게 구성되어 있습니다 (fillMaxWidthclickableclipbackgroundborderpadding). noRippleClickable 사용은 디자인 의도에 따른 것으로 보입니다.


107-122: LGTM!

시간 정보 표시 Row가 적절하게 구성되어 있습니다. 시계 아이콘은 durationText와 함께 표시되므로 장식적 요소로서 contentDescription = null이 적절합니다.


127-170: LGTM!

프리뷰가 잘 구성되어 있습니다. remembermutableStateOf를 활용한 인터랙티브 프리뷰로 선택 상태 토글을 직접 테스트할 수 있어 유용합니다.


43-44: 기본 border 색상이 동일함을 확인해 주세요

selectedBorderColorunselectedBorderColor 모두 기본값이 gray700으로 설정되어 있어, 기본 상태에서는 선택 여부에 따른 테두리 색상 변화가 없습니다. 의도된 동작인지 확인이 필요합니다.

프리뷰에서는 다른 색상으로 오버라이드하고 있으므로 실제 사용 시에도 명시적으로 지정해야 할 것으로 보입니다.

Comment on lines +55 to +69
val resolvedTopRightContent: (@Composable () -> Unit)? = when {
topRightContent != null -> topRightContent
showCheckIcon -> {
{
Icon(
imageVector = ImageVector.vectorResource(
id = if (isSelected) selectedCheckIconResId else unselectedCheckIconResId
),
contentDescription = null,
tint = Color.Unspecified
)
}
}
else -> null
}
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

접근성(Accessibility) 개선 필요

체크 아이콘의 contentDescriptionnull로 설정되어 있어 스크린 리더 사용자가 선택 상태를 인지할 수 없습니다. 선택 상태에 따라 의미 있는 설명을 제공하는 것을 권장합니다.

♿ 접근성 개선 제안
 showCheckIcon -> {
     {
         Icon(
             imageVector = ImageVector.vectorResource(
                 id = if (isSelected) selectedCheckIconResId else unselectedCheckIconResId
             ),
-            contentDescription = null,
+            contentDescription = if (isSelected) "선택됨" else "선택 안됨",
             tint = Color.Unspecified
         )
     }
 }
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
around lines 55 - 69, The resolvedTopRightContent branch currently sets the
Icon's contentDescription to null, breaking accessibility; update the lambda
built in ProcedureCard (resolvedTopRightContent) to provide a meaningful
contentDescription based on isSelected (e.g., use a string like "Selected" vs
"Not selected" or fetch from string resources), ensuring the description is tied
to the same branch that uses selectedCheckIconResId/unselectedCheckIconResId and
preserving tint and imageVector; if topRightContent is provided leave it
untouched.

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: 0

🧹 Nitpick comments (3)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (3)

55-69: ImageVector.vectorResource 호출에 remember 적용 권장

resolvedTopRightContent 내부에서 ImageVector.vectorResource가 매 recomposition마다 호출될 수 있습니다. 벡터 리소스 로딩은 비용이 있으므로, remember로 캐싱하면 recomposition 최적화에 도움이 됩니다.

♻️ 제안된 수정
     val resolvedTopRightContent: (@Composable () -> Unit)? = when {
         topRightContent != null -> topRightContent
         showCheckIcon -> {
             {
+                val checkIconResId = if (isSelected) selectedCheckIconResId else unselectedCheckIconResId
+                val imageVector = remember(checkIconResId) {
+                    ImageVector.vectorResource(id = checkIconResId)
+                }
                 Icon(
-                    imageVector = ImageVector.vectorResource(
-                        id = if (isSelected) selectedCheckIconResId else unselectedCheckIconResId
-                    ),
+                    imageVector = imageVector,
                     contentDescription = null,
                     tint = Color.Unspecified
                 )
             }
         }
         else -> null
     }

참고: remember@Composable 컨텍스트에서만 호출 가능하므로, 람다 내부에서 사용해야 합니다.


112-116: 시계 아이콘에도 동일하게 remember 적용 권장

R.drawable.ic_clock 아이콘 로딩도 recomposition마다 수행됩니다. 이 값은 고정되어 있으므로 컴포넌트 레벨에서 한 번만 로드하도록 최적화할 수 있습니다.

♻️ 제안된 수정

Line 53 아래에 추가:

val clockIcon = ImageVector.vectorResource(id = R.drawable.ic_clock)

그리고 Line 112-116을:

                 Icon(
-                    imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
+                    imageVector = clockIcon,
                     contentDescription = null,
                     tint = Color.Unspecified
                 )

71-78: Modifier 체인 순서 확인

현재 순서가 noRippleClickableclipbackgroundborder입니다. clip이 클릭 이후에 적용되어 터치 영역이 둥근 모서리 바깥까지 포함될 수 있습니다. 시각적으로 정확한 터치 영역을 원한다면 clipnoRippleClickable 앞에 배치하는 것이 좋습니다.

♻️ 제안된 수정
     Box(
         modifier = modifier
             .fillMaxWidth()
+            .clip(shape)
             .noRippleClickable(onClick = onCardClick)
-            .clip(shape)
             .background(color = containerColor, shape = shape)
             .border(width = 1.dp, color = borderColor, shape = shape)
             .padding(horizontal = 14.dp, vertical = 12.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 3b40538 and 4b3d28d.

📒 Files selected for processing (1)
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.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/calendar/procedure/component/ProcedureCard.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (1)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
🔇 Additional comments (2)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (2)

127-170: LGTM!

프리뷰 함수들이 잘 구성되어 있습니다. CherrishTheme으로 감싸고 remember + mutableStateOf를 사용하여 인터랙티브하게 상태 변경을 확인할 수 있도록 구현되었습니다. 기본 상태와 체크 아이콘 포함 상태 두 가지 케이스를 잘 보여주고 있습니다.


33-49: 컴포넌트 API 설계가 잘 되어 있습니다.

필수 파라미터(title, description, durationText, onCardClick)를 먼저 배치하고, 커스터마이징 옵션들은 기본값과 함께 제공하여 유연한 사용이 가능합니다. topRightContent 슬롯과 showCheckIcon 플래그를 통해 다양한 사용 케이스를 지원하는 설계가 좋습니다.

Copy link
Copy Markdown
Contributor

@hyeminililo hyeminililo left a comment

Choose a reason for hiding this comment

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

수고하셨습니당 !! 코리 한 번 확인해주쎄용 ~~~

Box(
modifier = modifier
.fillMaxWidth()
.noRippleClickable(onClick = onCardClick)
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: noRippleClickableclip 보다 앞에 있으면 clip으로 잘려지지 않은 부분도 터치 영역으로 확보(??)될것 같아요 ..!!
clipnoRippleClickable보다 앞 순서에 넣는거 어떠신가용??

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.

오 !! 넵 clip 먼저 적용하고 그 이후에 noRippleClickable이 오도록 순서 변경하겠습니당


val shape = RoundedCornerShape(10.dp)

val resolvedTopRightContent: (@Composable () -> Unit)? = when {
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.

P3: Composable 함수에서 인자로 값을 전달받고 있어서,
해당 값이 변경될 때마다 recomposition이 발생할 것 같아용,,,!!

내부의 Icon 자체는 매번 다시 그릴 필요까지는 없어 보여서,
remember로 객체를 메모이제이션하면 불필요한 객체 생성을 줄일 수 있을 것 같습니다!!

한 번 고려해보시면 좋을 것 같아요 😊

Copy link
Copy Markdown
Contributor Author

@usuuhyn usuuhyn Jan 12, 2026

Choose a reason for hiding this comment

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

말씀해주신 부분 참고해서 구조 한 번 더 정리해봤습니다!!!
remember 대신 컴포저블 분기를 바로 ui 안에서 처리하도록 수정했어용

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: 0

🧹 Nitpick comments (3)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (3)

53-53: RoundedCornerShaperemember로 캐싱하는 것을 권장합니다.

RoundedCornerShape(10.dp)가 매 recomposition마다 새로 생성됩니다. 성능 최적화를 위해 remember를 사용하거나 companion object로 추출하는 것이 좋습니다.

♻️ 제안된 수정
-    val shape = RoundedCornerShape(10.dp)
+    val shape = remember { RoundedCornerShape(10.dp) }

76-93: topRightContentshowCheckIcon 우선순위에 대한 문서화를 권장합니다.

현재 topRightContent가 제공되면 showCheckIcon이 무시됩니다. 이 동작은 합리적이지만, API 사용자에게 명확하지 않을 수 있습니다. KDoc 주석으로 우선순위를 명시하거나, 두 옵션이 동시에 설정된 경우를 처리하는 것을 고려해보세요.

📝 KDoc 주석 예시
/**
 * 시술 카드 컴포넌트
 * ...
 * @param topRightContent 우측 상단에 표시할 커스텀 컨텐츠. 제공 시 [showCheckIcon]보다 우선 적용됨.
 * @param showCheckIcon 체크 아이콘 표시 여부. [topRightContent]가 null일 때만 적용됨.
 */

55-62: 접근성(Accessibility) 향상을 위해 semantics 추가를 고려해주세요.

카드가 클릭 가능하지만 스크린 리더 사용자를 위한 콘텐츠 설명이 없습니다. Modifier.semantics를 사용하여 카드의 역할과 상태를 명시하면 접근성이 향상됩니다.

♿ 접근성 개선 예시
 Box(
     modifier = modifier
         .fillMaxWidth()
+        .semantics {
+            role = Role.Button
+            selected = isSelected
+        }
         .noRippleClickable(onClick = onCardClick)
         .clip(shape)

필요한 import:

import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.selected
import androidx.compose.ui.semantics.semantics
📜 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 4b3d28d and 2f3dce7.

📒 Files selected for processing (1)
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.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/calendar/procedure/component/ProcedureCard.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (1)
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 Build Check
  • GitHub Check: PR Lint Check
🔇 Additional comments (3)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (3)

33-49: 컴포넌트 구조가 잘 설계되었습니다.

재사용 가능한 카드 컴포넌트로서 선택/비선택 상태에 따른 스타일 커스터마이징이 유연하게 지원됩니다. topRightContent 슬롯과 showCheckIcon 옵션으로 다양한 사용 사례를 커버할 수 있습니다.

다만, 파라미터가 14개로 많은 편입니다. 향후 확장 시 색상 관련 파라미터를 data class로 그룹화하는 것을 고려해볼 수 있습니다.


126-146: 프리뷰 함수가 잘 구성되었습니다.

CherrishTheme 래퍼와 remember { mutableStateOf() }를 사용한 인터랙티브 상태 토글이 올바르게 구현되었습니다. 프리뷰에서 선택/비선택 상태 전환을 직접 테스트할 수 있어 좋습니다.


148-169: 체크 아이콘 포함 프리뷰가 적절합니다.

Basic 프리뷰와 함께 컴포넌트의 두 가지 주요 사용 패턴(체크 아이콘 유/무)을 잘 보여줍니다. 녹색 테마 색상 적용도 의도대로 작동하는지 확인할 수 있습니다.

@usuuhyn usuuhyn changed the title [FEAT] 시술 카드 컴포넌트 구현 [FEAT/#33] 시술 카드 컴포넌트 구현 Jan 12, 2026
@hyeminililo hyeminililo self-requested a review January 12, 2026 16:38
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.

고민한 흔적이 정말 많이 보이는 피알이엿던거 가트요 ㅎㅎㅎ 작업 속도도 체고고 열심히 재미있게 작업하는 모습이 넘넘 보기 좋답니도 !! 조금만 더 파이팅해보쟈잉 리뷰 한번만 확인해조요 🫰 🫰 🫰 🫰 🫰

import com.cherrish.android.core.designsystem.theme.CherrishTheme

@Composable
internal fun ProcedureCard(
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 : 이거 우리는 지금 싱글 모듈이기 때문에 따로 internal 제한자가 불필요할거 가타용 ~~~ !!!! internal 같은 경우에는 같은 모듈 안에서만 사용하도록 접근을 제한해 주는 아이라서 ㅎㅎㅎ

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 +41 to +47
selectedContainerColor: Color = CherrishTheme.colors.gray500,
unselectedContainerColor: Color = CherrishTheme.colors.gray0,
selectedBorderColor: Color = CherrishTheme.colors.gray700,
unselectedBorderColor: Color = CherrishTheme.colors.gray700,
showCheckIcon: Boolean = false,
selectedCheckIconResId: Int = R.drawable.icon_check_circular_green,
unselectedCheckIconResId: Int = R.drawable.ic_check_circular,
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.

오호 좋은 생각입니다옹~~!!

Comment on lines +45 to +47
showCheckIcon: Boolean = false,
selectedCheckIconResId: Int = R.drawable.icon_check_circular_green,
unselectedCheckIconResId: Int = R.drawable.ic_check_circular,
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 : 이거 그리고 아이콘 따로 여기서 설정하지 않아도 아래의 topRightContent로도 받을 수 있을 것 가타용 ~~

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.

맞네용 !! 삭제하겟습니닷

onCardClick: () -> Unit,
modifier: Modifier = Modifier,
isSelected: Boolean = false,
selectedContainerColor: Color = CherrishTheme.colors.gray500,
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 : 요거 그리고 선택 되었을 때 컬러 이거 맞나용 ?!!? 밑에 보더도 확인 부탁해용ㅇ ~~

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.

잠시 정신을 잃엇나봅니다 ㅎㅎ 수정했습니다!

selectedContainerColor: Color = CherrishTheme.colors.gray500,
unselectedContainerColor: Color = CherrishTheme.colors.gray0,
selectedBorderColor: Color = CherrishTheme.colors.gray700,
unselectedBorderColor: Color = CherrishTheme.colors.gray700,
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 : 요거 보더두 500인듓 !!!!

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.

정신 잃음 22 수정했습니닷

Comment on lines +55 to +63
Box(
modifier = modifier
.fillMaxWidth()
.clip(shape)
.background(color = containerColor, shape = shape)
.border(width = 1.dp, color = borderColor, shape = shape)
.noRippleClickable(onClick = onCardClick)
.padding(horizontal = 14.dp, vertical = 12.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.

P1 : Box 컴포넌트의 경우 여러 요소의 배치를 자유자재로 할 수 있다는 점 같아요 !! 그런데 현재의 박스의 기능은 그냥 안에 있는 애들을 담고 있다고만 느껴집니다! Row나 Column 같은 아이들을 사용하지 않고도 Box 컴포넌트의 자식 컴포넌트 속성 중 align을 사용하면 굳이 Row나 Column으로 감싸지 않아도 될 아이들이 보입니다 !! 그리고 세미나 시간에 배웠던 컴포넌트화를 해보는 것두 좋을 것 같네용 ~~ !!!

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 +77 to +79
topRightContent != null -> {
topRightContent()
}
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.

P2 : 요기는 다른 아이콘이 들어가지는 않아서 이렇게 topRightContent 자체가 필요없지 않을까 라는 생각두 드네용이 ~~ !!

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.

저도 topRightContent가 불필요한 것 같습니다!
추가로 topRightContent 빼실거면 when 분기문 처리도 불필요할 것 같아 함께 정리해주시면 될 것 같습니다!

Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
contentDescription = null,
tint = Color.Unspecified
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 : 요거는 색상 gray700 같슴니동동 ~~ !!

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

@sohee6989 sohee6989 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!
리뷰 한 번만 확인 부탁드립니다!


@Preview(showBackground = true)
@Composable
private fun ProcedureCardPreview_Basic() {
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.

p2: 프리뷰여도 네이밍 규칙 지켜주세여~!!
밑에 프리뷰도

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.

알겟습니다람쥐

tint = Color.Unspecified
)
Text(
text = durationText,
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: 이 부분 다운타임이라는 텍스트는 고정이니 다운타임 기간에 대해서만 파라미터로 빼는게 더 좋을 것 같습니다!

스크린샷 2026-01-13 오후 12 06 59

추가로 서버 명세서를 확인해보니 3, 5 이렇게 최소 다운타임/ 최대 다운타임 날짜만 int로 받을 거라서 그 부분 미리 고려해서 만들어도 좋을 듯 싶습니다

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.

넵 !! 좋습니당~~

imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
contentDescription = null,
tint = Color.Unspecified
)
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.

p2: 가독성 위해 공백 한 줄 부탁드려요~!

Comment on lines +77 to +79
topRightContent != null -> {
topRightContent()
}
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.

저도 topRightContent가 불필요한 것 같습니다!
추가로 topRightContent 빼실거면 when 분기문 처리도 불필요할 것 같아 함께 정리해주시면 될 것 같습니다!

val containerColor = if (isSelected) selectedContainerColor else unselectedContainerColor
val borderColor = if (isSelected) selectedBorderColor else unselectedBorderColor

val shape = RoundedCornerShape(10.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.

p3: shape 변수로 빼신 이유가 궁금합니다!
중복 작성 때문에 빼신건가여??

Copy link
Copy Markdown
Contributor Author

@usuuhyn usuuhyn Jan 13, 2026

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: 0

🧹 Nitpick comments (1)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (1)

153-167: 레이아웃 캡슐화를 고려해 보세요.

현재 ProcedureCardDurationIconText를 형제 요소로 렌더링하며, 부모의 Row에 의존하여 가로 배치됩니다. 이 컴포저블만 단독으로 사용될 경우 레이아웃이 의도대로 동작하지 않을 수 있습니다.

♻️ Row로 감싸는 개선 제안
 @Composable
 private fun ProcedureCardDuration(
     durationText: String
 ) {
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        horizontalArrangement = Arrangement.spacedBy(4.dp)
+    ) {
         Icon(
             imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
             contentDescription = null,
             tint = CherrishTheme.colors.gray700
         )
         Text(
             text = durationText,
             style = CherrishTheme.typography.body2R13,
             color = CherrishTheme.colors.gray700
         )
+    }
 }

현재 사용 맥락에서는 문제없이 동작하지만, 재사용성을 높이려면 자체 레이아웃을 포함하는 것이 좋습니다.

📜 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 2f3dce7 and 12b002a.

📒 Files selected for processing (3)
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardDisplayMode.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.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/calendar/procedure/model/ProcedureCardDisplayMode.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.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/calendar/procedure/model/ProcedureCardDisplayMode.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (1)
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 Build Check
  • GitHub Check: PR Lint Check
🔇 Additional comments (6)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.kt (1)

5-26: LGTM! 토큰 모델 구조가 잘 설계되었습니다.

sealed interface를 사용하여 토큰 타입을 제한하고, data class로 불변 토큰을 정의한 점이 적절합니다. SelectableProcedureCardTokens에서 체크 아이콘 리소스 ID를 추가로 노출하여 모드별 확장성을 확보했습니다.

app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardDisplayMode.kt (1)

3-6: LGTM! 디스플레이 모드 정의가 적절합니다.

sealed interfacedata object를 사용하여 닫힌 집합의 모드를 정의했습니다. 싱글톤 시맨틱과 함께 equals/hashCode 자동 생성을 활용할 수 있어 좋습니다.

app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (4)

62-109: LGTM! 컴포넌트 구조와 Modifier 체인 순서가 적절합니다.

  • clipbackgroundbordernoRippleClickablepadding 순서로 Modifier가 적용되어 클릭 영역과 시각적 경계가 올바르게 동작합니다.
  • isSelecteddisplayMode에 따른 조건부 스타일링이 깔끔하게 구현되었습니다.

129-141: 타입 체크를 통한 조건부 렌더링이 잘 동작합니다.

tokens is SelectableProcedureCardTokens 체크를 통해 Selectable 모드에서만 체크 아이콘을 표시하는 로직이 명확합니다. Color.Unspecified를 사용하여 벡터 에셋의 원본 색상을 유지한 점도 적절합니다.


169-201: LGTM! 프리뷰 설정이 적절합니다.

두 가지 디스플레이 모드(Basic, Selectable)에 대한 프리뷰가 제공되고, mutableStateOf를 사용하여 인터랙티브 프리뷰에서 클릭 동작을 테스트할 수 있습니다.


37-60: @Composable 함수 내에서 CompositionLocal 색상 값을 안전하게 처리하세요.

procedureCardTokens 함수는 CherrishTheme.colors라는 CompositionLocal을 참조합니다. CompositionLocal은 동적으로 변경될 수 있으므로, remember(displayMode)로 토큰 객체를 메모이제이션하면 테마 색상이 변경되어도 캐시된 이전 값이 반영되지 않습니다.

토큰 객체 생성 비용이 미미하고, 색상이 동적이므로 현재 코드 유지를 권장합니다. 만약 메모이제이션이 필수라면, 모든 색상 의존성을 remember의 키에 포함해야 하므로 복잡성이 증가합니다.

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/calendar/procedure/component/ProcedureCard.kt:
- Around line 153-167: ProcedureCardDuration renders an Icon immediately
followed by Text with no gap; wrap the Icon and Text in a Row (or ensure they
already sit in a horizontal layout) and insert a Spacer with a small horizontal
width (e.g., 4–8.dp) between ImageVector.vectorResource(...) Icon and Text to
provide the missing spacing; update the ProcedureCardDuration composable to
include the Spacer (or use Modifier.padding on the Text) so the icon and
durationText are visually separated.
🧹 Nitpick comments (2)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (2)

37-60: 토큰 인스턴스 생성 최적화 고려

procedureCardTokens 함수가 매 recomposition마다 새로운 토큰 인스턴스를 생성합니다. displayMode가 변경되지 않는 한 동일한 토큰을 재사용할 수 있습니다.

♻️ remember를 사용한 최적화 제안
 @Composable
-private fun procedureCardTokens(displayMode: ProcedureCardDisplayMode): ProcedureCardTokens {
-    return when (displayMode) {
+private fun procedureCardTokens(displayMode: ProcedureCardDisplayMode): ProcedureCardTokens {
+    val colors = CherrishTheme.colors
+    return remember(displayMode, colors) {
+        when (displayMode) {
         ProcedureCardDisplayMode.Basic -> {
             BasicProcedureCardTokens(
-                selectedContainerColor = CherrishTheme.colors.gray300,
-                unselectedContainerColor = CherrishTheme.colors.gray0,
-                selectedBorderColor = CherrishTheme.colors.gray500,
-                unselectedBorderColor = CherrishTheme.colors.gray500
+                selectedContainerColor = colors.gray300,
+                unselectedContainerColor = colors.gray0,
+                selectedBorderColor = colors.gray500,
+                unselectedBorderColor = colors.gray500
             )
         }
-
         ProcedureCardDisplayMode.Selectable -> {
             SelectableProcedureCardTokens(
-                selectedContainerColor = CherrishTheme.colors.green1,
-                unselectedContainerColor = CherrishTheme.colors.gray0,
-                selectedBorderColor = CherrishTheme.colors.green3,
-                unselectedBorderColor = CherrishTheme.colors.gray500,
+                selectedContainerColor = colors.green1,
+                unselectedContainerColor = colors.gray0,
+                selectedBorderColor = colors.green3,
+                unselectedBorderColor = colors.gray500,
                 selectedCheckIconResId = R.drawable.icon_check_circular_green,
                 unselectedCheckIconResId = R.drawable.ic_check_circular
             )
         }
+        }
     }
 }

129-141: 접근성 개선 고려

체크 아이콘의 contentDescriptionnull로 설정되어 있습니다. 선택 가능한 카드의 경우 스크린 리더 사용자를 위해 선택 상태를 전달하는 것이 좋습니다.

♻️ 접근성 개선 제안
             Icon(
                 imageVector = ImageVector.vectorResource(id = checkIconResId),
-                contentDescription = null,
+                contentDescription = if (isSelected) "선택됨" else "선택되지 않음",
                 tint = Color.Unspecified
             )
📜 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 12b002a and 60f038a.

📒 Files selected for processing (1)
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.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/calendar/procedure/component/ProcedureCard.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/calendar/procedure/component/ProcedureCard.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (1)
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 Build Check
  • GitHub Check: PR Lint Check
🔇 Additional comments (2)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (2)

62-109: LGTM!

ProcedureCard 컴포저블 구조가 잘 설계되어 있습니다. modifier 파라미터가 필수 파라미터 뒤, 기본값 파라미터 앞에 적절히 배치되어 있고, 선택/비선택 상태에 따른 스타일링이 명확합니다.


169-201: LGTM!

Preview 함수들이 두 가지 displayMode(Basic, Selectable)를 모두 테스트할 수 있도록 잘 구성되어 있습니다. mutableStateOf를 사용한 인터랙티브 프리뷰로 선택 상태 변경을 확인할 수 있습니다.

Comment on lines +153 to +167
@Composable
private fun ProcedureCardDuration(
durationText: String
) {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
contentDescription = null,
tint = CherrishTheme.colors.gray700
)
Text(
text = durationText,
style = CherrishTheme.typography.body2R13,
color = CherrishTheme.colors.gray700
)
}
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

아이콘과 텍스트 사이 간격 누락

ProcedureCardDuration에서 IconText 사이에 간격이 없습니다. UI에서 아이콘과 텍스트가 붙어서 표시됩니다.

🐛 간격 추가 제안
 @Composable
 private fun ProcedureCardDuration(
     durationText: String
 ) {
     Icon(
         imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
         contentDescription = null,
         tint = CherrishTheme.colors.gray700
     )
+    Spacer(modifier = Modifier.size(4.dp))
     Text(
         text = durationText,
         style = CherrishTheme.typography.body2R13,
         color = CherrishTheme.colors.gray700
     )
 }
📝 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 ProcedureCardDuration(
durationText: String
) {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
contentDescription = null,
tint = CherrishTheme.colors.gray700
)
Text(
text = durationText,
style = CherrishTheme.typography.body2R13,
color = CherrishTheme.colors.gray700
)
}
@Composable
private fun ProcedureCardDuration(
durationText: String
) {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_clock),
contentDescription = null,
tint = CherrishTheme.colors.gray700
)
Spacer(modifier = Modifier.size(4.dp))
Text(
text = durationText,
style = CherrishTheme.typography.body2R13,
color = CherrishTheme.colors.gray700
)
}
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
around lines 153 - 167, ProcedureCardDuration renders an Icon immediately
followed by Text with no gap; wrap the Icon and Text in a Row (or ensure they
already sit in a horizontal layout) and insert a Spacer with a small horizontal
width (e.g., 4–8.dp) between ImageVector.vectorResource(...) Icon and Text to
provide the missing spacing; update the ProcedureCardDuration composable to
include the Spacer (or use Modifier.padding on the Text) so the icon and
durationText are visually separated.

@usuuhyn usuuhyn requested a review from nhyeonii January 13, 2026 08:13
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.

굿굿 ~~ 코드가 훨 깔끔해졋네요 ㅎㅎㅎㅎ 컬러랑 컨벤션 한번씩만 확인해서 반영해주세요!! 수고햇삼 !~~~

tokens = tokens
)

Spacer(modifier = Modifier.size(8.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.

P2 : 얘 height 말고 size 사용하신 이유가 잇나용 ??

Copy link
Copy Markdown
Contributor Author

@usuuhyn usuuhyn Jan 13, 2026

Choose a reason for hiding this comment

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

그냥 생각나는 거 썻습니당. .ㅎㅎ ㅎ ㅎ

*** column -> height / row -> width / 영역 -> size

SelectableProcedureCardTokens(
selectedContainerColor = CherrishTheme.colors.green1,
unselectedContainerColor = CherrishTheme.colors.gray0,
selectedBorderColor = CherrishTheme.colors.green3,
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 : border green2 가타요 ~~!!!

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 +56 to +57
selectedCheckIconResId = R.drawable.icon_check_circular_green,
unselectedCheckIconResId = R.drawable.ic_check_circular
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 : 요거 icon ic로 통일하능거 어떠신지용 ?!

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 +36 to +37
@Composable
private fun procedureCardTokens(
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.

요 로직을 ProcedureCard보다는 ProcedureTokens으로 옮기는 거 어떤지용 ?!?!

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.

오호 넵 !!

@sohee6989
Copy link
Copy Markdown
Contributor

굿굿 ~~ 코드가 훨 깔끔해졋네요 ㅎㅎㅎㅎ 컬러랑 컨벤션 한번씩만 확인해서 반영해주세요!! 수고햇삼 !~~~

삼다수
스크린샷 2026-01-13 오후 8 27 52

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/calendar/procedure/component/ProcedureCard.kt:
- Around line 113-121: The Icon currently sets contentDescription = null and the
Spacer uses Modifier.size(2.dp); change the Icon to provide an accessible
description (e.g., use a localized string via stringResource or a passed-in
label that reflects selection state — reference the Icon call and
checkIconResId) instead of null so screen readers announce the icon (e.g.,
"selected" or "completed"), and replace Spacer(modifier = Modifier.size(2.dp))
with Spacer(modifier = Modifier.height(2.dp)) to create a vertical gap rather
than a square area.
🧹 Nitpick comments (3)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.kt (1)

31-56: 토큰 인스턴스 생성 최적화를 고려해볼 수 있습니다.

현재 구현은 매 recomposition마다 새로운 토큰 인스턴스를 생성합니다. 성능에 큰 영향은 없지만, remember를 사용하여 불필요한 객체 생성을 줄일 수 있습니다.

♻️ 선택적 최적화 제안
 @Composable
 fun procedureCardTokens(
     displayMode: ProcedureCardDisplayMode
 ): ProcedureCardTokens {
-    return when (displayMode) {
+    return remember(displayMode) {
+        when (displayMode) {
-        ProcedureCardDisplayMode.Basic -> {
+            ProcedureCardDisplayMode.Basic -> {
-            BasicProcedureCardTokens(
+                BasicProcedureCardTokens(
                     selectedContainerColor = CherrishTheme.colors.gray300,
                     ...
                 )
             }
             ...
         }
     }
+    }
 }

단, CherrishTheme.colors가 CompositionLocal에서 제공되므로 테마 변경 시 토큰이 갱신되어야 한다면 현재 구현을 유지하는 것이 적절합니다.

app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (2)

37-86: 컴포넌트 구조가 잘 설계되었습니다.

토큰 기반 테마 적용과 파라미터 설계가 재사용성을 고려하여 잘 구현되었습니다. 몇 가지 개선 포인트를 제안드립니다:

  1. Shape 최적화: RoundedCornerShape(10.dp)가 매 recomposition마다 생성됩니다.
  2. 접근성 고려: noRippleClickable 사용 시 시각적 피드백이 없어 접근성에 영향을 줄 수 있습니다.
♻️ Shape 추출 및 접근성 개선 제안
+private val ProcedureCardShape = RoundedCornerShape(10.dp)
+
 @Composable
 fun ProcedureCard(
     ...
 ) {
     val tokens = procedureCardTokens(displayMode)
     ...
-    val shape = RoundedCornerShape(10.dp)
+    val shape = ProcedureCardShape

     Column(
         modifier = modifier
             .fillMaxWidth()
             .clip(shape)
             .background(color = containerColor, shape = shape)
             .border(width = 1.dp, color = borderColor, shape = shape)
-            .noRippleClickable(onClick = onCardClick)
+            .clickable(onClick = onCardClick)  // 리플 피드백으로 접근성 향상
             .padding(horizontal = 14.dp, vertical = 12.dp)
     ) {

디자인 요구사항에 따라 noRippleClickable이 의도된 것이라면 현재 구현을 유지해도 됩니다.


144-148: 하드코딩된 문자열을 string resource로 분리하는 것을 권장합니다.

"다운타임* $minDowntimeDay-${maxDowntimeDay}일" 문자열이 하드코딩되어 있습니다. 국제화(i18n) 지원과 유지보수를 위해 string resource 사용을 고려해주세요.

♻️ String resource 적용 예시

strings.xml에 추가:

<string name="procedure_card_downtime">다운타임* %1$d-%2$d일</string>

코드 수정:

 Text(
-    text = "다운타임* $minDowntimeDay-${maxDowntimeDay}일",
+    text = stringResource(R.string.procedure_card_downtime, minDowntimeDay, maxDowntimeDay),
     style = CherrishTheme.typography.body2R13,
     color = CherrishTheme.colors.gray700
 )
📜 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 a73a9c9 and eb1a8a5.

📒 Files selected for processing (3)
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.kt
  • app/src/main/res/drawable/ic_check_circular_green.xml
🧰 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/calendar/procedure/model/ProcedureCardTokens.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.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/calendar/procedure/model/ProcedureCardTokens.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (2)
app/src/main/java/com/cherrish/android/presentation/calendar/procedure/model/ProcedureCardTokens.kt (1)
  • procedureCardTokens (31-56)
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/presentation/calendar/procedure/model/ProcedureCardTokens.kt (1)

8-29: LGTM! 토큰 기반 디자인 시스템 구조가 잘 설계되었습니다.

Sealed interface를 사용하여 BasicSelectable 두 가지 디스플레이 모드에 대한 토큰을 명확하게 분리했습니다. SelectableProcedureCardTokens에 체크 아이콘 리소스 ID를 추가한 것도 적절합니다.

app/src/main/res/drawable/ic_check_circular_green.xml (1)

1-12: LGTM! 벡터 드로어블이 올바르게 정의되었습니다.

24dp 크기의 원형 체크 아이콘이 적절하게 구현되었습니다. 선택 상태를 나타내는 녹색 배경(#9AD342)과 체크마크(#FBFFF3) 구성이 디자인 요구사항에 부합합니다.

app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt (1)

152-186: LGTM! Preview 구현이 잘 되어 있습니다.

Basic과 Selectable 두 가지 디스플레이 모드에 대한 프리뷰가 각각 제공되어 있고, mutableStateOf를 활용한 인터랙티브 프리뷰로 선택 상태 전환을 테스트할 수 있습니다. CherrishTheme으로 감싸서 테마가 올바르게 적용됩니다.

Comment on lines +113 to +121
Icon(
imageVector = ImageVector.vectorResource(id = checkIconResId),
contentDescription = null,
tint = Color.Unspecified
)
}
}

Spacer(modifier = Modifier.size(2.dp))
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

접근성 및 Spacer 사용 개선이 필요합니다.

  1. 접근성: contentDescription = null은 스크린 리더 사용자에게 정보를 제공하지 않습니다. 선택 상태를 나타내는 아이콘이므로 적절한 설명이 필요합니다.
  2. Spacer: Modifier.size(2.dp)는 정사각형 영역을 생성합니다. 수직 간격에는 Modifier.height()가 더 적절합니다.
🔧 수정 제안
         Icon(
             imageVector = ImageVector.vectorResource(id = checkIconResId),
-            contentDescription = null,
+            contentDescription = if (isSelected) "선택됨" else "선택 안됨",
             tint = Color.Unspecified
         )
     }
 }

-Spacer(modifier = Modifier.size(2.dp))
+Spacer(modifier = Modifier.height(2.dp))
🤖 Prompt for AI Agents
In
@app/src/main/java/com/cherrish/android/presentation/calendar/procedure/component/ProcedureCard.kt
around lines 113 - 121, The Icon currently sets contentDescription = null and
the Spacer uses Modifier.size(2.dp); change the Icon to provide an accessible
description (e.g., use a localized string via stringResource or a passed-in
label that reflects selection state — reference the Icon call and
checkIconResId) instead of null so screen readers announce the icon (e.g.,
"selected" or "completed"), and replace Spacer(modifier = Modifier.size(2.dp))
with Spacer(modifier = Modifier.height(2.dp)) to create a vertical gap rather
than a square area.

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.

image

컴포넌트 끗 ~~ 머지하쟈잉 LGTM 🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀

@usuuhyn usuuhyn merged commit 55d8c29 into develop Jan 13, 2026
3 checks passed
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] 시술 카드 컴포넌트 구현

4 participants