feat(filters): чипы растворяются под кнопкой-категорией (fade left edge)

Кнопка-категории теперь ПОВЕРХ чипов (Box-оверлей), чипы идут во всю ширину с
отступом слева под кнопку. У левого края — затухание прозрачности (Modifier.
fadingStartEdge: graphicsLayer Offscreen + horizontalGradient BlendMode.DstIn), так
чипы при прокрутке влево красиво уплывают под кнопку и растворяются, а не обрезаются.
FilterChips/GenreSelector получили параметр contentPadding. Экраны Радио и Чарты.
This commit is contained in:
nk
2026-06-07 17:33:35 +03:00
parent 78282e97ca
commit 87dca7a6df
3 changed files with 60 additions and 20 deletions

View File

@@ -46,6 +46,7 @@ import com.radiola.domain.model.StatPoint
import com.radiola.domain.model.TrackStats
import com.radiola.ui.components.CategoryPicker
import com.radiola.ui.components.EmptyState
import com.radiola.ui.components.fadingStartEdge
import com.radiola.ui.components.PopularityChart
import com.radiola.ui.components.crossfadeModel
import com.radiola.ui.components.serviceLogoRes
@@ -102,19 +103,23 @@ fun ChartsScreen(
// Фильтр по жанру (если бэкенд уже накопил жанры)
if (genres.isNotEmpty()) {
Spacer(Modifier.height(10.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
Box(modifier = Modifier.fillMaxWidth().height(44.dp)) {
GenreSelector(
genres = genres,
selected = selectedGenre,
onSelect = viewModel::selectGenre,
contentPadding = PaddingValues(start = 70.dp, end = 20.dp),
modifier = Modifier
.fillMaxWidth()
.align(Alignment.Center)
.fadingStartEdge(62.dp)
)
CategoryPicker(
title = "Стиль музыки",
items = genres,
selected = selectedGenre,
onSelect = viewModel::selectGenre,
modifier = Modifier.padding(start = 20.dp)
)
GenreSelector(
genres = genres,
selected = selectedGenre,
onSelect = viewModel::selectGenre,
modifier = Modifier.weight(1f)
modifier = Modifier.align(Alignment.CenterStart).padding(start = 20.dp)
)
}
}
@@ -225,12 +230,13 @@ private fun GenreSelector(
genres: List<String>,
selected: String?,
onSelect: (String?) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(horizontal = 20.dp)
) {
LazyRow(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(9.dp),
contentPadding = PaddingValues(horizontal = 20.dp)
contentPadding = contentPadding
) {
item {
PeriodChip(

View File

@@ -20,18 +20,45 @@ import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.radiola.ui.theme.Motion
import com.radiola.ui.theme.RadiolaTheme
/**
* Плавное затухание содержимого у ЛЕВОГО края (прозрачность) на ширину [width].
* Чипы, заезжая под кнопку-«категории», красиво растворяются, а не обрезаются.
*/
fun Modifier.fadingStartEdge(width: Dp): Modifier = this
.graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen }
.drawWithContent {
drawContent()
val w = width.toPx().coerceAtMost(size.width)
drawRect(
brush = Brush.horizontalGradient(
colorStops = arrayOf(
0f to Color.Transparent,
(w / size.width) to Color.Black
)
),
blendMode = BlendMode.DstIn
)
}
@Composable
fun FilterChips(
tags: List<String>,
selectedTag: String?,
onTagSelected: (String?) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp)
) {
val listState = rememberLazyListState()
// Доводим выбранный чип в зону видимости (важно при свайп-переключении).
@@ -43,7 +70,7 @@ fun FilterChips(
modifier = modifier,
state = listState,
horizontalArrangement = Arrangement.spacedBy(9.dp),
contentPadding = PaddingValues(horizontal = 16.dp)
contentPadding = contentPadding
) {
item {
Chip(label = "Все", selected = selectedTag == null) { onTagSelected(null) }

View File

@@ -178,19 +178,26 @@ fun StationsScreen(
)
.padding(top = 2.dp, bottom = 12.dp)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Box(modifier = Modifier.fillMaxWidth().height(44.dp)) {
// Чипы во всю ширину, но с отступом слева под кнопку; у левого
// края — затухание прозрачности (чипы «уплывают» под кнопку).
FilterChips(
tags = tags,
selectedTag = selectedTag,
onTagSelected = viewModel::onTagSelected,
contentPadding = PaddingValues(start = 66.dp, end = 16.dp),
modifier = Modifier
.fillMaxWidth()
.align(Alignment.Center)
.fadingStartEdge(60.dp)
)
// Кнопка-категории — поверх чипов, слева.
CategoryPicker(
title = "Категории",
items = tags,
selected = selectedTag,
onSelect = viewModel::onTagSelected,
modifier = Modifier.padding(start = 16.dp)
)
FilterChips(
tags = tags,
selectedTag = selectedTag,
onTagSelected = viewModel::onTagSelected,
modifier = Modifier.weight(1f)
modifier = Modifier.align(Alignment.CenterStart).padding(start = 16.dp)
)
}
}