From e9a247b169cea453cdd713e7513b0f5e8fc8d1df Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Thu, 12 Feb 2026 13:47:08 +0900 Subject: [PATCH 01/15] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20Dat?= =?UTF-8?q?ePicker=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 새로운 디자인 시스템 컴포넌트로 DatePicker를 추가했습니다. * `DatePickerScreen`: 날짜 선택을 위한 전체 스크린 UI 구현 (TopAppBar, 요일 표시, 월별 리스트) * `MonthSection`, `MonthGrid`: 월별 날짜 그리드 레이아웃 구현 * `DayCellView`: 개별 날짜 셀의 디자인 및 상태(선택, 오늘, 일요일 등) 처리 * 날짜 계산 로직(`MonthGridBuilder`) 및 데이터 모델(`DatePickerModels`) 추가 --- .../datepicker/DatePickerDayCellView.kt | 54 +++++++ .../component/datepicker/DatePickerModels.kt | 34 ++++ .../component/datepicker/DatePickerStyles.kt | 13 ++ .../component/datepicker/MonthGrid.kt | 42 +++++ .../component/datepicker/MonthGridBuilder.kt | 34 ++++ .../component/datepicker/MonthSection.kt | 36 +++++ .../component/datepicker/PrezelDatePicker.kt | 148 ++++++++++++++++++ 7 files changed, 361 insertions(+) create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt new file mode 100644 index 00000000..5efc265c --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -0,0 +1,54 @@ +package com.team.prezel.core.designsystem.component.datepicker + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.theme.PrezelTheme + +@Composable +internal fun RowScope.DayCellView( + uiModel: DayCellUiModel?, + onClick: () -> Unit, +) { + Box( + modifier = Modifier + .weight(1f) + .aspectRatio(1f) + .padding(6.dp) + .clip(CircleShape) + .background( + if (uiModel?.isSelected == true) { + PrezelTheme.colors.interactiveRegular + } else { + Color.Transparent + }, + ).clickable( + enabled = uiModel?.enabled == true, + onClick = onClick, + ), + contentAlignment = Alignment.Center, + ) { + if (uiModel != null) { + Text( + text = uiModel.text, + color = dayTextColor(uiModel), + style = if (uiModel.isSelected) { + PrezelTheme.typography.body3Bold + } else { + PrezelTheme.typography.body3Medium + }, + ) + } + } +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt new file mode 100644 index 00000000..cd4a50c4 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt @@ -0,0 +1,34 @@ +package com.team.prezel.core.designsystem.component.datepicker + +import java.time.DayOfWeek +import java.time.LocalDate + +data class DayCell( + val date: LocalDate?, + val isInMonth: Boolean, +) + +data class DayCellUiModel( + val date: LocalDate, + val text: String, + val isSelected: Boolean, + val isToday: Boolean, + val isSunday: Boolean, + val enabled: Boolean, +) + +internal fun DayCell.toUiModel( + selectedDate: LocalDate?, + today: LocalDate, + enabled: Boolean = true, +): DayCellUiModel? { + val d = date ?: return null + return DayCellUiModel( + date = d, + text = d.dayOfMonth.toString(), + isSelected = d == selectedDate, + isToday = d == today, + isSunday = d.dayOfWeek == DayOfWeek.SUNDAY, + enabled = enabled, + ) +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt new file mode 100644 index 00000000..a3ecf543 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt @@ -0,0 +1,13 @@ +package com.team.prezel.core.designsystem.component.datepicker + +import androidx.compose.ui.graphics.Color +import com.team.prezel.core.designsystem.theme.PrezelTheme + +@androidx.compose.runtime.Composable +internal fun dayTextColor(ui: DayCellUiModel): Color = + when { + ui.isSelected -> PrezelTheme.colors.bgRegular + ui.isToday -> PrezelTheme.colors.interactiveRegular + ui.isSunday -> PrezelTheme.colors.accentMagentaRegular + else -> PrezelTheme.colors.textMedium + } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt new file mode 100644 index 00000000..e7914af3 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt @@ -0,0 +1,42 @@ +package com.team.prezel.core.designsystem.component.datepicker + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import java.time.DayOfWeek +import java.time.LocalDate +import java.time.YearMonth + +@Composable +internal fun MonthGrid( + month: YearMonth, + selectedDate: LocalDate?, + today: LocalDate, + onSelect: (LocalDate) -> Unit, +) { + val cells = remember(month) { + buildMonthGrid(month, firstDayOfWeek = DayOfWeek.SUNDAY) + } + val lastWeek = remember(cells) { lastWeekIndexToRender(cells) } + + Column(modifier = Modifier.padding(vertical = 16.dp)) { + for (week in 0..lastWeek) { + Row(Modifier.fillMaxWidth()) { + for (day in 0 until 7) { + val cell = cells[week * 7 + day] + val uiModel = cell.toUiModel(selectedDate = selectedDate, today = today) + + DayCellView( + uiModel = uiModel, + onClick = { cell.date?.let(onSelect) }, + ) + } + } + } + } +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt new file mode 100644 index 00000000..98eae302 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt @@ -0,0 +1,34 @@ +package com.team.prezel.core.designsystem.component.datepicker + +import java.time.DayOfWeek +import java.time.YearMonth + +fun buildMonthGrid( + month: YearMonth, + firstDayOfWeek: DayOfWeek, +): List { + val firstOfMonth = month.atDay(1) + val lastDay = month.lengthOfMonth() + + val shift = ((firstOfMonth.dayOfWeek.value - firstDayOfWeek.value) + 7) % 7 + val totalCells = 42 + + return (0 until totalCells).map { index -> + val dayNumber = index - shift + 1 + if (dayNumber in 1..lastDay) { + DayCell(date = month.atDay(dayNumber), isInMonth = true) + } else { + DayCell(date = null, isInMonth = false) + } + } +} + +internal fun lastWeekIndexToRender(cells: List): Int { + // 마지막으로 실제 날짜가 존재하는 셀 인덱스 (0..41) + val last = cells.indexOfLast { it.date != null } + // month가 비정상일 경우 방어 + if (last < 0) return 0 + + // 주 단위로 올림 → 마지막 날짜가 포함된 주 index (0..5) + return (last / 7).coerceIn(0, 5) +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt new file mode 100644 index 00000000..16a91c91 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt @@ -0,0 +1,36 @@ +package com.team.prezel.core.designsystem.component.datepicker + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.theme.PrezelTheme +import java.time.LocalDate +import java.time.YearMonth + +@Composable +internal fun MonthSection( + month: YearMonth, + selectedDate: LocalDate?, + today: LocalDate, + onSelect: (LocalDate) -> Unit, +) { + Column( + modifier = Modifier.padding(20.dp), + ) { + Text( + text = "${month.year}년 ${month.monthValue}월", + color = PrezelTheme.colors.textLarge, + style = PrezelTheme.typography.body3Medium, + ) + + MonthGrid( + month = month, + selectedDate = selectedDate, + today = today, + onSelect = onSelect, + ) + } +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt new file mode 100644 index 00000000..2ca7e15e --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -0,0 +1,148 @@ +package com.team.prezel.core.designsystem.component.datepicker + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.component.PrezelDividerType +import com.team.prezel.core.designsystem.component.PrezelHorizontalDivider +import com.team.prezel.core.designsystem.component.PrezelTopAppBar +import com.team.prezel.core.designsystem.component.button.PrezelButtonHierarchy +import com.team.prezel.core.designsystem.component.button.PrezelButtonSize +import com.team.prezel.core.designsystem.component.button.PrezelButtonStyle +import com.team.prezel.core.designsystem.component.button.PrezelButtonType +import com.team.prezel.core.designsystem.component.button.PrezelTextButton +import com.team.prezel.core.designsystem.icon.PrezelIcons +import com.team.prezel.core.designsystem.theme.PrezelTheme +import java.time.LocalDate +import java.time.YearMonth + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PrezelDatePicker( + title: String, + initialMonth: YearMonth = YearMonth.now(), + selectedDate: LocalDate? = null, + today: LocalDate = LocalDate.now(), + onClose: () -> Unit = {}, + onConfirm: (LocalDate) -> Unit = {}, + modifier: Modifier = Modifier, +) { + val months = remember(initialMonth) { + (0..12).map { initialMonth.plusMonths(it.toLong()) } + } + + var picked by remember { mutableStateOf(selectedDate) } + + Column( + modifier = modifier + .fillMaxSize() + .background(PrezelTheme.colors.bgRegular), + ) { + Column { + PrezelTopAppBar( + title = { Text(text = title) }, + trailingIcons = { + IconButton(onClick = onClose) { + Icon( + painter = painterResource(PrezelIcons.Cancel), + contentDescription = "닫기", + ) + } + }, + ) + WeekdayRow() + PrezelHorizontalDivider(type = PrezelDividerType.THICK) + } + + LazyColumn( + modifier = Modifier.weight(1f), + contentPadding = PaddingValues(bottom = 16.dp), + ) { + items(months, key = { it.toString() }) { month -> + MonthSection( + month = month, + selectedDate = picked, + today = today, + onSelect = { picked = it }, + ) + } + } + + Column { + PrezelHorizontalDivider(type = PrezelDividerType.THICK) + PrezelTextButton( + text = "선택하기", + onClick = { picked?.let(onConfirm) }, + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + enabled = picked != null, + PrezelButtonStyle( + buttonType = PrezelButtonType.FILLED, + buttonHierarchy = PrezelButtonHierarchy.PRIMARY, + buttonSize = PrezelButtonSize.REGULAR, + ), + ) + } + } +} + +@Composable +private fun WeekdayRow() { + val labels = listOf("일", "월", "화", "수", "목", "금", "토") + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp, vertical = 12.dp), + ) { + labels.forEach { text -> + Box( + modifier = Modifier.weight(1f), + contentAlignment = Alignment.Center, + ) { + Text( + text = text, + color = PrezelTheme.colors.textMedium, + style = PrezelTheme.typography.body3Medium, + ) + } + } + } +} + +@Preview(showBackground = true) +@Composable +private fun PrezelDatePickerPreview() { + PrezelTheme { + PrezelDatePicker( + title = "발표 날짜", + initialMonth = YearMonth.of(2026, 2), + selectedDate = LocalDate.of(2026, 2, 28), + today = LocalDate.of(2026, 2, 12), + onClose = {}, + onConfirm = {}, + ) + } +} From 3ce1d486b767253c906a3615b3563cdf5b7605e6 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 20 Feb 2026 13:26:26 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20PrezelDatePicker=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20=EA=B4=80=EB=A0=A8=20=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인 시스템 내 날짜 선택을 위한 `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 참조로 변경 --- .../component/datepicker/DatePickerModels.kt | 6 ++++-- .../designsystem/component/datepicker/MonthGrid.kt | 6 +++--- .../component/datepicker/PrezelDatePicker.kt | 14 ++++++++------ .../designsystem/src/main/res/values/strings.xml | 1 + 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt index cd4a50c4..b6ee6606 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt @@ -14,13 +14,14 @@ data class DayCellUiModel( val isSelected: Boolean, val isToday: Boolean, val isSunday: Boolean, + val isInMonth: Boolean, val enabled: Boolean, ) internal fun DayCell.toUiModel( selectedDate: LocalDate?, today: LocalDate, - enabled: Boolean = true, + enabled: Boolean = isInMonth, ): DayCellUiModel? { val d = date ?: return null return DayCellUiModel( @@ -29,6 +30,7 @@ internal fun DayCell.toUiModel( isSelected = d == selectedDate, isToday = d == today, isSunday = d.dayOfWeek == DayOfWeek.SUNDAY, - enabled = enabled, + isInMonth = isInMonth, + enabled = enabled && isInMonth, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt index e7914af3..5a80f47f 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt @@ -19,10 +19,10 @@ internal fun MonthGrid( today: LocalDate, onSelect: (LocalDate) -> Unit, ) { - val cells = remember(month) { - buildMonthGrid(month, firstDayOfWeek = DayOfWeek.SUNDAY) + val (cells, lastWeek) = remember(month) { + val c = buildMonthGrid(month, firstDayOfWeek = DayOfWeek.SUNDAY) + c to lastWeekIndexToRender(c) } - val lastWeek = remember(cells) { lastWeekIndexToRender(cells) } Column(modifier = Modifier.padding(vertical = 16.dp)) { for (week in 0..lastWeek) { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index 2ca7e15e..5e8e673e 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -22,8 +22,10 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.R import com.team.prezel.core.designsystem.component.PrezelDividerType import com.team.prezel.core.designsystem.component.PrezelHorizontalDivider import com.team.prezel.core.designsystem.component.PrezelTopAppBar @@ -52,7 +54,7 @@ fun PrezelDatePicker( (0..12).map { initialMonth.plusMonths(it.toLong()) } } - var picked by remember { mutableStateOf(selectedDate) } + var selectedDate by remember { mutableStateOf(selectedDate) } Column( modifier = modifier @@ -66,7 +68,7 @@ fun PrezelDatePicker( IconButton(onClick = onClose) { Icon( painter = painterResource(PrezelIcons.Cancel), - contentDescription = "닫기", + contentDescription = stringResource(R.string.core_designsystem_close_date_picker_desc), ) } }, @@ -82,9 +84,9 @@ fun PrezelDatePicker( items(months, key = { it.toString() }) { month -> MonthSection( month = month, - selectedDate = picked, + selectedDate = selectedDate, today = today, - onSelect = { picked = it }, + onSelect = { selectedDate = it }, ) } } @@ -93,11 +95,11 @@ fun PrezelDatePicker( PrezelHorizontalDivider(type = PrezelDividerType.THICK) PrezelTextButton( text = "선택하기", - onClick = { picked?.let(onConfirm) }, + onClick = { selectedDate?.let(onConfirm) }, modifier = Modifier .fillMaxWidth() .padding(20.dp), - enabled = picked != null, + enabled = selectedDate != null, PrezelButtonStyle( buttonType = PrezelButtonType.FILLED, buttonHierarchy = PrezelButtonHierarchy.PRIMARY, diff --git a/Prezel/core/designsystem/src/main/res/values/strings.xml b/Prezel/core/designsystem/src/main/res/values/strings.xml index 519ffa15..d9a24adc 100644 --- a/Prezel/core/designsystem/src/main/res/values/strings.xml +++ b/Prezel/core/designsystem/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ 플로팅 버튼 닫기 + DatePicker 닫기 체크박스 From cdb4fcfb32c632c671c6fb8dddf25e7304e03a41 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 20 Feb 2026 13:34:55 +0900 Subject: [PATCH 03/15] =?UTF-8?q?refactor:=20PrezelDatePicker=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelDatePicker` 컴포넌트의 내부 상태 관리 로직을 개선하여 상태를 외부에서 주입받도록 수정했습니다. * `selectedDate`를 관리하던 내부 `mutableStateOf`를 제거하고, `onSelect` 콜백을 통해 외부에서 상태를 직접 제어하도록 변경했습니다. * 가독성 향상을 위해 함수 파라미터의 순서를 조정했습니다. * 변경된 구조에 맞춰 Preview 코드를 수정했습니다. --- .../component/datepicker/PrezelDatePicker.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index 5e8e673e..0b480a51 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -43,19 +43,18 @@ import java.time.YearMonth @Composable fun PrezelDatePicker( title: String, - initialMonth: YearMonth = YearMonth.now(), - selectedDate: LocalDate? = null, - today: LocalDate = LocalDate.now(), - onClose: () -> Unit = {}, - onConfirm: (LocalDate) -> Unit = {}, + initialMonth: YearMonth, + today: LocalDate, + selectedDate: LocalDate?, + onSelect: (LocalDate) -> Unit, + onClose: () -> Unit, + onConfirm: (LocalDate) -> Unit, modifier: Modifier = Modifier, ) { val months = remember(initialMonth) { (0..12).map { initialMonth.plusMonths(it.toLong()) } } - var selectedDate by remember { mutableStateOf(selectedDate) } - Column( modifier = modifier .fillMaxSize() @@ -86,7 +85,7 @@ fun PrezelDatePicker( month = month, selectedDate = selectedDate, today = today, - onSelect = { selectedDate = it }, + onSelect = onSelect, ) } } @@ -138,11 +137,16 @@ private fun WeekdayRow() { @Composable private fun PrezelDatePickerPreview() { PrezelTheme { + var selected by remember { + mutableStateOf(LocalDate.of(2026, 2, 26)) + } + PrezelDatePicker( title = "발표 날짜", initialMonth = YearMonth.of(2026, 2), - selectedDate = LocalDate.of(2026, 2, 28), - today = LocalDate.of(2026, 2, 12), + today = LocalDate.of(2026, 2, 20), + selectedDate = selected, + onSelect = { selected = it }, onClose = {}, onConfirm = {}, ) From fc7ba56648b58cbb213a70af714e2de25494e6fa Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 20 Feb 2026 14:05:18 +0900 Subject: [PATCH 04/15] =?UTF-8?q?refactor:=20PrezelDatePicker=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=B0=8F=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=A6=AC?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelDatePicker`의 가독성과 유지보수성을 높이기 위해 내부 UI 로직을 분리하고 하드코딩된 문자열을 리소스화했습니다. * `DatePickerHeader`, `DatePickerFooter` 컴포저블을 추출하여 `PrezelDatePicker` 구조를 단순화했습니다. * 하단 확인 버튼의 텍스트("선택하기")를 `core_designsystem_date_picker_confirm_btn` 리소스로 대체했습니다. * `DatePickerStyles.kt` 내 불필요한 full qualifier `androidx.compose.runtime.Composable`을 `import` 문으로 정리했습니다. --- .../component/datepicker/DatePickerStyles.kt | 3 +- .../component/datepicker/PrezelDatePicker.kt | 80 ++++++++++++------- .../src/main/res/values/strings.xml | 1 + 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt index a3ecf543..02490e67 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt @@ -1,9 +1,10 @@ package com.team.prezel.core.designsystem.component.datepicker +import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import com.team.prezel.core.designsystem.theme.PrezelTheme -@androidx.compose.runtime.Composable +@Composable internal fun dayTextColor(ui: DayCellUiModel): Color = when { ui.isSelected -> PrezelTheme.colors.bgRegular diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index 0b480a51..0c607919 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -60,21 +60,7 @@ fun PrezelDatePicker( .fillMaxSize() .background(PrezelTheme.colors.bgRegular), ) { - Column { - PrezelTopAppBar( - title = { Text(text = title) }, - trailingIcons = { - IconButton(onClick = onClose) { - Icon( - painter = painterResource(PrezelIcons.Cancel), - contentDescription = stringResource(R.string.core_designsystem_close_date_picker_desc), - ) - } - }, - ) - WeekdayRow() - PrezelHorizontalDivider(type = PrezelDividerType.THICK) - } + DatePickerHeader(title = title, onClose = onClose) LazyColumn( modifier = Modifier.weight(1f), @@ -90,22 +76,54 @@ fun PrezelDatePicker( } } - Column { - PrezelHorizontalDivider(type = PrezelDividerType.THICK) - PrezelTextButton( - text = "선택하기", - onClick = { selectedDate?.let(onConfirm) }, - modifier = Modifier - .fillMaxWidth() - .padding(20.dp), - enabled = selectedDate != null, - PrezelButtonStyle( - buttonType = PrezelButtonType.FILLED, - buttonHierarchy = PrezelButtonHierarchy.PRIMARY, - buttonSize = PrezelButtonSize.REGULAR, - ), - ) - } + DatePickerFooter(selectedDate = selectedDate, onConfirm = onConfirm) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun DatePickerHeader( + title: String, + onClose: () -> Unit, +) { + Column { + PrezelTopAppBar( + title = { Text(text = title) }, + trailingIcons = { + IconButton(onClick = onClose) { + Icon( + painter = painterResource(PrezelIcons.Cancel), + contentDescription = stringResource(R.string.core_designsystem_close_date_picker_desc), + ) + } + }, + ) + WeekdayRow() + PrezelHorizontalDivider(type = PrezelDividerType.THICK) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun DatePickerFooter( + selectedDate: LocalDate?, + onConfirm: (LocalDate) -> Unit, +) { + Column { + PrezelHorizontalDivider(type = PrezelDividerType.THICK) + PrezelTextButton( + text = stringResource(R.string.core_designsystem_date_picker_confirm_btn), + onClick = { selectedDate?.let(onConfirm) }, + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + enabled = selectedDate != null, + PrezelButtonStyle( + buttonType = PrezelButtonType.FILLED, + buttonHierarchy = PrezelButtonHierarchy.PRIMARY, + buttonSize = PrezelButtonSize.REGULAR, + ), + ) } } diff --git a/Prezel/core/designsystem/src/main/res/values/strings.xml b/Prezel/core/designsystem/src/main/res/values/strings.xml index d9a24adc..9a532efd 100644 --- a/Prezel/core/designsystem/src/main/res/values/strings.xml +++ b/Prezel/core/designsystem/src/main/res/values/strings.xml @@ -3,4 +3,5 @@ 플로팅 버튼 닫기 DatePicker 닫기 체크박스 + 선택하기 From 7d157b6625088e01677b15b2abff9699f273f17a Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 20 Feb 2026 14:53:02 +0900 Subject: [PATCH 05/15] =?UTF-8?q?feat:=20DatePicker=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=8A=A4=ED=83=80=EC=9D=BC?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인 시스템에 `PrezelDatePicker` 컴포넌트를 추가하고 관련 스타일과 로직을 개선했습니다. * `PrezelDatePicker` 컴포넌트 추가 * 헤더, 요일 표시, 월별 그리드, 푸터(확인 버튼)로 구성된 날짜 선택 다이얼로그를 구현했습니다. * `DatePickerState`를 통해 현재 연도/월, 선택된 날짜, 달력 표시 여부 등의 상태를 관리합니다. * 스타일 및 리소스 추가 * 선택된 날짜, 오늘, 비활성화된 날짜 등에 따라 텍스트 색상을 다르게 적용하는 `dayTextColor` 로직을 추가했습니다. * 요일 라벨(`일`~`토`)을 `string-array` 리소스로 분리하여 관리하도록 개선했습니다. * 접근성 수정 및 내부 구현 변경 * `DatePicker` 관련 모델(`DayCell`, `DayCellUiModel`)과 유틸리티 함수(`buildMonthGrid`)의 접근 제어자를 `internal`로 변경했습니다. * DatePicker 닫기 버튼의 콘텐츠 설명을 "DatePicker 닫기"에서 "날짜 선택 닫기"로 명확하게 수정했습니다. --- .../component/datepicker/DatePickerModels.kt | 4 ++-- .../component/datepicker/DatePickerStyles.kt | 1 + .../component/datepicker/MonthGridBuilder.kt | 2 +- .../component/datepicker/PrezelDatePicker.kt | 4 ++-- .../designsystem/src/main/res/values/strings.xml | 12 +++++++++++- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt index b6ee6606..7a725790 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt @@ -3,12 +3,12 @@ package com.team.prezel.core.designsystem.component.datepicker import java.time.DayOfWeek import java.time.LocalDate -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, diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt index 02490e67..bd7bf36e 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt @@ -7,6 +7,7 @@ import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable 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 diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt index 98eae302..2e508e95 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt @@ -3,7 +3,7 @@ package com.team.prezel.core.designsystem.component.datepicker import java.time.DayOfWeek import java.time.YearMonth -fun buildMonthGrid( +internal fun buildMonthGrid( month: YearMonth, firstDayOfWeek: DayOfWeek, ): List { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index 0c607919..9758a95c 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -103,7 +104,6 @@ private fun DatePickerHeader( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun DatePickerFooter( selectedDate: LocalDate?, @@ -129,7 +129,7 @@ private fun DatePickerFooter( @Composable private fun WeekdayRow() { - val labels = listOf("일", "월", "화", "수", "목", "금", "토") + val labels = stringArrayResource(R.array.core_designsystem_weekday_labels).toList() Row( modifier = Modifier diff --git a/Prezel/core/designsystem/src/main/res/values/strings.xml b/Prezel/core/designsystem/src/main/res/values/strings.xml index 9a532efd..8f9e80c9 100644 --- a/Prezel/core/designsystem/src/main/res/values/strings.xml +++ b/Prezel/core/designsystem/src/main/res/values/strings.xml @@ -1,7 +1,17 @@ 플로팅 버튼 닫기 - DatePicker 닫기 + 날짜 선택 닫기 체크박스 선택하기 + + + + + + + + + + From bf3059b8c003af76d3e880af2637109dda0a4aa2 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Mon, 23 Feb 2026 00:25:05 +0900 Subject: [PATCH 06/15] =?UTF-8?q?refactor:=20DatePicker=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=B0=8F=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=8B=9C?= =?UTF-8?q?=EC=8A=A4=ED=85=9C=20=ED=85=8C=EB=A7=88=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DatePicker 관련 모델 및 스타일 파일명을 단수형으로 변경하고, 매직 넘버로 선언된 여백 값을 디자인 시스템의 `PrezelTheme.spacing`으로 교체하였습니다. * `DatePickerModels.kt` -> `DatePickerModel.kt`로 변경 및 `DayCellUiModel`에 `@Immutable` 어노테이션 추가 * `DatePickerStyles.kt` -> `DatePickerStyle.kt`로 변경 * `MonthSection`, `PrezelDatePicker`, `MonthGrid` 내 `dp` 단위 여백을 `PrezelTheme.spacing` 상수로 수정 * `DatePickerDayCellView` 클릭 시 리플 효과(`ripple()`) 추가 및 인터렉션 로직 개선 --- .../component/datepicker/DatePickerDayCellView.kt | 3 +++ .../datepicker/{DatePickerModels.kt => DatePickerModel.kt} | 2 ++ .../datepicker/{DatePickerStyles.kt => DatePickerStyle.kt} | 0 .../core/designsystem/component/datepicker/MonthGrid.kt | 4 ++-- .../core/designsystem/component/datepicker/MonthSection.kt | 3 +-- .../designsystem/component/datepicker/PrezelDatePicker.kt | 7 +++++-- 6 files changed, 13 insertions(+), 6 deletions(-) rename Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/{DatePickerModels.kt => DatePickerModel.kt} (94%) rename Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/{DatePickerStyles.kt => DatePickerStyle.kt} (100%) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt index 5efc265c..d0524e40 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Text +import androidx.compose.material3.ripple import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -36,6 +37,8 @@ internal fun RowScope.DayCellView( ).clickable( enabled = uiModel?.enabled == true, onClick = onClick, + indication = ripple(), + interactionSource = null ), contentAlignment = Alignment.Center, ) { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt similarity index 94% rename from Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt rename to Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt index 7a725790..f534c024 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModels.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt @@ -1,5 +1,6 @@ package com.team.prezel.core.designsystem.component.datepicker +import androidx.compose.runtime.Immutable import java.time.DayOfWeek import java.time.LocalDate @@ -8,6 +9,7 @@ internal data class DayCell( val isInMonth: Boolean, ) +@Immutable internal data class DayCellUiModel( val date: LocalDate, val text: String, diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt similarity index 100% rename from Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyles.kt rename to Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt index 5a80f47f..bcb86688 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt @@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.theme.PrezelTheme import java.time.DayOfWeek import java.time.LocalDate import java.time.YearMonth @@ -24,7 +24,7 @@ internal fun MonthGrid( c to lastWeekIndexToRender(c) } - Column(modifier = Modifier.padding(vertical = 16.dp)) { + Column(modifier = Modifier.padding(top = PrezelTheme.spacing.V16)) { for (week in 0..lastWeek) { Row(Modifier.fillMaxWidth()) { for (day in 0 until 7) { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt index 16a91c91..7c2e9870 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.theme.PrezelTheme import java.time.LocalDate import java.time.YearMonth @@ -18,7 +17,7 @@ internal fun MonthSection( onSelect: (LocalDate) -> Unit, ) { Column( - modifier = Modifier.padding(20.dp), + modifier = Modifier.padding(PrezelTheme.spacing.V20), ) { Text( text = "${month.year}년 ${month.monthValue}월", diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index 9758a95c..a3dd9610 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -116,7 +116,7 @@ private fun DatePickerFooter( onClick = { selectedDate?.let(onConfirm) }, modifier = Modifier .fillMaxWidth() - .padding(20.dp), + .padding(PrezelTheme.spacing.V20), enabled = selectedDate != null, PrezelButtonStyle( buttonType = PrezelButtonType.FILLED, @@ -134,7 +134,10 @@ private fun WeekdayRow() { Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 20.dp, vertical = 12.dp), + .padding( + horizontal = PrezelTheme.spacing.V20, + vertical = PrezelTheme.spacing.V12, + ), ) { labels.forEach { text -> Box( From e41832b45c52cbb8c6c58183db650958801972a8 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Mon, 23 Feb 2026 00:34:18 +0900 Subject: [PATCH 07/15] =?UTF-8?q?refactor:=20DatePicker=20UI=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EB=B0=8F=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DatePicker 구성 요소의 가독성과 코드 구조를 개선했습니다. * `DatePickerModel.kt`: `date` 변수의 널 체크 로직을 정리하고 불필요한 지역 변수 할당을 제거했습니다. * `DatePickerStyle.kt`: 기존 `dayTextColor` 함수를 `DayCellUiModel`의 확장 함수로 변경하여 캡슐화를 강화했습니다. * `DatePickerDayCellView.kt`: 확장 함수로 변경된 `dayTextColor`를 적용하고 코드 포맷을 정리했습니다. --- .../component/datepicker/DatePickerDayCellView.kt | 4 ++-- .../component/datepicker/DatePickerModel.kt | 13 +++++++------ .../component/datepicker/DatePickerStyle.kt | 10 +++++----- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt index d0524e40..892208c7 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -38,14 +38,14 @@ internal fun RowScope.DayCellView( enabled = uiModel?.enabled == true, onClick = onClick, indication = ripple(), - interactionSource = null + interactionSource = null, ), contentAlignment = Alignment.Center, ) { if (uiModel != null) { Text( text = uiModel.text, - color = dayTextColor(uiModel), + color = uiModel.dayTextColor(), style = if (uiModel.isSelected) { PrezelTheme.typography.body3Bold } else { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt index f534c024..138d29c5 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt @@ -25,13 +25,14 @@ internal fun DayCell.toUiModel( today: LocalDate, enabled: Boolean = isInMonth, ): DayCellUiModel? { - val d = date ?: return null + if (date == null) return null + return DayCellUiModel( - date = d, - text = d.dayOfMonth.toString(), - isSelected = d == selectedDate, - isToday = d == today, - isSunday = d.dayOfWeek == DayOfWeek.SUNDAY, + date = date, + text = date.dayOfMonth.toString(), + isSelected = date == selectedDate, + isToday = date == today, + isSunday = date.dayOfWeek == DayOfWeek.SUNDAY, isInMonth = isInMonth, enabled = enabled && isInMonth, ) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt index bd7bf36e..75ade291 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt @@ -5,11 +5,11 @@ import androidx.compose.ui.graphics.Color import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable -internal fun dayTextColor(ui: DayCellUiModel): Color = +internal fun DayCellUiModel.dayTextColor(): Color = when { - !ui.enabled -> PrezelTheme.colors.textDisabled - ui.isSelected -> PrezelTheme.colors.bgRegular - ui.isToday -> PrezelTheme.colors.interactiveRegular - ui.isSunday -> PrezelTheme.colors.accentMagentaRegular + !this.enabled -> PrezelTheme.colors.textDisabled + this.isSelected -> PrezelTheme.colors.bgRegular + this.isToday -> PrezelTheme.colors.interactiveRegular + this.isSunday -> PrezelTheme.colors.accentMagentaRegular else -> PrezelTheme.colors.textMedium } From 44d561c27bb6c6e9e26166e695919e21cfc97015 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Mon, 23 Feb 2026 00:37:30 +0900 Subject: [PATCH 08/15] =?UTF-8?q?refactor:=20DatePicker=20UI=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=97=AC=EB=B0=B1=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EB=AF=B8=EB=A6=AC=EB=B3=B4=EA=B8=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DatePicker 구성 요소의 디자인 일관성을 높이고 가독성을 개선했습니다. * `DatePickerDayCellView`: 날짜 셀의 패딩 값을 하드코딩된 `6.dp`에서 `PrezelTheme.spacing.V4`로 변경했습니다. * `MonthGrid`: 컴포넌트 확인을 위한 `MonthGridPreview`를 추가했습니다. * `MonthSection`: 컴포넌트 확인을 위한 `MonthSectionPreview`를 추가했습니다. --- .../component/datepicker/DatePickerDayCellView.kt | 3 +-- .../designsystem/component/datepicker/MonthGrid.kt | 14 ++++++++++++++ .../component/datepicker/MonthSection.kt | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt index 892208c7..d6711fb4 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -14,7 +14,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable @@ -26,7 +25,7 @@ internal fun RowScope.DayCellView( modifier = Modifier .weight(1f) .aspectRatio(1f) - .padding(6.dp) + .padding(PrezelTheme.spacing.V4) .clip(CircleShape) .background( if (uiModel?.isSelected == true) { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt index bcb86688..82867685 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelTheme import java.time.DayOfWeek import java.time.LocalDate @@ -40,3 +41,16 @@ internal fun MonthGrid( } } } + +@ThemePreview +@Composable +private fun MonthGridPreview() { + PrezelTheme { + MonthGrid( + month = YearMonth.of(2026, 2), + selectedDate = LocalDate.of(2026, 2, 26), + today = LocalDate.of(2026, 2, 23), + onSelect = {}, + ) + } +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt index 7c2e9870..e911e0f0 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelTheme import java.time.LocalDate import java.time.YearMonth @@ -33,3 +34,16 @@ internal fun MonthSection( ) } } + +@ThemePreview +@Composable +private fun MonthSectionPreview() { + PrezelTheme { + MonthSection( + month = YearMonth.of(2026, 2), + selectedDate = LocalDate.of(2026, 2, 26), + today = LocalDate.of(2026, 2, 23), + onSelect = {}, + ) + } +} From 767af4d1b82c88902b37fd2290b745b62e899a42 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Mon, 23 Feb 2026 01:03:16 +0900 Subject: [PATCH 09/15] =?UTF-8?q?feat:=20PrezelDatePicker=20=EA=B3=BC?= =?UTF-8?q?=EA=B1=B0=20=EB=82=A0=EC=A7=9C=20=EB=B9=84=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94=20=EB=B0=8F=20=EA=B0=80=EC=8B=9C=EC=84=B1=20=EC=A0=9C?= =?UTF-8?q?=EC=96=B4=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PrezelDatePicker 컴포넌트에서 오늘 이전의 날짜를 숨기고 선택할 수 없도록 개선하였습니다. * `DayCellUiModel` 및 `toUiModel`: `isVisible` 상태를 추가하고, 현재 월(isInMonth)에 해당하면서 오늘 이후인 날짜만 노출 및 활성화되도록 로직 수정 * `PrezelDatePicker`: `initialMonth`와 `today` 파라미터의 기본값을 설정하여 사용성을 높이고, 내부 `LazyColumn`의 여백을 디자인 시스템 토큰(`PrezelTheme.spacing.V16`)으로 교체 * `DatePickerDayCellView`: `uiModel.isVisible`이 `false`인 경우 날짜 텍스트를 렌더링하지 않도록 수정 및 코드 정렬 적용 --- .../datepicker/DatePickerDayCellView.kt | 23 ++++++++++--------- .../component/datepicker/DatePickerModel.kt | 9 ++++++-- .../component/datepicker/PrezelDatePicker.kt | 10 ++++---- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt index d6711fb4..35c8eb01 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -41,16 +41,17 @@ internal fun RowScope.DayCellView( ), contentAlignment = Alignment.Center, ) { - if (uiModel != null) { - Text( - text = uiModel.text, - color = uiModel.dayTextColor(), - style = if (uiModel.isSelected) { - PrezelTheme.typography.body3Bold - } else { - PrezelTheme.typography.body3Medium - }, - ) - } + if (uiModel == null) return@Box + if (!uiModel.isVisible) return@Box + + Text( + text = uiModel.text, + color = uiModel.dayTextColor(), + style = if (uiModel.isSelected) { + PrezelTheme.typography.body3Bold + } else { + PrezelTheme.typography.body3Medium + }, + ) } } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt index 138d29c5..02de4df6 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt @@ -17,16 +17,20 @@ internal data class DayCellUiModel( val isToday: Boolean, val isSunday: Boolean, val isInMonth: Boolean, + val isVisible: Boolean, val enabled: Boolean, ) internal fun DayCell.toUiModel( selectedDate: LocalDate?, today: LocalDate, - enabled: Boolean = isInMonth, + enabled: Boolean = true, ): DayCellUiModel? { if (date == null) return null + val isPast = date.isBefore(today) + val isVisible = isInMonth && !isPast + return DayCellUiModel( date = date, text = date.dayOfMonth.toString(), @@ -34,6 +38,7 @@ internal fun DayCell.toUiModel( isToday = date == today, isSunday = date.dayOfWeek == DayOfWeek.SUNDAY, isInMonth = isInMonth, - enabled = enabled && isInMonth, + isVisible = isVisible, + enabled = isVisible && enabled, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index a3dd9610..e6a30703 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -25,7 +25,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.R import com.team.prezel.core.designsystem.component.PrezelDividerType import com.team.prezel.core.designsystem.component.PrezelHorizontalDivider @@ -44,14 +43,14 @@ import java.time.YearMonth @Composable fun PrezelDatePicker( title: String, - initialMonth: YearMonth, - today: LocalDate, selectedDate: LocalDate?, onSelect: (LocalDate) -> Unit, onClose: () -> Unit, onConfirm: (LocalDate) -> Unit, modifier: Modifier = Modifier, + today: LocalDate = LocalDate.now(), ) { + val initialMonth = remember(today) { YearMonth.from(today) } val months = remember(initialMonth) { (0..12).map { initialMonth.plusMonths(it.toLong()) } } @@ -65,7 +64,7 @@ fun PrezelDatePicker( LazyColumn( modifier = Modifier.weight(1f), - contentPadding = PaddingValues(bottom = 16.dp), + contentPadding = PaddingValues(bottom = PrezelTheme.spacing.V16), ) { items(months, key = { it.toString() }) { month -> MonthSection( @@ -164,8 +163,7 @@ private fun PrezelDatePickerPreview() { PrezelDatePicker( title = "발표 날짜", - initialMonth = YearMonth.of(2026, 2), - today = LocalDate.of(2026, 2, 20), + today = LocalDate.of(2026, 2, 23), selectedDate = selected, onSelect = { selected = it }, onClose = {}, From 0bc6d1a9216fd43d2c0e959a391ef35180febe1d Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Tue, 24 Feb 2026 15:54:47 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactor:=20DatePicker=20UI=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=EC=9D=98=20=ED=95=84=EB=93=9C=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `DatePicker` 컴포넌트에서 사용되는 `DayCellUiModel`의 프로퍼티를 정리하고 관련 로직을 수정했습니다. * `DayCellUiModel`에서 불필요한 `date` 필드를 제거하고, `text`를 `dayText`로 변경하였습니다. * `DatePickerDayCellView`에서 변경된 `dayText` 필드를 사용하도록 수정하고, `Box` 컴포저블의 수정자(Modifier) 체이닝 가독성을 개선했습니다. --- .../component/datepicker/DatePickerDayCellView.kt | 2 +- .../designsystem/component/datepicker/DatePickerModel.kt | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt index 35c8eb01..e2b4eb6c 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -45,7 +45,7 @@ internal fun RowScope.DayCellView( if (!uiModel.isVisible) return@Box Text( - text = uiModel.text, + text = uiModel.dayText, color = uiModel.dayTextColor(), style = if (uiModel.isSelected) { PrezelTheme.typography.body3Bold diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt index 02de4df6..9aac1e5f 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt @@ -11,8 +11,7 @@ internal data class DayCell( @Immutable internal data class DayCellUiModel( - val date: LocalDate, - val text: String, + val dayText: String, val isSelected: Boolean, val isToday: Boolean, val isSunday: Boolean, @@ -32,8 +31,7 @@ internal fun DayCell.toUiModel( val isVisible = isInMonth && !isPast return DayCellUiModel( - date = date, - text = date.dayOfMonth.toString(), + dayText = date.dayOfMonth.toString(), isSelected = date == selectedDate, isToday = date == today, isSunday = date.dayOfWeek == DayOfWeek.SUNDAY, From f1ef9a70cac87136a35a8e6d65f35429691ad42f Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Tue, 24 Feb 2026 16:07:02 +0900 Subject: [PATCH 11/15] =?UTF-8?q?feat:=20PrezelDatePicker=20=ED=95=98?= =?UTF-8?q?=EB=8B=A8=20=ED=91=B8=ED=84=B0=20UI=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8B=AB=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: `PrezelDatePicker` 내 닫기 버튼 추가 및 레이아웃 수정 * `DatePickerFooter`에 `onClose` 콜백을 추가하고, 기존 `PrezelTextButton`을 `PrezelButtonArea`로 교체하여 확인/닫기 버튼이 공존하는 구조로 개선했습니다. * `PrezelButtonArea` 적용을 통해 버튼 영역의 배경 및 상단 구분선 스타일을 업데이트했습니다. * feat: 관련 문자열 리소스 추가 * `core_designsystem_date_picker_close_btn` ("닫기") 리소스를 추가했습니다. --- .../component/datepicker/PrezelDatePicker.kt | 33 +++++++++---------- .../src/main/res/values/strings.xml | 1 + 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index e6a30703..d4f7982e 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -29,11 +29,8 @@ import com.team.prezel.core.designsystem.R import com.team.prezel.core.designsystem.component.PrezelDividerType import com.team.prezel.core.designsystem.component.PrezelHorizontalDivider import com.team.prezel.core.designsystem.component.PrezelTopAppBar -import com.team.prezel.core.designsystem.component.button.PrezelButtonHierarchy -import com.team.prezel.core.designsystem.component.button.PrezelButtonSize -import com.team.prezel.core.designsystem.component.button.PrezelButtonStyle -import com.team.prezel.core.designsystem.component.button.PrezelButtonType -import com.team.prezel.core.designsystem.component.button.PrezelTextButton +import com.team.prezel.core.designsystem.component.button.ButtonAreaButtonSpec +import com.team.prezel.core.designsystem.component.button.PrezelButtonArea import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.theme.PrezelTheme import java.time.LocalDate @@ -76,7 +73,7 @@ fun PrezelDatePicker( } } - DatePickerFooter(selectedDate = selectedDate, onConfirm = onConfirm) + DatePickerFooter(selectedDate = selectedDate, onConfirm = onConfirm, onClose = onClose) } } @@ -107,21 +104,21 @@ private fun DatePickerHeader( private fun DatePickerFooter( selectedDate: LocalDate?, onConfirm: (LocalDate) -> Unit, + onClose: () -> Unit, ) { Column { - PrezelHorizontalDivider(type = PrezelDividerType.THICK) - PrezelTextButton( - text = stringResource(R.string.core_designsystem_date_picker_confirm_btn), - onClick = { selectedDate?.let(onConfirm) }, - modifier = Modifier - .fillMaxWidth() - .padding(PrezelTheme.spacing.V20), - enabled = selectedDate != null, - PrezelButtonStyle( - buttonType = PrezelButtonType.FILLED, - buttonHierarchy = PrezelButtonHierarchy.PRIMARY, - buttonSize = PrezelButtonSize.REGULAR, + PrezelButtonArea( + mainButton = ButtonAreaButtonSpec( + label = stringResource(R.string.core_designsystem_date_picker_confirm_btn), + onClick = { selectedDate?.let(onConfirm) }, + ), + subButton = ButtonAreaButtonSpec( + label = stringResource(R.string.core_designsystem_date_picker_close_btn), + onClick = onClose, ), + isVertical = false, + showBackground = true, + isStrongStrength = true, ) } } diff --git a/Prezel/core/designsystem/src/main/res/values/strings.xml b/Prezel/core/designsystem/src/main/res/values/strings.xml index 8f9e80c9..751a7cd3 100644 --- a/Prezel/core/designsystem/src/main/res/values/strings.xml +++ b/Prezel/core/designsystem/src/main/res/values/strings.xml @@ -4,6 +4,7 @@ 날짜 선택 닫기 체크박스 선택하기 +  닫기  From 9bd4f8b90a0e51362b3e320fb0d2ddd93dd5a027 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Wed, 25 Feb 2026 00:26:58 +0900 Subject: [PATCH 12/15] =?UTF-8?q?refactor:=20PrezelDatePicker=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelDatePicker`의 내부 데이터 모델과 렌더링 로직을 최적화하고, UI 구성을 일부 변경하였습니다. * **데이터 모델 및 그리드 생성 로직 개선**: * `DayCellUiModel`을 제거하고 `DayCell` 클래스로 통합하여 상태 관리를 단순화했습니다. * `buildMonthGrid`가 `LocalDate?` 리스트를 반환하도록 수정하고, `kotlinx-collections-immutable`을 적용하여 안정성을 높였습니다. * `DayCell`에서 `isSunday`, `dayText` 등을 직접 계산하도록 변경했습니다. * **UI 컴포넌트 리팩터링**: * `MonthGrid` 내부의 주간 반복 로직을 `WeekRow` 컴포저블로 분리했습니다. * `DayCellView`에서 사용되지 않는 `enabled` 상태를 제거하고 `isVisible` 기반의 클릭 처리를 적용했습니다. * 일요일 텍스트 색상 및 선택 상태 등에 따른 색상 적용 로직을 정리했습니다. * **기능 및 스타일 수정**: * `PrezelDatePicker`의 `LazyColumn`에 `overscrollEffect = null`을 추가하여 스크롤 효과를 제거했습니다. * `DatePickerFooter`에서 닫기 버튼(subButton)을 제거하고, 날짜가 선택되었을 때만 확인 버튼이 활성화되도록 수정했습니다. * 프리뷰 데이터의 `today` 날짜를 최신화했습니다. --- .../datepicker/DatePickerDayCellView.kt | 6 +-- .../component/datepicker/DatePickerModel.kt | 36 ++------------ .../component/datepicker/DatePickerStyle.kt | 3 +- .../component/datepicker/MonthGrid.kt | 48 ++++++++++++++----- .../component/datepicker/MonthGridBuilder.kt | 26 +++++----- .../component/datepicker/MonthSection.kt | 2 +- .../component/datepicker/PrezelDatePicker.kt | 31 +++++------- 7 files changed, 75 insertions(+), 77 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt index e2b4eb6c..4d16c03c 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -18,7 +18,7 @@ import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable internal fun RowScope.DayCellView( - uiModel: DayCellUiModel?, + uiModel: DayCell?, onClick: () -> Unit, ) { Box( @@ -34,10 +34,10 @@ internal fun RowScope.DayCellView( Color.Transparent }, ).clickable( - enabled = uiModel?.enabled == true, - onClick = onClick, indication = ripple(), interactionSource = null, + enabled = uiModel?.isVisible == true, + onClick = onClick, ), contentAlignment = Alignment.Center, ) { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt index 9aac1e5f..b6561ff1 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt @@ -4,39 +4,13 @@ import androidx.compose.runtime.Immutable import java.time.DayOfWeek import java.time.LocalDate -internal data class DayCell( - val date: LocalDate?, - val isInMonth: Boolean, -) - @Immutable -internal data class DayCellUiModel( - val dayText: String, +internal data class DayCell( + val date: LocalDate, val isSelected: Boolean, val isToday: Boolean, - val isSunday: Boolean, - val isInMonth: Boolean, val isVisible: Boolean, - val enabled: Boolean, -) - -internal fun DayCell.toUiModel( - selectedDate: LocalDate?, - today: LocalDate, - enabled: Boolean = true, -): DayCellUiModel? { - if (date == null) return null - - val isPast = date.isBefore(today) - val isVisible = isInMonth && !isPast - - return DayCellUiModel( - dayText = date.dayOfMonth.toString(), - isSelected = date == selectedDate, - isToday = date == today, - isSunday = date.dayOfWeek == DayOfWeek.SUNDAY, - isInMonth = isInMonth, - isVisible = isVisible, - enabled = isVisible && enabled, - ) +) { + val dayText: String = date.dayOfMonth.toString() + val isSunday: Boolean = date.dayOfWeek == DayOfWeek.SUNDAY } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt index 75ade291..ebffaafc 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerStyle.kt @@ -5,9 +5,8 @@ import androidx.compose.ui.graphics.Color import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable -internal fun DayCellUiModel.dayTextColor(): Color = +internal fun DayCell.dayTextColor(): Color = when { - !this.enabled -> PrezelTheme.colors.textDisabled this.isSelected -> PrezelTheme.colors.bgRegular this.isToday -> PrezelTheme.colors.interactiveRegular this.isSunday -> PrezelTheme.colors.accentMagentaRegular diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt index 82867685..52ac5bd9 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelTheme +import kotlinx.collections.immutable.ImmutableList import java.time.DayOfWeek import java.time.LocalDate import java.time.YearMonth @@ -27,17 +28,42 @@ internal fun MonthGrid( Column(modifier = Modifier.padding(top = PrezelTheme.spacing.V16)) { for (week in 0..lastWeek) { - Row(Modifier.fillMaxWidth()) { - for (day in 0 until 7) { - val cell = cells[week * 7 + day] - val uiModel = cell.toUiModel(selectedDate = selectedDate, today = today) - - DayCellView( - uiModel = uiModel, - onClick = { cell.date?.let(onSelect) }, - ) - } + WeekRow(cells = cells, week = week, selectedDate = selectedDate, today = today, onSelect = onSelect) + } + } +} + +@Composable +private fun WeekRow( + cells: ImmutableList, + week: Int, + selectedDate: LocalDate?, + today: LocalDate, + onSelect: (LocalDate) -> Unit, +) { + Row(modifier = Modifier.fillMaxWidth()) { + for (day in 0 until 7) { + val date = cells[week * 7 + day] + + if (date == null) { + DayCellView( + uiModel = null, + ) { } + continue } + + val isPast = date.isBefore(today) + val uiModel = DayCell( + date = date, + isSelected = date == selectedDate, + isToday = date == today, + isVisible = !isPast, + ) + + DayCellView( + uiModel = uiModel, + onClick = { onSelect(date) }, + ) } } } @@ -49,7 +75,7 @@ private fun MonthGridPreview() { MonthGrid( month = YearMonth.of(2026, 2), selectedDate = LocalDate.of(2026, 2, 26), - today = LocalDate.of(2026, 2, 23), + today = LocalDate.of(2026, 2, 25), onSelect = {}, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt index 2e508e95..97f14390 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt @@ -1,31 +1,35 @@ package com.team.prezel.core.designsystem.component.datepicker +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toPersistentList import java.time.DayOfWeek +import java.time.LocalDate import java.time.YearMonth internal fun buildMonthGrid( month: YearMonth, firstDayOfWeek: DayOfWeek, -): List { +): ImmutableList { val firstOfMonth = month.atDay(1) val lastDay = month.lengthOfMonth() val shift = ((firstOfMonth.dayOfWeek.value - firstDayOfWeek.value) + 7) % 7 val totalCells = 42 - return (0 until totalCells).map { index -> - val dayNumber = index - shift + 1 - if (dayNumber in 1..lastDay) { - DayCell(date = month.atDay(dayNumber), isInMonth = true) - } else { - DayCell(date = null, isInMonth = false) - } - } + return (0 until totalCells) + .map { index -> + val dayNumber = index - shift + 1 + if (dayNumber in 1..lastDay) { + month.atDay(dayNumber) + } else { + null + } + }.toPersistentList() } -internal fun lastWeekIndexToRender(cells: List): Int { +internal fun lastWeekIndexToRender(cells: List): Int { // 마지막으로 실제 날짜가 존재하는 셀 인덱스 (0..41) - val last = cells.indexOfLast { it.date != null } + val last = cells.indexOfLast { it != null } // month가 비정상일 경우 방어 if (last < 0) return 0 diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt index e911e0f0..f9025d25 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt @@ -42,7 +42,7 @@ private fun MonthSectionPreview() { MonthSection( month = YearMonth.of(2026, 2), selectedDate = LocalDate.of(2026, 2, 26), - today = LocalDate.of(2026, 2, 23), + today = LocalDate.of(2026, 2, 25), onSelect = {}, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index d4f7982e..37828120 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -62,8 +62,9 @@ fun PrezelDatePicker( LazyColumn( modifier = Modifier.weight(1f), contentPadding = PaddingValues(bottom = PrezelTheme.spacing.V16), + overscrollEffect = null, ) { - items(months, key = { it.toString() }) { month -> + items(items = months, key = { it.toString() }) { month -> MonthSection( month = month, selectedDate = selectedDate, @@ -73,7 +74,7 @@ fun PrezelDatePicker( } } - DatePickerFooter(selectedDate = selectedDate, onConfirm = onConfirm, onClose = onClose) + DatePickerFooter(selectedDate = selectedDate, onConfirm = onConfirm) } } @@ -104,23 +105,17 @@ private fun DatePickerHeader( private fun DatePickerFooter( selectedDate: LocalDate?, onConfirm: (LocalDate) -> Unit, - onClose: () -> Unit, ) { - Column { - PrezelButtonArea( - mainButton = ButtonAreaButtonSpec( - label = stringResource(R.string.core_designsystem_date_picker_confirm_btn), - onClick = { selectedDate?.let(onConfirm) }, - ), - subButton = ButtonAreaButtonSpec( - label = stringResource(R.string.core_designsystem_date_picker_close_btn), - onClick = onClose, - ), - isVertical = false, - showBackground = true, - isStrongStrength = true, - ) - } + PrezelButtonArea( + mainButton = ButtonAreaButtonSpec( + label = stringResource(R.string.core_designsystem_date_picker_confirm_btn), + enabled = selectedDate != null, + onClick = { selectedDate?.let(onConfirm) }, + ), + subButton = null, + isVertical = false, + showBackground = true, + ) } @Composable From ccc14c2845cc337d23b0e8edcf88db9553f82af2 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Wed, 25 Feb 2026 00:58:59 +0900 Subject: [PATCH 13/15] =?UTF-8?q?refactor:=20DatePicker=EC=97=90=EC=84=9C?= =?UTF-8?q?=20java.time=EC=9D=84=20kotlinx-datetime=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DatePicker 관련 컴포넌트에서 사용하던 `java.time` API를 멀티플랫폼 호환성을 위해 `kotlinx-datetime`으로 전면 교체하였습니다. * `PrezelDatePicker`, `MonthGrid`, `MonthSection` 등 주요 컴포넌트의 날짜 관련 타입을 `kotlinx.datetime.LocalDate`, `kotlinx.datetime.YearMonth` 등으로 변경했습니다. * 날짜 계산 및 비교 로직을 `kotlinx-datetime`의 API에 맞게 수정했습니다. (`plusMonths` -> `plus(DateTimeUnit.MONTH)`, `atDay` -> `onDay` 등) * `kotlinx-datetime` 라이브러리 의존성을 `core:designsystem` 모듈에 추가하고, `libs.versions.toml`에 관련 버전을 정의했습니다. * `PrezelDatePicker` 컴포넌트의 불필요한 `ExperimentalMaterial3Api` 어노테이션을 제거했습니다. --- Prezel/core/designsystem/build.gradle.kts | 1 + .../datepicker/DatePickerDayCellView.kt | 41 +++++++++++++++++++ .../component/datepicker/DatePickerModel.kt | 6 +-- .../component/datepicker/MonthGrid.kt | 20 ++++----- .../component/datepicker/MonthGridBuilder.kt | 18 ++++---- .../component/datepicker/MonthSection.kt | 17 ++++---- .../component/datepicker/PrezelDatePicker.kt | 24 +++++++---- .../src/main/res/values/strings.xml | 1 - Prezel/gradle/libs.versions.toml | 24 ++++++----- 9 files changed, 103 insertions(+), 49 deletions(-) diff --git a/Prezel/core/designsystem/build.gradle.kts b/Prezel/core/designsystem/build.gradle.kts index 229c0f1d..ab87ab2b 100644 --- a/Prezel/core/designsystem/build.gradle.kts +++ b/Prezel/core/designsystem/build.gradle.kts @@ -10,4 +10,5 @@ android { dependencies { implementation(libs.kotlinx.collections.immutable) implementation(libs.coil.kt.compose) + implementation(libs.kotlinx.datetime) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt index 4d16c03c..3aa2aaf7 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerDayCellView.kt @@ -3,9 +3,11 @@ package com.team.prezel.core.designsystem.component.datepicker import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Text import androidx.compose.material3.ripple @@ -14,7 +16,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelTheme +import kotlinx.datetime.LocalDate @Composable internal fun RowScope.DayCellView( @@ -55,3 +60,39 @@ internal fun RowScope.DayCellView( ) } } + +@ThemePreview +@Composable +private fun DayCellViewPreview() { + PrezelTheme { + Row(modifier = Modifier.width(320.dp)) { + DayCellView( + uiModel = DayCell( + date = LocalDate(2024, 1, 1), + isSelected = false, + isToday = false, + isVisible = true, + ), + onClick = {}, + ) + DayCellView( + uiModel = DayCell( + date = LocalDate(2024, 1, 2), + isSelected = true, + isToday = false, + isVisible = true, + ), + onClick = {}, + ) + DayCellView( + uiModel = DayCell( + date = LocalDate(2024, 1, 3), + isSelected = false, + isToday = true, + isVisible = true, + ), + onClick = {}, + ) + } + } +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt index b6561ff1..fce69a12 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt @@ -1,8 +1,8 @@ package com.team.prezel.core.designsystem.component.datepicker import androidx.compose.runtime.Immutable -import java.time.DayOfWeek -import java.time.LocalDate +import kotlinx.datetime.DayOfWeek +import kotlinx.datetime.LocalDate @Immutable internal data class DayCell( @@ -11,6 +11,6 @@ internal data class DayCell( val isToday: Boolean, val isVisible: Boolean, ) { - val dayText: String = date.dayOfMonth.toString() + val dayText: String = date.day.toString() val isSunday: Boolean = date.dayOfWeek == DayOfWeek.SUNDAY } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt index 52ac5bd9..0d70efe2 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGrid.kt @@ -10,19 +10,19 @@ import androidx.compose.ui.Modifier import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelTheme import kotlinx.collections.immutable.ImmutableList -import java.time.DayOfWeek -import java.time.LocalDate -import java.time.YearMonth +import kotlinx.datetime.DayOfWeek +import kotlinx.datetime.LocalDate +import kotlinx.datetime.YearMonth @Composable internal fun MonthGrid( - month: YearMonth, + yearMonth: YearMonth, selectedDate: LocalDate?, today: LocalDate, onSelect: (LocalDate) -> Unit, ) { - val (cells, lastWeek) = remember(month) { - val c = buildMonthGrid(month, firstDayOfWeek = DayOfWeek.SUNDAY) + val (cells, lastWeek) = remember(yearMonth) { + val c = buildMonthGrid(yearMonth = yearMonth, firstDayOfWeek = DayOfWeek.SUNDAY) c to lastWeekIndexToRender(c) } @@ -52,7 +52,7 @@ private fun WeekRow( continue } - val isPast = date.isBefore(today) + val isPast = date < today val uiModel = DayCell( date = date, isSelected = date == selectedDate, @@ -73,9 +73,9 @@ private fun WeekRow( private fun MonthGridPreview() { PrezelTheme { MonthGrid( - month = YearMonth.of(2026, 2), - selectedDate = LocalDate.of(2026, 2, 26), - today = LocalDate.of(2026, 2, 25), + yearMonth = YearMonth(year = 2026, month = 2), + selectedDate = LocalDate(year = 2026, month = 2, day = 26), + today = LocalDate(year = 2026, month = 2, day = 25), onSelect = {}, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt index 97f14390..64e2ac4c 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthGridBuilder.kt @@ -2,25 +2,27 @@ package com.team.prezel.core.designsystem.component.datepicker import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList -import java.time.DayOfWeek -import java.time.LocalDate -import java.time.YearMonth +import kotlinx.datetime.DayOfWeek +import kotlinx.datetime.LocalDate +import kotlinx.datetime.YearMonth +import kotlinx.datetime.isoDayNumber +import kotlinx.datetime.onDay internal fun buildMonthGrid( - month: YearMonth, + yearMonth: YearMonth, firstDayOfWeek: DayOfWeek, ): ImmutableList { - val firstOfMonth = month.atDay(1) - val lastDay = month.lengthOfMonth() + val firstOfMonth = yearMonth.onDay(1) + val lastDay = yearMonth.numberOfDays - val shift = ((firstOfMonth.dayOfWeek.value - firstDayOfWeek.value) + 7) % 7 + val shift = ((firstOfMonth.dayOfWeek.isoDayNumber - firstDayOfWeek.isoDayNumber) + 7) % 7 val totalCells = 42 return (0 until totalCells) .map { index -> val dayNumber = index - shift + 1 if (dayNumber in 1..lastDay) { - month.atDay(dayNumber) + yearMonth.onDay(dayNumber) } else { null } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt index f9025d25..0f264492 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt @@ -7,12 +7,13 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelTheme -import java.time.LocalDate -import java.time.YearMonth +import kotlinx.datetime.LocalDate +import kotlinx.datetime.YearMonth +import kotlinx.datetime.number @Composable internal fun MonthSection( - month: YearMonth, + yearMonth: YearMonth, selectedDate: LocalDate?, today: LocalDate, onSelect: (LocalDate) -> Unit, @@ -21,13 +22,13 @@ internal fun MonthSection( modifier = Modifier.padding(PrezelTheme.spacing.V20), ) { Text( - text = "${month.year}년 ${month.monthValue}월", + text = "${yearMonth.year}년 ${yearMonth.month.number}월", color = PrezelTheme.colors.textLarge, style = PrezelTheme.typography.body3Medium, ) MonthGrid( - month = month, + yearMonth = yearMonth, selectedDate = selectedDate, today = today, onSelect = onSelect, @@ -40,9 +41,9 @@ internal fun MonthSection( private fun MonthSectionPreview() { PrezelTheme { MonthSection( - month = YearMonth.of(2026, 2), - selectedDate = LocalDate.of(2026, 2, 26), - today = LocalDate.of(2026, 2, 25), + yearMonth = YearMonth(year = 2026, month = 2), + selectedDate = LocalDate(year = 2026, month = 2, day = 26), + today = LocalDate(year = 2026, month = 2, day = 25), onSelect = {}, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt index 37828120..51730dce 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/PrezelDatePicker.kt @@ -33,10 +33,14 @@ import com.team.prezel.core.designsystem.component.button.ButtonAreaButtonSpec import com.team.prezel.core.designsystem.component.button.PrezelButtonArea import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.theme.PrezelTheme -import java.time.LocalDate -import java.time.YearMonth +import kotlinx.datetime.DateTimeUnit +import kotlinx.datetime.LocalDate +import kotlinx.datetime.TimeZone +import kotlinx.datetime.YearMonth +import kotlinx.datetime.plus +import kotlinx.datetime.todayIn +import kotlin.time.Clock -@OptIn(ExperimentalMaterial3Api::class) @Composable fun PrezelDatePicker( title: String, @@ -45,11 +49,13 @@ fun PrezelDatePicker( onClose: () -> Unit, onConfirm: (LocalDate) -> Unit, modifier: Modifier = Modifier, - today: LocalDate = LocalDate.now(), + today: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault()), ) { - val initialMonth = remember(today) { YearMonth.from(today) } + val initialMonth = remember(today) { YearMonth(today.year, today.month) } val months = remember(initialMonth) { - (0..12).map { initialMonth.plusMonths(it.toLong()) } + List(12) { offset -> + initialMonth.plus(value = offset, unit = DateTimeUnit.MONTH) + } } Column( @@ -66,7 +72,7 @@ fun PrezelDatePicker( ) { items(items = months, key = { it.toString() }) { month -> MonthSection( - month = month, + yearMonth = month, selectedDate = selectedDate, today = today, onSelect = onSelect, @@ -150,12 +156,12 @@ private fun WeekdayRow() { private fun PrezelDatePickerPreview() { PrezelTheme { var selected by remember { - mutableStateOf(LocalDate.of(2026, 2, 26)) + mutableStateOf(LocalDate(year = 2026, month = 2, day = 26)) } PrezelDatePicker( title = "발표 날짜", - today = LocalDate.of(2026, 2, 23), + today = LocalDate(year = 2026, month = 2, day = 23), selectedDate = selected, onSelect = { selected = it }, onClose = {}, diff --git a/Prezel/core/designsystem/src/main/res/values/strings.xml b/Prezel/core/designsystem/src/main/res/values/strings.xml index 751a7cd3..8f9e80c9 100644 --- a/Prezel/core/designsystem/src/main/res/values/strings.xml +++ b/Prezel/core/designsystem/src/main/res/values/strings.xml @@ -4,7 +4,6 @@ 날짜 선택 닫기 체크박스 선택하기 -  닫기  diff --git a/Prezel/gradle/libs.versions.toml b/Prezel/gradle/libs.versions.toml index 0c8088a5..2e3fdc93 100644 --- a/Prezel/gradle/libs.versions.toml +++ b/Prezel/gradle/libs.versions.toml @@ -1,8 +1,6 @@ [versions] agp = "8.13.2" kotlin = "2.3.0" -kotlinMetadataJvm = "2.3.0" -kotlinxCoroutines = "1.10.2" coil = "2.7.0" coreKtx = "1.17.0" junit = "4.13.2" @@ -16,13 +14,16 @@ detekt = "1.23.8" ksp = "2.3.4" hilt = "2.58" desugarJdk = "2.1.5" -kotlintxCollectionsImmutable = "0.4.0" ktor = "3.3.3" ktorfit = "2.7.2" -kotlinx-serialization = "1.9.0" timber = "5.0.1" navigation3 = "1.0.0" +kotlinxDatetime = "0.7.1" +kotlinxCoroutines = "1.10.2" +kotlintxCollectionsImmutable = "0.4.0" +kotlinxSerialization = "1.9.0" + [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -45,12 +46,9 @@ hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" } hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" } hilt-core = { group = "com.google.dagger", name = "hilt-core", version.ref = "hilt" } -kotlin-metadata-jvm = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version.ref = "kotlinMetadataJvm" } +kotlin-metadata-jvm = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version.ref = "kotlin" } kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" } -kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlintxCollectionsImmutable" } -kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } -kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } -kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } + ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } @@ -58,10 +56,16 @@ ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } ktorfit-lib = { module = "de.jensklingenberg.ktorfit:ktorfit-lib", version.ref = "ktorfit" } ktorfit-ksp = { module = "de.jensklingenberg.ktorfit:ktorfit-ksp", version.ref = "ktorfit" } -kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" } timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } coil-kt-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } +kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlintxCollectionsImmutable" } +kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } +kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } + # Dependencies of the included build-logic android-gradleApiPlugin = { group = "com.android.tools.build", name = "gradle-api", version.ref = "agp" } compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } From 64ae167b9e6af6a0cad5b552bff09ff0840fb5ff Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Wed, 25 Feb 2026 01:00:44 +0900 Subject: [PATCH 14/15] =?UTF-8?q?refactor:=20DatePickerModel=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EB=AA=85=EC=9D=84=20DayCell=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DatePicker 관련 컴포넌트의 역할을 더 명확하게 나타내기 위해 `DatePickerModel.kt` 파일의 이름을 `DayCell.kt`로 변경했습니다. --- .../component/datepicker/{DatePickerModel.kt => DayCell.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/{DatePickerModel.kt => DayCell.kt} (100%) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DayCell.kt similarity index 100% rename from Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DatePickerModel.kt rename to Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/DayCell.kt From 6000f21b62142562106e651fbc4fdcee0f27892f Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Wed, 25 Feb 2026 01:11:09 +0900 Subject: [PATCH 15/15] =?UTF-8?q?refactor:=20DatePicker=20=EC=9B=94=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=20=ED=98=95=EC=8B=9D=EC=97=90=20=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EC=97=B4=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DatePicker의 월(Month) 표시 부분에 하드코딩된 문자열 대신, `%1$d년 %2$d월` 형식의 문자열 리소스를 사용하도록 수정했습니다. --- .../designsystem/component/datepicker/MonthSection.kt | 8 +++++++- Prezel/core/designsystem/src/main/res/values/strings.xml | 1 + Prezel/gradle/libs.versions.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt index 0f264492..12a57bbd 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/MonthSection.kt @@ -5,6 +5,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.team.prezel.core.designsystem.R import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelTheme import kotlinx.datetime.LocalDate @@ -22,7 +24,11 @@ internal fun MonthSection( modifier = Modifier.padding(PrezelTheme.spacing.V20), ) { Text( - text = "${yearMonth.year}년 ${yearMonth.month.number}월", + text = stringResource( + id = R.string.core_designsystem_date_picker_month_title, + yearMonth.year, + yearMonth.month.number, + ), color = PrezelTheme.colors.textLarge, style = PrezelTheme.typography.body3Medium, ) diff --git a/Prezel/core/designsystem/src/main/res/values/strings.xml b/Prezel/core/designsystem/src/main/res/values/strings.xml index 8f9e80c9..65940253 100644 --- a/Prezel/core/designsystem/src/main/res/values/strings.xml +++ b/Prezel/core/designsystem/src/main/res/values/strings.xml @@ -4,6 +4,7 @@ 날짜 선택 닫기 체크박스 선택하기 + %1$d년 %2$d월 diff --git a/Prezel/gradle/libs.versions.toml b/Prezel/gradle/libs.versions.toml index 2e3fdc93..a51a5f81 100644 --- a/Prezel/gradle/libs.versions.toml +++ b/Prezel/gradle/libs.versions.toml @@ -21,7 +21,7 @@ navigation3 = "1.0.0" kotlinxDatetime = "0.7.1" kotlinxCoroutines = "1.10.2" -kotlintxCollectionsImmutable = "0.4.0" +kotlinxCollectionsImmutable = "0.4.0" kotlinxSerialization = "1.9.0" [libraries] @@ -59,7 +59,7 @@ ktorfit-ksp = { module = "de.jensklingenberg.ktorfit:ktorfit-ksp", version.ref = timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } coil-kt-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } -kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlintxCollectionsImmutable" } +kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" }