Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e9a247b
feat: 커스텀 DatePicker 컴포넌트 구현
HamBeomJoon Feb 12, 2026
ad55165
Merge remote-tracking branch 'origin/develop' into feat/#53-prezel-da…
HamBeomJoon Feb 20, 2026
3ce1d48
feat: PrezelDatePicker 구현 및 관련 모델 구조 개선
HamBeomJoon Feb 20, 2026
cdb4fcf
refactor: PrezelDatePicker 상태 관리 로직 수정
HamBeomJoon Feb 20, 2026
fc7ba56
refactor: PrezelDatePicker 컴포넌트 구조 개선 및 문자열 리소스화
HamBeomJoon Feb 20, 2026
7d157b6
feat: DatePicker 기능 추가 및 스타일 개선
HamBeomJoon Feb 20, 2026
bf3059b
refactor: DatePicker 컴포넌트 구조 개선 및 디자인 시스템 테마 적용
HamBeomJoon Feb 22, 2026
e41832b
refactor: DatePicker UI 모델 및 스타일 처리 로직 개선
HamBeomJoon Feb 22, 2026
44d561c
refactor: DatePicker UI 컴포넌트 여백 수정 및 미리보기 추가
HamBeomJoon Feb 22, 2026
767af4d
feat: PrezelDatePicker 과거 날짜 비활성화 및 가시성 제어 로직 추가
HamBeomJoon Feb 22, 2026
0bc6d1a
refactor: DatePicker UI 모델의 필드명 변경 및 코드 정리
HamBeomJoon Feb 24, 2026
0269dfc
Merge remote-tracking branch 'origin/develop' into feat/#53-prezel-da…
HamBeomJoon Feb 24, 2026
f1ef9a7
feat: PrezelDatePicker 하단 푸터 UI 개선 및 닫기 버튼 추가
HamBeomJoon Feb 24, 2026
9bd4f8b
refactor: PrezelDatePicker 컴포넌트 구조 개선 및 기능 수정
HamBeomJoon Feb 24, 2026
ccc14c2
refactor: DatePicker에서 java.time을 kotlinx-datetime으로 마이그레이션
HamBeomJoon Feb 24, 2026
64ae167
refactor: DatePickerModel 파일명을 DayCell로 변경
HamBeomJoon Feb 24, 2026
6000f21
refactor: DatePicker 월 표시 형식에 문자열 리소스 적용
HamBeomJoon Feb 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Prezel/core/designsystem/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ android {
dependencies {
implementation(libs.kotlinx.collections.immutable)
implementation(libs.coil.kt.compose)
implementation(libs.kotlinx.datetime)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
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
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.preview.ThemePreview
import com.team.prezel.core.designsystem.theme.PrezelTheme
import kotlinx.datetime.LocalDate

@Composable
internal fun RowScope.DayCellView(
uiModel: DayCell?,
onClick: () -> Unit,
) {
Box(
modifier = Modifier
.weight(1f)
.aspectRatio(1f)
.padding(PrezelTheme.spacing.V4)
.clip(CircleShape)
.background(
if (uiModel?.isSelected == true) {
PrezelTheme.colors.interactiveRegular
} else {
Color.Transparent
},
).clickable(
indication = ripple(),
interactionSource = null,
enabled = uiModel?.isVisible == true,
onClick = onClick,
),
Comment thread
HamBeomJoon marked this conversation as resolved.
contentAlignment = Alignment.Center,
) {
if (uiModel == null) return@Box
if (!uiModel.isVisible) return@Box

Text(
text = uiModel.dayText,
color = uiModel.dayTextColor(),
style = if (uiModel.isSelected) {
PrezelTheme.typography.body3Bold
} else {
PrezelTheme.typography.body3Medium
},
)
}
}

@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 = {},
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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

@Composable
internal fun DayCell.dayTextColor(): Color =
when {
this.isSelected -> PrezelTheme.colors.bgRegular
this.isToday -> PrezelTheme.colors.interactiveRegular
this.isSunday -> PrezelTheme.colors.accentMagentaRegular
else -> PrezelTheme.colors.textMedium
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.team.prezel.core.designsystem.component.datepicker

import androidx.compose.runtime.Immutable
import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.LocalDate

@Immutable
internal data class DayCell(
val date: LocalDate,
val isSelected: Boolean,
val isToday: Boolean,
val isVisible: Boolean,
) {
val dayText: String = date.day.toString()
val isSunday: Boolean = date.dayOfWeek == DayOfWeek.SUNDAY
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
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 com.team.prezel.core.designsystem.preview.ThemePreview
import com.team.prezel.core.designsystem.theme.PrezelTheme
import kotlinx.collections.immutable.ImmutableList
import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.LocalDate
import kotlinx.datetime.YearMonth

@Composable
internal fun MonthGrid(
Comment thread
HamBeomJoon marked this conversation as resolved.
yearMonth: YearMonth,
selectedDate: LocalDate?,
today: LocalDate,
onSelect: (LocalDate) -> Unit,
) {
val (cells, lastWeek) = remember(yearMonth) {
val c = buildMonthGrid(yearMonth = yearMonth, firstDayOfWeek = DayOfWeek.SUNDAY)
c to lastWeekIndexToRender(c)
}

Column(modifier = Modifier.padding(top = PrezelTheme.spacing.V16)) {
for (week in 0..lastWeek) {
WeekRow(cells = cells, week = week, selectedDate = selectedDate, today = today, onSelect = onSelect)
}
}
}

@Composable
private fun WeekRow(
cells: ImmutableList<LocalDate?>,
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 < today
val uiModel = DayCell(
date = date,
isSelected = date == selectedDate,
isToday = date == today,
isVisible = !isPast,
)

DayCellView(
uiModel = uiModel,
onClick = { onSelect(date) },
)
}
}
}

@ThemePreview
@Composable
private fun MonthGridPreview() {
PrezelTheme {
MonthGrid(
yearMonth = YearMonth(year = 2026, month = 2),
selectedDate = LocalDate(year = 2026, month = 2, day = 26),
today = LocalDate(year = 2026, month = 2, day = 25),
onSelect = {},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.team.prezel.core.designsystem.component.datepicker

import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toPersistentList
import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.LocalDate
import kotlinx.datetime.YearMonth
import kotlinx.datetime.isoDayNumber
import kotlinx.datetime.onDay

internal fun buildMonthGrid(
yearMonth: YearMonth,
firstDayOfWeek: DayOfWeek,
): ImmutableList<LocalDate?> {
val firstOfMonth = yearMonth.onDay(1)
val lastDay = yearMonth.numberOfDays

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) {
yearMonth.onDay(dayNumber)
} else {
null
}
}.toPersistentList()
}

internal fun lastWeekIndexToRender(cells: List<LocalDate?>): Int {
// 마지막으로 실제 날짜가 존재하는 셀 인덱스 (0..41)
val last = cells.indexOfLast { it != null }
// month가 비정상일 경우 방어
if (last < 0) return 0

// 주 단위로 올림 → 마지막 날짜가 포함된 주 index (0..5)
return (last / 7).coerceIn(0, 5)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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.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
import kotlinx.datetime.YearMonth
import kotlinx.datetime.number

@Composable
internal fun MonthSection(
Comment thread
HamBeomJoon marked this conversation as resolved.
yearMonth: YearMonth,
selectedDate: LocalDate?,
today: LocalDate,
onSelect: (LocalDate) -> Unit,
) {
Column(
modifier = Modifier.padding(PrezelTheme.spacing.V20),
) {
Text(
text = stringResource(
id = R.string.core_designsystem_date_picker_month_title,
yearMonth.year,
yearMonth.month.number,
),
color = PrezelTheme.colors.textLarge,
style = PrezelTheme.typography.body3Medium,
)
Comment thread
HamBeomJoon marked this conversation as resolved.

MonthGrid(
yearMonth = yearMonth,
selectedDate = selectedDate,
today = today,
onSelect = onSelect,
)
}
}

@ThemePreview
@Composable
private fun MonthSectionPreview() {
PrezelTheme {
MonthSection(
yearMonth = YearMonth(year = 2026, month = 2),
selectedDate = LocalDate(year = 2026, month = 2, day = 26),
today = LocalDate(year = 2026, month = 2, day = 25),
onSelect = {},
)
}
}
Loading