feat(filters): быстрый выбор категории + очистка поиска

- Кнопка-«категории» (круглая, акцентная рамка, иконка SlidersHorizontal) СЛЕВА от
  чипа «Все» — на экранах Радио и Чарты. Открывает шторку со списком всех категорий
  (Радио — жанры, Чарты — стили) + поиск, чтобы не листать чипы. CategoryPicker —
  переиспользуемый компонент с поиском и отметкой выбранного.
- SearchBar: анимированная кнопка очистки (X, scale+fade появление, haptic) при
  непустом запросе.
This commit is contained in:
nk
2026-06-07 17:25:12 +03:00
parent 645c2f14db
commit 78282e97ca
4 changed files with 258 additions and 11 deletions

View File

@@ -1,17 +1,32 @@
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
@@ -22,6 +37,7 @@ fun SearchBar(
modifier: Modifier = Modifier
) {
val colors = RadiolaTheme.colors
val haptics = LocalHapticFeedback.current
TextField(
value = query,
onValueChange = onQueryChange,
@@ -29,6 +45,31 @@ fun SearchBar(
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,