Skip to content

[FEAT/#26] 캘린더 뷰 조립#27

Merged
nhyeonii merged 13 commits intodevelopfrom
feat/#26-calendar-view
Jan 14, 2026
Merged

[FEAT/#26] 캘린더 뷰 조립#27
nhyeonii merged 13 commits intodevelopfrom
feat/#26-calendar-view

Conversation

@nhyeonii
Copy link
Copy Markdown
Contributor

@nhyeonii nhyeonii commented Jan 10, 2026

Related issue 🛠

Work Description ✏️

  • 캘린더 뷰를 조립했어요

Screenshot 📸

Figma Calendar View
image image

Uncompleted Tasks 😅

  • EmptyCardView

To Reviewers 📢

뷰 조립 끝냈습니다! 엠티뷰 나오면 추가해두고, 서버 연결 작업 시작하면 될 것 같아요. #16 브랜치 풀 받아와서 작업했어요. 브랜치 머지 되면 드래프트 풀게요!

Summary by CodeRabbit

  • 새로운 기능
    • 달력 화면이 데이터 기반으로 재구성되어 월 변경, 날짜 선택, 이벤트 클릭 및 추가 버튼(플레이스홀더)을 통한 상호작용 지원
    • 일정 카드에 이벤트 수 표시 및 일정이 없을 때를 위한 빈 상태(추가 버튼) UI 추가
    • 정상/다운타임/일정 없음 등 다양한 UI 상태를 확인할 수 있는 미리보기 추가
  • 추가
    • 달력용 UI 상태 모델과 이를 노출하는 뷰모델이 도입되어 화면 상태 관리를 명확히 함

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

@nhyeonii nhyeonii self-assigned this Jan 10, 2026
@nhyeonii nhyeonii added FEAT✨ 새로운 기능 구현 나현🍒 나현 담당 labels Jan 10, 2026
@nhyeonii nhyeonii requested a review from a team as a code owner January 10, 2026 08:58
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 10, 2026

Walkthrough

Hilt로 주입된 ViewModel과 새로운 CalendarUiState를 추가하고, CalendarRoute/CalendarScreen을 uiState 기반으로 변경했습니다. 캘린더 표시 및 일정 카드(ProcedureScheduleCard)에 빈 상태와 이벤트 카운트 노출이 추가되었습니다.

Changes

Cohort / File(s) 변경 요약
ViewModel & UiState
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt, app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt
Hilt 주입 CalendarViewModel 추가 및 uiState: StateFlow<UiState<CalendarUiState>> 공개. onMonthChanged, onDateClick, onEventClick 메서드(스텁) 추가. CalendarUiState 데이터 클래스와 FakeNormal/FakeDowntime/FakeEmpty 프리셋 추가.
화면 통합 및 컴포저블 변경
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt
CalendarRoute에서 ViewModel 주입·구독 구현. CalendarScreen 시그니처 확장( uiState, onMonthChange, onDateClick, onEventClick, onAddButtonClick ) 및 레이아웃을 Column 기반으로 교체. 프리뷰 3종 추가.
모드 기본값 변경
app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarDisplayMode.kt
Normal.procedureCountByDate, Downtime.downtimeByDatepersistentMapOf() 기본값 추가.
스케줄 카드 빈 상태·헤더 개선
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt
빈 상태 처리(EmptyCardView) 추가 및 빈 경우 다른 패딩/레이아웃 적용. ScheduleHeadereventCount: Int 추가, ScheduleTitle 도입으로 이벤트 수 노출. 기존 항목 렌더링 로직 유지.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CalendarRoute
    participant CalendarViewModel
    participant CalendarScreen
    participant CherrishCalendar
    participant ProcedureScheduleCard

    User->>CalendarRoute: 화면 진입
    CalendarRoute->>CalendarViewModel: ViewModel 주입/구독
    CalendarViewModel-->>CalendarRoute: uiState(StateFlow) 제공
    CalendarRoute->>CalendarScreen: uiState 전달
    CalendarScreen->>CherrishCalendar: selectedYearMonth/selectedDate 전달
    CalendarScreen->>ProcedureScheduleCard: procedureInfoList 전달
    User->>CherrishCalendar: 월 변경 / 날짜 선택
    CherrishCalendar->>CalendarScreen: onMonthChange / onDateClick 콜백
    CalendarScreen->>CalendarViewModel: onMonthChanged / onDateClick 호출
    CalendarViewModel-->>CalendarRoute: uiState 갱신
    CalendarRoute->>CalendarScreen: 새로운 uiState로 재렌더링
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • hyeminililo
  • sohee6989
  • usuuhyn
🚥 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/#26] 캘린더 뷰 조립'으로 변경 사항의 주요 내용을 명확하게 반영하고 있습니다.
Description check ✅ Passed PR 설명은 템플릿의 주요 섹션(Related issue, Work Description, Screenshot, Uncompleted Tasks, To Reviewers)을 모두 포함하고 있습니다.
Linked Issues check ✅ Passed PR의 코드 변경사항이 #26 이슈의 목표인 '캘린더 뷰 조립'을 충족합니다: CalendarScreen UI 구성, CalendarUiState 데이터 클래스 추가, CalendarViewModel 구현, ProcedureScheduleCard 컴포넌트 개선.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #26 이슈의 캘린더 뷰 조립 목표와 관련되어 있으며, 범위를 벗어난 변경사항은 없습니다.

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

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent 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 7418614 and e1f014b.

📒 Files selected for processing (1)
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.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

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

@nhyeonii nhyeonii marked this pull request as draft January 10, 2026 08:59
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: 6

🤖 Fix all issues with AI agents
In
@app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt:
- Around line 54-88: The CalendarScreen currently always renders
ProcedureScheduleCard even when uiState.procedureInfoList is empty; add a simple
branch around the ProcedureScheduleCard render: check
uiState.procedureInfoList.isEmpty() and render the intended EmptyCardView (or a
placeholder container) when empty, otherwise render ProcedureScheduleCard with
the same props (displayMode, onClick, modifier) so layout and padding remain
unchanged.
- Around line 24-52: 현재 CalendarRoute의 when에서 UiState.Loading과 UiState.Failure가
빈 블록으로 남아 있어 사용자에게 빈 화면으로 보이고 있고, 마지막의 else -> {}는 sealed UiState의 누락을 감지하지 못하게
합니다. 수정 방법: CalendarRoute에서 UiState.Loading 분기에 최소한의 로딩 UI(예: 가운데 정렬된 로딩 인디케이터)
렌더링하고 UiState.Failure 분기에는 간단한 에러 메시지와 재시도 버튼(또는 viewModel에 retry/onRetry 같은
메서드가 없으면 ViewModel에 retry 메서드 추가)을 연결하여 사용자가 재시도할 수 있게 하며, 마지막 else 분기는 제거해
when을 UiState의 모든 케이스에 대해 명시적으로 처리하도록 만드세요(참조: CalendarRoute, UiState.Loading,
UiState.Failure, CalendarScreen, viewModel::onMonthChanged 등).

In
@app/src/main/java/com/cherrish/android/presentation/calendar/component/AddProcedureButton.kt:
- Around line 30-36: The default parameter uses remember {
MutableInteractionSource() } which is evaluated at declaration time and causes
all AddProcedureButton instances to share the same interaction source; change
the signature so the default is not created at declaration (e.g., make
interactionSource nullable or remove the default) and create/remember a per-call
instance inside the Composable: keep the parameter named interactionSource
(MutableInteractionSource) but set its default to null or remove the remember
call, then inside AddProcedureButton do val interactionSource =
passedInteractionSource ?: remember { MutableInteractionSource() } so each
composable instance gets its own remembered MutableInteractionSource.

In
@app/src/main/java/com/cherrish/android/presentation/calendar/component/CalendarMonthHeader.kt:
- Around line 53-58: The right-arrow Icon currently has contentDescription =
null which breaks accessibility; update the Icon (the instance using
ImageVector.vectorResource(id = R.drawable.ic_calendar_right) and
Modifier.noRippleClickable(onClick = onRightArrowClick)) to provide a meaningful
contentDescription (e.g., use stringResource for a localized label like "Next
month" or a passed-in parameter) so screen readers can announce the action.
- Around line 37-42: The clickable Icon in CalendarMonthHeader currently sets
contentDescription = null, which breaks screen reader accessibility; update the
Icon (the one using ImageVector.vectorResource and modifier =
Modifier.noRippleClickable(onClick = onLeftArrowClick)) to provide a localized
content description via stringResource (e.g., use
stringResource(R.string.cd_previous_month) or similar) so the action reads as
"Previous month" to assistive tech; apply the same fix for the right-arrow Icon
counterpart (onRightArrowClick) and add the new string resource entries for
localization.

In
@app/src/main/java/com/cherrish/android/presentation/calendar/component/DownTimeStatusIndicator.kt:
- Around line 38-68: In DownTimeStatusItem, the Box representing the dot uses
size(12.dp) followed by .padding(vertical = 3.dp) which inflates the actual
rendered dot beyond 12dp and is unnecessary since the Box has no content; remove
the trailing .padding(vertical = 3.dp) from the Box modifier (or, if spacing is
required, move any padding to the Row or adjust size accordingly) so the dot
remains the intended 12.dp circle (refer to the Box modifier chain in
DownTimeStatusItem).
🧹 Nitpick comments (18)
app/src/main/java/com/cherrish/android/presentation/calendar/component/AddProcedureButton.kt (2)

55-70: 중첩된 Row 구조 고려

CherrishBasicButton이 이미 fillMaxWidth()와 중앙 정렬이 적용된 Row를 포함하고 있으며, 여기서 또 다른 Row를 생성하고 있습니다. 현재 구현이 작동하기는 하지만, 약간의 중복이 있습니다. 필요에 따라 content를 직접 전달하는 것을 고려해볼 수 있습니다.


66-66: 하드코딩된 텍스트 문자열

"시술 일정 추가하기" 텍스트가 하드코딩되어 있습니다. 앱이 다국어를 지원할 계획이라면 string 리소스로 추출하는 것을 권장합니다.

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

1-11: 아이콘 스타일 간 strokeWidth 불일치 확인 필요합니다.

이 파일의 strokeWidth="0.2"가 같은 PR에서 추가된 다른 캘린더 네비게이션 아이콘(ic_calendar_left.xml, ic_calendar_right.xml)의 strokeWidth="0.4"와 다릅니다. 의도된 시각적 차이인지, 아니면 일관성을 맞춰야 하는지 확인이 필요합니다.

또한 색상 값이 하드코딩되어 있으므로, 추후 디자인 시스템 변경이나 다크 모드 지원 시 수정이 어려울 수 있습니다.

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

1-14: 색상 값이 하드코딩되어 있습니다.

기술적으로는 올바르지만, fillColorstrokeColor 값이 하드코딩되어 있습니다(#1B1D1F). 추후 디자인 시스템 변경이나 다크 모드 지원이 필요한 경우 유지보수가 어려울 수 있습니다.

만약 프로젝트에서 색상 리소스 정의 체계가 있다면, 하드코딩된 색상 대신 리소스 참조 사용을 고려해보세요.

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

1-14: 좌측 네비게이션 아이콘 구현이 올바릅니다.

ic_calendar_right.xml과 적절히 대칭되어 있으며, 스타일이 일관되게 적용되었습니다. 우측 아이콘과 동일하게, 색상 값 하드코딩에 대한 제안은 동일하게 적용됩니다.

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

6-10: Compose 안정성을 위해 ImmutableList 사용 권장

@Immutable 어노테이션이 있지만, List는 Kotlin에서 기본적으로 가변(mutable)으로 간주됩니다. Compose의 스마트 recomposition 최적화를 위해 kotlinx.collections.immutableImmutableList를 사용하는 것이 좋습니다.

♻️ ImmutableList 적용 제안
 package com.cherrish.android.presentation.calendar.model
 
 import androidx.compose.runtime.Immutable
 import java.time.YearMonth
+import kotlinx.collections.immutable.ImmutableList
 
 @Immutable
 data class CalendarMonth(
     val yearMonth: YearMonth,
-    val weekDays: List<List<CalendarDay>>
+    val weekDays: ImmutableList<ImmutableList<CalendarDay>>
 )

As per coding guidelines, 불필요한 recomposition 가능성과 remember/derivedStateOf 적절한 사용을 확인해야 합니다.

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

5-11: 타입 안전성 및 명확성 개선 고려

현재 구현은 동작하지만, 다음 사항을 고려해 보세요:

  • procedureDay: StringLocalDate 타입을 사용하면 날짜 파싱 오류를 방지하고 일관성을 높일 수 있습니다.
  • downTimeDuration → 단위가 명확하지 않습니다. downTimeDurationDays 등으로 명명하거나 KDoc을 추가하면 좋겠습니다.
app/src/main/java/com/cherrish/android/presentation/calendar/util/DownTimeColors.kt (2)

7-10: DownTimeColors@Immutable 부여 고려
Compose에서 색상 묶음 타입이 자주 재사용/전달되니, 모델들과 동일하게 @Immutable로 안정성 힌트를 맞추는 편이 좋습니다.

제안 diff
+import androidx.compose.runtime.Immutable
 import androidx.compose.ui.graphics.Color
 import com.cherrish.android.core.designsystem.theme.CherrishColors
 import com.cherrish.android.presentation.calendar.model.DownTimeStatus

+@Immutable
 data class DownTimeColors(
     val background: Color,
     val border: Color
 )

12-34: 네이밍 일관성(DownTime vs Downtime)만 정리하면 더 깔끔
DownTimeStatus와 함께 쓰이는데 함수명이 getDowntimeColors라서 팀 컨벤션에 따라 getDownTimeColors/toDownTimeColors 등으로 맞추면 추후 탐색성이 좋아집니다. 매핑 자체는 명확합니다.

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

12-27: CalendarDay.Date 타입명은 더 구체적으로 바꾸는 것 고려
Date는 의미가 넓어서, WithDate/Dated/CalendarDateCell 같이 도메인에 맞게 좁히면 호출부 가독성이 좋아집니다. 또한 procedureCount는 음수 방지를 원하면 생성 시 require(procedureCount >= 0)도 선택지입니다.

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

67-92: IntrinsicSize.Max는 리스트 렌더링에서 비용이 커질 수 있음
Modifier.height(IntrinsicSize.Max)는 측정 패스가 늘어날 수 있어서, 아이템이 많이 쌓이는 화면이면 피하는 편이 안전합니다(디바이더 높이를 고정하거나, 레이아웃을 재구성하는 방식 고려).


94-116: 문자열 하드코딩("다운타임 ${it}일", "-")은 stringResource로 분리 권장
UI 조립 PR이라도, 나중에 서버 연동/다국어 대응 들어가면 여기부터 갈아엎기 쉬워서 지금 분리해두는 게 편합니다.

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

27-65: 리스트 렌더링에 key(procedureId) 추가 권장 (재구성 안정성)
procedureInfo.forEach로 그릴 때 항목 추가/삭제/정렬 변경이 생기면 상태가 섞일 수 있어서, 최소한 key(procedure.procedureId)로 identity를 고정하는 게 안전합니다.

제안 diff
+import androidx.compose.runtime.key
@@
         Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
             procedureInfo.forEach { procedure ->
-                ProcedureInfoItem(
-                    procedureName = procedure.procedureName,
-                    procedureDay = procedure.procedureDay,
-                    downTimeDuration = procedure.downTimeDuration,
-                    procedureType = getProcedureType(displayMode, procedure.procedureId),
-                    onClick = { onClick(procedure.procedureId) }
-                )
+                key(procedure.procedureId) {
+                    ProcedureInfoItem(
+                        procedureName = procedure.procedureName,
+                        procedureDay = procedure.procedureDay,
+                        downTimeDuration = procedure.downTimeDuration,
+                        procedureType = getProcedureType(displayMode, procedure.procedureId),
+                        onClick = { onClick(procedure.procedureId) }
+                    )
+                }
             }
         }

67-88: 헤더 텍스트/분기 처리 소폭 정리 여지
Line 78의 "일정"stringResource로 빼는 게 좋고, CalendarDisplayMode.Normal -> { }-> Unit 등으로 정리하면 의도가 더 분명해집니다.

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

46-46: 테마 색상 사용 권장

하드코딩된 Color.Black 대신 CherrishTheme.colors.gray1000 또는 적절한 테마 색상을 사용하면 다크모드 대응 및 디자인 시스템 일관성이 향상됩니다.

♻️ 테마 색상 적용 제안
                 Text(
                     text = dayOfWeek.getDisplayName(
                         TextStyle.SHORT,
                         Locale.getDefault()
                     ),
                     textAlign = TextAlign.Center,
-                    color = Color.Black
+                    color = CherrishTheme.colors.gray1000
                 )
app/src/main/java/com/cherrish/android/presentation/calendar/component/DayItem.kt (1)

40-42: 중복 타입 체크 제거 가능

enabled 파라미터에서 이미 day is CalendarDay.Date를 체크하므로, onClick 람다 내부의 조건문은 불필요합니다. 스마트 캐스트가 적용되어야 합니다.

♻️ 중복 제거 제안
             .noRippleClickable(
                 enabled = day is CalendarDay.Date,
-                onClick = { if (day is CalendarDay.Date) onDateClick(day.date) }
+                onClick = { onDateClick((day as CalendarDay.Date).date) }
             ),

참고: enabled = true일 때만 onClick이 호출되므로 타입 안정성이 보장됩니다.

app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt (1)

14-16: 기본값으로 now() 사용 시 주의 필요.

YearMonth.now()LocalDate.now()를 기본값으로 사용하면 객체 생성 시점의 시간이 고정되므로, ViewModel이나 StateFlow에서 재사용될 때 의도치 않은 날짜가 사용될 수 있습니다.

프로덕션 코드에서는 ViewModel 초기화 시 명시적으로 현재 날짜를 전달하거나, 기본값을 null로 두고 초기화 로직에서 설정하는 것이 더 명확합니다.

♻️ 제안하는 개선 방안
 data class CalendarUiState(
-    val selectedYearMonth: YearMonth = YearMonth.now(),
+    val selectedYearMonth: YearMonth,
     val calendarDisplayMode: CalendarDisplayMode = CalendarDisplayMode.Normal(),
-    val selectedDate: LocalDate? = LocalDate.now(),
+    val selectedDate: LocalDate? = null,
     val procedureInfoList: ImmutableList<ProcedureInfoModel> = persistentListOf(),
 )

ViewModel에서 초기화:

private val _uiState = MutableStateFlow<UiState<CalendarUiState>>(
    UiState.Success(
        CalendarUiState(
            selectedYearMonth = YearMonth.now(),
            selectedDate = LocalDate.now()
        )
    )
)
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt (1)

33-39: 이벤트 핸들러 구현이 필요합니다.

onDateClickonEventClick 함수가 빈 구현으로 남아 있습니다. UI 조립 단계에서는 문제없으나, 서버 연동 및 상태 업데이트 로직 구현이 필요합니다.

예상되는 구현:

  • onDateClick: selectedDate 업데이트 및 해당 날짜의 프로시저 목록 로드
  • onEventClick: 프로시저 상세 화면으로 네비게이션 또는 다운타임 모드 전환

구현 코드 생성이 필요하시면 도움을 드릴 수 있습니다. 이슈를 생성하시겠습니까?

📜 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 ad96acb and 08d0d4f.

📒 Files selected for processing (27)
  • app/src/main/java/com/cherrish/android/core/designsystem/theme/Color.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/AddProcedureButton.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/BasicCalendar.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/CalendarMonthHeader.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/CherrishCalendar.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/DayItem.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/DaysOfWeekTitle.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/DownTimeStatusIndicator.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarDay.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarDisplayMode.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarMonth.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/DownTimeStatus.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/ProcedureInfoModel.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/ProcedureType.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/DateExtensions.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/DownTimeColors.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/MonthData.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt
  • app/src/main/res/drawable/ic_calendar_left.xml
  • app/src/main/res/drawable/ic_calendar_right.xml
  • app/src/main/res/drawable/ic_plus.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/model/ProcedureType.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/CalendarMonthHeader.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarDay.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/DownTimeStatusIndicator.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/DownTimeColors.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/MonthData.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/DownTimeStatus.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/DayItem.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/DateExtensions.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/AddProcedureButton.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarDisplayMode.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/BasicCalendar.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/CherrishCalendar.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/ProcedureInfoModel.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/component/DaysOfWeekTitle.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarMonth.kt
  • app/src/main/java/com/cherrish/android/core/designsystem/theme/Color.kt
🧬 Code graph analysis (12)
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.kt (2)
app/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt (1)
  • getProcedureColors (15-33)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
app/src/main/java/com/cherrish/android/presentation/calendar/component/CalendarMonthHeader.kt (1)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
app/src/main/java/com/cherrish/android/presentation/calendar/component/DownTimeStatusIndicator.kt (2)
app/src/main/java/com/cherrish/android/presentation/calendar/util/DownTimeColors.kt (1)
  • getDowntimeColors (12-34)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt (3)
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.kt (1)
  • ProcedureInfoItem (28-65)
app/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt (1)
  • getProcedureType (35-47)
app/src/main/java/com/cherrish/android/presentation/calendar/component/DownTimeStatusIndicator.kt (1)
  • DownTimeStatusIndicator (22-36)
app/src/main/java/com/cherrish/android/presentation/calendar/util/DownTimeColors.kt (1)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • colors (12-23)
app/src/main/java/com/cherrish/android/presentation/calendar/component/DayItem.kt (2)
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt (1)
  • onDateClick (33-35)
app/src/main/java/com/cherrish/android/presentation/calendar/util/DownTimeColors.kt (1)
  • getDowntimeColors (12-34)
app/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt (1)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • colors (12-23)
app/src/main/java/com/cherrish/android/presentation/calendar/component/AddProcedureButton.kt (2)
app/src/main/java/com/cherrish/android/core/designsystem/component/button/CherrishBasicButton.kt (1)
  • CherrishBasicButton (19-42)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
app/src/main/java/com/cherrish/android/presentation/calendar/component/BasicCalendar.kt (3)
app/src/main/java/com/cherrish/android/presentation/calendar/util/MonthData.kt (1)
  • generateMonthData (53-61)
app/src/main/java/com/cherrish/android/presentation/calendar/util/DateExtensions.kt (1)
  • daysOfWeek (9-13)
app/src/main/java/com/cherrish/android/presentation/calendar/component/DaysOfWeekTitle.kt (1)
  • DaysOfWeekTitle (24-51)
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt (3)
app/src/main/java/com/cherrish/android/presentation/calendar/component/CherrishCalendar.kt (1)
  • CherrishCalendar (23-53)
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt (1)
  • ProcedureScheduleCard (27-65)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
app/src/main/java/com/cherrish/android/presentation/calendar/component/CherrishCalendar.kt (4)
app/src/main/java/com/cherrish/android/presentation/calendar/component/CalendarMonthHeader.kt (1)
  • CalendarMonthHeader (24-60)
app/src/main/java/com/cherrish/android/presentation/calendar/component/BasicCalendar.kt (1)
  • BasicCalendar (24-58)
app/src/main/java/com/cherrish/android/presentation/calendar/component/DayItem.kt (1)
  • DayItem (30-59)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
app/src/main/java/com/cherrish/android/presentation/calendar/component/DaysOfWeekTitle.kt (2)
app/src/main/java/com/cherrish/android/core/designsystem/theme/Theme.kt (1)
  • CherrishTheme (38-61)
app/src/main/java/com/cherrish/android/presentation/calendar/util/DateExtensions.kt (1)
  • daysOfWeek (9-13)
⏰ 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 (38)
app/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.kt (1)

1-5: LGTM!

DayOfWeek 간의 날짜 차이를 계산하는 간결하고 정확한 확장 함수입니다. 모듈로 연산을 통해 주(week) 경계를 올바르게 처리합니다.

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

44-51: LGTM!

YearMonth 포맷팅과 테마 스타일 적용이 적절합니다.

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

1-10: LGTM!

다운타임 상태를 명확하게 정의한 enum입니다. 각 상태별 한국어 레이블이 적절하게 지정되어 있습니다.

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

1-6: LGTM!

시술 타입을 구분하는 간결한 enum 정의입니다.

app/src/main/java/com/cherrish/android/core/designsystem/theme/Color.kt (3)

38-39: LGTM!

shadow 색상이 기존 색상 패턴과 일관되게 추가되었습니다. 투명도 적용 방식도 적절합니다.


66-69: LGTM!

CherrishColors 데이터 클래스에 shadow 속성이 올바르게 추가되었습니다.


214-218: LGTM!

프리뷰에 Shadow 색상이 적절히 추가되어 디자인 시스템 확인이 용이합니다.

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

6-27: 모델 구조(Empty/Normal/Downtime) 깔끔하고 Compose 친화적
@Immutable 적용 + Empty로 달력 그리드 채우기 패턴이 명확합니다.

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

118-142: 프리뷰 구성 좋습니다
ACTIVE/INACTIVE 케이스를 동시에 보여줘서 디자인 확인에 도움이 됩니다.


28-65: noRippleClickable는 semantics를 올바르게 제공합니다

noRippleClickable은 내부적으로 androidx.compose.foundation.clickable()을 사용하며, indication = null은 시각적 ripple 효과만 제거합니다. Jetpack Compose의 clickable() 모디파이어는 indication 파라미터와 무관하게 자동으로 Role.Button, onClick 시멘틱 액션, enabled 상태 등의 접근성 정보를 제공합니다. 따라서 현재 구현은 접근성 요구사항을 충족합니다.

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

22-36: Indicator 구성 단순/명확해서 재사용하기 좋습니다
상태를 고정 3종으로 보여주는 요구사항에 맞게 구현이 깔끔합니다.


70-76: 프리뷰 OK

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

90-167: 프리뷰가 Normal/Downtime 둘 다 제공돼서 QA에 유용

app/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt (3)

8-13: LGTM! 깔끔한 색상 데이터 캡슐화

불변 데이터 클래스로 프로시저 관련 색상을 그룹화한 설계가 적절합니다.


15-33: LGTM! 명확한 색상 매핑 로직

순수 함수로 구현되어 테스트가 용이하고, when 표현식으로 모든 케이스를 명시적으로 처리합니다.


35-47: LGTM! 표시 모드에 따른 프로시저 타입 결정 로직

CalendarDisplayMode에 따라 적절하게 프로시저 활성/비활성 상태를 결정하는 로직이 명확합니다.

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

24-51: ImmutableList 사용으로 안정성 확보가 잘 되어 있습니다

파라미터로 ImmutableList를 사용하여 Compose의 스마트 리컴포지션을 활용한 점이 좋습니다.


53-60: LGTM! 적절한 프리뷰 구성

CherrishTheme으로 감싸고 실제 사용 케이스를 반영한 프리뷰입니다.

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

61-95: LGTM! 조건부 Modifier 처리가 적절합니다

.then()을 활용한 조건부 보더 처리와 procedureCount > 0 조건부 렌더링이 효율적으로 구현되었습니다.


97-116: LGTM! 리컴포지션 최적화가 잘 되어 있습니다

remember에 적절한 키(day.status, cherrishColors)를 지정하여 불필요한 색상 재계산을 방지한 점이 훌륭합니다.


127-149: LGTM! 방어적 프로그래밍

min(count, 3)으로 최대 표시 개수를 제한하여 UI 오버플로우를 방지한 점이 좋습니다.


151-184: LGTM! 다양한 상태를 보여주는 포괄적인 프리뷰

Normal, 선택 상태, 다운타임 등 여러 상태를 시각화하여 디자인 검증에 유용합니다.

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

6-15: LGTM! 깔끔한 sealed interface 설계

persistentMapOf()를 기본값으로 사용하여 불변성을 보장하고, sealed interface로 타입 안전성을 확보한 설계가 훌륭합니다. 단방향 데이터 흐름 패턴에 적합한 구조입니다.

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

24-58: LGTM! 리컴포지션 최적화가 탁월합니다

remember에 모든 관련 키(yearMonth, displayMode, firstDayOfWeek)를 지정하여 불필요한 재계산을 방지한 점이 훌륭합니다. Jetpack Compose 베스트 프랙티스를 잘 따르고 있습니다.


60-87: LGTM! 명확한 그리드 레이아웃 구조

중첩 루프와 weight/aspectRatio를 활용한 균등한 그리드 레이아웃이 적절하며, dayContent 슬롯 패턴으로 유연성을 확보했습니다.

app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt (1)

19-77: 프리뷰용 Fake 데이터가 잘 구성되어 있습니다.

companion object의 Fake 프리셋들이 Normal, Downtime, Empty 상태를 모두 커버하고 있어 프리뷰 및 테스트에 유용합니다. 하드코딩된 날짜(2026, 1, 7)는 테스트 일관성을 보장하는 좋은 선택입니다.

app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt (2)

18-21: 초기 상태가 Fake 데이터로 설정되어 있습니다.

현재 UiState.Success(CalendarUiState.FakeNormal)로 초기화되어 있어 프로덕션 환경에서 테스트 데이터가 표시됩니다. PR 목표가 UI 조립이고 서버 연동이 다음 단계임을 고려할 때, 현재 단계에서는 허용 가능하지만 서버 연동 시 반드시 수정이 필요합니다.

서버 연동 작업 시 다음과 같이 변경하는 것을 권장합니다:

  • 초기 상태를 UiState.Loading 또는 빈 상태로 설정
  • init 블록 또는 별도 함수에서 실제 데이터 로드
  • Repository/UseCase를 통한 데이터 페칭

23-31: 월 변경 로직이 적절하게 구현되었습니다.

updateSuccess 확장 함수를 사용해 안전하게 상태를 업데이트하고 있으며, 월 변경 시 selectedDate를 초기화하고 procedureInfoList를 비우는 것은 합리적인 UX 설계입니다. 단방향 데이터 흐름도 잘 준수하고 있습니다.

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

23-53: Compose 구조와 상태 관리가 잘 설계되었습니다.

컴포넌트 구조가 명확하며, 파라미터 순서(data → callbacks → modifier)가 Compose 권장 사항을 따릅니다. DayItemisSelected 계산이 dayContent 람다 내부에서 이루어지지만 단순 비교 연산이므로 성능 영향이 미미합니다.

단방향 데이터 흐름도 잘 준수하고 있습니다:

  • 상태는 상위에서 전달 (yearMonth, selectedDate, displayMode)
  • 이벤트는 콜백으로 위임 (onDateClick, onMonthChange)

55-103: 프리뷰가 다양한 시나리오를 잘 커버하고 있습니다.

두 개의 프리뷰가 Normal 모드와 Downtime 모드를 각각 시연하고 있어 UI 개발 및 테스트에 유용합니다. remembermutableStateOf를 사용한 상태 관리가 프리뷰 환경에 적합하게 구현되었습니다.

app/src/main/java/com/cherrish/android/presentation/calendar/util/MonthData.kt (3)

10-27: 데이터 클래스 구조가 효율적으로 설계되었습니다.

calendarMonth 프로퍼티가 val로 선언되어 객체 생성 시 한 번만 계산되므로 불필요한 재계산이 방지됩니다. chunked(7)과 중첩 map을 사용한 주 단위 그리드 생성 로직이 명확하고, 불변성을 유지하여 Compose recomposition 최적화에 유리합니다.


29-50: 날짜 매핑 로직이 정확하게 구현되었습니다.

getDay 함수가 경계 조건(빈 셀)을 올바르게 처리하고, when 표현식으로 두 가지 표시 모드를 명확하게 분기합니다. Downtime 모드에서 DownTimeStatus.NONE일 때 Normal 타입으로 폴백하는 로직이 합리적이며, Elvis 연산자로 null 안전성도 확보되었습니다.


53-61: daysUntil 확장 함수가 올바르게 구현되어 있습니다.

CalendarCalculator.kt에 정의된 fun DayOfWeek.daysUntil(other: DayOfWeek) = (other.value - value + 7) % 7 확장 함수는 한 요일에서 다른 요일까지의 일수를 정확하게 계산합니다. generateMonthData 함수는 이 확장 함수를 올바르게 활용하며, 함수 자체도 간결하고 명확합니다.

app/src/main/java/com/cherrish/android/presentation/calendar/util/DateExtensions.kt (3)

9-13: 요일 순환 로직이 정확하게 구현되었습니다.

pivot 계산과 takeLast/dropLast 조합을 사용한 요일 순환 로직이 모든 경우에 올바르게 동작합니다. 로케일에 따른 첫 요일을 기준으로 요일 배열을 회전시키는 로직이 명확하고 효율적입니다.


15-16: 로케일 기반 첫 요일 처리가 적절합니다.

WeekFields를 사용한 표준적인 접근 방식으로 다양한 로케일의 첫 요일 규칙을 올바르게 처리합니다.


18-27: 유틸리티 확장 함수들이 잘 정의되었습니다.

YearMonthLocalDate에 대한 확장 프로퍼티/함수들이 명확하고 재사용 가능하게 구현되었습니다. 코드 가독성이 향상되고, Java Time API를 관용적으로 사용하고 있습니다.

app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt (2)

3-23: import 변경은 자연스럽고, 화면 구성에 필요한 의존성만 추가되어 있어요.
현 파일 관점에서 불필요한 의존성은 없어 보입니다.


90-130: 프리뷰 케이스를 Normal/Downtime/NoSchedule로 나눈 건 좋아요.
다만 NoSchedule은 실제로 “빈 상태 UI”가 생겼을 때 프리뷰에서도 그 컴포넌트가 보이도록 연결되는지까지 확인해 주세요(현재는 TODO 상태).

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.

수고하셨습니다 제가 궁금한 거 답변해주시길 바랄게요요요용

modifier = modifier
.fillMaxSize()
.background(color = CherrishTheme.colors.gray100)
.padding(paddingValues)
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.

P4: padding이 두 번 들어가있는 것 같은데 이유를 알 수 있을까욥??

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.

아하 ㅎㅎ 여기서의 paddingValues는 상위 MainScreen에서 받아오는 패딩값 (Scaffold 의 innerPadding)이 전달되는거고, 아래의 패딩값은 실제 화면에서 보이는 수직, 수평 패딩을 의미합니다!

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.

아아 이래서 그래야 하는거군요 !!!저도 리팩토링 요 방식으로 해보겠습니다 !!

@nhyeonii nhyeonii marked this pull request as ready for review January 12, 2026 16:58
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/CalendarScreen.kt (2)

31-49: Loading 및 Failure 상태에 대한 UI가 누락되었습니다.

현재 UiState.LoadingUiState.Failure 상태에서 아무것도 렌더링하지 않아 사용자 경험이 좋지 않습니다. 또한 else -> {} 분기는 UiState가 sealed class라면 불필요합니다.

♻️ 제안된 개선안
     when (val state = uiState) {
         is UiState.Loading -> {
+            // TODO: 로딩 인디케이터 추가
+            Box(
+                modifier = Modifier.fillMaxSize(),
+                contentAlignment = Alignment.Center
+            ) {
+                CircularProgressIndicator()
+            }
         }

         is UiState.Failure -> {
+            // TODO: 에러 UI 추가
+            Box(
+                modifier = Modifier.fillMaxSize(),
+                contentAlignment = Alignment.Center
+            ) {
+                Text(text = "오류가 발생했습니다")
+            }
         }

         is UiState.Success -> {
             CalendarScreen(
                 uiState = state.data,
                 paddingValues = paddingValues,
                 onMonthChange = viewModel::onMonthChanged,
                 onDateClick = viewModel::onDateClick,
                 onEventClick = viewModel::onEventClick,
                 onAddButtonClick = { /*TODO: 시술 선택 플로우로 이동*/ }
             )
         }
-
-        else -> {}
     }

45-45: TODO 주석이 남아있습니다.

시술 선택 플로우로의 네비게이션 구현이 필요합니다. 이 작업을 추적하기 위한 이슈를 생성하시겠습니까?

app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt (1)

19-95: Fake 데이터를 별도 파일로 분리하는 것을 고려해 보세요.

현재 구조도 동작하지만, mock 데이터가 상당히 많습니다. 프로덕션 코드와 테스트/프리뷰용 데이터를 분리하면 유지보수성이 향상됩니다.

♻️ 제안된 구조
// CalendarUiState.kt - 프로덕션 코드만 유지
@Immutable
data class CalendarUiState(
    val selectedYearMonth: YearMonth = YearMonth.now(),
    val calendarDisplayMode: CalendarDisplayMode = CalendarDisplayMode.Normal(),
    val selectedDate: LocalDate? = LocalDate.now(),
    val procedureInfoList: ImmutableList<ProcedureInfoModel> = persistentListOf()
)

// CalendarUiStatePreviewData.kt - 프리뷰/테스트 데이터
object CalendarUiStatePreviewData {
    private val today = LocalDate.of(2026, 1, 7)
    // ... mockProcedures, FakeNormal, FakeDowntime, FakeEmpty
}
📜 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 08d0d4f and 2f0a7d7.

📒 Files selected for processing (4)
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarDisplayMode.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/model/CalendarDisplayMode.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/CalendarScreen.kt
  • app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt (3)
app/src/main/java/com/cherrish/android/presentation/calendar/component/CherrishCalendar.kt (1)
  • CherrishCalendar (23-53)
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt (1)
  • ProcedureScheduleCard (43-157)
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). (1)
  • GitHub Check: PR Build Check
🔇 Additional comments (3)
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarScreen.kt (2)

53-89: LGTM!

CalendarScreen 컴포저블이 잘 구성되어 있습니다:

  • 상태 호이스팅 패턴을 올바르게 적용
  • modifier 파라미터를 마지막에 배치하여 Compose 컨벤션 준수
  • Arrangement.spacedBy를 사용하여 일관된 간격 유지
  • CherrishCalendarProcedureScheduleCard에 uiState 데이터를 적절히 전달

91-134: LGTM!

Preview 함수들이 잘 구성되어 있습니다. CherrishTheme으로 래핑하고 CalendarUiState의 Fake 프리셋들을 활용하여 Normal, Downtime, Empty 상태를 효과적으로 미리보기할 수 있습니다.

app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt (1)

12-18: LGTM!

데이터 클래스 구조가 적절합니다:

  • @Immutable 어노테이션으로 Compose 안정성 보장
  • ImmutableList 사용으로 불필요한 recomposition 방지
  • 적절한 기본값 제공

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/component/ProcedureScheduleCard.kt (3)

48-63: 빈 상태에서 불필요한 상태 초기화

procedureInfo가 비어 있을 때 listState, isFirstItemVisible, isLastItemVisible은 사용되지 않지만 항상 초기화됩니다. 빈 상태에서의 불필요한 할당을 피하기 위해 조건부로 초기화하거나 non-empty 블록 내부로 이동하는 것을 고려해 주세요.

♻️ 제안된 수정
 @Composable
 fun ProcedureScheduleCard(
     displayMode: CalendarDisplayMode,
     procedureInfo: ImmutableList<ProcedureInfoModel>,
     onProcedureClick: (Long) -> Unit,
     onAddProcedureClick: () -> Unit,
     modifier: Modifier = Modifier
 ) {
-    val listState = rememberLazyListState()
-
-    val isFirstItemVisible = remember {
-        derivedStateOf {
-            val firstVisibleItem = listState.layoutInfo.visibleItemsInfo.firstOrNull()
-            firstVisibleItem?.index == 0
-        }
-    }
-
-    val isLastItemVisible = remember {
-        derivedStateOf {
-            val lastVisibleItem = listState.layoutInfo.visibleItemsInfo.lastOrNull()
-            val lastItemIndex = procedureInfo.size - 1
-            lastVisibleItem?.index == lastItemIndex
-        }
-    }
+    val isEmpty = procedureInfo.isEmpty()

     Box(
         modifier = modifier
             // ... existing modifiers
     ) {
-        if (procedureInfo.isEmpty()) {
+        if (isEmpty) {
             EmptyCardView(/* ... */)
         } else {
+            val listState = rememberLazyListState()
+            val isFirstItemVisible = remember {
+                derivedStateOf {
+                    listState.layoutInfo.visibleItemsInfo.firstOrNull()?.index == 0
+                }
+            }
+            val isLastItemVisible = remember {
+                derivedStateOf {
+                    listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index == procedureInfo.size - 1
+                }
+            }
             // ... rest of non-empty content
         }
     }
 }

238-239: TODO 주석: 디자인 확정 후 수정 필요

엠티뷰 디자인이 확정되면 Spacer를 사용한 임시 레이아웃 대신 확정된 디자인으로 교체가 필요합니다. 디자인 확정 시 일러스트나 아이콘 추가 등의 작업이 예상됩니다.

디자인 확정 후 수정 작업을 추적하기 위해 새 이슈를 생성하는 것이 도움이 될까요?


241-245: 문자열 리소스 추출 고려

사용자에게 표시되는 텍스트 "오늘 예정된 일정이 없어요."strings.xml로 추출하면 향후 다국어 지원(i18n)에 유리합니다.

♻️ 제안된 수정

res/values/strings.xml에 추가:

<string name="calendar_empty_message">오늘 예정된 일정이 없어요.</string>

컴포저블에서 사용:

 Text(
-    text = "오늘 예정된 일정이 없어요.",
+    text = stringResource(R.string.calendar_empty_message),
     color = CherrishTheme.colors.gray600,
     style = CherrishTheme.typography.body1R14
 )
📜 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 b643530 and 7418614.

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

79-86: LGTM!

빈 상태 처리가 깔끔하게 구현되었습니다. 조건부 렌더링과 패딩 적용이 적절합니다.


199-227: LGTM!

ScheduleTitle 컴포저블이 깔끔하게 구현되었습니다. 테마 스타일을 적절히 활용하고 있습니다.


395-415: LGTM!

빈 상태에 대한 프리뷰가 추가되어 UI 확인이 용이해졌습니다. 기존 프리뷰 패턴과 일관성 있게 구현되었습니다.

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.

수고하셨습니다!!
넘 깔끔하네여~!!

)

Spacer(modifier = Modifier.height(6.dp))
Spacer(modifier = Modifier.height(6.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: 이거 Column에서
verticalArrangement = Arrangement.spacedBy(8.dp)
써도 되지 않나여?!

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.

수고하셨습니다!! ! ! ! ! 짱짱 굿 ~~😻😻

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.

수고하셨습니다아 ~~~!!

@nhyeonii nhyeonii merged commit 0de3412 into develop Jan 14, 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