fix(now-playing): мгновенный рефреш эфира при возврате из фона + восстановление сессии

Опрос now-playing был привязан к play()/жизни ViewModel — при заморозке ColorOS
в фоне или пересоздании ViewModel трек «застывал». Теперь: startNowPlaying()
с мгновенным refresh, восстановление привязки к играющей станции из
PlayerController.currentStationId, и onAppForeground() на ON_RESUME.
This commit is contained in:
nk
2026-06-10 18:05:32 +03:00
parent 3c7ae1eb4c
commit 7a00f53b20
2 changed files with 50 additions and 0 deletions

View File

@@ -118,6 +118,20 @@ class PlayerViewModel @Inject constructor(
viewModelScope.launch {
settingsRepository.getPreferredBitrate().collect { preferredBitrate = it }
}
// Восстановление сессии: если процесс/Activity пересоздались, а станция уже
// играет в фоновом сервисе (PlayerController помнит id) — заново привязываемся
// и запускаем опрос now-playing. Иначе мини-плеер/эфир «застывают».
viewModelScope.launch {
combine(playerController.currentStationId, _stations) { id, list ->
id?.let { sid -> list.firstOrNull { it.id == sid } }
}.collect { station ->
if (station != null && _currentStation.value == null) {
_currentStation.value = station
_playlist.value = _stations.value
startNowPlaying(station)
}
}
}
viewModelScope.launch {
_currentTrack
.filterNotNull()
@@ -150,8 +164,20 @@ class PlayerViewModel @Inject constructor(
playerController.play(url, station.prefix, station.name, station.id)
}
viewModelScope.launch { pushHistoryUseCase(station.id) }
startNowPlaying(station)
}
/**
* Запускает опрос now-playing для станции: мгновенный рефреш + цикл раз в 5с
* (пока играем) + сбор трека из API (приоритет) и ICY (фолбэк). Вынесено из
* play(), чтобы переиспользовать при восстановлении сессии (возврат из фона /
* пересоздание ViewModel) — иначе эфир «застывает» на последнем значении.
*/
private fun startNowPlaying(station: Station) {
nowPlayingJob?.cancel()
nowPlayingJob = viewModelScope.launch {
// Сразу тянем свежий эфир — не ждём первые 5с цикла.
launch { nowPlayingRepository.refreshNowPlaying() }
// Поллинг now-playing — ТОЛЬКО пока играем. collectLatest отменяет
// внутренний цикл при паузе (иначе на паузе радио зря дёргали сеть
// каждые 5с → батарея + лишняя нагрузка на бэкенд).
@@ -208,6 +234,17 @@ class PlayerViewModel @Inject constructor(
}
}
/**
* Возврат приложения на передний план: мгновенно освежаем эфир (чтобы юзер не
* видел залипший трек после фоновой заморозки) и, если опрос почему-то не идёт,
* перезапускаем его для текущей станции.
*/
fun onAppForeground() {
val station = _currentStation.value ?: return
viewModelScope.launch { nowPlayingRepository.refreshNowPlaying() }
if (nowPlayingJob?.isActive != true) startNowPlaying(station)
}
/** Стартовое качество станции с учётом предпочтения пользователя. */
private fun pickInitialQuality(station: Station): StreamQuality? {
val list = station.qualities