- Кнопка-«категории» (круглая, акцентная рамка, иконка SlidersHorizontal) СЛЕВА от чипа «Все» — на экранах Радио и Чарты. Открывает шторку со списком всех категорий (Радио — жанры, Чарты — стили) + поиск, чтобы не листать чипы. CategoryPicker — переиспользуемый компонент с поиском и отметкой выбранного. - SearchBar: анимированная кнопка очистки (X, scale+fade появление, haptic) при непустом запросе.
85 lines
3.4 KiB
Kotlin
85 lines
3.4 KiB
Kotlin
package com.radiola.ui.components
|
||
|
||
import androidx.compose.animation.AnimatedVisibility
|
||
import androidx.compose.animation.fadeIn
|
||
import androidx.compose.animation.fadeOut
|
||
import androidx.compose.animation.scaleIn
|
||
import androidx.compose.animation.scaleOut
|
||
import androidx.compose.foundation.clickable
|
||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||
import androidx.compose.foundation.layout.fillMaxWidth
|
||
import androidx.compose.foundation.layout.padding
|
||
import androidx.compose.foundation.layout.size
|
||
import androidx.compose.foundation.shape.CircleShape
|
||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||
import androidx.compose.material3.Icon
|
||
import androidx.compose.material3.Text
|
||
import androidx.compose.material3.TextField
|
||
import androidx.compose.material3.TextFieldDefaults
|
||
import androidx.compose.runtime.Composable
|
||
import androidx.compose.runtime.remember
|
||
import androidx.compose.ui.Modifier
|
||
import androidx.compose.ui.draw.clip
|
||
import androidx.compose.ui.graphics.Color
|
||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||
import androidx.compose.ui.unit.dp
|
||
import com.composables.icons.lucide.Lucide
|
||
import com.composables.icons.lucide.Search
|
||
import com.composables.icons.lucide.X
|
||
import com.radiola.ui.theme.RadiolaTheme
|
||
|
||
@Composable
|
||
fun SearchBar(
|
||
query: String,
|
||
onQueryChange: (String) -> Unit,
|
||
placeholder: String = "Поиск станции...",
|
||
modifier: Modifier = Modifier
|
||
) {
|
||
val colors = RadiolaTheme.colors
|
||
val haptics = LocalHapticFeedback.current
|
||
TextField(
|
||
value = query,
|
||
onValueChange = onQueryChange,
|
||
modifier = modifier.fillMaxWidth(),
|
||
shape = RoundedCornerShape(14.dp),
|
||
placeholder = { Text(placeholder, color = colors.textMuted) },
|
||
leadingIcon = { Icon(Lucide.Search, contentDescription = null, tint = colors.textMuted) },
|
||
// Кнопка «очистить» — появляется/исчезает с анимацией (scale + fade).
|
||
trailingIcon = {
|
||
AnimatedVisibility(
|
||
visible = query.isNotEmpty(),
|
||
enter = scaleIn() + fadeIn(),
|
||
exit = scaleOut() + fadeOut()
|
||
) {
|
||
Icon(
|
||
imageVector = Lucide.X,
|
||
contentDescription = "Очистить",
|
||
tint = colors.textSecondary,
|
||
modifier = Modifier
|
||
.size(34.dp)
|
||
.padding(7.dp)
|
||
.clip(CircleShape)
|
||
.clickable(
|
||
interactionSource = remember { MutableInteractionSource() },
|
||
indication = null
|
||
) {
|
||
haptics.performHapticFeedback(HapticFeedbackType.TextHandleMove)
|
||
onQueryChange("")
|
||
}
|
||
)
|
||
}
|
||
},
|
||
singleLine = true,
|
||
colors = TextFieldDefaults.colors(
|
||
focusedContainerColor = colors.surface,
|
||
unfocusedContainerColor = colors.surface,
|
||
focusedIndicatorColor = Color.Transparent,
|
||
unfocusedIndicatorColor = Color.Transparent,
|
||
cursorColor = colors.accent,
|
||
focusedTextColor = colors.textPrimary,
|
||
unfocusedTextColor = colors.textPrimary
|
||
)
|
||
)
|
||
}
|