Skip to content

Commit

Permalink
[REFACTOR/#16] TextField Component ์ˆ˜์ •
Browse files Browse the repository at this point in the history
  • Loading branch information
MoonsuKang committed Jan 8, 2025
1 parent a7d07ba commit 354b671
Showing 1 changed file with 46 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
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.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
Expand All @@ -29,6 +32,7 @@ import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
Expand All @@ -39,11 +43,10 @@ import com.yapp.designsystem.theme.OrbitTheme
fun OrbitTextField(
text: String,
onTextChange: (String) -> Unit,
maxLength: Int,
hint: String,
modifier: Modifier = Modifier,
showWarning: Boolean = false,
onFocusChanged: (Boolean) -> Unit = {},
onValidationStateChanged: (isValid: Boolean, isTooLong: Boolean) -> Unit = { _, _ -> },
) {
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current
Expand All @@ -56,7 +59,6 @@ fun OrbitTextField(
CompositionLocalProvider(LocalTextSelectionColors provides customTextSelectionColors) {
Box(
modifier = modifier
.fillMaxSize()
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
Expand All @@ -65,60 +67,65 @@ fun OrbitTextField(
onFocusChanged(false)
},
),
contentAlignment = Alignment.Center,
) {
Column(
modifier = Modifier.fillMaxWidth(),
) {
TextFieldContainer(
text = text,
maxLength = maxLength,
hint = hint,
showWarning = showWarning,
onTextChange = { input ->
onTextChange(input)
val isValid = validateText(input)
val isTooLong = input.length > maxLength
onValidationStateChanged(isValid, isTooLong)
},
onTextChange = onTextChange,
onFocusChanged = onFocusChanged,
focusRequester = focusRequester,
)

Spacer(modifier = Modifier.height(12.dp))

WarningMessage(
text = text,
maxLength = maxLength,
showWarning = showWarning,
)
if (showWarning) {
WarningMessage()
}
}
}
}
}

@Composable
private fun WarningMessage() {
Box(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
contentAlignment = Alignment.Center,
) {
Text(
text = "์ž…๋ ฅํ•œ ์ˆซ์ž๋ฅผ ํ™•์ธํ•ด ์ฃผ์„ธ์š”",
color = OrbitTheme.colors.alert,
style = OrbitTheme.typography.label1SemiBold,
)
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TextFieldContainer(
text: String,
maxLength: Int,
hint: String,
showWarning: Boolean,
onTextChange: (String) -> Unit,
onFocusChanged: (Boolean) -> Unit,
focusRequester: FocusRequester,
) {
var isFocused by remember { mutableStateOf(false) }
val isTextValid = validateText(text)
val isTextTooLong = text.length > maxLength

Box(
modifier = Modifier
.border(
width = 3.dp,
color = when {
isFocused && !isTextValid && text.isNotEmpty() -> OrbitTheme.colors.alert
isFocused && showWarning -> OrbitTheme.colors.alert
isFocused -> OrbitTheme.colors.main.copy(alpha = 0.2f)
isTextTooLong -> OrbitTheme.colors.alert
showWarning && !isTextValid && text.isNotEmpty() -> OrbitTheme.colors.alert
showWarning && text.isEmpty() -> OrbitTheme.colors.main.copy(alpha = 0.2f)
showWarning -> OrbitTheme.colors.alert
else -> Color.Transparent
},
shape = RoundedCornerShape(10.dp),
Expand All @@ -135,7 +142,6 @@ private fun TextFieldContainer(
isFocused = true
},
),
contentAlignment = Alignment.Center,
) {
BasicTextField(
value = text,
Expand All @@ -152,7 +158,7 @@ private fun TextFieldContainer(
) {
if (text.isEmpty()) {
Text(
text = "PlaceHolder",
text = hint,
style = OrbitTheme.typography.body1Regular.copy(textAlign = TextAlign.Center),
color = OrbitTheme.colors.gray_500,
)
Expand All @@ -167,48 +173,34 @@ private fun TextFieldContainer(
onFocusChanged(focusState.isFocused)
},
)
}
}

@Composable
private fun WarningMessage(
text: String,
maxLength: Int,
showWarning: Boolean,
) {
val isTextValid = validateText(text)
val isTextTooLong = text.length > maxLength

Box(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
contentAlignment = Alignment.Center,
) {
if (showWarning && (!isTextValid || isTextTooLong)) {
Text(
text = "์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๊ฑธ๋ฆผ",
color = OrbitTheme.colors.alert,
style = OrbitTheme.typography.label1SemiBold,
if (text.isNotEmpty()) {
Icon(
painter = painterResource(id = core.designsystem.R.drawable.ic_circle_delete),
contentDescription = "delete",
tint = null,
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 20.dp)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = { onTextChange("") },
),
)
}
}
}

private fun validateText(text: String): Boolean {
val textWithoutSpaces = text.replace("\\s".toRegex(), "")
return textWithoutSpaces.matches(Regex("^[a-zA-Z๊ฐ€-ํžฃ0-9ใ„ฑ-ใ…Žใ…-ใ…ฃ๊ฐ€-ํžฃ\\W]{2,50}$"))
}

@Composable
@Preview
fun OrbitTextFieldPreview() {
OrbitTheme {
OrbitTextField(
text = "",
text = "123",
onTextChange = {},
maxLength = 50,
showWarning = true,
hint = "์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”",
modifier = Modifier
.fillMaxWidth(),
)
Expand Down

0 comments on commit 354b671

Please sign in to comment.