feat: add playlist naming dialog on import
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package xyz.cottongin.radio247.ui.screens.stationlist
|
||||
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
|
||||
@Composable
|
||||
fun NamePlaylistDialog(
|
||||
suggestedName: String,
|
||||
onDismiss: () -> Unit,
|
||||
onConfirm: (String) -> Unit
|
||||
) {
|
||||
var name by remember { mutableStateOf(suggestedName) }
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text("Name this playlist") },
|
||||
text = {
|
||||
OutlinedTextField(
|
||||
value = name,
|
||||
onValueChange = { name = it },
|
||||
label = { Text("Playlist name") },
|
||||
singleLine = true
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = { onConfirm(name) },
|
||||
enabled = name.isNotBlank()
|
||||
) { Text("OK") }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) { Text("Cancel") }
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -82,6 +82,7 @@ fun StationListScreen(
|
||||
) {
|
||||
val viewState by viewModel.viewState.collectAsState()
|
||||
val playbackState by viewModel.playbackState.collectAsState()
|
||||
val pendingImport by viewModel.pendingImport.collectAsState()
|
||||
|
||||
var showAddStation by remember { mutableStateOf(false) }
|
||||
var showAddPlaylist by remember { mutableStateOf(false) }
|
||||
@@ -322,6 +323,14 @@ fun StationListScreen(
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pendingImport?.let { pending ->
|
||||
NamePlaylistDialog(
|
||||
suggestedName = pending.suggestedName,
|
||||
onDismiss = { viewModel.cancelImport() },
|
||||
onConfirm = { name -> viewModel.confirmImport(name) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import xyz.cottongin.radio247.RadioApplication
|
||||
import xyz.cottongin.radio247.data.api.SomaFmApi
|
||||
import xyz.cottongin.radio247.data.importing.M3uParser
|
||||
import xyz.cottongin.radio247.data.importing.ParsedStation
|
||||
import xyz.cottongin.radio247.data.importing.PlsParser
|
||||
import xyz.cottongin.radio247.data.model.Playlist
|
||||
import xyz.cottongin.radio247.data.model.Station
|
||||
@@ -31,6 +32,11 @@ data class TabInfo(
|
||||
val isBuiltIn: Boolean
|
||||
)
|
||||
|
||||
data class PendingImport(
|
||||
val suggestedName: String,
|
||||
val stations: List<ParsedStation>
|
||||
)
|
||||
|
||||
enum class SortMode { DEFAULT, NAME_ASC, NAME_DESC }
|
||||
|
||||
data class StationListViewState(
|
||||
@@ -57,6 +63,9 @@ class StationListViewModel(application: Application) : AndroidViewModel(applicat
|
||||
private val _sortMode = MutableStateFlow(SortMode.DEFAULT)
|
||||
val sortMode: StateFlow<SortMode> = _sortMode.asStateFlow()
|
||||
|
||||
private val _pendingImport = MutableStateFlow<PendingImport?>(null)
|
||||
val pendingImport: StateFlow<PendingImport?> = _pendingImport.asStateFlow()
|
||||
|
||||
private val _isPollingListeners = MutableStateFlow(false)
|
||||
private val _showHidden = MutableStateFlow(false)
|
||||
private var pollingJob: Job? = null
|
||||
@@ -291,8 +300,18 @@ class StationListViewModel(application: Application) : AndroidViewModel(applicat
|
||||
val parsed = if (isM3u) M3uParser.parse(content) else PlsParser.parse(content)
|
||||
if (parsed.isEmpty()) return@launch
|
||||
|
||||
val playlistId = playlistDao.insert(Playlist(name = fileName))
|
||||
for ((index, station) in parsed.withIndex()) {
|
||||
withContext(Dispatchers.Main) {
|
||||
_pendingImport.value = PendingImport(fileName, parsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun confirmImport(name: String) {
|
||||
val pending = _pendingImport.value ?: return
|
||||
_pendingImport.value = null
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val playlistId = playlistDao.insert(Playlist(name = name))
|
||||
for ((index, station) in pending.stations.withIndex()) {
|
||||
stationDao.insert(
|
||||
Station(
|
||||
name = station.name,
|
||||
@@ -303,7 +322,6 @@ class StationListViewModel(application: Application) : AndroidViewModel(applicat
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
val playlists = playlistsFlow.value
|
||||
val tabs = buildTabs(playlists)
|
||||
@@ -314,4 +332,8 @@ class StationListViewModel(application: Application) : AndroidViewModel(applicat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelImport() {
|
||||
_pendingImport.value = null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user