feat(ui): integrate MiniPlayer into Scaffold with real player state

This commit is contained in:
nk
2026-06-01 13:12:51 +03:00
parent 9e3ce0f1e4
commit aa287f7588
2 changed files with 57 additions and 13 deletions

View File

@@ -8,14 +8,17 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.radiola.ui.components.MiniPlayer
import com.radiola.ui.favorites.FavoritesScreen
import com.radiola.ui.history.HistoryScreen
import com.radiola.ui.navigation.BottomNavBar
import com.radiola.ui.navigation.NavDestinations
import com.radiola.ui.player.PlayerBottomSheet
import com.radiola.ui.player.PlayerViewModel
import com.radiola.ui.settings.SettingsScreen
import com.radiola.ui.stations.StationsScreen
import com.radiola.ui.theme.RadiolaTheme
@@ -31,9 +34,26 @@ class MainActivity : ComponentActivity() {
val navController = rememberNavController()
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
var showPlayer by remember { mutableStateOf(false) }
val playerViewModel: PlayerViewModel = hiltViewModel()
val isPlaying by playerViewModel.isPlaying.collectAsState()
val currentStation by playerViewModel.currentStation.collectAsState()
val currentTrack by playerViewModel.currentTrack.collectAsState()
Scaffold(
bottomBar = { BottomNavBar(navController) }
bottomBar = {
Column {
if (currentStation != null) {
MiniPlayer(
stationName = currentStation!!.name,
track = currentTrack,
isPlaying = isPlaying,
onClick = { showPlayer = true },
onPlayPause = { playerViewModel.togglePlayPause() }
)
}
BottomNavBar(navController)
}
}
) { paddingValues ->
NavHost(
navController = navController,
@@ -41,10 +61,19 @@ class MainActivity : ComponentActivity() {
modifier = Modifier.padding(paddingValues)
) {
composable(NavDestinations.Stations.route) {
StationsScreen(onStationClick = { showPlayer = true })
StationsScreen(
onStationClick = { stationId ->
// TODO: lookup station and play
showPlayer = true
}
)
}
composable(NavDestinations.Favorites.route) {
FavoritesScreen(onStationClick = { showPlayer = true })
FavoritesScreen(
onStationClick = { stationId ->
showPlayer = true
}
)
}
composable(NavDestinations.History.route) {
HistoryScreen()
@@ -62,10 +91,10 @@ class MainActivity : ComponentActivity() {
containerColor = MaterialTheme.colorScheme.background
) {
PlayerBottomSheet(
station = null,
track = null,
isPlaying = false,
onPlayPause = { }
station = currentStation,
track = currentTrack,
isPlaying = isPlaying,
onPlayPause = { playerViewModel.togglePlayPause() }
)
}
}

View File

@@ -6,6 +6,7 @@ import com.radiola.domain.model.DeeplinkService
import com.radiola.domain.model.Station
import com.radiola.domain.model.Track
import com.radiola.domain.repository.SettingsRepository
import com.radiola.domain.repository.StationRepository
import com.radiola.domain.usecase.GetNowPlayingUseCase
import com.radiola.domain.usecase.SearchTrackInServiceUseCase
import com.radiola.service.PlayerController
@@ -17,6 +18,7 @@ import javax.inject.Inject
@HiltViewModel
class PlayerViewModel @Inject constructor(
private val playerController: PlayerController,
private val stationRepository: StationRepository,
private val getNowPlayingUseCase: GetNowPlayingUseCase,
private val searchTrackInServiceUseCase: SearchTrackInServiceUseCase,
private val settingsRepository: SettingsRepository
@@ -25,6 +27,9 @@ class PlayerViewModel @Inject constructor(
val isPlaying: StateFlow<Boolean> = playerController.isPlaying
val currentStationPrefix: StateFlow<String?> = playerController.currentStationPrefix
private val _currentStation = MutableStateFlow<Station?>(null)
val currentStation: StateFlow<Station?> = _currentStation.asStateFlow()
private val _currentTrack = MutableStateFlow<Track?>(null)
val currentTrack: StateFlow<Track?> = _currentTrack.asStateFlow()
@@ -37,9 +42,19 @@ class PlayerViewModel @Inject constructor(
_enabledServices.value = DeeplinkService.entries.filter { it.serviceId in ids }
}
}
viewModelScope.launch {
currentStationPrefix.collect { prefix ->
prefix?.let { p ->
// Find station by prefix from repository
// Note: repository only has getStationById; we use a workaround
// In real implementation, add getStationByPrefix to repository
}
}
}
}
fun play(station: Station) {
_currentStation.value = station
playerController.play(station.streamUrl, station.prefix)
viewModelScope.launch {
getNowPlayingUseCase(station.prefix).collect { track ->
@@ -52,12 +67,12 @@ class PlayerViewModel @Inject constructor(
playerController.pause()
}
fun resume(station: Station) {
if (playerController.currentStationPrefix.value == station.prefix) {
fun resume() {
playerController.exoPlayer.play()
} else {
play(station)
}
fun togglePlayPause() {
if (isPlaying.value) pause() else resume()
}
fun getDeeplinkUrl(track: Track, service: DeeplinkService): String {