Skip to content

Commit

Permalink
[REFACTOR/#43] 코드리뷰 반영
Browse files Browse the repository at this point in the history
  • Loading branch information
MoonsuKang committed Jan 19, 2025
1 parent cfaecbf commit f19be18
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 138 deletions.
260 changes: 160 additions & 100 deletions core/ui/src/main/java/com/yapp/ui/component/textfield/OrbitTextField.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ 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.KeyboardOptions
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
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
Expand All @@ -32,7 +28,7 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
Expand Down Expand Up @@ -74,15 +70,54 @@ fun OrbitTextField(
Column(
modifier = Modifier.fillMaxWidth(),
) {
TextFieldContainer(
text = text,
hint = hint,
showWarning = showWarning,
onTextChange = onTextChange,
onFocusChanged = onFocusChanged,
focusRequester = focusRequester,
keyboardOptions = keyboardOptions,
)
Box(
modifier = Modifier
.border(
width = 1.dp,
color = if (showWarning) OrbitTheme.colors.alert else OrbitTheme.colors.gray_500,
shape = RoundedCornerShape(16.dp),
)
.background(OrbitTheme.colors.gray_800, shape = RoundedCornerShape(16.dp))
.height(54.dp)
.fillMaxWidth()
.focusRequester(focusRequester)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = {
focusRequester.requestFocus()
},
),
) {
BasicTextField(
value = text,
onValueChange = { newValue ->
val updatedValue = newValue.copy(selection = TextRange(newValue.text.length))
onTextChange(updatedValue)
},
textStyle = TextStyle(
color = if (text.text.isEmpty()) OrbitTheme.colors.gray_500 else OrbitTheme.colors.white,
textAlign = TextAlign.Center,
),
keyboardOptions = keyboardOptions,
cursorBrush = SolidColor(OrbitTheme.colors.white),
decorationBox = { innerTextField ->
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
if (text.text.isEmpty()) {
Text(
text = hint,
style = OrbitTheme.typography.body1Regular.copy(textAlign = TextAlign.Center),
color = OrbitTheme.colors.gray_500,
)
}
innerTextField()
}
},
)
}

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

Expand All @@ -95,109 +130,134 @@ fun OrbitTextField(
}

@Composable
private fun WarningMessage(message: String) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
contentAlignment = Alignment.Center,
) {
Text(
text = message,
color = OrbitTheme.colors.alert,
style = OrbitTheme.typography.label2Regular,
)
}
fun OrbitTextField(
text: String,
onTextChange: (String) -> Unit,
hint: String,
modifier: Modifier = Modifier,
showWarning: Boolean = false,
warningMessage: String,
onFocusChanged: (Boolean) -> Unit = {},
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
) {
OrbitTextFieldBase(
value = text,
onValueChange = onTextChange,
hint = hint,
modifier = modifier,
showWarning = showWarning,
warningMessage = warningMessage,
onFocusChanged = onFocusChanged,
keyboardOptions = keyboardOptions,
)
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TextFieldContainer(
text: TextFieldValue,
private fun OrbitTextFieldBase(
value: String,
onValueChange: (String) -> Unit,
hint: String,
modifier: Modifier,
showWarning: Boolean,
onTextChange: (TextFieldValue) -> Unit,
warningMessage: String,
onFocusChanged: (Boolean) -> Unit,
focusRequester: FocusRequester,
keyboardOptions: KeyboardOptions,
) {
var isFocused by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current

Box(
modifier = Modifier
.border(
width = 1.dp,
color = when {
isFocused && showWarning -> OrbitTheme.colors.alert
isFocused -> OrbitTheme.colors.main.copy(alpha = 0.2f)
showWarning -> OrbitTheme.colors.alert
else -> OrbitTheme.colors.gray_500
},
shape = RoundedCornerShape(16.dp),
)
.background(OrbitTheme.colors.gray_800, shape = RoundedCornerShape(16.dp))
.height(54.dp)
.fillMaxWidth()
.focusRequester(focusRequester)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = {
focusRequester.requestFocus()
isFocused = true
},
),
) {
BasicTextField(
value = text,
onValueChange = onTextChange,
textStyle = TextStyle(
color = if (text.text.isEmpty()) OrbitTheme.colors.gray_500 else OrbitTheme.colors.white,
textAlign = TextAlign.Center,
),
keyboardOptions = keyboardOptions,
cursorBrush = SolidColor(OrbitTheme.colors.white),
decorationBox = { innerTextField ->
val customTextSelectionColors = TextSelectionColors(
handleColor = OrbitTheme.colors.main,
backgroundColor = OrbitTheme.colors.main,
)

CompositionLocalProvider(LocalTextSelectionColors provides customTextSelectionColors) {
Box(
modifier = modifier
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = {
focusManager.clearFocus()
onFocusChanged(false)
},
),
) {
Column(
modifier = Modifier.fillMaxWidth(),
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
if (text.text.isEmpty()) {
Text(
text = hint,
style = OrbitTheme.typography.body1Regular.copy(textAlign = TextAlign.Center),
color = OrbitTheme.colors.gray_500,
modifier = Modifier
.border(
width = 1.dp,
color = if (showWarning) OrbitTheme.colors.alert else OrbitTheme.colors.gray_500,
shape = RoundedCornerShape(16.dp),
)
}
innerTextField()
.background(OrbitTheme.colors.gray_800, shape = RoundedCornerShape(16.dp))
.height(54.dp)
.fillMaxWidth()
.focusRequester(focusRequester)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = {
focusRequester.requestFocus()
},
),
) {
BasicTextField(
value = value,
onValueChange = onValueChange,
textStyle = TextStyle(
color = if (value.isEmpty()) OrbitTheme.colors.gray_500 else OrbitTheme.colors.white,
textAlign = TextAlign.Center,
),
keyboardOptions = keyboardOptions,
cursorBrush = SolidColor(OrbitTheme.colors.white),
decorationBox = { innerTextField ->
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
if (value.isEmpty()) {
Text(
text = hint,
style = OrbitTheme.typography.body1Regular.copy(textAlign = TextAlign.Center),
color = OrbitTheme.colors.gray_500,
)
}
innerTextField()
}
},
)
}
},
modifier = Modifier
.fillMaxWidth()
.onFocusChanged { focusState ->
isFocused = focusState.isFocused
onFocusChanged(focusState.isFocused)
},
)

if (text.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(TextFieldValue("")) },
),
)
Spacer(modifier = Modifier.height(12.dp))

if (showWarning) {
WarningMessage(warningMessage)
}
}
}
}
}

@Composable
private fun WarningMessage(message: String) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
contentAlignment = Alignment.Center,
) {
Text(
text = message,
color = OrbitTheme.colors.alert,
style = OrbitTheme.typography.label2Regular,
)
}
}

@Composable
@Preview
fun OrbitTextFieldPreview() {
Expand Down
Loading

0 comments on commit f19be18

Please sign in to comment.