Settings as a screen with two tabs, and fields that cost one line
The settings dialog had outgrown a dialog: it scrolled inside itself, covered the session it is about, and had nowhere to put a second tab. It is a screen now, drawn over the session like the file explorer so the session under it stays composed, with the back gesture to leave it. The second tab is ProviderScreen itself -- the same composable the machines tab opens -- so a provider's settings have two ways in and one implementation. Every text field in the app goes through LabelledField: the label is a line above the box rather than a thing floating inside it, the hint says what leaving it blank means, and the padding is one line's worth. Material's outlined field spends the height of three lines to hold one, which on a form of a dozen settings is a screen and a half of scrolling. The value's own text is unchanged -- the framing was what cost. A session also gets a system prompt, which for llama.cpp is one entry in the params table and no app change: it rides in front of the conversation on every request rather than being recorded as the first thing in it, so changing it takes effect on the next message. ParamKind::Prose is new because a paragraph in a one-line box shows six words of itself.
This commit is contained in:
1 parent
386c1c4def
commit
7278a58387
17 files changed
+364
-176
No files matched your search
@@ -15,7 +15,6 @@ import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -350,41 +349,36 @@ private fun AddMachineDialog(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
OutlinedTextField(
|
||||
value = name,
|
||||
onValueChange = { name = it },
|
||||
label = { Text("Name") },
|
||||
singleLine = true,
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = address,
|
||||
onValueChange = { address = it },
|
||||
LabelledField(label = "Name", value = name, onValueChange = { name = it })
|
||||
Spacer(Modifier.height(8.dp))
|
||||
LabelledField(
|
||||
// Just the shape. What a blank one means is said once, in the text above this
|
||||
// form -- repeating it here wrapped the label onto a second line.
|
||||
label = { Text("user@host[:port]") },
|
||||
singleLine = true,
|
||||
label = "user@host[:port]",
|
||||
value = address,
|
||||
onValueChange = { address = it },
|
||||
)
|
||||
OutlinedTextField(
|
||||
Spacer(Modifier.height(8.dp))
|
||||
LabelledField(
|
||||
label = "Key path on the backend",
|
||||
value = identity,
|
||||
onValueChange = { identity = it },
|
||||
label = { Text("Key path on the backend") },
|
||||
singleLine = true,
|
||||
)
|
||||
// Where a file attached from the phone lands on that machine. Blank means the
|
||||
// session's own directory, which is what most people want.
|
||||
OutlinedTextField(
|
||||
Spacer(Modifier.height(8.dp))
|
||||
LabelledField(
|
||||
// Where a file attached from the phone lands on that machine.
|
||||
label = "Folder for attached files",
|
||||
value = attachmentsDir,
|
||||
onValueChange = { attachmentsDir = it },
|
||||
label = { Text("Folder for attached files (optional)") },
|
||||
singleLine = true,
|
||||
hint = "the session's own directory",
|
||||
)
|
||||
// Where that machine's GGUFs are, for a llama.cpp session on it. Blank means
|
||||
// the same place this backend keeps its own downloads, read on that machine.
|
||||
OutlinedTextField(
|
||||
Spacer(Modifier.height(8.dp))
|
||||
LabelledField(
|
||||
// Where that machine's GGUFs are, for a llama.cpp session on it.
|
||||
label = "Folder for models",
|
||||
value = modelsDir,
|
||||
onValueChange = { modelsDir = it },
|
||||
label = { Text("Folder for models (optional)") },
|
||||
singleLine = true,
|
||||
hint = "the same place this backend keeps its own downloads",
|
||||
)
|
||||
tested?.let {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
@@ -439,12 +433,7 @@ private fun RenameDialog(machine: Machine, onDismiss: () -> Unit, onRename: (Str
|
||||
title = { Text("Rename") },
|
||||
text = {
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
value = name,
|
||||
onValueChange = { name = it },
|
||||
label = { Text("Name") },
|
||||
singleLine = true,
|
||||
)
|
||||
LabelledField(label = "Name", value = name, onValueChange = { name = it })
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
"Sessions already running on it keep working -- they refer to the machine, " +
|
||||
|
||||
Reference in new issue
Block a user