1package soy.iko.opencode.ui.settings
3import androidx.compose.foundation.clickable
4import androidx.compose.foundation.layout.Arrangement
5import androidx.compose.foundation.layout.Column
6import androidx.compose.foundation.layout.Row
7import androidx.compose.foundation.layout.Spacer
8import androidx.compose.foundation.layout.fillMaxWidth
9import androidx.compose.foundation.layout.padding
10import androidx.compose.foundation.layout.size
11import androidx.compose.foundation.selection.selectable
12import androidx.compose.material.icons.Icons
13import androidx.compose.material.icons.automirrored.filled.ArrowBack
14import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
15import androidx.compose.material.icons.filled.Dns
16import androidx.compose.material3.ExperimentalMaterial3Api
17import androidx.compose.material3.HorizontalDivider
18import androidx.compose.material3.Icon
19import androidx.compose.material3.IconButton
20import androidx.compose.material3.MaterialTheme
21import androidx.compose.material3.RadioButton
22import androidx.compose.material3.Scaffold
23import androidx.compose.material3.Switch
24import androidx.compose.material3.Text
25import androidx.compose.material3.TextButton
26import androidx.compose.material3.TopAppBar
27import androidx.compose.runtime.Composable
28import androidx.compose.runtime.getValue
29import androidx.compose.runtime.remember
30import androidx.compose.runtime.rememberCoroutineScope
31import androidx.compose.ui.Alignment
32import androidx.compose.ui.Modifier
33import androidx.compose.ui.platform.LocalContext
34import androidx.compose.ui.unit.dp
35import androidx.lifecycle.compose.collectAsStateWithLifecycle
36import kotlinx.coroutines.launch
37import soy.iko.opencode.data.repo.ThemeMode
38import soy.iko.opencode.di.AppContainer
40@OptIn(ExperimentalMaterial3Api::class)
42fun SettingsScreen(container: AppContainer, onBack: () -> Unit, onManageServers: () -> Unit) {
43 val scope = rememberCoroutineScope()
44 val themeMode by container.settingsStore.themeMode.collectAsStateWithLifecycle(initialValue = ThemeMode.SYSTEM)
45 val dynamicColor by container.settingsStore.dynamicColor.collectAsStateWithLifecycle(initialValue = true)
46 val activeProfile = container.activeConnection.collectAsStateWithLifecycle().value?.profile
47 val context = LocalContext.current
48 val versionName = remember {
49 runCatching { context.packageManager.getPackageInfo(context.packageName, 0).versionName }
50 .getOrDefault("0.1.0")
56 title = { Text("Settings") },
58 IconButton(onClick = onBack) {
59 Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
65 Column(modifier = Modifier.padding(padding).padding(16.dp)) {
66 Text("Appearance", style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.primary)
67 ThemeMode.entries.forEach { mode ->
70 selected = themeMode == mode,
71 onSelect = { scope.launch { container.settingsStore.setThemeMode(mode) } },
75 Spacer(Modifier.size(8.dp))
77 modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
78 verticalAlignment = Alignment.CenterVertically,
80 Column(modifier = Modifier.weight(1f)) {
81 Text("Dynamic color", style = MaterialTheme.typography.bodyLarge)
83 "Use Material You wallpaper colors (Android 12+)",
84 style = MaterialTheme.typography.bodySmall,
85 color = MaterialTheme.colorScheme.onSurfaceVariant,
89 checked = dynamicColor,
90 onCheckedChange = { scope.launch { container.settingsStore.setDynamicColor(it) } },
94 HorizontalDivider(modifier = Modifier.padding(vertical = 16.dp))
96 Text("Connection", style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.primary)
97 if (activeProfile != null) {
98 Text(activeProfile.displayLabel, modifier = Modifier.padding(top = 8.dp))
100 activeProfile.baseUrl + if (activeProfile.hasAuth) " • Basic auth" else "",
101 style = MaterialTheme.typography.bodySmall,
102 color = MaterialTheme.colorScheme.onSurfaceVariant,
107 modifier = Modifier.padding(top = 8.dp),
108 color = MaterialTheme.colorScheme.onSurfaceVariant,
115 .clickable { onManageServers() }
116 .padding(vertical = 8.dp),
117 verticalAlignment = Alignment.CenterVertically,
119 Icon(Icons.Filled.Dns, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
120 Text(" Manage servers", modifier = Modifier.weight(1f))
121 Icon(Icons.AutoMirrored.Filled.KeyboardArrowRight, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant)
124 HorizontalDivider(modifier = Modifier.padding(vertical = 16.dp))
126 Text("About", style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.primary)
128 "opencode-android $versionName",
129 style = MaterialTheme.typography.bodyMedium,
130 modifier = Modifier.padding(top = 8.dp),
133 "A native Android client for the opencode serve HTTP API.",
134 style = MaterialTheme.typography.bodySmall,
135 color = MaterialTheme.colorScheme.onSurfaceVariant,
136 modifier = Modifier.padding(top = 4.dp),
143private fun ThemeRow(mode: ThemeMode, selected: Boolean, onSelect: () -> Unit) {
147 .selectable(selected = selected, onClick = onSelect)
148 .padding(vertical = 8.dp),
149 horizontalArrangement = Arrangement.spacedBy(8.dp),
150 verticalAlignment = Alignment.CenterVertically,
152 RadioButton(selected = selected, onClick = onSelect)
154 mode.name.lowercase().replaceFirstChar { it.uppercase() },
155 style = MaterialTheme.typography.bodyLarge,
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list