Skip to content
Merged
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
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
Expand All @@ -30,6 +31,7 @@ import androidx.compose.material3.SearchBarDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
Expand Down Expand Up @@ -58,7 +60,6 @@ import ru.yeahub.ui.R
private sealed class TextInputState {
data object Default : TextInputState()
data object Focused : TextInputState()
data object Active : TextInputState()
data object Error : TextInputState()
data object Disabled : TextInputState()
}
Expand All @@ -80,7 +81,7 @@ fun TextInput(
shape: Shape = RoundedCornerShape(12.dp),
contentPadding: PaddingValues = OutlinedTextFieldDefaults.contentPadding(),
singleLine: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
val isFocused by interactionSource.collectIsFocusedAsState()

Expand All @@ -96,7 +97,7 @@ fun TextInput(
Box(
modifier = modifier
.width(300.dp)
.height(300.dp)
.height(300.dp),
) {
SearchBar(
inputField = {
Expand All @@ -106,15 +107,15 @@ fun TextInput(
onValueChange(newValue)
},
modifier = Modifier,
label = label,
placeholder = label,
isFocused = isFocused,
isEnabled = isEnabled,
isError = isError,
onExpandedChange = onExpandedChange,
colors = colors,
shape = shape,
singleLine = singleLine,
interactionSource = interactionSource
interactionSource = interactionSource,
)
},
expanded = expanded,
Expand All @@ -124,15 +125,15 @@ fun TextInput(
shape = shape,
colors = SearchBarDefaults.colors(
containerColor = Color.Transparent,
dividerColor = Color.Transparent
dividerColor = Color.Transparent,
),
) {
Surface(
modifier = Modifier
.fillMaxWidth(),
shape = MaterialTheme.shapes.medium,
color = Theme.colors.white900,
border = BorderStroke(1.dp, TextInputColorsDefaults.defaultsBorder())
border = BorderStroke(1.dp, TextInputColorsDefaults.defaultsBorder()),
) {
LazyColumn(
modifier = Modifier.fillMaxWidth(),
Expand All @@ -145,13 +146,13 @@ fun TextInput(
onValueChange(suggestion)
onExpandedChange(false)
}
.padding(contentPadding)
.padding(contentPadding),
) {
Text(
text = suggestion,
color = colors.contentColor(isEnabled).value,
style = Theme.typography.body3,
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth(),
)
}
}
Expand All @@ -166,7 +167,7 @@ fun TextInput(
fun DefaultTextField(
value: String,
onValueChange: (String) -> Unit,
label: String,
placeholder: String,
modifier: Modifier = Modifier,
onExpandedChange: (Boolean) -> Unit,
colors: ColorsTextInputYeaHub = TextInputColorsDefaults.defaultColors(),
Expand All @@ -175,7 +176,10 @@ fun DefaultTextField(
isError: Boolean = false,
singleLine: Boolean = true,
shape: Shape = RoundedCornerShape(12.dp),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
readOnly: Boolean = false,
leadingIcon: (@Composable (() -> Unit))? = null,
trailingIcon: (@Composable (() -> Unit))? = null,
) {
val containerColor by colors.containerColor(isEnabled)
val contentColor by colors.contentColor(isEnabled)
Expand All @@ -186,26 +190,44 @@ fun DefaultTextField(
!isEnabled -> TextInputState.Disabled
isError -> TextInputState.Error
isFocused -> TextInputState.Focused
value.isNotEmpty() -> TextInputState.Active
else -> TextInputState.Default
}

val iconColor = when (state) {
TextInputState.Active -> Theme.colors.black900
else -> Theme.colors.black300
TextInputState.Default -> Theme.colors.black300
TextInputState.Disabled -> Theme.colors.black300
else -> Theme.colors.black900
}

val defaultBorder = when (state) {
TextInputState.Active -> TextInputColorsDefaults.activeBorder()
TextInputState.Focused -> TextInputColorsDefaults.activeBorder()
TextInputState.Error -> TextInputColorsDefaults.errorBorder()
else -> TextInputColorsDefaults.defaultsBorder()
}

fun provideIconColor(
slot: (@Composable () -> Unit)?,
color: Color,
): (@Composable () -> Unit)? =
slot?.let { content ->
{
CompositionLocalProvider(LocalContentColor provides color) {
content()
}
}
}

val leadingIconSlot = provideIconColor(leadingIcon, iconColor)

val trailingIconSlot = provideIconColor(trailingIcon, iconColor)

OutlinedTextField(
value = value,
onValueChange = onValueChange,
label = {
readOnly = readOnly,
placeholder = {
Text(
text = label,
text = placeholder,
color = Theme.colors.black300,
style = Theme.typography.body3,
)
Expand All @@ -215,17 +237,8 @@ fun DefaultTextField(
.height(58.dp),
enabled = isEnabled,
singleLine = singleLine,
leadingIcon =
{
Icon(
painter = painterResource(id = R.drawable.icon_search),
contentDescription = "Поиск",
tint = iconColor,
modifier = modifier
.width(20.dp)
.height(20.dp)
)
},
leadingIcon = leadingIconSlot,
trailingIcon = trailingIconSlot,
isError = isError,
shape = shape,
textStyle = Theme.typography.body3,
Expand All @@ -249,7 +262,7 @@ fun DefaultTextField(
onExpandedChange(false)
keyboardController?.hide()
focusManager.clearFocus(force = true)
}
},
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
interactionSource = interactionSource,
Expand All @@ -268,7 +281,7 @@ object TextInputColorsDefaults {
containerColor = containerColor,
contentColor = contentColor,
disabledContentColor = disabledContentColor,
disabledContainerColor = disabledContainerColor
disabledContainerColor = disabledContainerColor,
)
}

Expand Down Expand Up @@ -307,14 +320,23 @@ data class TextInputParams(
val value: String,
val onValueChange: (String) -> Unit,
val onExpandedChange: (Boolean) -> Unit,
val label: String,
val placeholder: String,
val modifier: Modifier = Modifier,
val isEnabled: Boolean = true,
val isError: Boolean = false,
val isExpanded: Boolean = false,
val isFocus: Boolean = false,
val colors: ColorsTextInputYeaHub = getTextInputColors(),
val singleLine: Boolean = true,
val leadingIcon: (@Composable () -> Unit)? = {
Icon(
painter = painterResource(R.drawable.icon_search),
contentDescription = "Поиск",
modifier = modifier
.width(20.dp)
.height(20.dp),
)
},
)

fun getTextInputColors(): ColorsTextInputYeaHub {
Expand All @@ -332,64 +354,75 @@ class TextInputParamsProvider : PreviewParameterProvider<TextInputParams> {
value = "",
onValueChange = {},
onExpandedChange = {},
label = "text",
placeholder = "placeholder",
isEnabled = true,
isError = false
isError = false,
),
TextInputParams(
value = "text",
onValueChange = {},
onExpandedChange = {},
label = "text",
placeholder = "placeholder",
isEnabled = true,
isError = false
isError = false,
isFocus = true,
),
TextInputParams(
value = "",
onValueChange = {},
onExpandedChange = {},
label = "text",
placeholder = "placeholder",
isEnabled = false,
isError = false
isError = false,
),
TextInputParams(
value = "",
onValueChange = {},
onExpandedChange = {},
label = "text",
placeholder = "placeholder",
isEnabled = true,
isError = true
isError = true,
),
TextInputParams(
value = "text",
onValueChange = {},
onExpandedChange = {},
placeholder = "placeholder",
isEnabled = true,
isError = false,
isFocus = false,
),
)
}

@StaticPreview
@Composable
fun TextInputPreview(
@PreviewParameter(TextInputParamsProvider::class) params: TextInputParams
@PreviewParameter(TextInputParamsProvider::class) params: TextInputParams,
) {
Box(
Modifier
.background(Color.White)
.padding(10.dp)
.padding(10.dp),
) {
DefaultTextField(
value = params.value,
onValueChange = params.onValueChange,
onExpandedChange = params.onExpandedChange,
label = params.label,
placeholder = params.placeholder,
isEnabled = params.isEnabled,
isError = params.isError,
colors = params.colors,
isFocused = params.isFocus
isFocused = params.isFocus,
leadingIcon = params.leadingIcon,
)
}
}

@StandardScreenSizePreview
@Composable
fun TextInputDynamicPreview(
@PreviewParameter(TextInputPreviewProvider::class) params: Pair<String, List<String>>
@PreviewParameter(TextInputPreviewProvider::class) params: Pair<String, List<String>>,
) {
val mockViewModel = object : SuggestionsViewModel() {
init {
Expand All @@ -413,7 +446,7 @@ fun ScreenSuggestions(
modifier = modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
verticalArrangement = Arrangement.Center,
) {
TextInput(
value = text,
Expand All @@ -424,7 +457,7 @@ fun ScreenSuggestions(
suggestions = suggestions,
onQueryChanged = { viewModel.onQueryChange(it, suggestions) },
expanded = expanded,
onExpandedChange = { expanded = it }
onExpandedChange = { expanded = it },
)
}
}
Expand All @@ -436,4 +469,4 @@ class TextInputPreviewProvider : PreviewParameterProvider<Pair<String, List<Stri
Pair("теле", listOf("телефон", "телевизор")),
Pair("телек", listOf("телефон", "телевизор")),
)
}
}