@@ -7,23 +7,31 @@ import androidx.compose.foundation.layout.heightIn
77import androidx.compose.foundation.layout.padding
88import androidx.compose.foundation.lazy.LazyColumn
99import androidx.compose.foundation.lazy.items
10+import androidx.compose.foundation.text.KeyboardOptions
1011import androidx.compose.material.icons.Icons
1112import androidx.compose.material.icons.automirrored.filled.PlaylistPlay
13+import androidx.compose.material.icons.filled.Search
1214import androidx.compose.material3.CircularProgressIndicator
1315import androidx.compose.material3.ExperimentalMaterial3Api
1416import androidx.compose.material3.Icon
1517import androidx.compose.material3.MaterialTheme
1618import androidx.compose.material3.ModalBottomSheet
19+import androidx.compose.material3.OutlinedTextField
1720import androidx.compose.material3.Text
1821import androidx.compose.material3.TextButton
1922import androidx.compose.runtime.Composable
23+import androidx.compose.runtime.getValue
24+import androidx.compose.runtime.mutableStateOf
25+import androidx.compose.runtime.remember
26+import androidx.compose.runtime.saveable.rememberSaveable
27+import androidx.compose.runtime.setValue
2028import androidx.compose.ui.Alignment
2129import androidx.compose.ui.Modifier
2230import androidx.compose.ui.res.stringResource
2331import androidx.compose.ui.semantics.Role
2432import androidx.compose.ui.semantics.contentDescription
25−import androidx.compose.ui.semantics.role
2633import androidx.compose.ui.semantics.semantics
34+import androidx.compose.ui.text.input.ImeAction
2735import androidx.compose.ui.text.style.TextOverflow
2836import androidx.compose.ui.unit.dp
2937import androidx.compose.foundation.layout.Box
@@ -75,32 +83,59 @@ fun CommandPickerSheet(
7583 modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp),
7684 )
7785 } else {
78− LazyColumn(modifier = Modifier.fillMaxWidth().heightIn(max = 420.dp)) {
79− items(commands, key = { it.name }) { cmd ->
80− Column(
81− modifier = Modifier
82− .fillMaxWidth()
83− .clickable(role = Role.Button) { onSelect(cmd); onDismiss() }
84− .padding(horizontal = 24.dp, vertical = 12.dp),
85− ) {
86− androidx.compose.foundation.layout.Row(
87− verticalAlignment = androidx.compose.ui.Alignment.CenterVertically,
86+ var query by rememberSaveable { mutableStateOf("") }
87+ OutlinedTextField(
88+ value = query,
89+ onValueChange = { query = it },
90+ modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp, vertical = 8.dp),
91+ placeholder = { Text(stringResource(R.string.search_commands)) },
92+ leadingIcon = { Icon(Icons.Filled.Search, contentDescription = null) },
93+ singleLine = true,
94+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
95+ )
96+ val filtered = remember(commands, query) {
97+ val q = query.trim()
98+ if (q.isEmpty()) commands
99+ else commands.filter {
100+ it.name.contains(q, ignoreCase = true) ||
101+ it.displayDescription.contains(q, ignoreCase = true)
102+ }
103+ }
104+ if (filtered.isEmpty()) {
105+ Text(
106+ stringResource(R.string.no_commands_match, query.trim()),
107+ style = MaterialTheme.typography.bodyMedium,
108+ color = MaterialTheme.colorScheme.onSurfaceVariant,
109+ modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp),
110+ )
111+ } else {
112+ LazyColumn(modifier = Modifier.fillMaxWidth().heightIn(max = 420.dp)) {
113+ items(filtered, key = { it.name }) { cmd ->
114+ Column(
115+ modifier = Modifier
116+ .fillMaxWidth()
117+ .clickable(role = Role.Button) { onSelect(cmd); onDismiss() }
118+ .padding(horizontal = 24.dp, vertical = 12.dp),
88119 ) {
89− Icon(Icons.AutoMirrored.Filled.PlaylistPlay, contentDescription = null)
120+ androidx.compose.foundation.layout.Row(
121+ verticalAlignment = androidx.compose.ui.Alignment.CenterVertically,
122+ ) {
123+ Icon(Icons.AutoMirrored.Filled.PlaylistPlay, contentDescription = null)
124+ Text(
125+ "/${cmd.name}",
126+ style = MaterialTheme.typography.bodyLarge,
127+ modifier = Modifier.padding(start = 8.dp),
128+ )
129+ }
90130 Text(
91− "/${cmd.name}",
92− style = MaterialTheme.typography.bodyLarge,
93− modifier = Modifier.padding(start = 8.dp),
131+ cmd.displayDescription,
132+ style = MaterialTheme.typography.bodySmall,
133+ color = MaterialTheme.colorScheme.onSurfaceVariant,
134+ maxLines = 2,
135+ overflow = TextOverflow.Ellipsis,
136+ modifier = Modifier.padding(start = 28.dp, top = 2.dp),
94137 )
95138 }
96− Text(
97− cmd.displayDescription,
98− style = MaterialTheme.typography.bodySmall,
99− color = MaterialTheme.colorScheme.onSurfaceVariant,
100− maxLines = 2,
101− overflow = TextOverflow.Ellipsis,
102− modifier = Modifier.padding(start = 28.dp, top = 2.dp),
103− )
104139 }
105140 }
106141 }