feat(stations): обложка текущего трека на карточке станции + подпись

Для станций без своей обложки (и для Radio Record — единый стиль) карточка
показывает обложку играющего трека с тёмным градиентом и подписью трек/исполнитель.
Источник — /now-playing (теперь с name станции), матч по имени, обновление 20с.
Приоритет: трек -> логотип станции -> фирменная плитка.
This commit is contained in:
nk
2026-06-03 12:18:19 +03:00
parent 9d115b148e
commit ee689ce380
8 changed files with 129 additions and 27 deletions

View File

@@ -34,6 +34,7 @@ fun FavoritesScreen(
) {
val favorites by viewModel.favorites.collectAsState()
val favoriteIds by viewModel.favoriteIds.collectAsState()
val nowPlaying by viewModel.nowPlaying.collectAsState()
val colors = RadiolaTheme.colors
Column(
@@ -93,6 +94,7 @@ fun FavoritesScreen(
isFavorite = favoriteIds.contains(station.id),
onClick = { onStationClick(station) },
onFavoriteClick = { viewModel.toggleFavorite(station) },
nowTrack = nowPlaying[station.name.trim().lowercase()],
modifier = Modifier.animateItemPlacement()
)
}

View File

@@ -3,11 +3,14 @@ package com.radiola.ui.favorites
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.radiola.domain.model.Station
import com.radiola.domain.model.Track
import com.radiola.domain.repository.FavoritesRepository
import com.radiola.domain.repository.NowPlayingRepository
import com.radiola.domain.usecase.ToggleFavoriteUseCase
import com.radiola.domain.usecase.auth.PushFavoriteUseCase
import com.radiola.domain.usecase.auth.SyncFavoritesUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
@@ -20,7 +23,8 @@ class FavoritesViewModel @Inject constructor(
private val favoritesRepository: FavoritesRepository,
private val toggleFavoriteUseCase: ToggleFavoriteUseCase,
private val pushFavoriteUseCase: PushFavoriteUseCase,
private val syncFavoritesUseCase: SyncFavoritesUseCase
private val syncFavoritesUseCase: SyncFavoritesUseCase,
private val nowPlayingRepository: NowPlayingRepository
) : ViewModel() {
val favorites: StateFlow<List<Station>> = favoritesRepository.getFavorites()
@@ -30,10 +34,21 @@ class FavoritesViewModel @Inject constructor(
.map { list -> list.map { it.id }.toSet() }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptySet())
// Текущие треки по lowercase-имени станции — для обложек на карточках.
val nowPlaying: StateFlow<Map<String, Track>> = nowPlayingRepository.getAllNowPlayingByName()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyMap())
init {
viewModelScope.launch {
syncFavoritesUseCase()
}
// Периодическое обновление now-playing каждые 20 секунд.
viewModelScope.launch {
while (true) {
nowPlayingRepository.refreshNowPlaying()
delay(20_000)
}
}
}
fun toggleFavorite(station: Station) {