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 ebd1f7ee97..2c625c6a0e 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
@@ -197,23 +197,7 @@ private fun CallvanDatePickerCard(
)
}
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 = RebrandKoinTheme.typography.medium14,
- color = RebrandKoinTheme.colors.primary500,
- modifier = Modifier.clickable(onClick = onReset)
- )
- Text(
- text = stringResource(R.string.callvan_create_picker_confirm),
- style = RebrandKoinTheme.typography.medium14,
- color = RebrandKoinTheme.colors.primary500,
- modifier = Modifier.clickable(onClick = onConfirm)
- )
- }
+ CallvanPickerFooter(onReset = onReset, onConfirm = onConfirm)
}
}
}
diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanPickerFooter.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanPickerFooter.kt
new file mode 100644
index 0000000000..db59ca5224
--- /dev/null
+++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanPickerFooter.kt
@@ -0,0 +1,38 @@
+package `in`.koreatech.koin.feature.callvan.ui.create.component
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme
+import `in`.koreatech.koin.feature.callvan.R
+
+@Composable
+fun CallvanPickerFooter(
+ onReset: () -> Unit,
+ onConfirm: () -> Unit
+) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.End)
+ ) {
+ Text(
+ text = stringResource(R.string.callvan_create_picker_reset),
+ style = RebrandKoinTheme.typography.medium14,
+ color = RebrandKoinTheme.colors.primary500,
+ modifier = Modifier.clickable(onClick = onReset)
+ )
+ Text(
+ text = stringResource(R.string.callvan_create_picker_confirm),
+ style = RebrandKoinTheme.typography.medium14,
+ color = RebrandKoinTheme.colors.primary500,
+ modifier = Modifier.clickable(onClick = onConfirm)
+ )
+ }
+}
diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanTimeField.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanTimeField.kt
new file mode 100644
index 0000000000..86aa7d5840
--- /dev/null
+++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanTimeField.kt
@@ -0,0 +1,212 @@
+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.border
+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.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Text
+import androidx.compose.material3.VerticalDivider
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+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
+import `in`.koreatech.koin.feature.callvan.R
+import java.util.Locale
+import kotlinx.collections.immutable.toImmutableList
+
+@Composable
+fun CallvanTimeField(
+ formattedTime: String,
+ isPickerVisible: Boolean,
+ isAm: Boolean,
+ selectedHour: Int,
+ selectedMinute: Int,
+ onFieldClick: () -> Unit = {},
+ onAmPmIndexChange: (Int) -> Unit = {},
+ onHourIndexChange: (Int) -> Unit = {},
+ onMinuteIndexChange: (Int) -> Unit = {},
+ onReset: () -> Unit = {},
+ onConfirm: () -> Unit = {}
+) {
+ val amPmText = stringResource(if (isAm) R.string.callvan_am else R.string.callvan_pm)
+
+ 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_time_label),
+ hint = stringResource(R.string.callvan_create_time_hint)
+ )
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .border(1.dp, RebrandKoinTheme.colors.neutral400, RoundedCornerShape(4.dp))
+ .clickable(onClick = onFieldClick),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = amPmText,
+ style = RebrandKoinTheme.typography.regular14,
+ color = RebrandKoinTheme.colors.neutral800,
+ modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
+ )
+ VerticalDivider(
+ modifier = Modifier.height(38.dp),
+ color = RebrandKoinTheme.colors.neutral400
+ )
+ Text(
+ text = formattedTime,
+ style = RebrandKoinTheme.typography.regular14,
+ color = RebrandKoinTheme.colors.neutral800,
+ modifier = Modifier
+ .weight(1f)
+ .padding(horizontal = 16.dp, vertical = 8.dp)
+ )
+ }
+ }
+ AnimatedVisibility(
+ visible = isPickerVisible,
+ enter = expandVertically(),
+ exit = shrinkVertically()
+ ) {
+ CallvanTimePickerCard(
+ isAm = isAm,
+ selectedHour = selectedHour,
+ selectedMinute = selectedMinute,
+ onAmPmIndexChange = onAmPmIndexChange,
+ onHourIndexChange = onHourIndexChange,
+ onMinuteIndexChange = onMinuteIndexChange,
+ onReset = onReset,
+ onConfirm = onConfirm
+ )
+ }
+ }
+}
+
+@Suppress("LongParameterList")
+@Composable
+private fun CallvanTimePickerCard(
+ isAm: Boolean,
+ selectedHour: Int,
+ selectedMinute: Int,
+ onAmPmIndexChange: (Int) -> Unit,
+ onHourIndexChange: (Int) -> Unit,
+ onMinuteIndexChange: (Int) -> Unit,
+ onReset: () -> Unit,
+ onConfirm: () -> Unit
+) {
+ val amLabel = stringResource(R.string.callvan_am)
+ val pmLabel = stringResource(R.string.callvan_pm)
+ val amPmItems = remember(amLabel, pmLabel) {
+ listOf(amLabel, pmLabel).toImmutableList()
+ }
+ val hourItems = remember {
+ (1..12).map { it.toString() }.toImmutableList()
+ }
+ val minuteItems = remember {
+ (0..59).map { String.format(Locale.ROOT, "%02d", it) }.toImmutableList()
+ }
+
+ val amPmIndex = if (isAm) 0 else 1
+ val hourIndex = (selectedHour - 1).coerceIn(0, 11)
+ val minuteIndex = selectedMinute.coerceIn(0, 59)
+
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 24.dp),
+ shape = RoundedCornerShape(8.dp),
+ colors = CardDefaults.cardColors(containerColor = RebrandKoinTheme.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()
+ ) {
+ CallvanScrollPicker(
+ items = amPmItems,
+ selectedIndex = amPmIndex,
+ onIndexChange = onAmPmIndexChange,
+ modifier = Modifier.weight(1f)
+ )
+ CallvanScrollPicker(
+ items = hourItems,
+ selectedIndex = hourIndex,
+ onIndexChange = onHourIndexChange,
+ modifier = Modifier.weight(1f),
+ textAlign = TextAlign.End
+ )
+ CallvanScrollPicker(
+ items = minuteItems,
+ selectedIndex = minuteIndex,
+ onIndexChange = onMinuteIndexChange,
+ modifier = Modifier.weight(1f),
+ textAlign = TextAlign.End
+ )
+ }
+ HorizontalDivider(color = RebrandKoinTheme.colors.neutral200)
+ CallvanPickerFooter(onReset = onReset, onConfirm = onConfirm)
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun CallvanTimeFieldPreview() {
+ CallvanTimeField(
+ formattedTime = "09:30",
+ isPickerVisible = false,
+ isAm = true,
+ selectedHour = 9,
+ selectedMinute = 30,
+ onFieldClick = {},
+ onAmPmIndexChange = {},
+ onHourIndexChange = {},
+ onMinuteIndexChange = {},
+ onReset = {},
+ onConfirm = {}
+ )
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun CallvanTimeFieldPickerVisiblePreview() {
+ CallvanTimeField(
+ formattedTime = "02:45",
+ isPickerVisible = true,
+ isAm = false,
+ selectedHour = 2,
+ selectedMinute = 45,
+ onFieldClick = {},
+ onAmPmIndexChange = {},
+ onHourIndexChange = {},
+ onMinuteIndexChange = {},
+ onReset = {},
+ onConfirm = {}
+ )
+}
diff --git a/feature/callvan/src/main/res/values/strings.xml b/feature/callvan/src/main/res/values/strings.xml
index d3325f4d50..1f0f872593 100644
--- a/feature/callvan/src/main/res/values/strings.xml
+++ b/feature/callvan/src/main/res/values/strings.xml
@@ -93,4 +93,7 @@
이미 신고가 접수된 사용자입니다.
같은 콜밴 참여자만 신고할 수 있습니다.
신고에 실패했습니다. 다시 시도해주세요.
-
\ No newline at end of file
+
+ 오전
+ 오후
+