From 939336246868f3607b0f49344c6651045d09683b Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 29 Dec 2023 19:55:04 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=20BasicButton=20Icon=20Slot=20Api?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/button/BasicButton.kt | 40 ++++++------------- .../component/button/SusuFilledButton.kt | 30 +++++++++----- .../component/button/SusuGhostButton.kt | 29 +++++++++----- .../component/button/SusuLinedButton.kt | 30 +++++++++----- 4 files changed, 72 insertions(+), 57 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt index 80bac04b..fea811d9 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt @@ -1,6 +1,5 @@ package com.susu.core.designsystem.component.button -import androidx.annotation.DrawableRes import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -10,7 +9,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -19,7 +17,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -31,7 +28,7 @@ import com.susu.core.ui.extension.susuClickable fun BasicButton( modifier: Modifier = Modifier, shape: Shape = RectangleShape, - text: String = "", + text: String? = null, textStyle: TextStyle = TextStyle.Default, contentColor: Color = Color.Unspecified, rippleColor: Color = Color.Unspecified, @@ -39,10 +36,8 @@ fun BasicButton( borderWidth: Dp = 0.dp, backgroundColor: Color = Color.Unspecified, padding: PaddingValues = PaddingValues(0.dp), - @DrawableRes leftIcon: Int? = null, - leftIconContentDescription: String? = null, - @DrawableRes rightIcon: Int? = null, - rightIconContentDescription: String? = null, + leftIcon: (@Composable () -> Unit)? = null, + rightIcon: (@Composable () -> Unit)? = null, iconSpacing: Dp = 0.dp, isActive: Boolean = true, onClick: () -> Unit = {}, @@ -66,33 +61,22 @@ fun BasicButton( ) { Row( modifier + .height(textStyle.lineHeight.value.dp) .wrapContentWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(iconSpacing), ) { - leftIcon?.let { - Icon( - modifier = Modifier.height(textStyle.lineHeight.value.dp), - painter = painterResource(id = it), - contentDescription = leftIconContentDescription, - tint = contentColor, - ) - } + leftIcon?.invoke() - Text( - text = text, - style = textStyle, - color = contentColor, - ) - - rightIcon?.let { - Icon( - modifier = Modifier.height(textStyle.lineHeight.value.dp), - painter = painterResource(id = it), - contentDescription = rightIconContentDescription, - tint = contentColor, + text?.let { + Text( + text = it, + style = textStyle, + color = contentColor, ) } + + rightIcon?.invoke() } } } diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt index 0d9e67e6..3a14c73a 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt @@ -1,15 +1,17 @@ package com.susu.core.designsystem.component.button -import androidx.annotation.DrawableRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.R @@ -47,13 +49,11 @@ enum class FilledButtonColor( fun SusuFilledButton( modifier: Modifier = Modifier, shape: Shape = RoundedCornerShape(4.dp), - text: String = "", + text: String? = null, color: FilledButtonColor, style: @Composable () -> ButtonStyle, - @DrawableRes leftIcon: Int? = null, - leftIconContentDescription: String? = null, - @DrawableRes rightIcon: Int? = null, - rightIconContentDescription: String? = null, + leftIcon: (@Composable () -> Unit)? = null, + rightIcon: (@Composable () -> Unit)? = null, isActive: Boolean = true, onClick: () -> Unit = {}, ) { @@ -68,9 +68,7 @@ fun SusuFilledButton( rippleColor = rippleColor, backgroundColor = if (isActive) activeBackgroundColor else inactiveBackgroundColor, leftIcon = leftIcon, - leftIconContentDescription = leftIconContentDescription, rightIcon = rightIcon, - rightIconContentDescription = rightIconContentDescription, padding = paddingValues, iconSpacing = iconSpacing, isActive = isActive, @@ -181,8 +179,20 @@ private fun SusuFilledButtonPreview( style = large, color = color, text = "Button", - rightIcon = R.drawable.ic_arrow_left, - leftIcon = R.drawable.ic_arrow_left, + leftIcon = { + Icon( + modifier = Modifier.size(16.dp), + painter = painterResource(id = R.drawable.ic_arrow_left), + contentDescription = "", tint = color.activeContentColor, + ) + }, + rightIcon = { + Icon( + modifier = Modifier.size(16.dp), + painter = painterResource(id = R.drawable.ic_arrow_left), + contentDescription = "", tint = color.activeContentColor, + ) + } ) SusuFilledButton( diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt index b003883f..d7cf391f 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt @@ -5,11 +5,14 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.R @@ -47,13 +50,11 @@ enum class GhostButtonColor( fun SusuGhostButton( modifier: Modifier = Modifier, shape: Shape = RoundedCornerShape(4.dp), - text: String = "", + text: String? = null, color: GhostButtonColor, style: @Composable () -> ButtonStyle, - @DrawableRes leftIcon: Int? = null, - leftIconContentDescription: String? = null, - @DrawableRes rightIcon: Int? = null, - rightIconContentDescription: String? = null, + leftIcon: (@Composable () -> Unit)? = null, + rightIcon: (@Composable () -> Unit)? = null, isActive: Boolean = true, onClick: () -> Unit = {}, ) { @@ -68,9 +69,7 @@ fun SusuGhostButton( rippleColor = rippleColor, backgroundColor = if (isActive) activeBackgroundColor else inactiveBackgroundColor, leftIcon = leftIcon, - leftIconContentDescription = leftIconContentDescription, rightIcon = rightIcon, - rightIconContentDescription = rightIconContentDescription, padding = paddingValues, iconSpacing = iconSpacing, isActive = isActive, @@ -181,8 +180,20 @@ private fun SusuGhostButtonPreview( style = large, color = color, text = "Button", - rightIcon = R.drawable.ic_arrow_left, - leftIcon = R.drawable.ic_arrow_left, + leftIcon = { + Icon( + modifier = Modifier.size(16.dp), + painter = painterResource(id = R.drawable.ic_arrow_left), + contentDescription = "", tint = color.activeContentColor, + ) + }, + rightIcon = { + Icon( + modifier = Modifier.size(16.dp), + painter = painterResource(id = R.drawable.ic_arrow_left), + contentDescription = "", tint = color.activeContentColor, + ) + } ) SusuGhostButton( diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt index 906b92ae..34858875 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt @@ -1,15 +1,17 @@ package com.susu.core.designsystem.component.button -import androidx.annotation.DrawableRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.R @@ -54,13 +56,11 @@ enum class LinedButtonColor( fun SusuLinedButton( modifier: Modifier = Modifier, shape: Shape = RoundedCornerShape(4.dp), - text: String = "", + text: String? = null, color: LinedButtonColor, style: @Composable () -> ButtonStyle, - @DrawableRes leftIcon: Int? = null, - leftIconContentDescription: String? = null, - @DrawableRes rightIcon: Int? = null, - rightIconContentDescription: String? = null, + leftIcon: (@Composable () -> Unit)? = null, + rightIcon: (@Composable () -> Unit)? = null, isActive: Boolean = true, onClick: () -> Unit = {}, ) { @@ -77,9 +77,7 @@ fun SusuLinedButton( rippleColor = rippleColor, backgroundColor = if (isActive) activeBackgroundColor else inactiveBackgroundColor, leftIcon = leftIcon, - leftIconContentDescription = leftIconContentDescription, rightIcon = rightIcon, - rightIconContentDescription = rightIconContentDescription, padding = paddingValues, iconSpacing = iconSpacing, isActive = isActive, @@ -190,8 +188,20 @@ private fun SusuLinedButtonPreview( style = large, color = color, text = "Button", - rightIcon = R.drawable.ic_arrow_left, - leftIcon = R.drawable.ic_arrow_left, + leftIcon = { + Icon( + modifier = Modifier.size(16.dp), + painter = painterResource(id = R.drawable.ic_arrow_left), + contentDescription = "", tint = color.activeContentColor, + ) + }, + rightIcon = { + Icon( + modifier = Modifier.size(16.dp), + painter = painterResource(id = R.drawable.ic_arrow_left), + contentDescription = "", tint = color.activeContentColor, + ) + }, ) SusuLinedButton( From 21bbac03d5c488d474e7f555c2e99380c653c8ff Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sat, 30 Dec 2023 00:00:11 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20TextFieldButtonStyle=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textfieldbutton/style/InnerButtonStyle.kt | 44 ++++ .../style/TextFieldButtonStyle.kt | 221 ++++++++++++++++++ .../susu/core/designsystem/theme/Spacing.kt | 3 + .../com/susu/core/designsystem/theme/Theme.kt | 2 + 4 files changed, 270 insertions(+) create mode 100644 core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/InnerButtonStyle.kt create mode 100644 core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/TextFieldButtonStyle.kt diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/InnerButtonStyle.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/InnerButtonStyle.kt new file mode 100644 index 00000000..63c8c69b --- /dev/null +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/InnerButtonStyle.kt @@ -0,0 +1,44 @@ +package com.susu.core.designsystem.component.textfieldbutton.style + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.theme.SusuTheme + +data class InnerButtonStyle( + val paddingValues: PaddingValues = PaddingValues(0.dp), + val textStyle: TextStyle = TextStyle.Default, +) + +object XSmallInnerButtonStyle { + val height28: @Composable () -> InnerButtonStyle = { + InnerButtonStyle( + paddingValues = PaddingValues( + horizontal = SusuTheme.spacing.spacing_xxs, + vertical = SusuTheme.spacing.spacing_xxxxs, + ), + textStyle = SusuTheme.typography.title_xxxs, + ) + } + + val height24: @Composable () -> InnerButtonStyle = { + InnerButtonStyle( + paddingValues = PaddingValues( + horizontal = SusuTheme.spacing.spacing_xxs, + vertical = SusuTheme.spacing.spacing_xxxxxs, + ), + textStyle = SusuTheme.typography.title_xxxs, + ) + } + + val height20: @Composable () -> InnerButtonStyle = { + InnerButtonStyle( + paddingValues = PaddingValues( + horizontal = SusuTheme.spacing.spacing_xxs, + vertical = SusuTheme.spacing.spacing_xxxxxs, + ), + textStyle = SusuTheme.typography.title_xxxxs, + ) + } +} diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/TextFieldButtonStyle.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/TextFieldButtonStyle.kt new file mode 100644 index 00000000..eb9147c7 --- /dev/null +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/style/TextFieldButtonStyle.kt @@ -0,0 +1,221 @@ +package com.susu.core.designsystem.component.textfieldbutton.style + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.theme.SusuTheme + +data class TextFieldButtonStyle( + val paddingValues: PaddingValues = PaddingValues(0.dp), + val iconSpacing: Dp = 0.dp, + val textStyle: TextStyle = TextStyle.Default, + val innerButtonStyle: @Composable () -> InnerButtonStyle, + val clearIconSize: Dp = 0.dp, + val closeIconSize: Dp = 0.dp, +) + +object LargeTextFieldButtonStyle { + + val height62: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_xl, + end = SusuTheme.spacing.spacing_m, + top = SusuTheme.spacing.spacing_m, + bottom = SusuTheme.spacing.spacing_m, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_s, + innerButtonStyle = XSmallInnerButtonStyle.height28, + clearIconSize = 24.dp, + closeIconSize = 24.dp, + ) + } + + val height54: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_l, + end = SusuTheme.spacing.spacing_xm, + top = SusuTheme.spacing.spacing_s, + bottom = SusuTheme.spacing.spacing_s, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_s, + innerButtonStyle = XSmallInnerButtonStyle.height28, + clearIconSize = 24.dp, + closeIconSize = 24.dp, + ) + } + + val height46: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_s, + top = SusuTheme.spacing.spacing_xs, + bottom = SusuTheme.spacing.spacing_xs, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_s, + innerButtonStyle = XSmallInnerButtonStyle.height28, + clearIconSize = 24.dp, + closeIconSize = 24.dp, + ) + } +} + +object MediumTextFieldButtonStyle { + + val height60: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_xl, + end = SusuTheme.spacing.spacing_m, + top = SusuTheme.spacing.spacing_m, + bottom = SusuTheme.spacing.spacing_m, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_xs, + innerButtonStyle = XSmallInnerButtonStyle.height28, + clearIconSize = 24.dp, + closeIconSize = 24.dp, + ) + } + + val height52: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_l, + end = SusuTheme.spacing.spacing_xm, + top = SusuTheme.spacing.spacing_s, + bottom = SusuTheme.spacing.spacing_s, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_xs, + innerButtonStyle = XSmallInnerButtonStyle.height28, + clearIconSize = 24.dp, + closeIconSize = 24.dp, + ) + } + + val height44: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_s, + top = SusuTheme.spacing.spacing_xxs, + bottom = SusuTheme.spacing.spacing_xxs, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_xs, + innerButtonStyle = XSmallInnerButtonStyle.height24, + clearIconSize = 20.dp, + closeIconSize = 20.dp, + ) + } +} + +object SmallTextFieldButtonStyle { + + val height48: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_s, + top = SusuTheme.spacing.spacing_s, + bottom = SusuTheme.spacing.spacing_s, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_xxs, + innerButtonStyle = XSmallInnerButtonStyle.height24, + clearIconSize = 20.dp, + closeIconSize = 20.dp, + ) + } + + val height40: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_s, + end = SusuTheme.spacing.spacing_xxs, + top = SusuTheme.spacing.spacing_xxs, + bottom = SusuTheme.spacing.spacing_xxs, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_xxs, + innerButtonStyle = XSmallInnerButtonStyle.height24, + clearIconSize = 20.dp, + closeIconSize = 20.dp, + ) + } + + val height32: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_xxs, + end = SusuTheme.spacing.spacing_xxs, + top = SusuTheme.spacing.spacing_xxxxs, + bottom = SusuTheme.spacing.spacing_xxxxs, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_xxs, + innerButtonStyle = XSmallInnerButtonStyle.height20, + clearIconSize = 16.dp, + closeIconSize = 20.dp, + ) + } +} + +object XSmallTextFieldButtonStyle { + + val height44: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + top = SusuTheme.spacing.spacing_s, + bottom = SusuTheme.spacing.spacing_s, + ), + iconSpacing = SusuTheme.spacing.spacing_xxs, + textStyle = SusuTheme.typography.title_xxxs, + innerButtonStyle = XSmallInnerButtonStyle.height20, + clearIconSize = 20.dp, + closeIconSize = 20.dp, + ) + } + + val height36: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_xxs, + end = SusuTheme.spacing.spacing_xxs, + top = SusuTheme.spacing.spacing_xxs, + bottom = SusuTheme.spacing.spacing_xxs, + ), + iconSpacing = SusuTheme.spacing.spacing_xxxs, + textStyle = SusuTheme.typography.title_xxxs, + innerButtonStyle = XSmallInnerButtonStyle.height20, + clearIconSize = 16.dp, + closeIconSize = 16.dp, + ) + } + + val height28: @Composable () -> TextFieldButtonStyle = { + TextFieldButtonStyle( + paddingValues = PaddingValues( + start = SusuTheme.spacing.spacing_xxs, + end = SusuTheme.spacing.spacing_xxxxs, + top = SusuTheme.spacing.spacing_xxxxs, + bottom = SusuTheme.spacing.spacing_xxxxs, + ), + iconSpacing = SusuTheme.spacing.spacing_xxxxs, + textStyle = SusuTheme.typography.title_xxxs, + innerButtonStyle = XSmallInnerButtonStyle.height20, + clearIconSize = 16.dp, + closeIconSize = 16.dp, + ) + } +} diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Spacing.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Spacing.kt index 3851b804..0b09b85f 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Spacing.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Spacing.kt @@ -12,6 +12,7 @@ internal val Spacing = SusuSpacing( spacing_xxs = 8.dp, spacing_xs = 10.dp, spacing_s = 12.dp, + spacing_xm = 14.dp, spacing_m = 16.dp, spacing_l = 20.dp, spacing_xl = 24.dp, @@ -30,6 +31,7 @@ data class SusuSpacing( val spacing_xs: Dp, val spacing_s: Dp, val spacing_m: Dp, + val spacing_xm: Dp, val spacing_l: Dp, val spacing_xl: Dp, val spacing_xxl: Dp, @@ -46,6 +48,7 @@ val LocalSpacing = staticCompositionLocalOf { spacing_xs = Dp.Unspecified, spacing_s = Dp.Unspecified, spacing_m = Dp.Unspecified, + spacing_xm = Dp.Unspecified, spacing_l = Dp.Unspecified, spacing_xl = Dp.Unspecified, spacing_xxl = Dp.Unspecified, diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Theme.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Theme.kt index 4ea4783d..57520bba 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Theme.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/theme/Theme.kt @@ -48,6 +48,8 @@ object SusuTheme { * * spacing_s = 12.dp, * + * spacing_xm = 14.dp, + * * spacing_m = 16.dp, * * spacing_l = 20.dp, From 5c3f84e2b0a1972049bf18d5841dc6695afaed84 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sat, 30 Dec 2023 18:50:26 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20TextFieldButton=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textfieldbutton/SusuTextFieldButton.kt | 367 ++++++++++++++++++ .../textfieldbutton/TextFieldButtonColor.kt | 49 +++ .../src/main/res/drawable/ic_clear.xml | 12 + .../src/main/res/drawable/ic_close.xml | 9 + .../src/main/res/values/strings.xml | 5 + .../com/susu/core/ui/extension/Modifier.kt | 14 + 6 files changed, 456 insertions(+) create mode 100644 core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt create mode 100644 core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt create mode 100644 core/designsystem/src/main/res/drawable/ic_clear.xml create mode 100644 core/designsystem/src/main/res/drawable/ic_close.xml create mode 100644 core/designsystem/src/main/res/values/strings.xml diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt new file mode 100644 index 00000000..9284c37d --- /dev/null +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt @@ -0,0 +1,367 @@ +package com.susu.core.designsystem.component.textfieldbutton + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +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.graphics.Shape +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.R +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.TextFieldButtonStyle +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.disabledHorizontalPointerInputScroll +import com.susu.core.ui.extension.susuClickable + +@Composable +fun SusuTextFieldFillMaxButton( + modifier: Modifier = Modifier, + shape: Shape = RoundedCornerShape(4.dp), + text: String = "", + onTextChange: (String) -> Unit = {}, + placeholder: String = "", + maxLines: Int = 1, + minLines: Int = 1, + style: @Composable () -> TextFieldButtonStyle, + color: TextFieldButtonColor = TextFieldButtonColor.Black, + isSaved: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + onClickClearIcon: () -> Unit = {}, + onClickCloseIcon: () -> Unit = {}, + onClickButton: () -> Unit = {}, +) { + val (backgroundColor, textColor) = with(color) { + if (isSaved) { + (savedBackgroundColor to savedTextColor) + } else { + (editBackgroundColor to editTextColor) + } + } + + with(style()) { + BasicTextField( + modifier = modifier + .fillMaxWidth(), + value = text, + onValueChange = onTextChange, + enabled = isSaved.not(), + singleLine = maxLines == 1, + maxLines = if (minLines > maxLines) minLines else maxLines, + minLines = minLines, + textStyle = textStyle.copy(textAlign = TextAlign.Center, color = textColor), + interactionSource = interactionSource, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + decorationBox = { innerTextField -> + Row( + modifier = Modifier + .clip(shape) + .background(backgroundColor) + .padding(paddingValues), + horizontalArrangement = Arrangement.spacedBy(iconSpacing), + verticalAlignment = Alignment.CenterVertically, + ) { + Box( + modifier = Modifier.weight(1f), + contentAlignment = Alignment.Center, + ) { + if (isSaved.not()) { + innerTextField() + } + + /** + * Problem : innerTextField 수정 중에 saved가 되면 underline이 생기는 현상. + * Solution : saved 상태에서는 Text 컴포저블 함수가 보이게 함. + */ + if (isSaved) { + Text( + text = text, + color = textColor, + style = textStyle, + textAlign = TextAlign.Start, + ) + } + + if (text.isEmpty()) { + Text( + text = placeholder, + color = color.placeholderColor, + style = textStyle, + textAlign = TextAlign.Center, + ) + } + } + + InnerButtons( + isSaved = isSaved, + isActive = text.isNotEmpty(), + color = color.buttonColor, + buttonStyle = innerButtonStyle, + onClickClearIcon = onClickClearIcon, + onClickCloseIcon = onClickCloseIcon, + onClickButton = onClickButton, + ) + } + }, + ) + } +} + +@Composable +fun SusuTextFieldWrapContentButton( + modifier: Modifier = Modifier, + shape: Shape = RoundedCornerShape(4.dp), + text: String = "", + onTextChange: (String) -> Unit = {}, + placeholder: String = "", + maxLines: Int = 1, + minLines: Int = 1, + style: @Composable () -> TextFieldButtonStyle, + color: TextFieldButtonColor = TextFieldButtonColor.Black, + isSaved: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + onClickClearIcon: () -> Unit = {}, + onClickCloseIcon: () -> Unit = {}, + onClickButton: () -> Unit = {}, +) { + val (backgroundColor, textColor) = with(color) { + if (isSaved) { + (savedBackgroundColor to savedTextColor) + } else { + (editBackgroundColor to editTextColor) + } + } + + with(style()) { + Row( + modifier = modifier + .clip(shape) + .background(backgroundColor) + .padding(paddingValues), + horizontalArrangement = Arrangement.spacedBy(iconSpacing), + verticalAlignment = Alignment.CenterVertically, + ) { + Box( + contentAlignment = Alignment.Center, + ) { + BasicTextField( + modifier = Modifier + .disabledHorizontalPointerInputScroll() + .widthIn(min = 2.dp) + /** + * BasicTextField의 기본 width를 없애기 위해 IntrinsicSize.Min을 사용함. + * see -> https://stackoverflow.com/questions/67719981/resizeable-basictextfield-in-jetpack-compose + */ + .width(IntrinsicSize.Min), + value = text, + enabled = isSaved.not(), + onValueChange = onTextChange, + singleLine = maxLines == 1, + maxLines = if (minLines > maxLines) minLines else maxLines, + minLines = minLines, + textStyle = textStyle + .copy(color = Color.Transparent), + interactionSource = interactionSource, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + decorationBox = { innerTextField -> + /** + * Problem : 만약 커서가 맨 끝으로 가게 된다면 innerTextField의 텍스트가 짤리는 현상 발생. + * Why : IntrinsicSize.Min을 사용하게 되면 innerTextField의 width는 텍스트의 너비 만큼만 설정이 되었기 때문. (커서의 너비는 포함되지 않음.) + * Solution : + * innerTextField의 color를 Transparent로 설정해 텍스트가 짤리는 현상을 안보이게 함. + * 눈에 보이는 텍스트는 Text 컴포저블 함수로 보이게 함. + */ + Text( + text = text, + color = textColor, + style = textStyle, + textAlign = TextAlign.Center, + ) + innerTextField() + }, + ) + + if (text.isEmpty()) { + Text( + text = placeholder, + color = color.placeholderColor, + style = textStyle, + textAlign = TextAlign.Center, + ) + } + } + + InnerButtons( + isSaved = isSaved, + isActive = text.isNotEmpty(), + color = color.buttonColor, + buttonStyle = innerButtonStyle, + onClickClearIcon = onClickClearIcon, + onClickCloseIcon = onClickCloseIcon, + onClickButton = onClickButton, + ) + } + } +} + +@Composable +private fun InnerButtons( + modifier: Modifier = Modifier, + shape: Shape = RoundedCornerShape(4.dp), + isSaved: Boolean, + isActive: Boolean, + color: TextButtonInnerButtonColor, + buttonStyle: @Composable () -> InnerButtonStyle, + onClickClearIcon: () -> Unit = {}, + onClickCloseIcon: () -> Unit = {}, + onClickButton: () -> Unit = {}, +) { + val (innerButtonTextColor, innerButtonBackgroundColor) = with(color) { + if (isActive || isSaved) { + (activeContentColor to activeBackgroundColor) + } else { + (inactiveContentColor to inactiveBackgroundColor) + } + } + + if (isSaved.not()) { + Image( + modifier = Modifier + .clip(CircleShape) + .susuClickable(onClick = onClickClearIcon), + painter = painterResource(id = R.drawable.ic_clear), + contentDescription = "", + ) + } + + with(buttonStyle()) { + Box( + modifier = modifier + .clip(shape) + .background(innerButtonBackgroundColor) + .susuClickable( + runIf = isActive || isSaved, + rippleColor = color.rippleColor, + onClick = onClickButton, + ) + .padding(paddingValues), + ) { + Text( + text = if (isSaved) stringResource(R.string.word_edit) else stringResource(R.string.word_save), + style = textStyle, + color = innerButtonTextColor, + ) + } + } + + if (isSaved) { + Image( + modifier = Modifier + .clip(CircleShape) + .susuClickable(onClick = onClickCloseIcon), + painter = painterResource(id = R.drawable.ic_close), + contentDescription = "", + ) + } +} + +@Preview(showBackground = true, backgroundColor = 0x000000) +@Composable +fun TextFieldButtonPreview() { + SusuTheme { + var text by remember { + mutableStateOf("Button") + } + + var isSaved by remember { + mutableStateOf(false) + } + + Column( + verticalArrangement = Arrangement.spacedBy(10.dp), + ) { + SusuTextFieldWrapContentButton( + text = text, + onTextChange = { text = it }, + placeholder = "", + maxLines = 1, + minLines = 1, + style = LargeTextFieldButtonStyle.height46, + onClickButton = { isSaved = isSaved.not() }, + onClickClearIcon = { text = "" }, + isSaved = isSaved, + ) + + SusuTextFieldFillMaxButton( + text = text, + onTextChange = { text = it }, + placeholder = "Button", + maxLines = 1, + minLines = 1, + style = LargeTextFieldButtonStyle.height46, + onClickButton = { isSaved = isSaved.not() }, + onClickClearIcon = { text = "" }, + isSaved = isSaved.not(), + ) + + SusuTextFieldWrapContentButton( + text = text, + onTextChange = { text = it }, + placeholder = "Button", + maxLines = 1, + minLines = 1, + color = TextFieldButtonColor.Orange, + style = LargeTextFieldButtonStyle.height46, + onClickButton = { isSaved = isSaved.not() }, + onClickClearIcon = { text = "" }, + isSaved = isSaved, + ) + + SusuTextFieldFillMaxButton( + text = text, + onTextChange = { text = it }, + placeholder = "Button", + maxLines = 1, + minLines = 1, + color = TextFieldButtonColor.Orange, + style = LargeTextFieldButtonStyle.height46, + onClickButton = { isSaved = isSaved.not() }, + onClickClearIcon = { text = "" }, + isSaved = isSaved.not(), + ) + } + } +} diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt new file mode 100644 index 00000000..0426a23f --- /dev/null +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt @@ -0,0 +1,49 @@ +package com.susu.core.designsystem.component.textfieldbutton + +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.Orange60 + +enum class TextFieldButtonColor( + val buttonColor: TextButtonInnerButtonColor, + val savedBackgroundColor: Color, + val editBackgroundColor: Color, + val editTextColor: Color, + val savedTextColor: Color, + val placeholderColor: Color, +) { + Black( + buttonColor = TextButtonInnerButtonColor.Black, + savedBackgroundColor = Gray10, + editBackgroundColor = Gray10, + editTextColor = Gray100, + savedTextColor = Gray100, + placeholderColor = Gray30, + ), + Orange( + buttonColor = TextButtonInnerButtonColor.Black, + savedBackgroundColor = Orange60, + editBackgroundColor = Gray10, + editTextColor = Gray100, + savedTextColor = Gray10, + placeholderColor = Gray30, + ), +} + +enum class TextButtonInnerButtonColor( + val activeContentColor: Color, + val inactiveContentColor: Color, + val activeBackgroundColor: Color, + val inactiveBackgroundColor: Color, + val rippleColor: Color, +) { + Black( + activeContentColor = Gray10, + inactiveContentColor = Gray10, + activeBackgroundColor = Gray100, + inactiveBackgroundColor = Gray30, + rippleColor = Gray10, + ), +} diff --git a/core/designsystem/src/main/res/drawable/ic_clear.xml b/core/designsystem/src/main/res/drawable/ic_clear.xml new file mode 100644 index 00000000..fef3a2ae --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_clear.xml @@ -0,0 +1,12 @@ + + + + diff --git a/core/designsystem/src/main/res/drawable/ic_close.xml b/core/designsystem/src/main/res/drawable/ic_close.xml new file mode 100644 index 00000000..bb21304f --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_close.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml new file mode 100644 index 00000000..a0872b86 --- /dev/null +++ b/core/designsystem/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + + 편집 + 저장 + diff --git a/core/ui/src/main/java/com/susu/core/ui/extension/Modifier.kt b/core/ui/src/main/java/com/susu/core/ui/extension/Modifier.kt index d0de0994..90e1690a 100644 --- a/core/ui/src/main/java/com/susu/core/ui/extension/Modifier.kt +++ b/core/ui/src/main/java/com/susu/core/ui/extension/Modifier.kt @@ -7,7 +7,12 @@ import androidx.compose.material.ripple.rememberRipple import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.composed +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.unit.Velocity import com.susu.core.ui.util.MultipleEventsCutter import com.susu.core.ui.util.get @@ -56,3 +61,12 @@ fun Modifier.susuClickable( ) } } + +// https://stackoverflow.com/questions/73309395/strange-scroll-in-the-basictextfield-with-intrinsicsize-min +fun Modifier.disabledHorizontalPointerInputScroll(disabled: Boolean = true) = + if (disabled) this.nestedScroll(HorizontalScrollConsumer) else this + +private val HorizontalScrollConsumer = object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource) = available.copy(y = 0f) + override suspend fun onPreFling(available: Velocity) = available.copy(y = 0f) +} From e48ce096f37b106b250b22e186b15b830983cd0f Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sat, 30 Dec 2023 18:54:21 +0900 Subject: [PATCH 4/7] chore: ktlint format --- .../designsystem/component/button/SusuFilledButton.kt | 8 +++++--- .../designsystem/component/button/SusuGhostButton.kt | 9 +++++---- .../designsystem/component/button/SusuLinedButton.kt | 6 ++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt index 3a14c73a..25028202 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt @@ -183,16 +183,18 @@ private fun SusuFilledButtonPreview( Icon( modifier = Modifier.size(16.dp), painter = painterResource(id = R.drawable.ic_arrow_left), - contentDescription = "", tint = color.activeContentColor, + contentDescription = "", + tint = color.activeContentColor, ) }, rightIcon = { Icon( modifier = Modifier.size(16.dp), painter = painterResource(id = R.drawable.ic_arrow_left), - contentDescription = "", tint = color.activeContentColor, + contentDescription = "", + tint = color.activeContentColor, ) - } + }, ) SusuFilledButton( diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt index d7cf391f..02f3bcf1 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt @@ -1,6 +1,5 @@ package com.susu.core.designsystem.component.button -import androidx.annotation.DrawableRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -184,16 +183,18 @@ private fun SusuGhostButtonPreview( Icon( modifier = Modifier.size(16.dp), painter = painterResource(id = R.drawable.ic_arrow_left), - contentDescription = "", tint = color.activeContentColor, + contentDescription = "", + tint = color.activeContentColor, ) }, rightIcon = { Icon( modifier = Modifier.size(16.dp), painter = painterResource(id = R.drawable.ic_arrow_left), - contentDescription = "", tint = color.activeContentColor, + contentDescription = "", + tint = color.activeContentColor, ) - } + }, ) SusuGhostButton( diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt index 34858875..8bf8ef3f 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt @@ -192,14 +192,16 @@ private fun SusuLinedButtonPreview( Icon( modifier = Modifier.size(16.dp), painter = painterResource(id = R.drawable.ic_arrow_left), - contentDescription = "", tint = color.activeContentColor, + contentDescription = "", + tint = color.activeContentColor, ) }, rightIcon = { Icon( modifier = Modifier.size(16.dp), painter = painterResource(id = R.drawable.ic_arrow_left), - contentDescription = "", tint = color.activeContentColor, + contentDescription = "", + tint = color.activeContentColor, ) }, ) From 7579697c707ff199496cae5082bba328c179f1df Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 31 Dec 2023 19:36:33 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20TextFieldButton=20-=20maxLines,=20m?= =?UTF-8?q?inLines,=20textOverflow,=20icon=20visible=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textfieldbutton/SusuTextFieldButton.kt | 73 +++++++++++++++---- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt index 9284c37d..75bbfc24 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.CircleShape @@ -17,6 +18,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -31,6 +33,7 @@ import androidx.compose.ui.graphics.Shape import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.R @@ -50,12 +53,15 @@ fun SusuTextFieldFillMaxButton( placeholder: String = "", maxLines: Int = 1, minLines: Int = 1, + overflow: TextOverflow = TextOverflow.Clip, style: @Composable () -> TextFieldButtonStyle, color: TextFieldButtonColor = TextFieldButtonColor.Black, isSaved: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + showCloseIcon: Boolean = true, + showClearIcon: Boolean = true, onClickClearIcon: () -> Unit = {}, onClickCloseIcon: () -> Unit = {}, onClickButton: () -> Unit = {}, @@ -109,6 +115,9 @@ fun SusuTextFieldFillMaxButton( color = textColor, style = textStyle, textAlign = TextAlign.Start, + overflow = overflow, + maxLines = maxLines, + minLines = minLines, ) } @@ -118,11 +127,16 @@ fun SusuTextFieldFillMaxButton( color = color.placeholderColor, style = textStyle, textAlign = TextAlign.Center, + overflow = overflow, + maxLines = maxLines, + minLines = minLines, ) } } InnerButtons( + showCloseIcon = showCloseIcon, + showClearIcon = showClearIcon, isSaved = isSaved, isActive = text.isNotEmpty(), color = color.buttonColor, @@ -146,12 +160,15 @@ fun SusuTextFieldWrapContentButton( placeholder: String = "", maxLines: Int = 1, minLines: Int = 1, + overflow: TextOverflow = TextOverflow.Clip, style: @Composable () -> TextFieldButtonStyle, color: TextFieldButtonColor = TextFieldButtonColor.Black, isSaved: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + showCloseIcon: Boolean = true, + showClearIcon: Boolean = true, onClickClearIcon: () -> Unit = {}, onClickCloseIcon: () -> Unit = {}, onClickButton: () -> Unit = {}, @@ -208,7 +225,9 @@ fun SusuTextFieldWrapContentButton( text = text, color = textColor, style = textStyle, - textAlign = TextAlign.Center, + overflow = overflow, + maxLines = maxLines, + minLines = minLines, ) innerTextField() }, @@ -220,11 +239,16 @@ fun SusuTextFieldWrapContentButton( color = color.placeholderColor, style = textStyle, textAlign = TextAlign.Center, + overflow = overflow, + maxLines = maxLines, + minLines = minLines, ) } } InnerButtons( + showCloseIcon = showCloseIcon, + showClearIcon = showClearIcon, isSaved = isSaved, isActive = text.isNotEmpty(), color = color.buttonColor, @@ -243,6 +267,8 @@ private fun InnerButtons( shape: Shape = RoundedCornerShape(4.dp), isSaved: Boolean, isActive: Boolean, + showCloseIcon: Boolean = true, + showClearIcon: Boolean = true, color: TextButtonInnerButtonColor, buttonStyle: @Composable () -> InnerButtonStyle, onClickClearIcon: () -> Unit = {}, @@ -258,13 +284,17 @@ private fun InnerButtons( } if (isSaved.not()) { - Image( - modifier = Modifier - .clip(CircleShape) - .susuClickable(onClick = onClickClearIcon), - painter = painterResource(id = R.drawable.ic_clear), - contentDescription = "", - ) + Box(modifier = Modifier.size(24.dp)) { + if (showClearIcon) { + Image( + modifier = Modifier + .clip(CircleShape) + .susuClickable(onClick = onClickClearIcon), + painter = painterResource(id = R.drawable.ic_clear), + contentDescription = "", + ) + } + } } with(buttonStyle()) { @@ -287,7 +317,7 @@ private fun InnerButtons( } } - if (isSaved) { + if (isSaved && showCloseIcon) { Image( modifier = Modifier .clip(CircleShape) @@ -313,35 +343,43 @@ fun TextFieldButtonPreview() { Column( verticalArrangement = Arrangement.spacedBy(10.dp), ) { + Text(text = "텍스트 길이에 딱 맞는 너비 (wrap)") SusuTextFieldWrapContentButton( text = text, onTextChange = { text = it }, placeholder = "", - maxLines = 1, + maxLines = 2, minLines = 1, + showClearIcon = true, style = LargeTextFieldButtonStyle.height46, onClickButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, isSaved = isSaved, ) + HorizontalDivider() + + Text(text = "최대 너비 (fillMaxWidth)") SusuTextFieldFillMaxButton( text = text, onTextChange = { text = it }, placeholder = "Button", - maxLines = 1, + maxLines = 2, minLines = 1, style = LargeTextFieldButtonStyle.height46, onClickButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, - isSaved = isSaved.not(), + isSaved = isSaved, ) + HorizontalDivider() + + Text(text = "텍스트가 없는 경우 : placeHolder 길이에 딱 맞는 너비\n텍스트가 있는 경우 : 텍스트가 차지하는 너비") SusuTextFieldWrapContentButton( text = text, onTextChange = { text = it }, placeholder = "Button", - maxLines = 1, + maxLines = 2, minLines = 1, color = TextFieldButtonColor.Orange, style = LargeTextFieldButtonStyle.height46, @@ -350,17 +388,22 @@ fun TextFieldButtonPreview() { isSaved = isSaved, ) + HorizontalDivider() + + Text(text = "고정된 너비 : 200dp") SusuTextFieldFillMaxButton( + modifier = Modifier.width(200.dp), text = text, + overflow = TextOverflow.Ellipsis, onTextChange = { text = it }, placeholder = "Button", - maxLines = 1, + maxLines = 2, minLines = 1, color = TextFieldButtonColor.Orange, style = LargeTextFieldButtonStyle.height46, onClickButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, - isSaved = isSaved.not(), + isSaved = isSaved, ) } } From ca369a3d757e7702813b1d8f198b4419ca5f794a Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 31 Dec 2023 19:42:46 +0900 Subject: [PATCH 6/7] =?UTF-8?q?chore:=20TextAlign=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/textfieldbutton/SusuTextFieldButton.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt index 75bbfc24..0690f835 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt @@ -114,7 +114,7 @@ fun SusuTextFieldFillMaxButton( text = text, color = textColor, style = textStyle, - textAlign = TextAlign.Start, + textAlign = TextAlign.Center, overflow = overflow, maxLines = maxLines, minLines = minLines, @@ -348,7 +348,7 @@ fun TextFieldButtonPreview() { text = text, onTextChange = { text = it }, placeholder = "", - maxLines = 2, + maxLines = 1, minLines = 1, showClearIcon = true, style = LargeTextFieldButtonStyle.height46, @@ -364,7 +364,7 @@ fun TextFieldButtonPreview() { text = text, onTextChange = { text = it }, placeholder = "Button", - maxLines = 2, + maxLines = 1, minLines = 1, style = LargeTextFieldButtonStyle.height46, onClickButton = { isSaved = isSaved.not() }, @@ -379,7 +379,7 @@ fun TextFieldButtonPreview() { text = text, onTextChange = { text = it }, placeholder = "Button", - maxLines = 2, + maxLines = 1, minLines = 1, color = TextFieldButtonColor.Orange, style = LargeTextFieldButtonStyle.height46, @@ -397,7 +397,7 @@ fun TextFieldButtonPreview() { overflow = TextOverflow.Ellipsis, onTextChange = { text = it }, placeholder = "Button", - maxLines = 2, + maxLines = 1, minLines = 1, color = TextFieldButtonColor.Orange, style = LargeTextFieldButtonStyle.height46, From f3bab736678dc8c37617c54a433b0a993fcf78b3 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 31 Dec 2023 20:05:22 +0900 Subject: [PATCH 7/7] =?UTF-8?q?feat:=20TextFieldButton=20-=20Icon=20size?= =?UTF-8?q?=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textfieldbutton/SusuTextFieldButton.kt | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt index 0690f835..a9fb2336 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt @@ -35,10 +35,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.susu.core.designsystem.R 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 import com.susu.core.designsystem.component.textfieldbutton.style.TextFieldButtonStyle import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.disabledHorizontalPointerInputScroll @@ -141,6 +143,8 @@ fun SusuTextFieldFillMaxButton( isActive = text.isNotEmpty(), color = color.buttonColor, buttonStyle = innerButtonStyle, + clearIconSize = clearIconSize, + closeIconSize = closeIconSize, onClickClearIcon = onClickClearIcon, onClickCloseIcon = onClickCloseIcon, onClickButton = onClickButton, @@ -253,6 +257,8 @@ fun SusuTextFieldWrapContentButton( isActive = text.isNotEmpty(), color = color.buttonColor, buttonStyle = innerButtonStyle, + clearIconSize = clearIconSize, + closeIconSize = closeIconSize, onClickClearIcon = onClickClearIcon, onClickCloseIcon = onClickCloseIcon, onClickButton = onClickButton, @@ -270,6 +276,8 @@ private fun InnerButtons( showCloseIcon: Boolean = true, showClearIcon: Boolean = true, color: TextButtonInnerButtonColor, + clearIconSize: Dp = 0.dp, + closeIconSize: Dp = 0.dp, buttonStyle: @Composable () -> InnerButtonStyle, onClickClearIcon: () -> Unit = {}, onClickCloseIcon: () -> Unit = {}, @@ -284,11 +292,12 @@ private fun InnerButtons( } if (isSaved.not()) { - Box(modifier = Modifier.size(24.dp)) { + Box(modifier = Modifier.size(clearIconSize)) { if (showClearIcon) { Image( modifier = Modifier .clip(CircleShape) + .size(clearIconSize) .susuClickable(onClick = onClickClearIcon), painter = painterResource(id = R.drawable.ic_clear), contentDescription = "", @@ -297,6 +306,10 @@ private fun InnerButtons( } } + if (isSaved && showCloseIcon.not()) { + Box(modifier = Modifier.size(closeIconSize)) + } + with(buttonStyle()) { Box( modifier = modifier @@ -321,6 +334,7 @@ private fun InnerButtons( Image( modifier = Modifier .clip(CircleShape) + .size(closeIconSize) .susuClickable(onClick = onClickCloseIcon), painter = painterResource(id = R.drawable.ic_close), contentDescription = "", @@ -381,6 +395,8 @@ fun TextFieldButtonPreview() { placeholder = "Button", maxLines = 1, minLines = 1, + showClearIcon = false, + showCloseIcon = false, color = TextFieldButtonColor.Orange, style = LargeTextFieldButtonStyle.height46, onClickButton = { isSaved = isSaved.not() }, @@ -400,7 +416,7 @@ fun TextFieldButtonPreview() { maxLines = 1, minLines = 1, color = TextFieldButtonColor.Orange, - style = LargeTextFieldButtonStyle.height46, + style = SmallTextFieldButtonStyle.height32, onClickButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, isSaved = isSaved,