Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.lyrics.feelin.core.designsystem.component

import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
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.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.InputTransformation
import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.clearText
import androidx.compose.foundation.text.input.maxLength
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.lyrics.feelin.core.designsystem.icon.SearchIcon
import com.lyrics.feelin.presentation.designsystem.theme.FeelinTheme
import com.lyrics.feelin.presentation.designsystem.theme.FeelinTypography
import com.lyrics.feelin.presentation.designsystem.theme.LocalFeelinColors

private const val MAX_INPUT_LENGTH: Int = 100

/**
* Feelin 앱의 검색 입력 필드 컴포넌트입니다.
*
* 라이트/다크 모드에 따라 자동으로 색상이 변경됩니다.
*
* @param state 텍스트 입력 상태
* @param modifier 컴포넌트 수정자
* @param placeholder 입력 필드의 플레이스홀더 텍스트
* @param onClearClick 클리어 버튼 클릭 시 호출되는 콜백
*/
@Composable
fun FeelinSearchInputField(
state: TextFieldState,
modifier: Modifier = Modifier,
placeholder: String = "",
onSearchClick: () -> Unit = {},
onClearClick: () -> Unit = {}
) {
val feelinColors = LocalFeelinColors.current

val backgroundColor = feelinColors.inputField
val textColor = feelinColors.gray09
val placeholderColor = feelinColors.gray04
val iconTintColor = feelinColors.gray05
val clearButtonColor = feelinColors.gray03

val interactionSource = remember { MutableInteractionSource() }

BasicTextField(
state = state,
modifier = modifier,
lineLimits = TextFieldLineLimits.SingleLine,
inputTransformation = InputTransformation.maxLength(MAX_INPUT_LENGTH),
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Search,
keyboardType = KeyboardType.Text,
autoCorrectEnabled = false
),
onKeyboardAction = { onSearchClick.invoke() },
textStyle = FeelinTypography.body3.copy(color = textColor),
cursorBrush = SolidColor(textColor),
decorator = { innerTextField ->
Row(
modifier = Modifier
.fillMaxWidth()
.background(
color = backgroundColor,
shape = RoundedCornerShape(8.dp),
)
.padding(all = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
// 검색 아이콘
Icon(
painter = SearchIcon,
contentDescription = null,
modifier = Modifier.size(20.dp),
tint = iconTintColor,
)

Spacer(modifier = Modifier.width(8.dp))

// 텍스트 입력 영역
InnerTextFieldComponent(
isTextEmpty = state.text.isEmpty(),
placeholder = placeholder,
placeholderColor = placeholderColor,
placeholderTextStyle = FeelinTypography.body3,
clearIconColor = clearButtonColor,
innerTextField = innerTextField,
onClearButtonClick = { onClearClick.invoke() },
clearButtonInteractionSource = interactionSource
)
}
},
)
}

@Preview(name = "Light mode", showBackground = true, backgroundColor = 0xff000000)
@Preview(name = "Dark mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun FeelinSearchInputFieldPreview() {
val state = remember { TextFieldState() }
FeelinTheme {
FeelinSearchInputField(
state = state,
placeholder = "텍스트",
onSearchClick = { println("onSearchClick invoke") },
onClearClick = { state.clearText() }
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.lyrics.feelin.core.designsystem.component

import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import com.lyrics.feelin.core.designsystem.icon.XCircleIcon

/**
* BasicTextField 기반의 입력창에서 텍스트필드에 공통된 디자인을 사용하기 위한 컴포넌트입니다.
* */
@Composable
fun RowScope.InnerTextFieldComponent(
isTextEmpty: Boolean,
placeholder: String,
placeholderTextStyle: TextStyle,
placeholderColor: Color,
clearIconColor: Color,
innerTextField: @Composable (() -> Unit),
onClearButtonClick: () -> Unit,
clearButtonInteractionSource: MutableInteractionSource?,
modifier: Modifier = Modifier
) {
Box(modifier = Modifier.weight(1f)) {
if (isTextEmpty) {
Text(
text = placeholder,
style = placeholderTextStyle,
color = placeholderColor,
)
}
innerTextField()
}

// 클리어 버튼 (입력값 있을 때만 표시)
if (!isTextEmpty) {
Spacer(modifier = Modifier.width(8.dp))

Icon(
painter = XCircleIcon,
contentDescription = "입력 내용 지우기",
tint = clearIconColor,
modifier = Modifier.size(20.dp).clickable(
interactionSource = clearButtonInteractionSource,
indication = null,
onClick = onClearButtonClick,
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,11 @@ val EmptyImageDarkIcon: Painter
val EmptyImageLightIcon: Painter
@Composable
get() = painterResource(id = R.drawable.empty_image_light)

val XCircleIcon: Painter
@Composable
get() = painterResource(id = R.drawable.xcircle)

val SearchIcon: Painter
@Composable
get() = painterResource(id = R.drawable.search)
25 changes: 25 additions & 0 deletions app/src/main/res/drawable/search.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M21.795,20.204L17.343,15.75C18.678,14.01 19.301,11.828 19.086,9.646C18.872,7.464 17.835,5.445 16.186,3.999C14.538,2.553 12.401,1.789 10.209,1.861C8.018,1.932 5.935,2.835 4.385,4.385C2.834,5.936 1.932,8.018 1.86,10.21C1.788,12.401 2.553,14.538 3.999,16.187C5.445,17.835 7.463,18.872 9.645,19.087C11.828,19.302 14.01,18.678 15.749,17.344L20.205,21.801C20.31,21.905 20.434,21.988 20.571,22.045C20.708,22.101 20.854,22.131 21.002,22.131C21.15,22.131 21.297,22.101 21.434,22.045C21.57,21.988 21.694,21.905 21.799,21.801C21.904,21.696 21.987,21.572 22.043,21.435C22.1,21.298 22.129,21.152 22.129,21.004C22.129,20.856 22.1,20.709 22.043,20.572C21.987,20.436 21.904,20.311 21.799,20.207L21.795,20.204ZM4.124,10.5C4.124,9.239 4.498,8.006 5.199,6.958C5.899,5.91 6.895,5.093 8.06,4.61C9.225,4.128 10.507,4.001 11.743,4.247C12.98,4.493 14.116,5.101 15.007,5.992C15.899,6.884 16.506,8.02 16.752,9.256C16.998,10.493 16.872,11.775 16.389,12.939C15.907,14.104 15.09,15.1 14.041,15.8C12.993,16.501 11.76,16.875 10.499,16.875C8.809,16.873 7.189,16.201 5.994,15.006C4.798,13.811 4.126,12.19 4.124,10.5Z"
android:fillColor="#101223"/>
<path
android:pathData="M21.795,20.204L17.343,15.75C18.678,14.01 19.301,11.828 19.086,9.646C18.872,7.464 17.835,5.445 16.186,3.999C14.538,2.553 12.401,1.789 10.209,1.861C8.018,1.932 5.935,2.835 4.385,4.385C2.834,5.936 1.932,8.018 1.86,10.21C1.788,12.401 2.553,14.538 3.999,16.187C5.445,17.835 7.463,18.872 9.645,19.087C11.828,19.302 14.01,18.678 15.749,17.344L20.205,21.801C20.31,21.905 20.434,21.988 20.571,22.045C20.708,22.101 20.854,22.131 21.002,22.131C21.15,22.131 21.297,22.101 21.434,22.045C21.57,21.988 21.694,21.905 21.799,21.801C21.904,21.696 21.987,21.572 22.043,21.435C22.1,21.298 22.129,21.152 22.129,21.004C22.129,20.856 22.1,20.709 22.043,20.572C21.987,20.436 21.904,20.311 21.799,20.207L21.795,20.204ZM4.124,10.5C4.124,9.239 4.498,8.006 5.199,6.958C5.899,5.91 6.895,5.093 8.06,4.61C9.225,4.128 10.507,4.001 11.743,4.247C12.98,4.493 14.116,5.101 15.007,5.992C15.899,6.884 16.506,8.02 16.752,9.256C16.998,10.493 16.872,11.775 16.389,12.939C15.907,14.104 15.09,15.1 14.041,15.8C12.993,16.501 11.76,16.875 10.499,16.875C8.809,16.873 7.189,16.201 5.994,15.006C4.798,13.811 4.126,12.19 4.124,10.5Z"
android:fillColor="#000000"
android:fillAlpha="0.2"/>
<path
android:pathData="M21.795,20.204L17.343,15.75C18.678,14.01 19.301,11.828 19.086,9.646C18.872,7.464 17.835,5.445 16.186,3.999C14.538,2.553 12.401,1.789 10.209,1.861C8.018,1.932 5.935,2.835 4.385,4.385C2.834,5.936 1.932,8.018 1.86,10.21C1.788,12.401 2.553,14.538 3.999,16.187C5.445,17.835 7.463,18.872 9.645,19.087C11.828,19.302 14.01,18.678 15.749,17.344L20.205,21.801C20.31,21.905 20.434,21.988 20.571,22.045C20.708,22.101 20.854,22.131 21.002,22.131C21.15,22.131 21.297,22.101 21.434,22.045C21.57,21.988 21.694,21.905 21.799,21.801C21.904,21.696 21.987,21.572 22.043,21.435C22.1,21.298 22.129,21.152 22.129,21.004C22.129,20.856 22.1,20.709 22.043,20.572C21.987,20.436 21.904,20.311 21.799,20.207L21.795,20.204ZM4.124,10.5C4.124,9.239 4.498,8.006 5.199,6.958C5.899,5.91 6.895,5.093 8.06,4.61C9.225,4.128 10.507,4.001 11.743,4.247C12.98,4.493 14.116,5.101 15.007,5.992C15.899,6.884 16.506,8.02 16.752,9.256C16.998,10.493 16.872,11.775 16.389,12.939C15.907,14.104 15.09,15.1 14.041,15.8C12.993,16.501 11.76,16.875 10.499,16.875C8.809,16.873 7.189,16.201 5.994,15.006C4.798,13.811 4.126,12.19 4.124,10.5Z"
android:fillColor="#000000"
android:fillAlpha="0.2"/>
<path
android:pathData="M21.795,20.204L17.343,15.75C18.678,14.01 19.301,11.828 19.086,9.646C18.872,7.464 17.835,5.445 16.186,3.999C14.538,2.553 12.401,1.789 10.209,1.861C8.018,1.932 5.935,2.835 4.385,4.385C2.834,5.936 1.932,8.018 1.86,10.21C1.788,12.401 2.553,14.538 3.999,16.187C5.445,17.835 7.463,18.872 9.645,19.087C11.828,19.302 14.01,18.678 15.749,17.344L20.205,21.801C20.31,21.905 20.434,21.988 20.571,22.045C20.708,22.101 20.854,22.131 21.002,22.131C21.15,22.131 21.297,22.101 21.434,22.045C21.57,21.988 21.694,21.905 21.799,21.801C21.904,21.696 21.987,21.572 22.043,21.435C22.1,21.298 22.129,21.152 22.129,21.004C22.129,20.856 22.1,20.709 22.043,20.572C21.987,20.436 21.904,20.311 21.799,20.207L21.795,20.204ZM4.124,10.5C4.124,9.239 4.498,8.006 5.199,6.958C5.899,5.91 6.895,5.093 8.06,4.61C9.225,4.128 10.507,4.001 11.743,4.247C12.98,4.493 14.116,5.101 15.007,5.992C15.899,6.884 16.506,8.02 16.752,9.256C16.998,10.493 16.872,11.775 16.389,12.939C15.907,14.104 15.09,15.1 14.041,15.8C12.993,16.501 11.76,16.875 10.499,16.875C8.809,16.873 7.189,16.201 5.994,15.006C4.798,13.811 4.126,12.19 4.124,10.5Z"
android:fillColor="#000000"
android:fillAlpha="0.2"/>
<path
android:pathData="M21.795,20.204L17.343,15.75C18.678,14.01 19.301,11.828 19.086,9.646C18.872,7.464 17.835,5.445 16.186,3.999C14.538,2.553 12.401,1.789 10.209,1.861C8.018,1.932 5.935,2.835 4.385,4.385C2.834,5.936 1.932,8.018 1.86,10.21C1.788,12.401 2.553,14.538 3.999,16.187C5.445,17.835 7.463,18.872 9.645,19.087C11.828,19.302 14.01,18.678 15.749,17.344L20.205,21.801C20.31,21.905 20.434,21.988 20.571,22.045C20.708,22.101 20.854,22.131 21.002,22.131C21.15,22.131 21.297,22.101 21.434,22.045C21.57,21.988 21.694,21.905 21.799,21.801C21.904,21.696 21.987,21.572 22.043,21.435C22.1,21.298 22.129,21.152 22.129,21.004C22.129,20.856 22.1,20.709 22.043,20.572C21.987,20.436 21.904,20.311 21.799,20.207L21.795,20.204ZM4.124,10.5C4.124,9.239 4.498,8.006 5.199,6.958C5.899,5.91 6.895,5.093 8.06,4.61C9.225,4.128 10.507,4.001 11.743,4.247C12.98,4.493 14.116,5.101 15.007,5.992C15.899,6.884 16.506,8.02 16.752,9.256C16.998,10.493 16.872,11.775 16.389,12.939C15.907,14.104 15.09,15.1 14.041,15.8C12.993,16.501 11.76,16.875 10.499,16.875C8.809,16.873 7.189,16.201 5.994,15.006C4.798,13.811 4.126,12.19 4.124,10.5Z"
android:fillColor="#000000"
android:fillAlpha="0.2"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/xcircle.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2.25C10.072,2.25 8.187,2.822 6.583,3.893C4.98,4.965 3.73,6.487 2.992,8.269C2.254,10.05 2.061,12.011 2.437,13.902C2.814,15.793 3.742,17.531 5.106,18.894C6.469,20.258 8.207,21.187 10.098,21.563C11.989,21.939 13.95,21.746 15.731,21.008C17.513,20.27 19.035,19.02 20.107,17.417C21.178,15.813 21.75,13.928 21.75,12C21.747,9.415 20.719,6.937 18.891,5.109C17.063,3.281 14.585,2.253 12,2.25ZM15.531,14.469C15.6,14.539 15.656,14.622 15.693,14.713C15.731,14.804 15.75,14.901 15.75,15C15.75,15.099 15.731,15.196 15.693,15.287C15.656,15.378 15.6,15.461 15.531,15.531C15.461,15.6 15.378,15.656 15.287,15.693C15.196,15.731 15.099,15.75 15,15.75C14.901,15.75 14.804,15.731 14.713,15.693C14.622,15.656 14.539,15.6 14.469,15.531L12,13.06L9.531,15.531C9.461,15.6 9.378,15.656 9.287,15.693C9.196,15.731 9.099,15.75 9,15.75C8.901,15.75 8.804,15.731 8.713,15.693C8.622,15.656 8.539,15.6 8.469,15.531C8.4,15.461 8.344,15.378 8.307,15.287C8.269,15.196 8.25,15.099 8.25,15C8.25,14.901 8.269,14.804 8.307,14.713C8.344,14.622 8.4,14.539 8.469,14.469L10.94,12L8.469,9.531C8.329,9.39 8.25,9.199 8.25,9C8.25,8.801 8.329,8.61 8.469,8.469C8.61,8.329 8.801,8.25 9,8.25C9.199,8.25 9.39,8.329 9.531,8.469L12,10.94L14.469,8.469C14.539,8.4 14.622,8.344 14.713,8.307C14.804,8.269 14.901,8.25 15,8.25C15.099,8.25 15.196,8.269 15.287,8.307C15.378,8.344 15.461,8.4 15.531,8.469C15.6,8.539 15.656,8.622 15.693,8.713C15.731,8.804 15.75,8.901 15.75,9C15.75,9.099 15.731,9.196 15.693,9.287C15.656,9.378 15.6,9.461 15.531,9.531L13.06,12L15.531,14.469Z"
android:fillColor="#B3B5BD"/>
</vector>