fix(library): overflow menu for refresh/delete/multi-select so title keeps full width; song-count plural

This commit is contained in:
avi 2026-09-30 10:23:21 -05:00
commit a490b394d3

View file

@ -29,6 +29,7 @@ import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Checklist import androidx.compose.material.icons.filled.Checklist
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.MusicNote import androidx.compose.material.icons.filled.MusicNote
@ -108,6 +109,7 @@ fun LibraryScreen(
var showSearch by remember { mutableStateOf(false) } var showSearch by remember { mutableStateOf(false) }
var searchQuery by remember { mutableStateOf("") } var searchQuery by remember { mutableStateOf("") }
var showImportMenu by remember { mutableStateOf(false) } var showImportMenu by remember { mutableStateOf(false) }
var showMoreMenu by remember { mutableStateOf(false) }
var showAppearance by remember { mutableStateOf(false) } var showAppearance by remember { mutableStateOf(false) }
var playlistToDelete by remember { mutableStateOf<PlaylistEntity?>(null) } var playlistToDelete by remember { mutableStateOf<PlaylistEntity?>(null) }
var songForPlaylist by remember { mutableStateOf<SavedSongEntity?>(null) } var songForPlaylist by remember { mutableStateOf<SavedSongEntity?>(null) }
@ -155,7 +157,14 @@ fun LibraryScreen(
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Library") }, title = {
Text(
"Library",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Bold,
)
},
navigationIcon = { navigationIcon = {
Row(horizontalArrangement = Arrangement.Start) { Row(horizontalArrangement = Arrangement.Start) {
AppHomeButton(onClick = onHome) AppHomeButton(onClick = onHome)
@ -198,43 +207,73 @@ fun LibraryScreen(
Icon(Icons.Default.Shuffle, contentDescription = "Shuffle play") Icon(Icons.Default.Shuffle, contentDescription = "Shuffle play")
} }
} }
IconButton( // Refresh / delete-folder / multi-select live in one
onClick = { viewModel.refreshImportedFolders() }, // overflow menu so the title keeps its full width instead
enabled = !uiState.isImporting, // of wrapping mid-word ("Libr|ary"). All still reachable.
) { Box {
IconButton(onClick = { showMoreMenu = true }) {
Icon( Icon(
Icons.Default.Refresh, Icons.Default.MoreVert,
contentDescription = "Refresh imported folders", contentDescription = "More library actions",
tint = if (uiState.isImporting) { tint = if (uiState.isMultiSelect) LocalTokens.current.accentFill
LocalTokens.current.textSecondary.copy(alpha = 0.4f) else LocalTokens.current.textSecondary,
} else { )
LocalTokens.current.textSecondary }
DropdownMenu(
expanded = showMoreMenu,
onDismissRequest = { showMoreMenu = false },
) {
DropdownMenuItem(
text = { Text("Refresh imported folders") },
enabled = !uiState.isImporting,
onClick = {
showMoreMenu = false
viewModel.refreshImportedFolders()
},
leadingIcon = { Icon(Icons.Default.Refresh, contentDescription = null) },
)
if (uiState.selectedPlaylistId != null) {
allPlaylists.firstOrNull { it.id == uiState.selectedPlaylistId }
?.let { selected ->
DropdownMenuItem(
text = { Text("Delete “${selected.name}”") },
onClick = {
showMoreMenu = false
playlistToDelete = selected
},
leadingIcon = {
Icon(
Icons.Default.Delete,
contentDescription = null,
tint = MaterialTheme.colorScheme.error,
)
}, },
) )
} }
// Reliable delete path for the selected folder (besides long-press).
if (uiState.selectedPlaylistId != null) {
allPlaylists.firstOrNull { it.id == uiState.selectedPlaylistId }?.let { selected ->
IconButton(onClick = { playlistToDelete = selected }) {
Icon(
Icons.Default.Delete,
contentDescription = "Delete folder",
tint = LocalTokens.current.textSecondary,
)
} }
}
}
// Multi-select: combine several folders, shuffle the union.
if (tabLabels.size > 1) { if (tabLabels.size > 1) {
IconButton(onClick = { DropdownMenuItem(
text = {
Text(
if (uiState.isMultiSelect) "Exit multi-select"
else "Select multiple folders",
)
},
onClick = {
showMoreMenu = false
if (uiState.isMultiSelect) viewModel.exitMultiSelect() if (uiState.isMultiSelect) viewModel.exitMultiSelect()
else viewModel.enterMultiSelect() else viewModel.enterMultiSelect()
}) { },
leadingIcon = {
Icon( Icon(
Icons.Default.Checklist, Icons.Default.Checklist,
contentDescription = if (uiState.isMultiSelect) "Exit playlist selection" else "Select multiple playlists", contentDescription = null,
tint = if (uiState.isMultiSelect) LocalTokens.current.accentFill else LocalTokens.current.textSecondary, tint = if (uiState.isMultiSelect) LocalTokens.current.accentFill
else LocalTokens.current.textSecondary,
) )
},
)
}
} }
} }
IconButton(onClick = { showAppearance = true }) { IconButton(onClick = { showAppearance = true }) {
@ -298,7 +337,7 @@ fun LibraryScreen(
) )
} }
Text( Text(
text = "${uiState.songs.size} songs", text = "${uiState.songs.size} ${if (uiState.songs.size == 1) "song" else "songs"}",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
color = LocalTokens.current.textSecondary, color = LocalTokens.current.textSecondary,
) )