Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/mz 174 add ledger UI textfield button focus state #51

Merged
merged 10 commits into from
Jan 12, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.susu.core.designsystem.R
import com.susu.core.designsystem.component.button.ClearIconButton
import com.susu.core.designsystem.component.button.FilledButtonColor
import com.susu.core.designsystem.component.button.LargeButtonStyle
import com.susu.core.designsystem.component.button.SusuFilledButton
import com.susu.core.designsystem.component.textfieldbutton.style.InnerButtonStyle
import com.susu.core.designsystem.component.textfieldbutton.style.LargeTextFieldButtonStyle
import com.susu.core.designsystem.component.textfieldbutton.style.SmallTextFieldButtonStyle
Expand All @@ -60,30 +63,33 @@ fun SusuTextFieldFillMaxButton(
style: @Composable () -> TextFieldButtonStyle,
color: TextFieldButtonColor = TextFieldButtonColor.Black,
isSaved: Boolean = false,
isFocused: Boolean = true,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
showCloseIcon: Boolean = true,
showClearIcon: Boolean = true,
onClickClearIcon: () -> Unit = {},
onClickCloseIcon: () -> Unit = {},
onClickButton: () -> Unit = {},
onClickFilledButton: () -> Unit = {},
onClickButton: (isFocused: Boolean) -> Unit = {},
) {
val (backgroundColor, textColor) = with(color) {
if (isSaved) {
(savedBackgroundColor to savedTextColor)
} else {
(editBackgroundColor to editTextColor)
when {
isFocused.not() -> (unFocusedBackgroundColor to unFocusedTextColor)
isSaved -> (savedBackgroundColor to savedTextColor)
else -> (editBackgroundColor to editTextColor)
}
}

with(style()) {
BasicTextField(
modifier = modifier
.fillMaxWidth(),
.fillMaxWidth()
.susuClickable { onClickButton(isFocused) },
value = text,
onValueChange = onTextChange,
enabled = isSaved.not(),
enabled = isSaved.not() && isFocused,
singleLine = maxLines == 1,
maxLines = if (minLines > maxLines) minLines else maxLines,
minLines = minLines,
Expand Down Expand Up @@ -142,13 +148,14 @@ fun SusuTextFieldFillMaxButton(
showClearIcon = showClearIcon,
isSaved = isSaved,
isActive = text.isNotEmpty(),
isFocused = isFocused,
color = color.buttonColor,
buttonStyle = innerButtonStyle,
clearIconSize = clearIconSize,
closeIconSize = closeIconSize,
onClickClearIcon = onClickClearIcon,
onClickCloseIcon = onClickCloseIcon,
onClickButton = onClickButton,
onClickFilledButton = onClickFilledButton,
)
}
},
Expand All @@ -169,20 +176,22 @@ fun SusuTextFieldWrapContentButton(
style: @Composable () -> TextFieldButtonStyle,
color: TextFieldButtonColor = TextFieldButtonColor.Black,
isSaved: Boolean = false,
isFocused: Boolean = true,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
showCloseIcon: Boolean = true,
showClearIcon: Boolean = true,
onClickClearIcon: () -> Unit = {},
onClickCloseIcon: () -> Unit = {},
onClickButton: () -> Unit = {},
onClickFilledButton: () -> Unit = {},
onClickButton: (isFocused: Boolean) -> Unit = {},
) {
val (backgroundColor, textColor) = with(color) {
if (isSaved) {
(savedBackgroundColor to savedTextColor)
} else {
(editBackgroundColor to editTextColor)
when {
isFocused.not() -> (unFocusedBackgroundColor to unFocusedTextColor)
isSaved -> (savedBackgroundColor to savedTextColor)
else -> (editBackgroundColor to editTextColor)
Comment on lines +191 to +194
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ˜„

}
}

Expand All @@ -191,6 +200,7 @@ fun SusuTextFieldWrapContentButton(
modifier = modifier
.clip(shape)
.background(backgroundColor)
.susuClickable { onClickButton(isFocused) }
.padding(paddingValues),
horizontalArrangement = Arrangement.spacedBy(iconSpacing),
verticalAlignment = Alignment.CenterVertically,
Expand All @@ -206,9 +216,10 @@ fun SusuTextFieldWrapContentButton(
* BasicTextField의 κΈ°λ³Έ widthλ₯Ό μ—†μ• κΈ° μœ„ν•΄ IntrinsicSize.Min을 μ‚¬μš©ν•¨.
* see -> https://stackoverflow.com/questions/67719981/resizeable-basictextfield-in-jetpack-compose
*/
.width(IntrinsicSize.Min),
.width(IntrinsicSize.Min)
.susuClickable(rippleEnabled = false, runIf = isFocused.not(), onClick = { onClickButton(isFocused) }),
value = text,
enabled = isSaved.not(),
enabled = isSaved.not() && isFocused,
onValueChange = onTextChange,
singleLine = maxLines == 1,
maxLines = if (minLines > maxLines) minLines else maxLines,
Expand Down Expand Up @@ -256,13 +267,14 @@ fun SusuTextFieldWrapContentButton(
showClearIcon = showClearIcon,
isSaved = isSaved,
isActive = text.isNotEmpty(),
isFocused = isFocused,
color = color.buttonColor,
buttonStyle = innerButtonStyle,
clearIconSize = clearIconSize,
closeIconSize = closeIconSize,
onClickClearIcon = onClickClearIcon,
onClickCloseIcon = onClickCloseIcon,
onClickButton = onClickButton,
onClickFilledButton = onClickFilledButton,
)
}
}
Expand All @@ -274,6 +286,7 @@ private fun InnerButtons(
shape: Shape = RoundedCornerShape(4.dp),
isSaved: Boolean,
isActive: Boolean,
isFocused: Boolean,
showCloseIcon: Boolean = true,
showClearIcon: Boolean = true,
color: TextButtonInnerButtonColor,
Expand All @@ -282,13 +295,13 @@ private fun InnerButtons(
buttonStyle: @Composable () -> InnerButtonStyle,
onClickClearIcon: () -> Unit = {},
onClickCloseIcon: () -> Unit = {},
onClickButton: () -> Unit = {},
onClickFilledButton: () -> Unit = {},
) {
val (innerButtonTextColor, innerButtonBackgroundColor) = with(color) {
if (isActive || isSaved) {
(activeContentColor to activeBackgroundColor)
} else {
(inactiveContentColor to inactiveBackgroundColor)
when {
isFocused.not() -> (unFocusedContentColor to unFocusedBackgroundColor)
isActive || isSaved -> (activeContentColor to activeBackgroundColor)
else -> (inactiveContentColor to inactiveBackgroundColor)
}
}

Expand All @@ -315,7 +328,7 @@ private fun InnerButtons(
.susuClickable(
runIf = isActive || isSaved,
rippleColor = color.rippleColor,
onClick = onClickButton,
onClick = onClickFilledButton,
)
.padding(paddingValues),
) {
Expand Down Expand Up @@ -351,6 +364,10 @@ fun TextFieldButtonPreview() {
mutableStateOf(false)
}

var isFocused by remember {
mutableStateOf(true)
}

Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
) {
Expand All @@ -362,8 +379,10 @@ fun TextFieldButtonPreview() {
maxLines = 1,
minLines = 1,
showClearIcon = true,
isFocused = isFocused,
onClickButton = { isFocused = !isFocused },
style = LargeTextFieldButtonStyle.height46,
onClickButton = { isSaved = isSaved.not() },
onClickFilledButton = { isSaved = isSaved.not() },
onClickClearIcon = { text = "" },
isSaved = isSaved,
)
Expand All @@ -377,8 +396,10 @@ fun TextFieldButtonPreview() {
placeholder = "Button",
maxLines = 1,
minLines = 1,
isFocused = !isFocused,
onClickButton = { isFocused = !isFocused },
style = LargeTextFieldButtonStyle.height46,
onClickButton = { isSaved = isSaved.not() },
onClickFilledButton = { isSaved = isSaved.not() },
onClickClearIcon = { text = "" },
isSaved = isSaved,
)
Expand All @@ -392,11 +413,13 @@ fun TextFieldButtonPreview() {
placeholder = "Button",
maxLines = 1,
minLines = 1,
isFocused = !isFocused,
onClickButton = { isFocused = !isFocused },
showClearIcon = false,
showCloseIcon = false,
color = TextFieldButtonColor.Orange,
style = LargeTextFieldButtonStyle.height46,
onClickButton = { isSaved = isSaved.not() },
onClickFilledButton = { isSaved = isSaved.not() },
onClickClearIcon = { text = "" },
isSaved = isSaved,
)
Expand All @@ -410,14 +433,91 @@ fun TextFieldButtonPreview() {
overflow = TextOverflow.Ellipsis,
onTextChange = { text = it },
placeholder = "Button",
isFocused = !isFocused,
onClickButton = { isFocused = !isFocused },
maxLines = 1,
minLines = 1,
color = TextFieldButtonColor.Orange,
style = SmallTextFieldButtonStyle.height32,
onClickButton = { isSaved = isSaved.not() },
onClickFilledButton = { isSaved = isSaved.not() },
onClickClearIcon = { text = "" },
isSaved = isSaved,
)
}
}
}

@Preview(showBackground = true, backgroundColor = 0x000000)
@Composable
fun TextFieldButtonFocusedPreview() {
SusuTheme {
var text by remember {
mutableStateOf("Button")
}

var isSaved by remember {
mutableStateOf(false)
}

var isFocusedTextFieldButton by remember {
mutableStateOf(true)
}

var isFocusedButton1 by remember {
mutableStateOf(false)
}

var isFocusedButton2 by remember {
mutableStateOf(false)
}

Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
) {
Text(text = "ν…μŠ€νŠΈ 길이에 λ”± λ§žλŠ” λ„ˆλΉ„ (wrap)")
SusuTextFieldWrapContentButton(
color = TextFieldButtonColor.Orange,
text = text,
onTextChange = { text = it },
placeholder = "",
maxLines = 1,
minLines = 1,
showClearIcon = true,
isFocused = isFocusedTextFieldButton,
onClickButton = {
isFocusedTextFieldButton = true
isFocusedButton1 = false
isFocusedButton2 = false
},
style = LargeTextFieldButtonStyle.height46,
onClickFilledButton = { isSaved = isSaved.not() },
onClickClearIcon = { text = "" },
isSaved = isSaved,
)

SusuFilledButton(
color = FilledButtonColor.Orange,
style = LargeButtonStyle.height46,
text = "ν…ŒμŠ€νŠΈ1",
isActive = isFocusedButton1,
onClick = {
isFocusedTextFieldButton = false
isFocusedButton1 = true
isFocusedButton2 = false
},
)

SusuFilledButton(
color = FilledButtonColor.Orange,
style = LargeButtonStyle.height46,
text = "ν…ŒμŠ€νŠΈ2",
isActive = isFocusedButton2,
onClick = {
isFocusedTextFieldButton = false
isFocusedButton1 = false
isFocusedButton2 = true
},
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import androidx.compose.ui.graphics.Color
import com.susu.core.designsystem.theme.Gray10
import com.susu.core.designsystem.theme.Gray100
import com.susu.core.designsystem.theme.Gray30
import com.susu.core.designsystem.theme.Gray40
import com.susu.core.designsystem.theme.Orange20
import com.susu.core.designsystem.theme.Orange60

enum class TextFieldButtonColor(
val buttonColor: TextButtonInnerButtonColor,
val savedBackgroundColor: Color,
val editBackgroundColor: Color,
val unFocusedBackgroundColor: Color,
val unFocusedTextColor: Color,
val editTextColor: Color,
val savedTextColor: Color,
val placeholderColor: Color,
Expand All @@ -18,32 +22,40 @@ enum class TextFieldButtonColor(
buttonColor = TextButtonInnerButtonColor.Black,
savedBackgroundColor = Gray10,
editBackgroundColor = Gray10,
unFocusedBackgroundColor = Gray10,
editTextColor = Gray100,
savedTextColor = Gray100,
placeholderColor = Gray30,
unFocusedTextColor = Gray30,
),
Orange(
buttonColor = TextButtonInnerButtonColor.Black,
savedBackgroundColor = Orange60,
editBackgroundColor = Gray10,
unFocusedBackgroundColor = Orange20,
editTextColor = Gray100,
savedTextColor = Gray10,
placeholderColor = Gray30,
unFocusedTextColor = Gray10,
),
}

enum class TextButtonInnerButtonColor(
val activeContentColor: Color,
val inactiveContentColor: Color,
val unFocusedContentColor: Color,
val activeBackgroundColor: Color,
val inactiveBackgroundColor: Color,
val unFocusedBackgroundColor: Color,
val rippleColor: Color,
) {
Black(
activeContentColor = Gray10,
inactiveContentColor = Gray10,
unFocusedContentColor = Gray10,
activeBackgroundColor = Gray100,
inactiveBackgroundColor = Gray30,
inactiveBackgroundColor = Gray40,
unFocusedBackgroundColor = Gray40,
rippleColor = Gray10,
),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.susu.core.ui.extension

import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.core.tween
import androidx.compose.animation.togetherWith

fun <S> AnimatedContentTransitionScope<S>.susuDefaultAnimatedContentTransitionSpec(leftDirectionCondition: Boolean): ContentTransform {
val direction = if (leftDirectionCondition) {
AnimatedContentTransitionScope.SlideDirection.Left
} else {
AnimatedContentTransitionScope.SlideDirection.Right
}
return slideIntoContainer(
towards = direction,
animationSpec = tween(500),
) togetherWith slideOutOfContainer(
towards = direction,
animationSpec = tween(500),
)
}
Comment on lines +8 to +21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘πŸ‘πŸ‘ λ‚˜μ€‘μ— νšŒμ›κ°€μž…λ„ 이거둜 κ΅μ²΄ν• κ²Œμš”~!

1 change: 1 addition & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<string name="word_category">μΉ΄ν…Œκ³ λ¦¬</string>
<string name="word_date">λ‚ μ§œ</string>
<string name="content_description_add_button">λ”ν•˜κΈ° λ²„νŠΌ</string>
<string name="word_input_yourself">직접 μž…λ ₯</string>
<string name="word_male">남성</string>
<string name="word_female">μ—¬μ„±</string>
<string name="word_birth">μΆœμƒλ…„λ„</string>
Expand Down
Loading