diff --git a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/HankkiModTextField.kt b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/HankkiModTextField.kt index 0917bf2b..0dcb0ab0 100644 --- a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/HankkiModTextField.kt +++ b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/HankkiModTextField.kt @@ -3,6 +3,8 @@ package com.hankki.feature.storedetail.component import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -10,6 +12,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -25,8 +28,9 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Color.Companion.Transparent -import androidx.compose.ui.res.painterResource +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -39,16 +43,24 @@ import com.hankki.core.designsystem.theme.WarnRed import com.hankki.feature.storedetail.R @Composable -fun HankkiModMenuField( +private fun HankkiBaseField( + modifier: Modifier, label: String, value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, clearText: () -> Unit, - placeholder: String = "새로운 메뉴 이름", isFocused: Boolean, - onMenuFocused: (Boolean) -> Unit + onFocusChanged: (Boolean) -> Unit, + placeholder: String = "", + suffix: String = "", + isError: Boolean = false, + errorMessage: String = "", + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + textColor: Color = Gray850, + borderColor: Color = Gray500, + content: (@Composable BoxScope.() -> Unit)? = null ) { - var isEditingMenu by remember { mutableStateOf(false) } + var isEditing by remember { mutableStateOf(false) } val focusRequester = remember { FocusRequester() } LaunchedEffect(isFocused) { @@ -57,91 +69,147 @@ fun HankkiModMenuField( } } - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - BasicTextField( - value = value, - onValueChange = onValueChange, - modifier = Modifier - .clip(RoundedCornerShape(8.dp)) - .border( - 1.dp, - if (isFocused) Gray500 else Transparent, - RoundedCornerShape(8.dp) - ) - .background(Color.White) - .padding(horizontal = 12.dp, vertical = 14.dp) - .focusRequester(focusRequester) - .onFocusChanged { focusState -> - isEditingMenu = focusState.isFocused - onMenuFocused(focusState.isFocused) - }, - textStyle = HankkiTheme.typography.body2.copy( - color = Gray850, - textAlign = TextAlign.End - ), - singleLine = true, - decorationBox = { innerTextField -> - Row(verticalAlignment = Alignment.CenterVertically) { - Text( - text = label, - style = if (isEditingMenu) { - HankkiTheme.typography.body4.copy(color = Gray850) - } else { - HankkiTheme.typography.body5.copy(color = Gray500) + Column { + Row( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + BasicTextField( + value = value, + onValueChange = onValueChange, + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .border( + 1.dp, + when { + isError -> WarnRed + isEditing -> borderColor + else -> Color.Transparent }, - modifier = Modifier.padding(end = 8.dp) + RoundedCornerShape(8.dp) ) - Box( - modifier = Modifier.weight(1f), - contentAlignment = Alignment.CenterEnd + .background(Color.White) + .padding(horizontal = 12.dp, vertical = 14.dp) + .focusRequester(focusRequester) + .onFocusChanged { focusState -> + isEditing = focusState.isFocused + onFocusChanged(focusState.isFocused) + }, + textStyle = HankkiTheme.typography.body2.copy( + color = if (isError) WarnRed else textColor, + textAlign = TextAlign.End + ), + singleLine = true, + keyboardOptions = keyboardOptions, + decorationBox = { innerTextField -> + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically ) { - if (value.text.isEmpty() && isEditingMenu) { + Text( + text = label, + style = if (isEditing) { + HankkiTheme.typography.body4.copy(color = Gray850) + } else { + HankkiTheme.typography.body5.copy(color = Gray500) + }, + modifier = Modifier.padding(end = 8.dp) + ) + Box( + modifier = Modifier + .weight(1f) + .fillMaxWidth(), + contentAlignment = Alignment.CenterEnd + ) { + if (value.text.isEmpty() && isEditing && placeholder.isNotEmpty()) { + Text( + text = placeholder, + color = Gray400, + style = HankkiTheme.typography.body2, + textAlign = TextAlign.End + ) + } + content?.invoke(this) ?: innerTextField() + } + + if (suffix.isNotEmpty()) { Text( - text = placeholder, - color = Gray400, - style = HankkiTheme.typography.body2, - textAlign = TextAlign.End + text = suffix, + style = HankkiTheme.typography.body2.copy(color = Gray850) ) - } else { - innerTextField() } - } - Spacer(modifier = Modifier.padding(8.dp)) - if (value.text.isNotEmpty() && isEditingMenu) { - Icon( - painter = painterResource(R.drawable.ic_cancel), - contentDescription = "Clear text", - modifier = Modifier - .size(24.dp) - .noRippleClickable(clearText), - tint = Color.Unspecified - ) - } else { - Icon( - painter = painterResource(R.drawable.ic_bg_edit), - contentDescription = "Edit text", - modifier = Modifier - .size(24.dp) - .noRippleClickable { - onMenuFocused(true) - }, - tint = Color.Unspecified - ) + Spacer(modifier = Modifier.padding(8.dp)) + if (isEditing) { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.ic_cancel), + contentDescription = "Clear text", + modifier = Modifier + .size(24.dp) + .noRippleClickable(clearText), + tint = Color.Unspecified + ) + } else { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.ic_bg_edit), + contentDescription = "Edit text", + modifier = Modifier + .size(24.dp) + .noRippleClickable { + focusRequester.requestFocus() + isEditing = true + }, + tint = Color.Unspecified + ) + } } } - } - ) + ) + } + + if (isError) { + Text( + text = errorMessage, + color = WarnRed, + style = HankkiTheme.typography.caption1, + modifier = Modifier + .fillMaxWidth() + .padding(end = 16.dp), + textAlign = TextAlign.End + ) + } } } +@Composable +fun HankkiModMenuField( + modifier: Modifier, + label: String, + value: TextFieldValue, + onValueChange: (TextFieldValue) -> Unit, + clearText: () -> Unit, + placeholder: String = "새로운 메뉴 이름", + isFocused: Boolean, + onMenuFocused: (Boolean) -> Unit +) { + HankkiBaseField( + modifier = modifier, + label = label, + value = value, + onValueChange = onValueChange, + clearText = clearText, + placeholder = placeholder, + isFocused = isFocused, + onFocusChanged = onMenuFocused + ) +} + @Composable fun HankkiModPriceField( + modifier: Modifier, label: String, value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, @@ -149,116 +217,23 @@ fun HankkiModPriceField( isError: Boolean = false, isFocused: Boolean, errorMessage: String = "유효하지 않은 가격입니다.", - warnRed: Color = WarnRed, onPriceFocused: (Boolean) -> Unit ) { - var isEditingPrice by remember { mutableStateOf(false) } - val focusRequester = remember { FocusRequester() } - - LaunchedEffect(isFocused) { - if (isFocused) { - focusRequester.requestFocus() - } - } - - val borderColor = when { - isError -> warnRed - isEditingPrice -> Gray500 - else -> Transparent - } - - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - BasicTextField( - value = value, - onValueChange = onValueChange, - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(10.dp)) - .border( - 1.dp, borderColor, RoundedCornerShape(10.dp) - ) - .background(Color.White) - .padding(horizontal = 12.dp, vertical = 14.dp) - .focusRequester(focusRequester) - .onFocusChanged { focusState -> - isEditingPrice = focusState.isFocused - onPriceFocused(focusState.isFocused) - }, - textStyle = HankkiTheme.typography.body2.copy( - color = if (isError) warnRed else Gray850, - textAlign = TextAlign.End - ), - singleLine = true, - decorationBox = { innerTextField -> - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = label, - style = if (isEditingPrice) { - HankkiTheme.typography.body4.copy(color = Gray850) - } else { - HankkiTheme.typography.body5.copy(color = Gray500) - }, - modifier = Modifier.padding(end = 8.dp) - ) - Box( - modifier = Modifier - .weight(1f) - .fillMaxWidth(), - contentAlignment = Alignment.CenterEnd - ) { - innerTextField() - } - - Text( - text = "원", - style = HankkiTheme.typography.body2.copy(color = Gray850) - ) - - Spacer(modifier = Modifier.padding(8.dp)) - if (isEditingPrice) { - Icon( - painter = painterResource(R.drawable.ic_cancel), - contentDescription = "Clear text", - modifier = Modifier - .size(24.dp) - .noRippleClickable(clearText), - tint = Color.Unspecified - ) - } else { - Icon( - painter = painterResource(R.drawable.ic_bg_edit), - contentDescription = "Edit text", - modifier = Modifier - .size(24.dp) - .noRippleClickable { - focusRequester.requestFocus() - isEditingPrice = true - }, - tint = Color.Unspecified - ) - } - } + HankkiBaseField( + modifier = modifier, + label = label, + value = value, + onValueChange = { newValue -> + if (newValue.text.isEmpty() || newValue.text.all { it.isDigit() }) { + onValueChange(newValue) } - ) - } - - if (isError) { - Text( - text = errorMessage, - color = warnRed, - style = HankkiTheme.typography.caption1, - modifier = Modifier - .fillMaxWidth() - .padding(end = 16.dp), - textAlign = TextAlign.End - ) - } -} \ No newline at end of file + }, + clearText = clearText, + isFocused = isFocused, + onFocusChanged = onPriceFocused, + isError = isError, + errorMessage = errorMessage, + suffix = "원", + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword) + ) +} diff --git a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/MenuItemComponent.kt b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/MenuItemComponent.kt index 675e22fd..5360aaaa 100644 --- a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/MenuItemComponent.kt +++ b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/MenuItemComponent.kt @@ -13,7 +13,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color.Companion.Transparent +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp import com.hankki.core.common.extension.formatPrice import com.hankki.core.common.extension.noRippleClickable @@ -27,13 +29,14 @@ import com.hankki.domain.storedetail.entity.MenuItem fun MenuItemComponent( menuItem: MenuItem, selectedMenu: String?, - onMenuSelected: (String) -> Unit + onMenuSelected: (String) -> Unit, + modifier: Modifier = Modifier ) { val isSelected = selectedMenu == menuItem.name val backgroundColor = if (isSelected) Red100 else Transparent Row( - modifier = Modifier + modifier = modifier .fillMaxWidth() .background(backgroundColor) .padding(vertical = 18.5.dp, horizontal = 22.dp) @@ -43,7 +46,7 @@ fun MenuItemComponent( ) { Row { Icon( - painter = painterResource( + imageVector = ImageVector.vectorResource( id = if (isSelected) com.hankki.core.designsystem.R.drawable.ic_btn_radio_check else com.hankki.core.designsystem.R.drawable.ic_btn_radio_uncheck ), diff --git a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/PriceWarningMessage.kt b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/PriceWarningMessage.kt index 51d4ca1a..338e1369 100644 --- a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/PriceWarningMessage.kt +++ b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/PriceWarningMessage.kt @@ -1,12 +1,10 @@ package com.hankki.feature.storedetail.component -import android.graphics.drawable.Icon import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -17,7 +15,8 @@ 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.painterResource +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp import com.hankki.core.common.extension.noRippleClickable import com.hankki.core.designsystem.theme.Gray200 @@ -65,12 +64,12 @@ fun PriceWarningMessage( color = Gray600 ) Text( - text = "8천원 이상은 메뉴 삭제를 추천해요", + text = "8천원을 넘는 메뉴는 삭제를 추천해요", style = HankkiTheme.typography.body5, color = Gray850 ) } - + Row( horizontalArrangement = Arrangement.spacedBy(14.dp), verticalAlignment = Alignment.CenterVertically @@ -93,7 +92,7 @@ fun PriceWarningMessage( } Icon( - painter = painterResource(R.drawable.ic_cancel), + imageVector = ImageVector.vectorResource(id = R.drawable.ic_cancel), contentDescription = "닫기", modifier = Modifier .size(20.dp) diff --git a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/SegmentedButton.kt b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/SegmentedButton.kt index a5857e28..48e7c2d7 100644 --- a/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/SegmentedButton.kt +++ b/feature/storedetail/src/main/java/com/hankki/feature/storedetail/component/SegmentedButton.kt @@ -17,89 +17,103 @@ 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.painterResource +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.hankki.core.common.extension.noRippleClickable import com.hankki.core.designsystem.theme.HankkiTheme +import com.hankki.core.designsystem.theme.Red400 import com.hankki.core.designsystem.theme.Red500 import com.hankki.core.designsystem.theme.White +import com.hankki.feature.storedetail.R @Composable fun SegmentedButton( modifier: Modifier = Modifier, option1: String, option2: String, - onOptionSelected: (String) -> Unit + enabled: Boolean = true, + onOptionSelected: (String) -> Unit, ) { - var selectedOption by remember { mutableStateOf(null) } - - Row( - modifier = modifier - .padding(horizontal = 22.dp) - .clip(RoundedCornerShape(16.dp)) - .background(Red500), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { + Box(modifier = modifier) { Row( modifier = Modifier - .weight(1f) - .noRippleClickable { - selectedOption = option1 - onOptionSelected(option1) - } - .padding(vertical = 10.dp), + .padding(horizontal = 22.dp) + .clip(RoundedCornerShape(16.dp)) + .background(if (enabled) Red500 else Red400), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center + horizontalArrangement = Arrangement.SpaceBetween ) { - Icon( - painter = painterResource(com.hankki.feature.storedetail.R.drawable.ic_delete), - contentDescription = null, - tint = White, - modifier = Modifier.size(14.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = option1, - fontSize = 16.sp, - color = White, - style = HankkiTheme.typography.body2 - ) - } - - Box( - modifier = Modifier - .width(1.dp) - .fillMaxHeight() - .padding(vertical = 15.dp) - .background(Color(0x1A9B331C)) - ) + Row( + modifier = Modifier + .weight(1f) + .then( + if (enabled) { + Modifier.noRippleClickable { + onOptionSelected(option1) + } + } else { + Modifier + } + ) + .padding(vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.ic_delete), + contentDescription = null, + tint = White, + modifier = Modifier.size(14.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = option1, + fontSize = 16.sp, + color = White, + style = HankkiTheme.typography.body2 + ) + } - Row( - modifier = Modifier - .weight(1f) - .noRippleClickable { - selectedOption = option2 - onOptionSelected(option2) - } - .padding(vertical = 10.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Icon( - painter = painterResource(com.hankki.feature.storedetail.R.drawable.ic_edit), - contentDescription = null, - tint = White, - modifier = Modifier.size(14.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = option2, - fontSize = 16.sp, - color = White, - style = HankkiTheme.typography.body2 + Box( + modifier = Modifier + .width(1.dp) + .fillMaxHeight() + .padding(vertical = 15.dp) + .background(Color(0x1A9B331C)) ) + + Row( + modifier = Modifier + .weight(1f) + .then( + if (enabled) { + Modifier.noRippleClickable { + onOptionSelected(option2) + } + } else { + Modifier + } + ) + .padding(vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.ic_edit), + contentDescription = null, + tint = White, + modifier = Modifier.size(14.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = option2, + fontSize = 16.sp, + color = White, + style = HankkiTheme.typography.body2 + ) + } } } -} +} \ No newline at end of file