ux: home 'Import music' opens import dialog directly instead of navigating to Library
This commit is contained in:
parent
c0aea3eabc
commit
153a132656
288 changed files with 136 additions and 56 deletions
|
|
@ -70,6 +70,9 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -108,7 +111,44 @@ fun PlayerScreen(
|
|||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val playlists by viewModel.playlists.collectAsState()
|
||||
val importMessage by viewModel.importMessage.collectAsState()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
var showImportDialog by remember { mutableStateOf(false) }
|
||||
|
||||
val importSongsPicker = rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.OpenMultipleDocuments()
|
||||
) { uris -> if (uris.isNotEmpty()) viewModel.importSongs(uris) }
|
||||
|
||||
val importFolderPicker = rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.OpenDocumentTree()
|
||||
) { treeUri -> if (treeUri != null) viewModel.importSongs(listOf(treeUri)) }
|
||||
|
||||
LaunchedEffect(importMessage) {
|
||||
importMessage?.let {
|
||||
snackbarHostState.showSnackbar(it)
|
||||
viewModel.clearImportMessage()
|
||||
}
|
||||
}
|
||||
|
||||
if (showImportDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showImportDialog = false },
|
||||
title = { Text("Import music") },
|
||||
text = { Text("Add songs from your device to your library.") },
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
showImportDialog = false
|
||||
importSongsPicker.launch(arrayOf("audio/*"))
|
||||
}) { Text("Choose songs…") }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = {
|
||||
showImportDialog = false
|
||||
importFolderPicker.launch(null)
|
||||
}) { Text("Choose folder…") }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Sync state when screen becomes visible (e.g. returning from Stations)
|
||||
LaunchedEffect(Unit) {
|
||||
|
|
@ -213,7 +253,7 @@ fun PlayerScreen(
|
|||
} else {
|
||||
EmptyStateView(
|
||||
onBrowseStations = onNavigateToStations,
|
||||
onImportMusic = onNavigateToLibrary,
|
||||
onImportMusic = { showImportDialog = true },
|
||||
modifier = Modifier.padding(padding),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.rada.data.local.entity.PlaylistEntity
|
||||
import com.rada.data.repository.PlaylistRepository
|
||||
import com.rada.data.repository.SongImporter
|
||||
import com.rada.data.repository.StationRepository
|
||||
import com.rada.domain.model.Station
|
||||
import com.rada.player.PlaybackManager
|
||||
|
|
@ -24,11 +25,36 @@ class PlayerViewModel @Inject constructor(
|
|||
private val playbackManager: PlaybackManager,
|
||||
private val stationRepository: StationRepository,
|
||||
private val playlistRepository: PlaylistRepository,
|
||||
private val songImporter: SongImporter,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(PlayerUiState())
|
||||
val uiState: StateFlow<PlayerUiState> = _uiState.asStateFlow()
|
||||
|
||||
private val _importMessage = MutableStateFlow<String?>(null)
|
||||
val importMessage: StateFlow<String?> = _importMessage.asStateFlow()
|
||||
|
||||
/** Manual import from the player's empty state: copies picked files/folders in. */
|
||||
fun importSongs(uris: List<android.net.Uri>) {
|
||||
if (uris.isEmpty()) return
|
||||
viewModelScope.launch {
|
||||
val result = songImporter.import(uris)
|
||||
_importMessage.value = buildString {
|
||||
append("Imported ${result.imported} song")
|
||||
if (result.imported != 1) append("s")
|
||||
if (result.errors.isNotEmpty()) {
|
||||
append(" (${result.errors.size} failed: ${result.errors.first()}")
|
||||
if (result.errors.size > 1) append(", +${result.errors.size - 1} more")
|
||||
append(")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clearImportMessage() {
|
||||
_importMessage.value = null
|
||||
}
|
||||
|
||||
val playlists: StateFlow<List<PlaylistEntity>> = playlistRepository.getAllPlaylists()
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue