git.iko.soy/opencode-android
on 3e723a1 help sign in
97 lines 4.3 kB history raw
1package soy.iko.opencode.ui.chat
3import androidx.compose.foundation.clickable
4import androidx.compose.foundation.layout.Column
5import androidx.compose.foundation.layout.Row
6import androidx.compose.foundation.layout.fillMaxWidth
7import androidx.compose.foundation.layout.heightIn
8import androidx.compose.foundation.layout.padding
9import androidx.compose.foundation.layout.size
10import androidx.compose.foundation.lazy.LazyColumn
11import androidx.compose.foundation.lazy.items
12import androidx.compose.material.icons.Icons
13import androidx.compose.material.icons.filled.Check
14import androidx.compose.material3.ExperimentalMaterial3Api
15import androidx.compose.material3.Icon
16import androidx.compose.material3.MaterialTheme
17import androidx.compose.material3.ModalBottomSheet
18import androidx.compose.material3.Text
19import androidx.compose.runtime.Composable
20import androidx.compose.ui.Alignment
21import androidx.compose.ui.Modifier
22import androidx.compose.ui.res.stringResource
23import androidx.compose.ui.semantics.Role
24import androidx.compose.ui.semantics.role
25import androidx.compose.ui.semantics.selected
26import androidx.compose.ui.semantics.semantics
27import androidx.compose.ui.unit.dp
28import soy.iko.opencode.data.model.ModelOption
29import soy.iko.opencode.R
31/** Bottom sheet that lists every provider/model and lets the user pick one. */
32@OptIn(ExperimentalMaterial3Api::class)
33@Composable
34fun ModelPickerSheet(
35 options: List<ModelOption>,
36 selected: ModelOption?,
37 onSelect: (ModelOption) -> Unit,
38 onDismiss: () -> Unit,
39) {
40 ModalBottomSheet(onDismissRequest = onDismiss) {
41 Text(
42 stringResource(R.string.model),
43 style = MaterialTheme.typography.titleMedium,
44 modifier = Modifier.padding(start = 24.dp, end = 24.dp, bottom = 8.dp),
45 )
46 if (options.isEmpty()) {
47 Text(
48 stringResource(R.string.no_models),
49 style = MaterialTheme.typography.bodyMedium,
50 color = MaterialTheme.colorScheme.onSurfaceVariant,
51 modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp),
52 )
53 } else {
54 LazyColumn(modifier = Modifier.fillMaxWidth().heightIn(max = 420.dp)) {
55 items(options, key = { it.providerID + "/" + it.modelID }) { option ->
56 val isSelected = option.providerID == selected?.providerID &&
57 option.modelID == selected.modelID
58 Column(
59 modifier = Modifier
60 .fillMaxWidth()
61 .semantics(mergeDescendants = true) {
62 role = Role.RadioButton
63 if (isSelected) this.selected = true
64 }
65 .clickable {
66 onSelect(option)
67 onDismiss()
68 }
69 .padding(horizontal = 24.dp, vertical = 12.dp),
70 ) {
71 Row(verticalAlignment = Alignment.CenterVertically) {
72 Text(
73 option.modelLabel,
74 style = MaterialTheme.typography.bodyLarge,
75 color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface,
76 modifier = Modifier.weight(1f),
77 )
78 if (isSelected) {
79 Icon(
80 Icons.Filled.Check,
81 contentDescription = null,
82 tint = MaterialTheme.colorScheme.primary,
83 modifier = Modifier.size(18.dp),
84 )
85 }
86 }
87 Text(
88 option.providerLabel,
89 style = MaterialTheme.typography.bodySmall,
90 color = MaterialTheme.colorScheme.onSurfaceVariant,
91 )
92 }
93 }
94 }
95 }
96 }