feat: add playlist naming dialog on import

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-11 16:25:58 -04:00
parent eb111fce35
commit 973bb9e7fe
3 changed files with 76 additions and 3 deletions

View File

@@ -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") }
}
)
}

View File

@@ -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

View File

@@ -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
}
}