Merge branch 'main' of git.arirex.me:iris/ai-app
This commit is contained in:
commit
1ed6e29bc6
14 files changed
+637
-180
No files matched your search
@@ -1478,30 +1478,44 @@ fun SessionScreen(
|
||||
},
|
||||
)
|
||||
}
|
||||
if (running) {
|
||||
// The same filled shape as the button beside it, not an outlined one: these
|
||||
// are two things you can do about the turn that is running, and weighting one
|
||||
// of them as secondary said they were a primary action and its qualifier.
|
||||
// What separates them is the colour and the mark, which is what they mean.
|
||||
Button(
|
||||
onClick = { act { interruptSession(settings, summary.id) } },
|
||||
colors = actionButtonColors(stopColor),
|
||||
) {
|
||||
// A filled square, which is what stop has looked like since tape decks.
|
||||
Glyph(
|
||||
STOP_GLYPH,
|
||||
colour = LocalContentColor.current,
|
||||
modifier = Modifier.semantics { contentDescription = "Stop" },
|
||||
)
|
||||
// The same filled shape as the button beside it, not an outlined one: these are
|
||||
// two things you can do about the session, and weighting one of them as secondary
|
||||
// said they were a primary action and its qualifier. What separates them is the
|
||||
// colour and the mark, which is what they mean.
|
||||
//
|
||||
// Always here, rather than arriving with the turn as it used to. A control that
|
||||
// comes and goes makes its own presence the signal, and its absence could not say
|
||||
// whether there was nothing to do; a button that is always in the same place also
|
||||
// cannot push Send off the end of the row by turning up.
|
||||
val process =
|
||||
when {
|
||||
running -> ProcessAction.Pause
|
||||
status == "exited" -> ProcessAction.Start
|
||||
else -> ProcessAction.Stop
|
||||
}
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Button(
|
||||
onClick = { act { process.perform(settings, summary.id) } },
|
||||
colors = actionButtonColors(process.colour()),
|
||||
) {
|
||||
Glyph(
|
||||
process.glyph,
|
||||
colour = LocalContentColor.current,
|
||||
modifier = Modifier.semantics { contentDescription = process.label },
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(8.dp))
|
||||
// The paper plane, with a clock on it while a turn is in flight: sending then
|
||||
// queues the message for the next tool boundary rather than starting a turn of
|
||||
// its own, and the two have to be told apart at a glance. The label says the same
|
||||
// thing to a screen reader, which has nothing else to read.
|
||||
//
|
||||
// Disabled while there is nothing to send, rather than pressable and silent:
|
||||
// `send` has always returned early on an empty composer, so the button promised
|
||||
// something it would not do, and the only feedback was the ripple. Disabled and
|
||||
// not hidden, for the reason the button beside it is always here.
|
||||
Button(
|
||||
onClick = { send() },
|
||||
enabled = input.isNotBlank() || pendingAttachments.isNotEmpty(),
|
||||
colors = actionButtonColors(if (running) queueColor else sendColor),
|
||||
) {
|
||||
Glyph(
|
||||
@@ -1522,6 +1536,39 @@ fun SessionScreen(
|
||||
/** What pressing Send does right now, said the same way to the eye and to a screen reader. */
|
||||
private fun sendLabel(running: Boolean) = if (running) "Queue" else "Send"
|
||||
|
||||
/**
|
||||
* What the composer's process button would do if it were pressed now.
|
||||
*
|
||||
* One value rather than four parallel conditions over the status, because the mark, the colour, the
|
||||
* name a screen reader is given and the request that goes out are four halves of one decision. A
|
||||
* button drawn as a pause that terminates the CLI is the worst bug available here, and separate
|
||||
* branches over the same condition are how that happens -- these three each have to cover every
|
||||
* case, and the compiler says so.
|
||||
*/
|
||||
private enum class ProcessAction(val glyph: String, val label: String) {
|
||||
/** A turn is running: take it back, and leave the process holding the conversation. */
|
||||
Pause(PAUSE_GLYPH, "Pause"),
|
||||
/** Nothing is running, but the process behind the session is: end it. */
|
||||
Stop(STOP_GLYPH, "Stop"),
|
||||
/** The process is gone: start it again, on the conversation it left. */
|
||||
Start(PLAY_GLYPH, "Start"),
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProcessAction.colour() =
|
||||
when (this) {
|
||||
ProcessAction.Pause -> pauseColor
|
||||
ProcessAction.Stop -> stopColor
|
||||
ProcessAction.Start -> startColor
|
||||
}
|
||||
|
||||
private fun ProcessAction.perform(settings: ServerSettings, sessionId: String) =
|
||||
when (this) {
|
||||
ProcessAction.Pause -> interruptSession(settings, sessionId)
|
||||
ProcessAction.Stop -> stopSession(settings, sessionId)
|
||||
ProcessAction.Start -> startSession(settings, sessionId)
|
||||
}
|
||||
|
||||
/**
|
||||
* An inline transcript image, fetched (authenticated, pinned) from the session's files route. The
|
||||
* bitmap is remembered per ref, so scrolling doesn't refetch.
|
||||
|
||||
Reference in new issue
Block a user