fix(android): StorageCard — simpler OutlinedButton + DropdownMenu

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<T> helper, which works without the Scope dance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 17:55:29 -04:00
parent 5455cd5d80
commit c9bf0479ec
@@ -11,17 +11,14 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ElevatedCard 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.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -122,12 +119,41 @@ private fun UsageRow(usedBytes: Long) {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun CapDropdown(label: String, value: Long, onSet: (Long) -> Unit) { 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 val selectedLabel = CAP_OPTIONS.firstOrNull { it.first == value }?.second
?: formatBytes(value) ?: 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 <T> LabeledDropdown(
label: String,
selectedLabel: String,
options: List<Pair<T, String>>,
onSelect: (T) -> Unit,
) {
var expanded by remember { mutableStateOf(false) }
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@@ -138,73 +164,18 @@ private fun CapDropdown(label: String, value: Long, onSet: (Long) -> Unit) {
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
) )
ExposedDropdownMenuBox( OutlinedButton(onClick = { expanded = true }) {
expanded = expanded, Text(selectedLabel)
onExpandedChange = { expanded = it }, DropdownMenu(
) {
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(
expanded = expanded, expanded = expanded,
onDismissRequest = { expanded = false }, onDismissRequest = { expanded = false },
) { ) {
PREFETCH_OPTIONS.forEach { n -> options.forEach { (value, name) ->
DropdownMenuItem( DropdownMenuItem(
text = { Text("$n tracks") }, text = { Text(name) },
onClick = { onClick = {
expanded = false expanded = false
onSet(n) onSelect(value)
}, },
) )
} }