Skip to content

PrezelDatePicker 구현#59

Open
HamBeomJoon wants to merge 6 commits intodevelopfrom
feat/#53-prezel-date-picker
Open

PrezelDatePicker 구현#59
HamBeomJoon wants to merge 6 commits intodevelopfrom
feat/#53-prezel-date-picker

Conversation

@HamBeomJoon
Copy link
Contributor

@HamBeomJoon HamBeomJoon commented Feb 20, 2026

📌 작업 내용

  • Prezel DatePicker 컴포넌트 구현

🧩 관련 이슈


📸 스크린샷

2026-02-20.13.36.28.mov

📢 논의하고 싶은 내용

Summary by CodeRabbit

  • 새 기능

    • 모달 형식의 전체 날짜 선택 UI 추가: 월별 캘린더, 다중 월 스크롤, 요일 행 및 월 헤더 포함.
    • 날짜 셀에 오늘/선택 상태 하이라이트, 활성/비활성 표시 및 셀 단위 선택 기능 제공.
    • 하단의 확인 버튼으로 선택 확정 및 상단 닫기 동작 지원.
  • 문서/문구

    • 닫기 설명, 확인 버튼 텍스트 및 요일 레이블(한글) 리소스 추가.

새로운 디자인 시스템 컴포넌트로 DatePicker를 추가했습니다.

*   `DatePickerScreen`: 날짜 선택을 위한 전체 스크린 UI 구현 (TopAppBar, 요일 표시, 월별 리스트)
*   `MonthSection`, `MonthGrid`: 월별 날짜 그리드 레이아웃 구현
*   `DayCellView`: 개별 날짜 셀의 디자인 및 상태(선택, 오늘, 일요일 등) 처리
*   날짜 계산 로직(`MonthGridBuilder`) 및 데이터 모델(`DatePickerModels`) 추가
디자인 시스템 내 날짜 선택을 위한 `PrezelDatePicker` 컴포넌트를 구현하고, 그리드 렌더링 로직 및 데이터 모델을 최적화했습니다.

* **feat: PrezelDatePicker 컴포넌트 추가**
    * `LazyColumn`을 활용하여 여러 달을 리스트 형태로 보여주는 데이트 피커 구현
    * 선택된 날짜 상태 관리(`selectedDate`) 및 '선택하기' 버튼 연동
    * 닫기 버튼에 대한 접근성 서비스용 문자열 리소스(`core_designsystem_close_date_picker_desc`) 추가

* **refactor: DatePicker 모델 및 유이 모델 변환 로직 개선**
    * `DayCellUiModel`에 `isInMonth` 프로퍼티 추가
    * `toUiModel` 확장 함수에서 해당 월에 속하지 않는 날짜(이전/다음 달)는 비활성화(`enabled = false`)되도록 수정

* **refactor: MonthGrid 성능 최적화**
    * `MonthGrid`에서 `buildMonthGrid`와 `lastWeekIndexToRender` 계산 로직을 하나의 `remember` 블록으로 결합하여 불필요한 재계산 방지

* **style: 변수명 및 리소스 참조 정리**
    * 내부 상태 변수명을 `picked`에서 `selectedDate`로 변경하여 가독성 개선
    * 하드코딩된 "닫기" 문자열을 리소스 ID 참조로 변경
`PrezelDatePicker` 컴포넌트의 내부 상태 관리 로직을 개선하여 상태를 외부에서 주입받도록 수정했습니다.

*   `selectedDate`를 관리하던 내부 `mutableStateOf`를 제거하고, `onSelect` 콜백을 통해 외부에서 상태를 직접 제어하도록 변경했습니다.
*   가독성 향상을 위해 함수 파라미터의 순서를 조정했습니다.
*   변경된 구조에 맞춰 Preview 코드를 수정했습니다.
@HamBeomJoon HamBeomJoon self-assigned this Feb 20, 2026
@HamBeomJoon HamBeomJoon added the ✨ feat 새로운 기능 추가 또는 기존 기능 확장 label Feb 20, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

Walkthrough

이번 변경으로 Prezel 디자인 시스템에 날짜 선택기 컴포넌트가 추가되었습니다. 공개 컴포저블 PrezelDatePicker와 내부 구성요소(MonthSection, MonthGrid, DayCellView, DatePickerHeader, DatePickerFooter, WeekdayRow)가 도입되었으며, 날짜 격자 생성 유틸(buildMonthGrid, lastWeekIndexToRender), 데이터 모델(DayCell, DayCellUiModel, toUiModel) 및 스타일 함수(dayTextColor)가 추가되었습니다. 관련 문자열 리소스도 새로 추가되었습니다.

🚥 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의 주요 변경사항을 명확하게 요약하고 있습니다. PrezelDatePicker 컴포넌트 구현이 이 PR의 핵심 목표입니다.
Description check ✅ Passed PR 설명이 저장소의 템플릿 구조를 따르고 있으며, 작업 내용, 관련 이슈, 스크린샷이 모두 포함되어 있습니다.
Linked Issues check ✅ Passed 코드 변경사항이 issue #53의 요구사항을 완벽하게 충족합니다. PrezelDatePicker 컴포넌트가 헤더, 요일 표시, 월별 그리드, 푸터로 구성되어 구현되었고, 테마가 적용된 재사용 가능한 UI가 제공됩니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 PrezelDatePicker 구현이라는 범위 내에 있습니다. 날짜 선택 기능에 필요한 모델, 유틸리티, UI 컴포넌트, 리소스만 추가되었습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt (1)

6-8: buildMonthGridinternal로 변경하는 것을 권장합니다.

이 함수는 날짜 선택기 내부 전용 구현 세부사항으로, 같은 패키지의 MonthGrid (internal)에서만 사용됩니다. 현재 public으로 노출되어 있어 모듈 API 표면을 불필요하게 넓힙니다.

♻️ 가시성 수정 제안
-fun buildMonthGrid(
+internal fun buildMonthGrid(
     month: YearMonth,
     firstDayOfWeek: DayOfWeek,
 ): List<DayCell> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt`
around lines 6 - 8, 함수 buildMonthGrid가 퍼블릭으로 노출되어 있어 모듈 API를 불필요하게 넓히고 있으므로 해당
함수의 가시성을 internal로 변경하세요; 즉 MonthGrid와 같은 패키지 내부에서만 사용되도록 buildMonthGrid 선언(함수
이름: buildMonthGrid, 관련 타입: YearMonth, DayOfWeek)을 public에서 internal로 바꾸고, 이 함수를
호출하는 곳들이 같은 패키지 내에 있는지 확인해 필요 시 호출부를 같은 패키지로 옮기거나 접근 범위를 조정하세요.
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt (2)

6-6: @Composable 어노테이션을 완전 한정 이름 대신 import로 선언하는 것을 권장합니다.

같은 패키지의 DatePickerDayCellView.ktimport androidx.compose.runtime.Composable을 사용하며, 이 파일만 완전 한정 이름을 사용해 일관성이 떨어집니다.

♻️ import 추가 제안
 import androidx.compose.ui.graphics.Color
+import androidx.compose.runtime.Composable
 import com.team.prezel.core.designsystem.theme.PrezelTheme

-@androidx.compose.runtime.Composable
+@Composable
 internal fun dayTextColor(ui: DayCellUiModel): Color =
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt`
at line 6, Replace the fully-qualified annotation usage
`@androidx.compose.runtime.Composable` in DatePickerStyles (the Composable
annotation on the top of DatePickerStyles.kt) with an import-based annotation:
add import androidx.compose.runtime.Composable at the top of the file and change
the annotation to `@Composable` so it matches the style used in
DatePickerDayCellView.kt and keeps annotations consistent across the design
system.

7-13: 비활성화(disabled) 상태에 대한 색상 처리가 누락되어 있습니다.

현재 dayTextColorui.enabledui.isInMonth를 확인하지 않습니다. 현재 구현에서는 date == null인 셀이 toUiModel에서 null을 반환하므로 실제로 문제가 되지 않지만, 추후 최소/최대 날짜 제한 기능이 추가될 경우 비활성화된 인월(in-month) 날짜가 활성화된 날짜와 동일한 색상으로 렌더링됩니다.

♻️ disabled 상태 색상 추가 제안
 internal fun dayTextColor(ui: DayCellUiModel): Color =
     when {
+        !ui.enabled -> PrezelTheme.colors.textDisabled
         ui.isSelected -> PrezelTheme.colors.bgRegular
         ui.isToday -> PrezelTheme.colors.interactiveRegular
         ui.isSunday -> PrezelTheme.colors.accentMagentaRegular
         else -> PrezelTheme.colors.textMedium
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt`
around lines 7 - 13, The dayTextColor function lacks handling for
disabled/in-month state: update dayTextColor(ui: DayCellUiModel) to first check
ui.enabled and ui.isInMonth and return the theme's disabled text color when the
cell is not enabled or not in the current month (e.g.,
PrezelTheme.colors.textDisabled or an equivalent low-emphasis color) before the
existing ui.isSelected/ui.isToday/ui.isSunday branches so disabled in-month
dates render with the disabled color.
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt (1)

6-19: DayCellDayCellUiModelinternal로 변경하는 것을 권장합니다.

두 클래스는 datepicker 패키지 내부에서만 소비되며 모듈 공개 API의 일부가 아닙니다. 현재 public으로 선언되어 있어 설계 시스템 모듈을 사용하는 소비자에게 의도치 않게 노출됩니다.

♻️ 가시성 수정 제안
-data class DayCell(
+internal data class DayCell(
     val date: LocalDate?,
     val isInMonth: Boolean,
 )

-data class DayCellUiModel(
+internal data class DayCellUiModel(
     val date: LocalDate,
     val text: String,
     val isSelected: Boolean,
     val isToday: Boolean,
     val isSunday: Boolean,
     val isInMonth: Boolean,
     val enabled: Boolean,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt`
around lines 6 - 19, The DayCell and DayCellUiModel data classes are
unnecessarily public; change their visibility to internal by updating the
declarations of DayCell and DayCellUiModel to internal data class so they are
only visible inside the datepicker package; update any external usages inside
the module if necessary and run a compile to catch and fix any places that
relied on the public visibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt`:
- Line 96: Move the hardcoded Korean label by adding a new string resource
(e.g., add <string name="core_designsystem_select">선택하기</string> to strings.xml)
and update PrezelDatePicker.kt to use that resource instead of the literal
(replace text = "선택하기" with text =
stringResource(R.string.core_designsystem_select) or
context.getString(R.string.core_designsystem_select) as appropriate); ensure you
import androidx.compose.ui.res.stringResource if using Compose.
- Around line 44-110: PrezelDatePicker is too long and violates Detekt
LongMethod; extract the header (TopAppBar + WeekdayRow +
PrezelHorizontalDivider) and footer (PrezelHorizontalDivider + PrezelTextButton)
into two private composable helpers (e.g., private fun
PrezelDatePickerHeader(...) and private fun PrezelDatePickerFooter(...)) and
replace the inline header/footer blocks inside PrezelDatePicker with calls to
those helpers, passing only the needed params (title, onClose for header;
selectedDate, onConfirm for footer) while keeping the LazyColumn/MonthSection
usage intact.

---

Nitpick comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt`:
- Around line 6-19: The DayCell and DayCellUiModel data classes are
unnecessarily public; change their visibility to internal by updating the
declarations of DayCell and DayCellUiModel to internal data class so they are
only visible inside the datepicker package; update any external usages inside
the module if necessary and run a compile to catch and fix any places that
relied on the public visibility.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt`:
- Line 6: Replace the fully-qualified annotation usage
`@androidx.compose.runtime.Composable` in DatePickerStyles (the Composable
annotation on the top of DatePickerStyles.kt) with an import-based annotation:
add import androidx.compose.runtime.Composable at the top of the file and change
the annotation to `@Composable` so it matches the style used in
DatePickerDayCellView.kt and keeps annotations consistent across the design
system.
- Around line 7-13: The dayTextColor function lacks handling for
disabled/in-month state: update dayTextColor(ui: DayCellUiModel) to first check
ui.enabled and ui.isInMonth and return the theme's disabled text color when the
cell is not enabled or not in the current month (e.g.,
PrezelTheme.colors.textDisabled or an equivalent low-emphasis color) before the
existing ui.isSelected/ui.isToday/ui.isSunday branches so disabled in-month
dates render with the disabled color.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt`:
- Around line 6-8: 함수 buildMonthGrid가 퍼블릭으로 노출되어 있어 모듈 API를 불필요하게 넓히고 있으므로 해당
함수의 가시성을 internal로 변경하세요; 즉 MonthGrid와 같은 패키지 내부에서만 사용되도록 buildMonthGrid 선언(함수
이름: buildMonthGrid, 관련 타입: YearMonth, DayOfWeek)을 public에서 internal로 바꾸고, 이 함수를
호출하는 곳들이 같은 패키지 내에 있는지 확인해 필요 시 호출부를 같은 패키지로 옮기거나 접근 범위를 조정하세요.

`PrezelDatePicker`의 가독성과 유지보수성을 높이기 위해 내부 UI 로직을 분리하고 하드코딩된 문자열을 리소스화했습니다.

* `DatePickerHeader`, `DatePickerFooter` 컴포저블을 추출하여 `PrezelDatePicker` 구조를 단순화했습니다.
* 하단 확인 버튼의 텍스트("선택하기")를 `core_designsystem_date_picker_confirm_btn` 리소스로 대체했습니다.
* `DatePickerStyles.kt` 내 불필요한 full qualifier `androidx.compose.runtime.Composable`을 `import` 문으로 정리했습니다.
Copy link
Contributor

@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

🧹 Nitpick comments (2)
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt (2)

131-152: WeekdayRow 요일 레이블이 하드코딩되어 있음

"일", "월", "화", "수", "목", "금", "토" 7개 레이블이 컴포저블 내부에 직접 리스트로 정의되어 있습니다. 프로젝트의 나머지 UI 문자열은 모두 strings.xml로 외부화되어 있으므로, 일관성 및 향후 현지화를 고려하면 이 레이블도 string-array 리소스로 이동하는 것을 권장합니다.

♻️ 리팩터링 제안

strings.xml에 추가:

+    <string-array name="core_designsystem_weekday_labels">
+        <item>일</item>
+        <item>월</item>
+        <item>화</item>
+        <item>수</item>
+        <item>목</item>
+        <item>금</item>
+        <item>토</item>
+    </string-array>

WeekdayRow 수정:

 `@Composable`
 private fun WeekdayRow() {
-    val labels = listOf("일", "월", "화", "수", "목", "금", "토")
+    val labels = stringArrayResource(R.array.core_designsystem_weekday_labels).toList()
     ...
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt`
around lines 131 - 152, WeekdayRow currently hardcodes the weekday labels
("일","월",...) inside the composable; extract these into a string-array resource
(e.g., <string-array name="weekday_labels"> in strings.xml) and update
WeekdayRow to load them via stringArrayResource(R.array.weekday_labels) (ensure
you import androidx.compose.ui.res.stringArrayResource) and use the resulting
array/list in the existing labels.forEach block so the UI follows the project's
resource/localization pattern.

106-106: DatePickerFooter에서 불필요한 @OptIn(ExperimentalMaterial3Api::class) 제거

DatePickerFooterPrezelHorizontalDividerPrezelTextButton만 호출하는데, 두 컴포저블 모두 @OptIn 어노테이션이 필요하지 않습니다. 반면 DatePickerHeaderPrezelTopAppBar를 호출하므로 @OptIn이 필요합니다. 불필요한 어노테이션을 제거해 코드를 정리하세요.

수정 제안
-@OptIn(ExperimentalMaterial3Api::class)
 `@Composable`
 private fun DatePickerFooter(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt`
at line 106, DatePickerFooter에 붙어 있는 불필요한
`@OptIn`(ExperimentalMaterial3Api::class) 어노테이션을 제거하세요; DatePickerFooter는
PrezelHorizontalDivider와 PrezelTextButton만 호출하므로 해당 OptIn이 필요 없습니다. 반면
DatePickerHeader는 PrezelTopAppBar를 사용하므로
`@OptIn`(ExperimentalMaterial3Api::class)는 DatePickerHeader에만 유지하도록 정리하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Prezel/core/designsystem/src/main/res/values/strings.xml`:
- Line 4: 문자열 리소스 core_designsystem_close_date_picker_desc가 영어 혼용("DatePicker
닫기")으로 되어 있어 접근성 읽기가 부자연스럽습니다; core_designsystem_close_date_picker_desc 값을 "날짜
선택기 닫기"처럼 완전한 한국어 표현으로 변경하여 core_designsystem_close_floating_btn_content_desc 등
기존 한국어 표기와 일관되게 수정하고, 변경 후 TalkBack/스크린리더에서 의도한 대로 읽히는지 확인하세요.

---

Nitpick comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt`:
- Around line 131-152: WeekdayRow currently hardcodes the weekday labels
("일","월",...) inside the composable; extract these into a string-array resource
(e.g., <string-array name="weekday_labels"> in strings.xml) and update
WeekdayRow to load them via stringArrayResource(R.array.weekday_labels) (ensure
you import androidx.compose.ui.res.stringArrayResource) and use the resulting
array/list in the existing labels.forEach block so the UI follows the project's
resource/localization pattern.
- Line 106: DatePickerFooter에 붙어 있는 불필요한 `@OptIn`(ExperimentalMaterial3Api::class)
어노테이션을 제거하세요; DatePickerFooter는 PrezelHorizontalDivider와 PrezelTextButton만 호출하므로
해당 OptIn이 필요 없습니다. 반면 DatePickerHeader는 PrezelTopAppBar를 사용하므로
`@OptIn`(ExperimentalMaterial3Api::class)는 DatePickerHeader에만 유지하도록 정리하세요.

디자인 시스템에 `PrezelDatePicker` 컴포넌트를 추가하고 관련 스타일과 로직을 개선했습니다.

*   `PrezelDatePicker` 컴포넌트 추가
    *   헤더, 요일 표시, 월별 그리드, 푸터(확인 버튼)로 구성된 날짜 선택 다이얼로그를 구현했습니다.
    *   `DatePickerState`를 통해 현재 연도/월, 선택된 날짜, 달력 표시 여부 등의 상태를 관리합니다.
*   스타일 및 리소스 추가
    *   선택된 날짜, 오늘, 비활성화된 날짜 등에 따라 텍스트 색상을 다르게 적용하는 `dayTextColor` 로직을 추가했습니다.
    *   요일 라벨(`일`~`토`)을 `string-array` 리소스로 분리하여 관리하도록 개선했습니다.
*   접근성 수정 및 내부 구현 변경
    *   `DatePicker` 관련 모델(`DayCell`, `DayCellUiModel`)과 유틸리티 함수(`buildMonthGrid`)의 접근 제어자를 `internal`로 변경했습니다.
    *   DatePicker 닫기 버튼의 콘텐츠 설명을 "DatePicker 닫기"에서 "날짜 선택 닫기"로 명확하게 수정했습니다.
Copy link
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt`:
- Line 11: The selected date cell is using bgRegular for its text color (in the
DatePickerStyles mapping for ui.isSelected) which yields poor contrast in dark
mode; update the mapping in DatePickerStyles so that when ui.isSelected the text
color uses a dedicated text token (e.g., textRegular or textMedium) or an
explicit high-contrast color (such as white) instead of
PrezelTheme.colors.bgRegular, and ensure the selected cell background remains
interactiveRegular; additionally, add an isSaturday Boolean to the
DayCellUiModel (matching the existing isSunday) so you can apply distinct
styling for Saturdays per Korean calendar conventions and update any code that
constructs/uses DayCellUiModel accordingly.

---

Duplicate comments:
In `@Prezel/core/designsystem/src/main/res/values/strings.xml`:
- Line 4: The accessibility string core_designsystem_close_date_picker_desc
currently reads "날짜 선택 닫기" which may be ambiguous for TalkBack; update its value
to "날짜 선택기 닫기" to clearly identify the component being closed—locate the string
resource named core_designsystem_close_date_picker_desc in strings.xml and
replace the text accordingly so TalkBack announces the component name
unambiguously.

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.

PrezelDatePicker 구현

1 participant

Comments