feat(lyrics): тексты песен внутри приложения через LRCLIB
- LrcLibApi (api/get + api/search, User-Agent), DI @Named(lrclib) Retrofit - LyricsRepository.fetchLyrics -> LyricsResult (plain/synced/instrumental) - LyricsViewModel + LyricsSheet (загрузка/инструментал/найдено/не найдено), прокрутка + атрибуция LRCLIB - кнопка «Текст песни» открывает встроенный экран (плеер + деталь трека чартов), вместо ссылки в браузере
This commit is contained in:
@@ -32,6 +32,10 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import coil.compose.AsyncImage
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import com.composables.icons.lucide.FileText
|
||||
import com.composables.icons.lucide.Heart
|
||||
import com.composables.icons.lucide.Lucide
|
||||
import com.composables.icons.lucide.Mic
|
||||
@@ -46,12 +50,13 @@ import com.radiola.deeplink.DeeplinkNavigator
|
||||
import com.radiola.domain.model.DeeplinkService
|
||||
import com.radiola.domain.model.Station
|
||||
import com.radiola.domain.model.Track
|
||||
import com.radiola.ui.lyrics.LyricsSheet
|
||||
import com.radiola.ui.theme.LiveEqualizer
|
||||
import com.radiola.ui.theme.Motion
|
||||
import com.radiola.ui.theme.RadiolaTheme
|
||||
import com.radiola.ui.theme.pressScale
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun PlayerBottomSheet(
|
||||
station: Station?,
|
||||
@@ -71,6 +76,7 @@ fun PlayerBottomSheet(
|
||||
val enabledServices by viewModel.enabledServices.collectAsState()
|
||||
val colors = RadiolaTheme.colors
|
||||
val haptics = LocalHapticFeedback.current
|
||||
var showLyrics by remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
@@ -265,6 +271,42 @@ fun PlayerBottomSheet(
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(12.dp))
|
||||
}
|
||||
|
||||
// Кнопка «Текст песни» — активна только когда играет трек
|
||||
if (track != null) {
|
||||
TextButton(
|
||||
onClick = { showLyrics = true },
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Lucide.FileText,
|
||||
contentDescription = null,
|
||||
tint = colors.accent,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
Spacer(Modifier.width(6.dp))
|
||||
Text(
|
||||
text = "Текст песни",
|
||||
color = colors.accent,
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Шторка текста песни
|
||||
if (showLyrics && track != null) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { showLyrics = false },
|
||||
containerColor = colors.bgBase,
|
||||
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
) {
|
||||
LyricsSheet(
|
||||
artist = track.artist,
|
||||
song = track.song
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user