diff --git a/compose/src/main/java/com/yourssu/design/system/compose/atom/SearchTextField.kt b/compose/src/main/java/com/yourssu/design/system/compose/atom/SearchTextField.kt new file mode 100644 index 00000000..31f81e5a --- /dev/null +++ b/compose/src/main/java/com/yourssu/design/system/compose/atom/SearchTextField.kt @@ -0,0 +1,174 @@ +package com.yourssu.design.system.compose.atom + +import android.widget.Toast +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsFocusedAsState +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +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.material.ExperimentalMaterialApi +import androidx.compose.material.LocalContentColor +import androidx.compose.material.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.yourssu.design.system.compose.R +import com.yourssu.design.system.compose.YdsTheme +import com.yourssu.design.system.compose.base.Icon +import com.yourssu.design.system.compose.base.IconSize +import com.yourssu.design.system.compose.base.YdsBaseButton +import com.yourssu.design.system.compose.base.YdsText +import com.yourssu.design.system.compose.states.ButtonColorState + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun SearchTextField( + text: String = "", + placeHolderText: String = "", + isDisabled: Boolean = false, + onValueChange: (String) -> Unit, + onX: () -> Unit, + onSearch: () -> Unit, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + modifier: Modifier = Modifier, +) { + val isFocused: Boolean = interactionSource.collectIsFocusedAsState().value + val isTyping: Boolean = isFocused and text.isNotBlank() + + BasicTextField( + value = text, + onValueChange = onValueChange, + textStyle = YdsTheme.typography.body1.toTextStyle(), + enabled = !isDisabled, + singleLine = true, + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Search + ), + keyboardActions = KeyboardActions( + onSearch = { + onSearch() + } + ), + cursorBrush = SolidColor(YdsTheme.colors.textPointed), + modifier = Modifier + .width(350.dp) + .height(40.dp) + .then(modifier) + .background( + color = YdsTheme.colors.inputFieldElevated, + shape = RoundedCornerShape(8.dp) + ), + interactionSource = interactionSource, + decorationBox = { innerTextField -> + TextFieldDefaults.OutlinedTextFieldDecorationBox( + value = text, + visualTransformation = VisualTransformation.None, + innerTextField = innerTextField, + placeholder = { + YdsText( + text = placeHolderText, + style = YdsTheme.typography.body1, + color = YdsTheme.colors.textTertiary + ) + }, + leadingIcon = { + Icon( + id = R.drawable.ic_search_line, + iconSize = IconSize.Small, + tint = if (isTyping) { + YdsTheme.colors.textSecondary + } else { + LocalContentColor.current + } + ) + }, + trailingIcon = { + if (isTyping) { + YdsBaseButton(onClick = { onX() }, colors = ButtonColorState()) { + Icon( + id = R.drawable.ic_x_line, + iconSize = IconSize.ExtraSmall, + tint = YdsTheme.colors.buttonNormal, + ) + } + } + }, + singleLine = true, + enabled = !isDisabled, + isError = false, + interactionSource = interactionSource, + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 12.dp), + colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = YdsTheme.colors.textSecondary, + disabledTextColor = YdsTheme.colors.textDisabled, + backgroundColor = YdsTheme.colors.inputFieldElevated, + cursorColor = YdsTheme.colors.textPointed, + errorCursorColor = YdsTheme.colors.textPointed, + focusedBorderColor = Color.Transparent, + unfocusedBorderColor = Color.Transparent, + disabledBorderColor = Color.Transparent, + errorBorderColor = YdsTheme.colors.textWarned, + leadingIconColor = YdsTheme.colors.textTertiary, + disabledLeadingIconColor = YdsTheme.colors.textDisabled, + errorLeadingIconColor = Color.Transparent, + trailingIconColor = YdsTheme.colors.textTertiary, + disabledTrailingIconColor = YdsTheme.colors.textDisabled, + errorTrailingIconColor = Color.Transparent, + focusedLabelColor = Color.Transparent, + unfocusedLabelColor = Color.Transparent, + disabledLabelColor = Color.Transparent, + errorLabelColor = Color.Transparent, + placeholderColor = YdsTheme.colors.textTertiary, + disabledPlaceholderColor = YdsTheme.colors.textDisabled + ) + ) + } + ) +} + +@Preview(name = "ExSearchTextField") +@Composable +private fun PreviewSearchTextField() { + val context = LocalContext.current + var text: String by rememberSaveable { mutableStateOf("") } + + SearchTextField( + onValueChange = { + text = it + }, + onX = { + Toast.makeText( + context, + "Erase!", + Toast.LENGTH_SHORT + ).show() + text = "" + }, + onSearch = { + Toast.makeText( + context, + "onSearch!", + Toast.LENGTH_SHORT + ).show() + }, + text = text, + placeHolderText = "플레이스 홀더 입니다", + isDisabled = false, + ) +} \ No newline at end of file diff --git a/compose/src/main/java/com/yourssu/design/system/compose/base/YdsBaseButton.kt b/compose/src/main/java/com/yourssu/design/system/compose/base/YdsBaseButton.kt index f0b8c304..a074eeed 100644 --- a/compose/src/main/java/com/yourssu/design/system/compose/base/YdsBaseButton.kt +++ b/compose/src/main/java/com/yourssu/design/system/compose/base/YdsBaseButton.kt @@ -38,6 +38,7 @@ internal fun YdsBaseButton( rounding: Dp = 8.dp, contentPadding: PaddingValues = YdsButtonDefaults.ContentPadding, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + isDefaultMinSize: Boolean = false, content: @Composable RowScope.() -> Unit ) { val localPressed by interactionSource.collectIsPressedAsState() @@ -57,10 +58,15 @@ internal fun YdsBaseButton( ProvideTextStyle(value = YdsTheme.typography.button2) { Row( modifier = Modifier -// .defaultMinSize( -// minWidth = YdsButtonDefaults.MinWidth, -// minHeight = YdsButtonDefaults.MinHeight -// ) + .conditional( + condition = isDefaultMinSize, + ifTrue = { + defaultMinSize( + minWidth = YdsButtonDefaults.MinWidth, + minHeight = YdsButtonDefaults.MinHeight + ) + }, + ) .padding(contentPadding), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, @@ -70,6 +76,16 @@ internal fun YdsBaseButton( } } +inline fun Modifier.conditional( + condition: Boolean, + ifTrue: Modifier.() -> Modifier, + ifFalse: Modifier.() -> Modifier = { this }, +): Modifier = if (condition) { + then(ifTrue(Modifier)) +} else { + then(ifFalse(Modifier)) +} + object YdsButtonDefaults { private val ButtonHorizontalPadding = 16.dp private val ButtonVerticalPadding = 12.dp diff --git a/compose/src/main/java/com/yourssu/design/system/compose/components/DoubleTitleTopBar.kt b/compose/src/main/java/com/yourssu/design/system/compose/components/DoubleTitleTopBar.kt index 3cbd6a8b..47f778c0 100644 --- a/compose/src/main/java/com/yourssu/design/system/compose/components/DoubleTitleTopBar.kt +++ b/compose/src/main/java/com/yourssu/design/system/compose/components/DoubleTitleTopBar.kt @@ -5,16 +5,13 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material.Text import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.yourssu.design.system.compose.R @@ -36,7 +33,7 @@ fun DoubleTitleTopBar( backgroundColor = YdsTheme.colors.bgElevated, contentColor = YdsTheme.colors.textPrimary, elevation = 0.dp, - contentPadding = PaddingValues(horizontal = 4.dp) + contentPadding = PaddingValues(end = 4.dp) ) { Box( modifier = Modifier.fillMaxWidth() @@ -64,9 +61,8 @@ fun DoubleTitleTopBar( Row( modifier = Modifier - .fillMaxHeight() - .padding(0.dp) - .align(Alignment.TopEnd), + .padding(top = 16.dp) + .align(Alignment.BottomEnd), verticalAlignment = Alignment.CenterVertically ) { actions() diff --git a/compose/src/main/java/com/yourssu/design/system/compose/components/SearchTopBar.kt b/compose/src/main/java/com/yourssu/design/system/compose/components/SearchTopBar.kt index 2dd7aa87..1f86d84f 100644 --- a/compose/src/main/java/com/yourssu/design/system/compose/components/SearchTopBar.kt +++ b/compose/src/main/java/com/yourssu/design/system/compose/components/SearchTopBar.kt @@ -1,22 +1,41 @@ package com.yourssu.design.system.compose.components +import android.widget.Toast +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.material.Text +import androidx.compose.foundation.layout.padding import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.yourssu.design.system.compose.R +import com.yourssu.design.system.compose.YdsTheme +import com.yourssu.design.system.compose.atom.SearchTextField +import com.yourssu.design.system.compose.atom.TopBarButton +import com.yourssu.design.system.compose.base.YdsScaffold + @Composable fun SearchTopBar( + text: String = "", + placeHolderText: String = "", + isDisabled: Boolean = false, onValueChange: (String) -> Unit, onX: () -> Unit, onSearch: () -> Unit, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, navigationIcon: @Composable () -> Unit = {}, ) { TopAppBar( @@ -26,22 +45,29 @@ fun SearchTopBar( backgroundColor = YdsTheme.colors.bgElevated, contentColor = YdsTheme.colors.textPrimary, elevation = 0.dp, - contentPadding = PaddingValues(horizontal = 4.dp) + contentPadding = PaddingValues(start = 4.dp) ) { Box( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .padding(start = 4.dp) + .fillMaxWidth() ) { Row( modifier = Modifier.fillMaxWidth() ) { navigationIcon() SearchTextField( - searchTextFieldState = searchTextFieldState, + text = text, + placeHolderText = placeHolderText, + isDisabled = isDisabled, onValueChange = onValueChange, - onX = onX - ) { - onSearch() - } + onX = onX, + onSearch = onSearch, + interactionSource = interactionSource, + modifier = Modifier + .padding(start = 4.dp, end = 16.dp) + .align(alignment = CenterVertically) + ) } } } @@ -50,5 +76,51 @@ fun SearchTopBar( @Preview(name = "SearchTopBar") @Composable private fun PreviewSearchTopBar() { - SearchTopBar() + val context = LocalContext.current + var text: String by rememberSaveable { mutableStateOf("") } + + YdsTheme { + YdsScaffold( + topBar = { + SearchTopBar( + text = text, + placeHolderText = "Enabled", + isDisabled = false, + onValueChange = { + text = it + }, + onX = { + Toast.makeText( + context, + "Erase!", + Toast.LENGTH_SHORT + ).show() + text = "" + }, + onSearch = { + Toast.makeText( + context, + "onSearch!", + Toast.LENGTH_SHORT + ).show() + }, + navigationIcon = { + TopBarButton( + icon = R.drawable.ic_arrow_left_line, + isDisabled = false, + onClick = { + Toast.makeText( + context, + "navigationIcon Clicked!", + Toast.LENGTH_SHORT + ).show() + } + ) + } + ) + } + ) { + + } + } } \ No newline at end of file