From c9bf0479ec0ae58104aa914d7f940cac8a5ae76c Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 26 May 2026 17:55:29 -0400 Subject: [PATCH] =?UTF-8?q?fix(android):=20StorageCard=20=E2=80=94=20simpl?= =?UTF-8?q?er=20OutlinedButton=20+=20DropdownMenu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compile errors on 6ef08ed: ExposedDropdownMenu is an extension on ExposedDropdownMenuBoxScope and can't be referenced by FQN from outside a Composable receiver. Rewrote both dropdowns using the plain OutlinedButton + DropdownMenu pattern wrapped in a small LabeledDropdown helper, which works without the Scope dance. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../minstrel/settings/ui/StorageCard.kt | 105 +++++++----------- 1 file changed, 38 insertions(+), 67 deletions(-) diff --git a/android/app/src/main/java/com/fabledsword/minstrel/settings/ui/StorageCard.kt b/android/app/src/main/java/com/fabledsword/minstrel/settings/ui/StorageCard.kt index 0654b5a7..22de2440 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/settings/ui/StorageCard.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/settings/ui/StorageCard.kt @@ -11,17 +11,14 @@ import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ElevatedCard -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -122,12 +119,41 @@ private fun UsageRow(usedBytes: Long) { } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun CapDropdown(label: String, value: Long, onSet: (Long) -> Unit) { - var expanded by remember { mutableStateOf(false) } val selectedLabel = CAP_OPTIONS.firstOrNull { it.first == value }?.second ?: formatBytes(value) + LabeledDropdown( + label = label, + selectedLabel = selectedLabel, + options = CAP_OPTIONS, + onSelect = onSet, + ) +} + +@Composable +private fun PrefetchDropdown(value: Int, onSet: (Int) -> Unit) { + val selected = if (value in PREFETCH_OPTIONS) value else PREFETCH_OPTIONS[2] + LabeledDropdown( + label = "Pre-fetch ahead", + selectedLabel = "$selected tracks", + options = PREFETCH_OPTIONS.map { it to "$it tracks" }, + onSelect = onSet, + ) +} + +/** + * Label on the left, button-with-current-value on the right that opens + * a DropdownMenu of [options]. Used by both Cap and Prefetch selectors. + */ +@Composable +private fun LabeledDropdown( + label: String, + selectedLabel: String, + options: List>, + onSelect: (T) -> Unit, +) { + var expanded by remember { mutableStateOf(false) } Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, @@ -138,73 +164,18 @@ private fun CapDropdown(label: String, value: Long, onSet: (Long) -> Unit) { color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.weight(1f), ) - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { expanded = it }, - ) { - TextField( - value = selectedLabel, - onValueChange = {}, - readOnly = true, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, - modifier = Modifier.menuAnchor(), - ) - ExposedDropdownMenuDefaults.run { - androidx.compose.material3.ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - ) { - CAP_OPTIONS.forEach { (bytes, name) -> - DropdownMenuItem( - text = { Text(name) }, - onClick = { - expanded = false - onSet(bytes) - }, - ) - } - } - } - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun PrefetchDropdown(value: Int, onSet: (Int) -> Unit) { - var expanded by remember { mutableStateOf(false) } - val selected = if (value in PREFETCH_OPTIONS) value else PREFETCH_OPTIONS[2] - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = "Pre-fetch ahead", - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.weight(1f), - ) - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { expanded = it }, - ) { - TextField( - value = "$selected tracks", - onValueChange = {}, - readOnly = true, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, - modifier = Modifier.menuAnchor(), - ) - androidx.compose.material3.ExposedDropdownMenu( + OutlinedButton(onClick = { expanded = true }) { + Text(selectedLabel) + DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, ) { - PREFETCH_OPTIONS.forEach { n -> + options.forEach { (value, name) -> DropdownMenuItem( - text = { Text("$n tracks") }, + text = { Text(name) }, onClick = { expanded = false - onSet(n) + onSelect(value) }, ) }