From a42ae2aedf715da80dce12c435460eaa819f93af Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Sat, 7 Mar 2026 21:01:21 +0900 Subject: [PATCH 1/9] feature: add callvan create location picker --- .../CallvanLocationPickerBottomSheet.kt | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt new file mode 100644 index 0000000000..1e7299613c --- /dev/null +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -0,0 +1,165 @@ +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.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.PaddingValues +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.foundation.text.BasicTextField +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.HorizontalDivider +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.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.component.button.FilledButton +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme +import `in`.koreatech.koin.feature.callvan.R +import `in`.koreatech.koin.feature.callvan.model.CallvanLocationOption +import `in`.koreatech.koin.feature.callvan.ui.component.CallvanBottomSheet + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun CallvanLocationPickerBottomSheet( + isDeparture: Boolean, + initialSelection: CallvanLocationOption? = null, + initialCustomText: String? = null, + onLocationSelected: (CallvanLocationOption, String?) -> Unit, + onDismiss: () -> Unit +) { + var selectedLocation by remember { mutableStateOf(initialSelection) } + var customText by remember { mutableStateOf(initialCustomText ?: "") } + val isOtherSelected = selectedLocation == CallvanLocationOption.OTHER + + CallvanBottomSheet( + title = stringResource( + if (isDeparture) { + R.string.callvan_create_departure_picker_question + } else { + R.string.callvan_create_arrival_picker_question + } + ), + onDismiss = onDismiss, + showCloseButton = true + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + FlowRow( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + CallvanLocationOption.entries.forEach { location -> + val isSelected = selectedLocation == location + Box( + modifier = Modifier + .height(34.dp) + .border( + width = 1.dp, + color = if (isSelected) { + RebrandKoinTheme.colors.primary500 + } else { + KoinTheme.colors.neutral300 + }, + shape = RoundedCornerShape(24.dp) + ) + .clip(RoundedCornerShape(24.dp)) + .background(Color.Transparent) + .clickable { + selectedLocation = location + if (location != CallvanLocationOption.OTHER) customText = "" + } + .padding(horizontal = 12.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = location.displayName, + style = KoinTheme.typography.medium14, + color = if (isSelected) { + RebrandKoinTheme.colors.primary500 + } else { + KoinTheme.colors.neutral500 + } + ) + } + } + } + AnimatedVisibility( + visible = isOtherSelected, + enter = expandVertically(), + exit = shrinkVertically() + ) { + BasicTextField( + value = customText, + onValueChange = { customText = it }, + singleLine = true, + textStyle = KoinTheme.typography.regular14.copy( + color = KoinTheme.colors.neutral600 + ), + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp) + .border(1.dp, KoinTheme.colors.neutral300, RoundedCornerShape(12.dp)) + .background(Color.White, RoundedCornerShape(12.dp)) + .padding(horizontal = 20.dp, vertical = 13.dp) + ) + } + HorizontalDivider( + color = KoinTheme.colors.neutral300, + thickness = 0.5.dp + ) + } + FilledButton( + text = stringResource( + if (isOtherSelected) { + R.string.callvan_create_location_picker_confirm_other + } else { + R.string.callvan_create_location_picker_select + } + ), + onClick = { + selectedLocation?.let { loc -> + onLocationSelected(loc, if (isOtherSelected) customText else null) + } + }, + enabled = selectedLocation != null && (!isOtherSelected || customText.isNotBlank()), + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp), + textStyle = KoinTheme.typography.bold16, + contentPadding = PaddingValues(vertical = 10.dp), + colors = ButtonDefaults.buttonColors( + containerColor = RebrandKoinTheme.colors.primary500, + disabledContainerColor = KoinTheme.colors.neutral400, + contentColor = Color.White, + disabledContentColor = Color.White + ) + ) + } + } +} From 72cebc4d9e333bfcb475aa2cffdec734e380eefe Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Sun, 8 Mar 2026 18:32:08 +0900 Subject: [PATCH 2/9] refactor: Optimize state management and apply RebrandKoinTheme --- .../CallvanLocationPickerBottomSheet.kt | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index 1e7299613c..25987ea0ca 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -21,6 +21,7 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -32,7 +33,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.component.button.FilledButton -import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R import `in`.koreatech.koin.feature.callvan.model.CallvanLocationOption @@ -42,14 +42,15 @@ import `in`.koreatech.koin.feature.callvan.ui.component.CallvanBottomSheet @Composable fun CallvanLocationPickerBottomSheet( isDeparture: Boolean, + modifier: Modifier = Modifier, initialSelection: CallvanLocationOption? = null, initialCustomText: String? = null, - onLocationSelected: (CallvanLocationOption, String?) -> Unit, - onDismiss: () -> Unit + onLocationSelected: (CallvanLocationOption, String?) -> Unit = { _, _ -> }, + onDismiss: () -> Unit = {} ) { var selectedLocation by remember { mutableStateOf(initialSelection) } var customText by remember { mutableStateOf(initialCustomText ?: "") } - val isOtherSelected = selectedLocation == CallvanLocationOption.OTHER + val isOtherSelected by remember { derivedStateOf { selectedLocation == CallvanLocationOption.OTHER } } CallvanBottomSheet( title = stringResource( @@ -63,7 +64,7 @@ fun CallvanLocationPickerBottomSheet( showCloseButton = true ) { Column( - modifier = Modifier + modifier = modifier .fillMaxWidth() .padding(horizontal = 32.dp, vertical = 12.dp), verticalArrangement = Arrangement.spacedBy(24.dp) @@ -85,7 +86,7 @@ fun CallvanLocationPickerBottomSheet( color = if (isSelected) { RebrandKoinTheme.colors.primary500 } else { - KoinTheme.colors.neutral300 + RebrandKoinTheme.colors.neutral300 }, shape = RoundedCornerShape(24.dp) ) @@ -100,11 +101,11 @@ fun CallvanLocationPickerBottomSheet( ) { Text( text = location.displayName, - style = KoinTheme.typography.medium14, + style = RebrandKoinTheme.typography.medium14, color = if (isSelected) { RebrandKoinTheme.colors.primary500 } else { - KoinTheme.colors.neutral500 + RebrandKoinTheme.colors.neutral500 } ) } @@ -119,19 +120,19 @@ fun CallvanLocationPickerBottomSheet( value = customText, onValueChange = { customText = it }, singleLine = true, - textStyle = KoinTheme.typography.regular14.copy( - color = KoinTheme.colors.neutral600 + textStyle = RebrandKoinTheme.typography.regular14.copy( + color = RebrandKoinTheme.colors.neutral600 ), modifier = Modifier .fillMaxWidth() .padding(top = 4.dp) - .border(1.dp, KoinTheme.colors.neutral300, RoundedCornerShape(12.dp)) - .background(Color.White, RoundedCornerShape(12.dp)) + .border(1.dp, RebrandKoinTheme.colors.neutral300, RebrandKoinTheme.shapes.medium) + .background(RebrandKoinTheme.colors.neutral0, RebrandKoinTheme.shapes.medium) .padding(horizontal = 20.dp, vertical = 13.dp) ) } HorizontalDivider( - color = KoinTheme.colors.neutral300, + color = RebrandKoinTheme.colors.neutral300, thickness = 0.5.dp ) } @@ -150,14 +151,14 @@ fun CallvanLocationPickerBottomSheet( }, enabled = selectedLocation != null && (!isOtherSelected || customText.isNotBlank()), modifier = Modifier.fillMaxWidth(), - shape = RoundedCornerShape(12.dp), - textStyle = KoinTheme.typography.bold16, + shape = RebrandKoinTheme.shapes.medium, + textStyle = RebrandKoinTheme.typography.bold16, contentPadding = PaddingValues(vertical = 10.dp), colors = ButtonDefaults.buttonColors( containerColor = RebrandKoinTheme.colors.primary500, - disabledContainerColor = KoinTheme.colors.neutral400, - contentColor = Color.White, - disabledContentColor = Color.White + disabledContainerColor = RebrandKoinTheme.colors.neutral400, + contentColor = RebrandKoinTheme.colors.neutral0, + disabledContentColor = RebrandKoinTheme.colors.neutral0 ) ) } From 2eac09a8000f74da97b9379790dfa7306a465e7b Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:57:05 +0900 Subject: [PATCH 3/9] fix: resolve errors from previous PR changes --- .../ui/create/component/CallvanLocationPickerBottomSheet.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index 25987ea0ca..3871619bdc 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -50,7 +50,7 @@ fun CallvanLocationPickerBottomSheet( ) { var selectedLocation by remember { mutableStateOf(initialSelection) } var customText by remember { mutableStateOf(initialCustomText ?: "") } - val isOtherSelected by remember { derivedStateOf { selectedLocation == CallvanLocationOption.OTHER } } + val isOtherSelected by remember { derivedStateOf { selectedLocation == CallvanLocationOption.CUSTOM } } CallvanBottomSheet( title = stringResource( @@ -94,13 +94,13 @@ fun CallvanLocationPickerBottomSheet( .background(Color.Transparent) .clickable { selectedLocation = location - if (location != CallvanLocationOption.OTHER) customText = "" + if (location != CallvanLocationOption.CUSTOM) customText = "" } .padding(horizontal = 12.dp), contentAlignment = Alignment.Center ) { Text( - text = location.displayName, + text = stringResource(location.displayNameRes), style = RebrandKoinTheme.typography.medium14, color = if (isSelected) { RebrandKoinTheme.colors.primary500 From 2e8892dad0cdcac79349ad1979aeedaf30b908a7 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Thu, 12 Mar 2026 17:31:59 +0900 Subject: [PATCH 4/9] fix: sync initial state and add previews --- .../CallvanLocationPickerBottomSheet.kt | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index 3871619bdc..ea48fc164b 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -31,6 +31,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.component.button.FilledButton import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme @@ -48,9 +51,20 @@ fun CallvanLocationPickerBottomSheet( onLocationSelected: (CallvanLocationOption, String?) -> Unit = { _, _ -> }, onDismiss: () -> Unit = {} ) { - var selectedLocation by remember { mutableStateOf(initialSelection) } - var customText by remember { mutableStateOf(initialCustomText ?: "") } + var selectedLocation by remember(initialSelection) { mutableStateOf(initialSelection) } + var customText by remember(initialSelection, initialCustomText) { + mutableStateOf( + if (initialSelection == CallvanLocationOption.CUSTOM) initialCustomText.orEmpty() else "" + ) + } val isOtherSelected by remember { derivedStateOf { selectedLocation == CallvanLocationOption.CUSTOM } } + val customInputDescription = stringResource( + if (isDeparture) { + R.string.callvan_create_departure_placeholder + } else { + R.string.callvan_create_arrival_placeholder + } + ) CallvanBottomSheet( title = stringResource( @@ -124,6 +138,9 @@ fun CallvanLocationPickerBottomSheet( color = RebrandKoinTheme.colors.neutral600 ), modifier = Modifier + .semantics { + contentDescription = customInputDescription + } .fillMaxWidth() .padding(top = 4.dp) .border(1.dp, RebrandKoinTheme.colors.neutral300, RebrandKoinTheme.shapes.medium) @@ -164,3 +181,31 @@ fun CallvanLocationPickerBottomSheet( } } } + +@Preview(showBackground = true) +@Composable +private fun CallvanLocationPickerBottomSheetPreview() { + RebrandKoinTheme { + CallvanLocationPickerBottomSheet( + isDeparture = true, + initialSelection = CallvanLocationOption.FRONT_GATE, + initialCustomText = null, + onLocationSelected = { _, _ -> }, + onDismiss = {} + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun CallvanLocationPickerBottomSheetCustomPreview() { + RebrandKoinTheme { + CallvanLocationPickerBottomSheet( + isDeparture = true, + initialSelection = CallvanLocationOption.CUSTOM, + initialCustomText = "test test test", + onLocationSelected = { _, _ -> }, + onDismiss = {} + ) + } +} From 85098cc599e2c7099ba8920a6553ad2b915c68f4 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Thu, 12 Mar 2026 17:43:49 +0900 Subject: [PATCH 5/9] chore: remove transparent background --- .../ui/create/component/CallvanLocationPickerBottomSheet.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index ea48fc164b..f664764da0 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.setValue 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.res.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics @@ -105,7 +104,6 @@ fun CallvanLocationPickerBottomSheet( shape = RoundedCornerShape(24.dp) ) .clip(RoundedCornerShape(24.dp)) - .background(Color.Transparent) .clickable { selectedLocation = location if (location != CallvanLocationOption.CUSTOM) customText = "" From 2b28e785304e3f6d9a809792379761f06ff9d150 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:19:25 +0900 Subject: [PATCH 6/9] chore: add trim --- .../ui/create/component/CallvanLocationPickerBottomSheet.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/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index f664764da0..6203eeff6e 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -161,7 +161,7 @@ fun CallvanLocationPickerBottomSheet( ), onClick = { selectedLocation?.let { loc -> - onLocationSelected(loc, if (isOtherSelected) customText else null) + onLocationSelected(loc, if (isOtherSelected) customText.trim() else null) } }, enabled = selectedLocation != null && (!isOtherSelected || customText.isNotBlank()), From a33126509e755fa10733b403707ecff26c729b96 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Mon, 16 Mar 2026 00:26:28 +0900 Subject: [PATCH 7/9] refactor: extract sub-components from CallvanLocationPickerBottomSheet --- .../CallvanLocationPickerBottomSheet.kt | 151 ++++++++++-------- 1 file changed, 82 insertions(+), 69 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index 6203eeff6e..4a181c161d 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -30,8 +30,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.component.button.FilledButton @@ -39,8 +37,8 @@ import `in`.koreatech.koin.core.designsystem.theme.RebrandKoinTheme import `in`.koreatech.koin.feature.callvan.R import `in`.koreatech.koin.feature.callvan.model.CallvanLocationOption import `in`.koreatech.koin.feature.callvan.ui.component.CallvanBottomSheet +import `in`.koreatech.koin.feature.callvan.ui.displayNameRes -@OptIn(ExperimentalLayoutApi::class) @Composable fun CallvanLocationPickerBottomSheet( isDeparture: Boolean, @@ -57,13 +55,6 @@ fun CallvanLocationPickerBottomSheet( ) } val isOtherSelected by remember { derivedStateOf { selectedLocation == CallvanLocationOption.CUSTOM } } - val customInputDescription = stringResource( - if (isDeparture) { - R.string.callvan_create_departure_placeholder - } else { - R.string.callvan_create_arrival_placeholder - } - ) CallvanBottomSheet( title = stringResource( @@ -85,67 +76,18 @@ fun CallvanLocationPickerBottomSheet( Column( verticalArrangement = Arrangement.spacedBy(12.dp) ) { - FlowRow( - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - CallvanLocationOption.entries.forEach { location -> - val isSelected = selectedLocation == location - Box( - modifier = Modifier - .height(34.dp) - .border( - width = 1.dp, - color = if (isSelected) { - RebrandKoinTheme.colors.primary500 - } else { - RebrandKoinTheme.colors.neutral300 - }, - shape = RoundedCornerShape(24.dp) - ) - .clip(RoundedCornerShape(24.dp)) - .clickable { - selectedLocation = location - if (location != CallvanLocationOption.CUSTOM) customText = "" - } - .padding(horizontal = 12.dp), - contentAlignment = Alignment.Center - ) { - Text( - text = stringResource(location.displayNameRes), - style = RebrandKoinTheme.typography.medium14, - color = if (isSelected) { - RebrandKoinTheme.colors.primary500 - } else { - RebrandKoinTheme.colors.neutral500 - } - ) - } + CallvanLocationChipGroup( + selectedLocation = selectedLocation, + onLocationClick = { location -> + selectedLocation = location + if (location != CallvanLocationOption.CUSTOM) customText = "" } - } - AnimatedVisibility( + ) + CallvanCustomLocationInput( visible = isOtherSelected, - enter = expandVertically(), - exit = shrinkVertically() - ) { - BasicTextField( - value = customText, - onValueChange = { customText = it }, - singleLine = true, - textStyle = RebrandKoinTheme.typography.regular14.copy( - color = RebrandKoinTheme.colors.neutral600 - ), - modifier = Modifier - .semantics { - contentDescription = customInputDescription - } - .fillMaxWidth() - .padding(top = 4.dp) - .border(1.dp, RebrandKoinTheme.colors.neutral300, RebrandKoinTheme.shapes.medium) - .background(RebrandKoinTheme.colors.neutral0, RebrandKoinTheme.shapes.medium) - .padding(horizontal = 20.dp, vertical = 13.dp) - ) - } + value = customText, + onValueChange = { customText = it } + ) HorizontalDivider( color = RebrandKoinTheme.colors.neutral300, thickness = 0.5.dp @@ -180,6 +122,77 @@ fun CallvanLocationPickerBottomSheet( } } +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun CallvanLocationChipGroup( + selectedLocation: CallvanLocationOption? = null, + onLocationClick: (CallvanLocationOption) -> Unit = {} +) { + FlowRow( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + CallvanLocationOption.entries.forEach { location -> + val isSelected = selectedLocation == location + Box( + modifier = Modifier + .height(34.dp) + .border( + width = 1.dp, + color = if (isSelected) { + RebrandKoinTheme.colors.primary500 + } else { + RebrandKoinTheme.colors.neutral300 + }, + shape = RoundedCornerShape(24.dp) + ) + .clip(RoundedCornerShape(24.dp)) + .clickable { onLocationClick(location) } + .padding(horizontal = 12.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = stringResource(location.displayNameRes()), + style = RebrandKoinTheme.typography.medium14, + color = if (isSelected) { + RebrandKoinTheme.colors.primary500 + } else { + RebrandKoinTheme.colors.neutral500 + } + ) + } + } + } +} + +@Composable +private fun CallvanCustomLocationInput( + visible: Boolean, + value: String, + onValueChange: (String) -> Unit = {} +) { + AnimatedVisibility( + visible = visible, + enter = expandVertically(), + exit = shrinkVertically() + ) { + BasicTextField( + value = value, + onValueChange = onValueChange, + singleLine = true, + textStyle = RebrandKoinTheme.typography.regular14.copy( + color = RebrandKoinTheme.colors.neutral600 + ), + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp) + .border(1.dp, RebrandKoinTheme.colors.neutral300, RebrandKoinTheme.shapes.medium) + .background(RebrandKoinTheme.colors.neutral0, RebrandKoinTheme.shapes.medium) + .padding(horizontal = 20.dp, vertical = 13.dp) + ) + } +} + @Preview(showBackground = true) @Composable private fun CallvanLocationPickerBottomSheetPreview() { From c3937bce0d9f6cf8cd789baabb134588c65a31b5 Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Mon, 16 Mar 2026 00:56:21 +0900 Subject: [PATCH 8/9] refactor: rename isOtherSelected to isCustomSelected and fix background clipping --- .../component/CallvanLocationPickerBottomSheet.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index 4a181c161d..307d5ab7eb 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -54,7 +54,7 @@ fun CallvanLocationPickerBottomSheet( if (initialSelection == CallvanLocationOption.CUSTOM) initialCustomText.orEmpty() else "" ) } - val isOtherSelected by remember { derivedStateOf { selectedLocation == CallvanLocationOption.CUSTOM } } + val isCustomSelected by remember { derivedStateOf { selectedLocation == CallvanLocationOption.CUSTOM } } CallvanBottomSheet( title = stringResource( @@ -84,7 +84,7 @@ fun CallvanLocationPickerBottomSheet( } ) CallvanCustomLocationInput( - visible = isOtherSelected, + visible = isCustomSelected, value = customText, onValueChange = { customText = it } ) @@ -95,7 +95,7 @@ fun CallvanLocationPickerBottomSheet( } FilledButton( text = stringResource( - if (isOtherSelected) { + if (isCustomSelected) { R.string.callvan_create_location_picker_confirm_other } else { R.string.callvan_create_location_picker_select @@ -103,10 +103,10 @@ fun CallvanLocationPickerBottomSheet( ), onClick = { selectedLocation?.let { loc -> - onLocationSelected(loc, if (isOtherSelected) customText.trim() else null) + onLocationSelected(loc, if (isCustomSelected) customText.trim() else null) } }, - enabled = selectedLocation != null && (!isOtherSelected || customText.isNotBlank()), + enabled = selectedLocation != null && (!isCustomSelected || customText.isNotBlank()), modifier = Modifier.fillMaxWidth(), shape = RebrandKoinTheme.shapes.medium, textStyle = RebrandKoinTheme.typography.bold16, @@ -125,7 +125,7 @@ fun CallvanLocationPickerBottomSheet( @OptIn(ExperimentalLayoutApi::class) @Composable private fun CallvanLocationChipGroup( - selectedLocation: CallvanLocationOption? = null, + selectedLocation: CallvanLocationOption?, onLocationClick: (CallvanLocationOption) -> Unit = {} ) { FlowRow( @@ -186,6 +186,7 @@ private fun CallvanCustomLocationInput( modifier = Modifier .fillMaxWidth() .padding(top = 4.dp) + .clip(RebrandKoinTheme.shapes.medium) .border(1.dp, RebrandKoinTheme.colors.neutral300, RebrandKoinTheme.shapes.medium) .background(RebrandKoinTheme.colors.neutral0, RebrandKoinTheme.shapes.medium) .padding(horizontal = 20.dp, vertical = 13.dp) From aa82678483342ff78ab626976716e9134721231a Mon Sep 17 00:00:00 2001 From: JaeYoung290 <172613798+JaeYoung290@users.noreply.github.com> Date: Tue, 17 Mar 2026 13:43:34 +0900 Subject: [PATCH 9/9] fix: add imePadding --- .../ui/create/component/CallvanLocationPickerBottomSheet.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt index 307d5ab7eb..775b67f268 100644 --- a/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt +++ b/feature/callvan/src/main/java/in/koreatech/koin/feature/callvan/ui/create/component/CallvanLocationPickerBottomSheet.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField @@ -70,6 +71,7 @@ fun CallvanLocationPickerBottomSheet( Column( modifier = modifier .fillMaxWidth() + .imePadding() .padding(horizontal = 32.dp, vertical = 12.dp), verticalArrangement = Arrangement.spacedBy(24.dp) ) {