From 1b6e8723dc48b2e14cedf99e0d2ae68e0434e62a Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Sat, 7 Mar 2026 21:01:38 +0900 Subject: [PATCH 01/13] feature: add callvan create date field --- .../ui/create/component/CallvanDateField.kt | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt new file mode 100644 index 0000000000..5156b32012 --- /dev/null +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -0,0 +1,222 @@ +package `in`.koreatech.koin.feature.callvan.ui.create.component + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +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.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.KeyboardArrowDown +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +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.rotate +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme +import `in`.koreatech.koin.feature.callvan.R +import java.util.Calendar + +@Composable +fun CallvanDateField( + formattedDate: String, + isPickerVisible: Boolean, + selectedYear: Int, + selectedMonth: Int, + selectedDay: Int, + onFieldClick: () -> Unit, + onYearIndexChange: (Int) -> Unit, + onMonthIndexChange: (Int) -> Unit, + onDayIndexChange: (Int) -> Unit, + onReset: () -> Unit, + onConfirm: () -> Unit +) { + Column(modifier = Modifier.fillMaxWidth()) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + CallvanSectionHeader( + label = stringResource(R.string.callvan_create_date_label), + hint = stringResource(R.string.callvan_create_date_hint) + ) + Row( + modifier = Modifier + .fillMaxWidth() + .background(KoinTheme.colors.neutral100, RoundedCornerShape(8.dp)) + .clickable(onClick = onFieldClick) + .padding(horizontal = 12.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = formattedDate, + style = KoinTheme.typography.regular14, + color = KoinTheme.colors.neutral800 + ) + Icon( + imageVector = Icons.Default.KeyboardArrowDown, + contentDescription = null, + tint = KoinTheme.colors.neutral800, + modifier = Modifier + .size(24.dp) + .rotate(if (isPickerVisible) 180f else 0f) + ) + } + } + AnimatedVisibility( + visible = isPickerVisible, + enter = expandVertically(), + exit = shrinkVertically() + ) { + CallvanDatePickerCard( + selectedYear = selectedYear, + selectedMonth = selectedMonth, + selectedDay = selectedDay, + onYearIndexChange = onYearIndexChange, + onMonthIndexChange = onMonthIndexChange, + onDayIndexChange = onDayIndexChange, + onReset = onReset, + onConfirm = onConfirm + ) + } + } +} + +@Composable +private fun CallvanDatePickerCard( + selectedYear: Int, + selectedMonth: Int, + selectedDay: Int, + onYearIndexChange: (Int) -> Unit, + onMonthIndexChange: (Int) -> Unit, + onDayIndexChange: (Int) -> Unit, + onReset: () -> Unit, + onConfirm: () -> Unit +) { + val currentYear = Calendar.getInstance().get(Calendar.YEAR) + val years = listOf("${currentYear}년", "${currentYear + 1}년") + val months = (1..12).map { "${it}월" } + val daysCount = Calendar.getInstance().apply { + set(Calendar.YEAR, selectedYear) + set(Calendar.MONTH, selectedMonth - 1) + }.getActualMaximum(Calendar.DAY_OF_MONTH) + val days = (1..daysCount).map { "${it}일" } + + val yearIndex = (selectedYear - currentYear).coerceIn(0, years.size - 1) + val monthIndex = (selectedMonth - 1).coerceIn(0, months.size - 1) + val dayIndex = (selectedDay - 1).coerceIn(0, days.size - 1) + + Card( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp), + shape = RoundedCornerShape(8.dp), + colors = CardDefaults.cardColors(containerColor = KoinTheme.colors.neutral100), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(40.dp, Alignment.CenterHorizontally) + ) { + CallvanScrollPicker( + items = years, + selectedIndex = yearIndex, + onIndexChange = onYearIndexChange, + modifier = Modifier.width(53.dp), + textAlign = TextAlign.End + ) + CallvanScrollPicker( + items = months, + selectedIndex = monthIndex, + onIndexChange = onMonthIndexChange, + modifier = Modifier.width(36.dp) + ) + CallvanScrollPicker( + items = days, + selectedIndex = dayIndex, + onIndexChange = onDayIndexChange, + modifier = Modifier.width(36.dp) + ) + } + HorizontalDivider(color = KoinTheme.colors.neutral200) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.End) + ) { + Text( + text = stringResource(R.string.callvan_create_picker_reset), + style = KoinTheme.typography.medium14, + color = RebrandKoinTheme.colors.primary500, + modifier = Modifier.clickable(onClick = onReset) + ) + Text( + text = stringResource(R.string.callvan_create_picker_confirm), + style = KoinTheme.typography.medium14, + color = RebrandKoinTheme.colors.primary500, + modifier = Modifier.clickable(onClick = onConfirm) + ) + } + } + } +} + +@Preview(showBackground = true) +@Composable +private fun CallvanDateFieldPreview() { + CallvanDateField( + formattedDate = "2026년 03월 07일", + isPickerVisible = false, + selectedYear = 2026, + selectedMonth = 3, + selectedDay = 7, + onFieldClick = {}, + onYearIndexChange = {}, + onMonthIndexChange = {}, + onDayIndexChange = {}, + onReset = {}, + onConfirm = {} + ) +} + +@Preview(showBackground = true) +@Composable +private fun CallvanDateFieldPickerVisiblePreview() { + CallvanDateField( + formattedDate = "2026년 03월 07일", + isPickerVisible = true, + selectedYear = 2026, + selectedMonth = 3, + selectedDay = 7, + onFieldClick = {}, + onYearIndexChange = {}, + onMonthIndexChange = {}, + onDayIndexChange = {}, + onReset = {}, + onConfirm = {} + ) +} From e5a40df1d5c0b8c7cfabef95667155edfcf48228 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Sat, 7 Mar 2026 21:49:24 +0900 Subject: [PATCH 02/13] fix: suppress LongParameterList in CallvanDateField --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index 5156b32012..5dc95d660c 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -33,6 +33,7 @@ import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R import java.util.Calendar +@Suppress("LongParameterList") @Composable fun CallvanDateField( formattedDate: String, @@ -101,6 +102,7 @@ fun CallvanDateField( } } +@Suppress("LongParameterList") @Composable private fun CallvanDatePickerCard( selectedYear: Int, From 63ad29bdab637b997125880db962c03ae2493133 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Sun, 8 Mar 2026 22:05:18 +0900 Subject: [PATCH 03/13] refactor: Optimize DatePicker performance and apply RebrandKoinTheme --- .../ui/create/component/CallvanDateField.kt | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index 5dc95d660c..c10b2e2245 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -11,8 +11,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material3.Card @@ -21,6 +19,7 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate @@ -28,10 +27,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R import java.util.Calendar +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList @Suppress("LongParameterList") @Composable @@ -41,14 +41,15 @@ fun CallvanDateField( selectedYear: Int, selectedMonth: Int, selectedDay: Int, - onFieldClick: () -> Unit, - onYearIndexChange: (Int) -> Unit, - onMonthIndexChange: (Int) -> Unit, - onDayIndexChange: (Int) -> Unit, - onReset: () -> Unit, - onConfirm: () -> Unit + modifier: Modifier = Modifier, + onFieldClick: () -> Unit = {}, + onYearIndexChange: (Int) -> Unit = {}, + onMonthIndexChange: (Int) -> Unit = {}, + onDayIndexChange: (Int) -> Unit = {}, + onReset: () -> Unit = {}, + onConfirm: () -> Unit = {} ) { - Column(modifier = Modifier.fillMaxWidth()) { + Column(modifier = modifier.fillMaxWidth()) { Column( modifier = Modifier .fillMaxWidth() @@ -62,7 +63,7 @@ fun CallvanDateField( Row( modifier = Modifier .fillMaxWidth() - .background(KoinTheme.colors.neutral100, RoundedCornerShape(8.dp)) + .background(RebrandKoinTheme.colors.neutral100, RebrandKoinTheme.shapes.small) .clickable(onClick = onFieldClick) .padding(horizontal = 12.dp, vertical = 8.dp), horizontalArrangement = Arrangement.SpaceBetween, @@ -70,13 +71,13 @@ fun CallvanDateField( ) { Text( text = formattedDate, - style = KoinTheme.typography.regular14, - color = KoinTheme.colors.neutral800 + style = RebrandKoinTheme.typography.regular14, + color = RebrandKoinTheme.colors.neutral800 ) Icon( imageVector = Icons.Default.KeyboardArrowDown, contentDescription = null, - tint = KoinTheme.colors.neutral800, + tint = RebrandKoinTheme.colors.neutral800, modifier = Modifier .size(24.dp) .rotate(if (isPickerVisible) 180f else 0f) @@ -108,31 +109,38 @@ private fun CallvanDatePickerCard( selectedYear: Int, selectedMonth: Int, selectedDay: Int, - onYearIndexChange: (Int) -> Unit, - onMonthIndexChange: (Int) -> Unit, - onDayIndexChange: (Int) -> Unit, - onReset: () -> Unit, - onConfirm: () -> Unit + modifier: Modifier = Modifier, + onYearIndexChange: (Int) -> Unit = {}, + onMonthIndexChange: (Int) -> Unit = {}, + onDayIndexChange: (Int) -> Unit = {}, + onReset: () -> Unit = {}, + onConfirm: () -> Unit = {} ) { val currentYear = Calendar.getInstance().get(Calendar.YEAR) - val years = listOf("${currentYear}년", "${currentYear + 1}년") - val months = (1..12).map { "${it}월" } + val years = persistentListOf("${currentYear}년", "${currentYear + 1}년") + val months = (1..12).map { "${it}월" }.toPersistentList() val daysCount = Calendar.getInstance().apply { set(Calendar.YEAR, selectedYear) set(Calendar.MONTH, selectedMonth - 1) }.getActualMaximum(Calendar.DAY_OF_MONTH) - val days = (1..daysCount).map { "${it}일" } + val days = (1..daysCount).map { "${it}일" }.toPersistentList() - val yearIndex = (selectedYear - currentYear).coerceIn(0, years.size - 1) - val monthIndex = (selectedMonth - 1).coerceIn(0, months.size - 1) - val dayIndex = (selectedDay - 1).coerceIn(0, days.size - 1) + val yearIndex = remember(selectedYear, currentYear) { + (selectedYear - currentYear).coerceIn(0, years.size - 1) + } + val monthIndex = remember(selectedMonth) { + (selectedMonth - 1).coerceIn(0, months.size - 1) + } + val dayIndex = remember(selectedDay, days.size) { + (selectedDay - 1).coerceIn(0, days.size - 1) + } Card( - modifier = Modifier + modifier = modifier .fillMaxWidth() .padding(horizontal = 24.dp), - shape = RoundedCornerShape(8.dp), - colors = CardDefaults.cardColors(containerColor = KoinTheme.colors.neutral100), + shape = RebrandKoinTheme.shapes.small, + colors = CardDefaults.cardColors(containerColor = RebrandKoinTheme.colors.neutral100), elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) ) { Column( @@ -149,36 +157,36 @@ private fun CallvanDatePickerCard( items = years, selectedIndex = yearIndex, onIndexChange = onYearIndexChange, - modifier = Modifier.width(53.dp), + modifier = Modifier.weight(1f), textAlign = TextAlign.End ) CallvanScrollPicker( items = months, selectedIndex = monthIndex, onIndexChange = onMonthIndexChange, - modifier = Modifier.width(36.dp) + modifier = Modifier.weight(1f) ) CallvanScrollPicker( items = days, selectedIndex = dayIndex, onIndexChange = onDayIndexChange, - modifier = Modifier.width(36.dp) + modifier = Modifier.weight(1f) ) } - HorizontalDivider(color = KoinTheme.colors.neutral200) + HorizontalDivider(color = RebrandKoinTheme.colors.neutral200) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.End) ) { Text( text = stringResource(R.string.callvan_create_picker_reset), - style = KoinTheme.typography.medium14, + style = RebrandKoinTheme.typography.medium14, color = RebrandKoinTheme.colors.primary500, modifier = Modifier.clickable(onClick = onReset) ) Text( text = stringResource(R.string.callvan_create_picker_confirm), - style = KoinTheme.typography.medium14, + style = RebrandKoinTheme.typography.medium14, color = RebrandKoinTheme.colors.primary500, modifier = Modifier.clickable(onClick = onConfirm) ) From 20cfac075d408131b31721bc01d80bb782f5d3bd Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:05:05 +0900 Subject: [PATCH 04/13] refactor: Refine UI design --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index c10b2e2245..17956eec34 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -150,15 +150,13 @@ private fun CallvanDatePickerCard( verticalArrangement = Arrangement.spacedBy(8.dp) ) { Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(40.dp, Alignment.CenterHorizontally) + modifier = Modifier.fillMaxWidth() ) { CallvanScrollPicker( items = years, selectedIndex = yearIndex, onIndexChange = onYearIndexChange, - modifier = Modifier.weight(1f), - textAlign = TextAlign.End + modifier = Modifier.weight(1f) ) CallvanScrollPicker( items = months, From 388620fd36d6f7d0f81363182758e4d0e3381feb Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:09:27 +0900 Subject: [PATCH 05/13] refactor: Remove unused imports --- .../koin/feature/callvan/ui/create/component/CallvanDateField.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index 17956eec34..06cde0dfce 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -24,7 +24,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme From e23eb47f2b94b46960ddeb03535b4a9530e4f46b Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:59:14 +0900 Subject: [PATCH 06/13] refactor: Optimize date calculation logic in CallvanDatePickerCard --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index 06cde0dfce..927beb3224 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -32,7 +32,6 @@ import java.util.Calendar import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList -@Suppress("LongParameterList") @Composable fun CallvanDateField( formattedDate: String, @@ -119,8 +118,8 @@ private fun CallvanDatePickerCard( val years = persistentListOf("${currentYear}년", "${currentYear + 1}년") val months = (1..12).map { "${it}월" }.toPersistentList() val daysCount = Calendar.getInstance().apply { - set(Calendar.YEAR, selectedYear) - set(Calendar.MONTH, selectedMonth - 1) + clear() + set(selectedYear, selectedMonth - 1, 1) }.getActualMaximum(Calendar.DAY_OF_MONTH) val days = (1..daysCount).map { "${it}일" }.toPersistentList() From 4f1bf676a1b4a891a67c80c5e4bc9149e4daeee3 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Thu, 12 Mar 2026 19:34:57 +0900 Subject: [PATCH 07/13] refactor: Replace Calender.get with indexed access operator --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index 927beb3224..dcc093e22a 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -114,7 +114,7 @@ private fun CallvanDatePickerCard( onReset: () -> Unit = {}, onConfirm: () -> Unit = {} ) { - val currentYear = Calendar.getInstance().get(Calendar.YEAR) + val currentYear = Calendar.getInstance()[Calendar.YEAR] val years = persistentListOf("${currentYear}년", "${currentYear + 1}년") val months = (1..12).map { "${it}월" }.toPersistentList() val daysCount = Calendar.getInstance().apply { From 514ef7dbb3b6d2b5a8629e92dca80f90c36ee70b Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Thu, 12 Mar 2026 19:55:11 +0900 Subject: [PATCH 08/13] refactor: Optimize date picker performance and add arrow animation --- .../ui/create/component/CallvanDateField.kt | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index dcc093e22a..c27b38a209 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -1,6 +1,7 @@ package `in`.koreatech.koin.feature.callvan.ui.create.component import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background @@ -19,6 +20,7 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -28,7 +30,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R -import java.util.Calendar +import java.time.Year +import java.time.YearMonth import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList @@ -41,12 +44,17 @@ fun CallvanDateField( selectedDay: Int, modifier: Modifier = Modifier, onFieldClick: () -> Unit = {}, - onYearIndexChange: (Int) -> Unit = {}, - onMonthIndexChange: (Int) -> Unit = {}, - onDayIndexChange: (Int) -> Unit = {}, + onYearChange: (Int) -> Unit = {}, + onMonthChange: (Int) -> Unit = {}, + onDayChange: (Int) -> Unit = {}, onReset: () -> Unit = {}, onConfirm: () -> Unit = {} ) { + val arrowRotation by animateFloatAsState( + targetValue = if (isPickerVisible) 180f else 0f, + label = "arrowRotation" + ) + Column(modifier = modifier.fillMaxWidth()) { Column( modifier = Modifier @@ -78,7 +86,7 @@ fun CallvanDateField( tint = RebrandKoinTheme.colors.neutral800, modifier = Modifier .size(24.dp) - .rotate(if (isPickerVisible) 180f else 0f) + .rotate(arrowRotation) ) } } @@ -91,9 +99,9 @@ fun CallvanDateField( selectedYear = selectedYear, selectedMonth = selectedMonth, selectedDay = selectedDay, - onYearIndexChange = onYearIndexChange, - onMonthIndexChange = onMonthIndexChange, - onDayIndexChange = onDayIndexChange, + onYearChange = onYearChange, + onMonthChange = onMonthChange, + onDayChange = onDayChange, onReset = onReset, onConfirm = onConfirm ) @@ -108,20 +116,19 @@ private fun CallvanDatePickerCard( selectedMonth: Int, selectedDay: Int, modifier: Modifier = Modifier, - onYearIndexChange: (Int) -> Unit = {}, - onMonthIndexChange: (Int) -> Unit = {}, - onDayIndexChange: (Int) -> Unit = {}, + onYearChange: (Int) -> Unit = {}, + onMonthChange: (Int) -> Unit = {}, + onDayChange: (Int) -> Unit = {}, onReset: () -> Unit = {}, onConfirm: () -> Unit = {} ) { - val currentYear = Calendar.getInstance()[Calendar.YEAR] - val years = persistentListOf("${currentYear}년", "${currentYear + 1}년") + val currentYear = remember { Year.now().value } + val years = remember(currentYear) { persistentListOf("${currentYear}년", "${currentYear + 1}년") } val months = (1..12).map { "${it}월" }.toPersistentList() - val daysCount = Calendar.getInstance().apply { - clear() - set(selectedYear, selectedMonth - 1, 1) - }.getActualMaximum(Calendar.DAY_OF_MONTH) - val days = (1..daysCount).map { "${it}일" }.toPersistentList() + val days = remember(selectedYear, selectedMonth) { + val daysCount = YearMonth.of(selectedYear, selectedMonth).lengthOfMonth() + (1..daysCount).map { "${it}일" }.toPersistentList() + } val yearIndex = remember(selectedYear, currentYear) { (selectedYear - currentYear).coerceIn(0, years.size - 1) @@ -153,19 +160,19 @@ private fun CallvanDatePickerCard( CallvanScrollPicker( items = years, selectedIndex = yearIndex, - onIndexChange = onYearIndexChange, + onIndexChange = { index -> onYearChange(currentYear + index) }, modifier = Modifier.weight(1f) ) CallvanScrollPicker( items = months, selectedIndex = monthIndex, - onIndexChange = onMonthIndexChange, + onIndexChange = { index -> onMonthChange(index + 1) }, modifier = Modifier.weight(1f) ) CallvanScrollPicker( items = days, selectedIndex = dayIndex, - onIndexChange = onDayIndexChange, + onIndexChange = { index -> onDayChange(index + 1) }, modifier = Modifier.weight(1f) ) } @@ -201,9 +208,9 @@ private fun CallvanDateFieldPreview() { selectedMonth = 3, selectedDay = 7, onFieldClick = {}, - onYearIndexChange = {}, - onMonthIndexChange = {}, - onDayIndexChange = {}, + onYearChange = {}, + onMonthChange = {}, + onDayChange = {}, onReset = {}, onConfirm = {} ) @@ -219,9 +226,9 @@ private fun CallvanDateFieldPickerVisiblePreview() { selectedMonth = 3, selectedDay = 7, onFieldClick = {}, - onYearIndexChange = {}, - onMonthIndexChange = {}, - onDayIndexChange = {}, + onYearChange = {}, + onMonthChange = {}, + onDayChange = {}, onReset = {}, onConfirm = {} ) From 0945a35c6ca0544b921c778f1f80fef0893fbc60 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Mon, 16 Mar 2026 01:46:30 +0900 Subject: [PATCH 09/13] refactor: add remember to months list and remove annotations --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index c27b38a209..c5ace0b3bd 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -109,7 +109,6 @@ fun CallvanDateField( } } -@Suppress("LongParameterList") @Composable private fun CallvanDatePickerCard( selectedYear: Int, @@ -124,7 +123,7 @@ private fun CallvanDatePickerCard( ) { val currentYear = remember { Year.now().value } val years = remember(currentYear) { persistentListOf("${currentYear}년", "${currentYear + 1}년") } - val months = (1..12).map { "${it}월" }.toPersistentList() + val months = remember { (1..12).map { "${it}월" }.toPersistentList() } val days = remember(selectedYear, selectedMonth) { val daysCount = YearMonth.of(selectedYear, selectedMonth).lengthOfMonth() (1..daysCount).map { "${it}일" }.toPersistentList() From 28b54549532a0cb10569e118a4b341db952319ee Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Mon, 16 Mar 2026 01:54:05 +0900 Subject: [PATCH 10/13] style: cleanup imports --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index c5ace0b3bd..b6b5c7dbf2 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -30,10 +30,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R -import java.time.Year -import java.time.YearMonth import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList +import java.time.Year +import java.time.YearMonth @Composable fun CallvanDateField( From 6a01da150c6e1bb38dad0b49bf909cdb6259a26f Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Mon, 16 Mar 2026 02:04:58 +0900 Subject: [PATCH 11/13] style: cleanup imports --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index b6b5c7dbf2..c5ace0b3bd 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -30,10 +30,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toPersistentList import java.time.Year import java.time.YearMonth +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList @Composable fun CallvanDateField( From 8ad2f03f9d453e6a8828864f6f3cad6e6da67bd7 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Mon, 16 Mar 2026 02:25:37 +0900 Subject: [PATCH 12/13] refactor: removing redundant key in remember --- .../feature/callvan/ui/create/component/CallvanDateField.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index c5ace0b3bd..bce016f5a4 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -122,7 +122,7 @@ private fun CallvanDatePickerCard( onConfirm: () -> Unit = {} ) { val currentYear = remember { Year.now().value } - val years = remember(currentYear) { persistentListOf("${currentYear}년", "${currentYear + 1}년") } + val years = remember { persistentListOf("${currentYear}년", "${currentYear + 1}년") } val months = remember { (1..12).map { "${it}월" }.toPersistentList() } val days = remember(selectedYear, selectedMonth) { val daysCount = YearMonth.of(selectedYear, selectedMonth).lengthOfMonth() From b944cd86106b5aebc1e351034780a2a64914c012 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Tue, 17 Mar 2026 14:31:17 +0900 Subject: [PATCH 13/13] refactor: add validation logic to CallvanDateField --- .../ui/create/component/CallvanDateField.kt | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt index bce016f5a4..ebd1f7ee97 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanDateField.kt @@ -30,7 +30,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R -import java.time.Year +import java.time.LocalDate import java.time.YearMonth import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList @@ -121,22 +121,33 @@ private fun CallvanDatePickerCard( onReset: () -> Unit = {}, onConfirm: () -> Unit = {} ) { - val currentYear = remember { Year.now().value } + val today = remember { LocalDate.now() } + val currentYear = remember { today.year } + val currentMonth = remember { today.monthValue } + val currentDay = remember { today.dayOfMonth } val years = remember { persistentListOf("${currentYear}년", "${currentYear + 1}년") } - val months = remember { (1..12).map { "${it}월" }.toPersistentList() } + val startMonth = remember(selectedYear) { + if (selectedYear == currentYear) currentMonth else 1 + } + val months = remember(selectedYear) { + (startMonth..12).map { "${it}월" }.toPersistentList() + } + val startDay = remember(selectedYear, selectedMonth) { + if (selectedYear == currentYear && selectedMonth == currentMonth) currentDay else 1 + } val days = remember(selectedYear, selectedMonth) { val daysCount = YearMonth.of(selectedYear, selectedMonth).lengthOfMonth() - (1..daysCount).map { "${it}일" }.toPersistentList() + (startDay..daysCount).map { "${it}일" }.toPersistentList() } val yearIndex = remember(selectedYear, currentYear) { (selectedYear - currentYear).coerceIn(0, years.size - 1) } - val monthIndex = remember(selectedMonth) { - (selectedMonth - 1).coerceIn(0, months.size - 1) + val monthIndex = remember(selectedMonth, startMonth) { + (selectedMonth - startMonth).coerceIn(0, months.size - 1) } - val dayIndex = remember(selectedDay, days.size) { - (selectedDay - 1).coerceIn(0, days.size - 1) + val dayIndex = remember(selectedDay, startDay, days.size) { + (selectedDay - startDay).coerceIn(0, days.size - 1) } Card( @@ -159,19 +170,29 @@ private fun CallvanDatePickerCard( CallvanScrollPicker( items = years, selectedIndex = yearIndex, - onIndexChange = { index -> onYearChange(currentYear + index) }, + onIndexChange = { index -> + val newYear = currentYear + index + onYearChange(newYear) + val newStartDay = if (newYear == currentYear && selectedMonth == currentMonth) currentDay else 1 + if (selectedDay < newStartDay) onDayChange(newStartDay) + }, modifier = Modifier.weight(1f) ) CallvanScrollPicker( items = months, selectedIndex = monthIndex, - onIndexChange = { index -> onMonthChange(index + 1) }, + onIndexChange = { index -> + val newMonth = startMonth + index + onMonthChange(newMonth) + val newStartDay = if (selectedYear == currentYear && newMonth == currentMonth) currentDay else 1 + if (selectedDay < newStartDay) onDayChange(newStartDay) + }, modifier = Modifier.weight(1f) ) CallvanScrollPicker( items = days, selectedIndex = dayIndex, - onIndexChange = { index -> onDayChange(index + 1) }, + onIndexChange = { index -> onDayChange(startDay + index) }, modifier = Modifier.weight(1f) ) }