fix(ui): иконочный таб-бар, заголовок станций, ровные кнопки плеера, рабочая ссылка на текст
- таб-бар только иконки (6 разделов не помещались с подписями) - «Откройте радио» -> «Выберите радиостанцию» - кнопки плеера (лайк/prev/next/запись) единого размера 24/48, ряд SpaceBetween (кнопка записи больше не обрезается и не выбивается размером) - текст песни: Musixmatch резал соединение -> веб-поиск трека (открывается)
This commit is contained in:
@@ -12,8 +12,11 @@ import javax.inject.Singleton
|
||||
class LyricsRepositoryImpl @Inject constructor() : LyricsRepository {
|
||||
|
||||
override fun providerUrl(artist: String, song: String): String {
|
||||
val query = URLEncoder.encode("$artist $song", "UTF-8")
|
||||
return "https://www.musixmatch.com/search/$query"
|
||||
// Musixmatch блокирует прямые переходы (connection reset). Открываем
|
||||
// веб-поиск по треку — пользователь сам выбирает сервис с текстом.
|
||||
// Сам текст не встраиваем и не храним (авторское право).
|
||||
val query = URLEncoder.encode("$artist $song текст песни", "UTF-8")
|
||||
return "https://yandex.ru/search/?text=$query"
|
||||
}
|
||||
|
||||
// TODO: подключить официальный Musixmatch API (с атрибуцией) и вернуть реальный сниппет.
|
||||
|
||||
@@ -66,7 +66,7 @@ fun BottomNavBar(navController: NavController) {
|
||||
label = destination.labelRes,
|
||||
icon = destination.icon,
|
||||
selected = selected,
|
||||
modifier = Modifier.weight(if (selected) 1.9f else 1f),
|
||||
modifier = Modifier.weight(1f),
|
||||
onClick = {
|
||||
if (currentRoute != destination.route) {
|
||||
navController.navigate(destination.route) {
|
||||
@@ -114,26 +114,12 @@ private fun PillTab(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// Только иконки — подписи не помещались для 6 разделов.
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = label,
|
||||
tint = content,
|
||||
modifier = Modifier.height(18.dp).width(18.dp)
|
||||
modifier = Modifier.height(22.dp).width(22.dp)
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = selected,
|
||||
enter = fadeIn(tween(Motion.Medium)) + expandHorizontally(tween(Motion.Medium)),
|
||||
exit = fadeOut(tween(Motion.Fast)) + shrinkHorizontally(tween(Motion.Fast))
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
text = label.uppercase(),
|
||||
color = content,
|
||||
style = androidx.compose.material3.MaterialTheme.typography.labelSmall,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,8 @@ fun PlayerBottomSheet(
|
||||
|
||||
// Управление воспроизведением
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(24.dp),
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// Кнопка избранного
|
||||
@@ -166,15 +167,15 @@ fun PlayerBottomSheet(
|
||||
animationSpec = tween(Motion.Medium),
|
||||
label = "heartTint"
|
||||
)
|
||||
PlayerIconBtn(size = 44.dp) {
|
||||
PlayerIconBtn(size = 48.dp) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
onToggleFavorite()
|
||||
},
|
||||
modifier = Modifier.size(44.dp)
|
||||
modifier = Modifier.size(48.dp)
|
||||
) {
|
||||
Icon(Lucide.Heart, "Избранное", tint = heartTint, modifier = Modifier.size(22.dp))
|
||||
Icon(Lucide.Heart, "Избранное", tint = heartTint, modifier = Modifier.size(24.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,8 +227,8 @@ fun PlayerBottomSheet(
|
||||
animationSpec = tween(Motion.Medium),
|
||||
label = "recordTint"
|
||||
)
|
||||
PlayerIconBtn(size = 44.dp) {
|
||||
IconButton(onClick = onToggleRecording, modifier = Modifier.size(44.dp)) {
|
||||
PlayerIconBtn(size = 48.dp) {
|
||||
IconButton(onClick = onToggleRecording, modifier = Modifier.size(48.dp)) {
|
||||
Crossfade(
|
||||
targetState = isRecording,
|
||||
animationSpec = tween(Motion.Fast),
|
||||
@@ -237,7 +238,7 @@ fun PlayerBottomSheet(
|
||||
imageVector = if (recording) Lucide.MicOff else Lucide.Mic,
|
||||
contentDescription = if (recording) "Остановить запись" else "Запись",
|
||||
tint = recordTint,
|
||||
modifier = Modifier.size(20.dp)
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ fun StationsScreen(
|
||||
// Двухцветный заголовок экрана
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
withStyle(SpanStyle(color = colors.textPrimary)) { append("Откройте ") }
|
||||
withStyle(SpanStyle(color = colors.accent)) { append("радио") }
|
||||
withStyle(SpanStyle(color = colors.textPrimary)) { append("Выберите ") }
|
||||
withStyle(SpanStyle(color = colors.accent)) { append("радиостанцию") }
|
||||
},
|
||||
style = MaterialTheme.typography.headlineLarge,
|
||||
modifier = Modifier.padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 16.dp)
|
||||
|
||||
Reference in New Issue
Block a user