69ef6f068abc0f4b8f118870384834c452985412
9
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
69ef6f068a |
Colour the composer by what its buttons do, and let the read-out breathe less
Queue is the paper plane with a clock on it (`md-send_clock`) rather than the plain plane plus the word: the pair is now told apart by the mark, which is what an icon is for, and the word survives as the button's accessible name where a screen reader still needs it. The three composer buttons take their colour from what pressing one does -- green sends now, blue sends later, red takes the running turn away -- and Stop becomes a filled button like the other two. Outlined said it was a qualifier on the primary action; it is a second thing you can do about the turn, and what separates them is the colour and the mark. The fills are named in Theme.kt with their content colour stated beside them, because a semantic colour has to carry its own contrast: these do not change with the surface, so nothing will rescue a foreground that stops being readable. Worth knowing when reading that file: the action greens and reds sit next to a `runningColor` green and a `failedColor` red, which are *states*. Nothing in one set is pressable and nothing in the other is a state, so a reader never has to tell them apart. The usage read-out loses its per-machine cards. A card is a step up the surface ladder and inside a dialog -- already a raised surface -- the step barely rendered while costing 16dp on every side. The machine and the service it answered for are one small quiet line instead of a heading over a subtitle, since the numbers underneath are what somebody opened this to see. The gaps between the bars now go *between* them rather than after each, which is what put a band of empty dialog above Close. The rest of that band was AlertDialog's own spacing, fixed at sizes meant for a sentence of prose and a decision, so this is a plain Dialog with the same container colour and corner and spacing chosen for a dense read-out. Looked at on the emulator: green send, then blue queue beside red stop during a `/slow 20` echo turn, and the dialog over the live session. The account had risen to 78% by then, which showed the five-hour bar and the header glyph going yellow on real numbers rather than forced ones. |
||
|
|
ff39ef5cf9 |
Say it in icons, and put the whole backend behind four tabs
Six things Bryan asked for, which turned out to be one change: the app had no icon set, so every one of them was blocked on having somewhere for icons to come from. That somewhere is dev-updater's arrangement, ported: a Nerd Fonts subset committed as an asset, drawn as text. `Gear.kt`'s hand-drawn canvas gear argued against icon fonts because a system font may not have the glyph and whoever gets the empty box is never the person who wrote it. The objection is right about *relying* on a system font and the answer is to ship the glyph, so the file is gone and its reasoning is restated in `NerdIcons.kt` rather than deleted -- otherwise the next reader re-derives it. `md-cog` and `md-refresh` are dev-updater's own codepoints, because a cog means the same thing in both apps. The root screen's four words under the title are now four tabs, and the two that act on the whole screen -- settings and refresh -- moved up onto the title row as glyphs. That row's old comment recorded that a fifth word would have had nowhere to go; tabs also say something the words did not, which is that sessions, import, models and setups are four views of one backend rather than four errands. Refresh feeds whichever tab is showing. Import, models and setups lose their headings and their Back buttons, since the tab row is now both. Usage is a dialog. It is checked *against* what you were reading -- "can I start this" is asked with the transcript still on screen -- and it had no navigation of its own, so the only thing its Back could mean was "put this away". The button that opens it is a chart glyph coloured by the worst of the machine's windows, so the row says whether the limits are worth opening before anybody opens them. One `quotaColor` now colours every bar that measures a quota: blue, yellow at 75%, red at 95%. The session bar escalates where it used to sit blue at every level, and the dialog's thresholds moved out of it. A download keeps plain blue at every value -- it has no limit to approach, and colouring it like one would say the opposite of what is happening. States that are not measurements take the ordinary control colour, since blue is the low end of this scale and would read as "checked, and fine" about a machine nobody could reach. Send and stop are the filled paper plane and the filled square. Send keeps the word "Queue" while a turn is in flight, because that is what pressing it then does, and an icon that does two things while looking identical would promise something immediate and do something that waits. Looked at on the emulator: all six glyphs render, the tabs and the system back gesture between them, the dialog over a live session, and the bar bands at 82% and 97% forced through a scratch build, since this account is at 72/31/5 and would only ever have shown blue. |
||
|
|
a50d72960c |
Say how long is left, not that the window is five hours
The bar read "31% of 5h", which is the one thing about the window a reader already knows. What decides whether to start something now is how long what is left has to last: 80% with twenty minutes to go and 80% with four hours to go are opposite answers, and the second number was a screen away on the usage screen. It now reads "31% - 2h 36m left", and the countdown is driven by a clock the refresh loop advances rather than computed at draw time. A percentage that comes back unchanged is an equal value, so Compose skips the recomposition -- a "left" recomputed only when the quota happens to move would have sat at a stale figure for hours while looking live. A window can arrive with no reset time, so that keeps its own wording: "reset time unknown" rather than "refresh soon", which would be a recommendation nothing measured. Under a minute, including past the end, is "refresh soon" -- "0m left" reads as a measurement. The span arithmetic was already on the usage screen, so it moves into `ResetCountdown.kt` and both callers supply their own sentence. That screen still reads "resets in 2h 37m" and "resets in 5d 21h", checked on the emulator alongside the bar it was not part of changing. The fill is blue rather than the scheme's primary: the bar sits under every session header, on a screen somebody opened to do something else, and it reports a quantity rather than a verdict. The usage screen is still where the same number turns yellow and then red, for a reader who went there to be told where the limits are. Also declares this project's resources for Dev Updater, whose declaration schema changed in d27b5a3: `resources.ron` says ai-app keeps its state as `ai-app`, so the Uninstall dialog offers the real directories instead of saying it cannot tell where they are. Only the name, because both XDG places are the conventional ones. What that dialog's config toggle would delete includes the CA under `certs`, which strands every phone running an APK pinned to it -- noted where somebody would be standing when it matters. |
||
|
|
749b2db287 |
Make a command a thing the app knows, and hold it until it can run
Typing "/" now suggests what this app understands -- `/compact` and `/rename <name>` -- with a line each about what they do, and anything else beginning with a slash is passed to whatever runs the session, because a dialect's own vocabulary grows without this list. None of them are messages, and that is the substance of the change. A line written into a running turn is read by the *model*, so a command sent mid-turn either does nothing or arrives as text somebody has to puzzle over. They now wait for the turn to end. The waiting is done once for every provider, in the pump that already watches every event for the boundary, rather than in each driver where a new provider could get it wrong by leaving it out. Waiting is a state, so it is on screen: the command sits at the reader's end of the conversation in blue, with a spinner and "waiting for this turn to end", and becomes an ordinary blue row when it goes. Blue because these are about the session rather than about the task -- the same blue a compaction already used, which is now one colour with one name rather than two. Renaming from the settings screen sends exactly this, so it waits and draws the same way. The name itself is not held: it is this server's own datum, so the list and the header change at once and only telling the session waits. Echo grew the same split, which is where the bug in it showed: its commands are its messages, so running one announced a `MessageTaken` as well, and the same line drew twice -- once blue, once purple. A command owes no announcement; the manager has already recorded that it was sent. Watched rather than reasoned about: `/compact` during a 25 second turn held with its bubble up, went out when the turn ended, and the compaction that followed reported what it recovered. |
||
|
|
404066fa7d |
Say when a session is working, and what it was told
Three things a phone could not see, all of them the same shape: the session was doing something and nothing on screen said so. A turn nobody here started never reported itself. `Running` was sent where a message was *sent*, so a session picked up mid-turn, one compacting on its own, or one another agent wrote to sat there reading as idle until it finished. The driver now says it from what it observes -- output that could only come from a turn in flight -- which is the same set of events that already announced a steer, with the ends swapped. An imported session had it worse: nothing but replayed lines ever reaches it, and a status was not among them, so it was permanently whatever it was when it was adopted. Its file does not record a turn ending, but it does record why each assistant message stopped, and `tool_use` versus anything else answers it. A record that says nothing leaves the status alone rather than voting for idle. Messages from other agents were dropped outright: the CLI marks them meta, and this replayed everything except meta. They are now a row of their own, closed by default like a tool call, named for the session that sent it -- not the reader's own bubble, because they did not say it, and a session working on something this phone never asked for is exactly what one of these explains. Measured against a real session file rather than guessed: the peer record carries the sender's name and the message body in `origin`, beside a copy wrapped for the model to read. |
||
|
|
c5dbd1535d |
Ask for permission on the call it is about, and read the input
A bash permission request arrived as a second card repeating the tool
call's input verbatim, so the same command appeared twice and the reader
had to work out it was one event. `Event::Question` now carries `about`:
the `tool_use_id` the CLI's `can_use_tool` request already names. That
makes the pairing a measured fact rather than a match on input text --
and it stays `Option`, because AskUserQuestion is not permission for
anything and an echo session's question is about no tool at all. Those
still draw as their own card, which is what every question did before.
The card also reads the input instead of dumping it. Every tool's input
is JSON, and showing it raw makes the reader parse `{"command":"…",
"timeout":5000}` to find the line they care about. A small table says
which field is the subject of which tool -- Bash's `command`, Read's
`file_path` -- and the rest is still listed, since dropping a field
would claim the tool had no other input when it might. The subject is
syntax-highlighted with dev.snipme:highlights, for the reason the
markdown renderer is a library: lexical rules are somebody else's
specification. Its theme is Catppuccin, mapped in Theme.kt beside the
rest of the palette rather than taken from the library's defaults.
The input shows whether or not the card is expanded. A row that says
only "Bash" says nothing anyone can act on, least of all when it is
asking to run something.
Verified on the emulator against a real haiku session: one card, the
description, `grep -rn "needle" /tmp | head -3` highlighted, `timeout:
5000` pulled out, and "Allow Bash?" with its buttons inside the card --
then Allow, which resolved in place and ran.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
9f403cddab |
Render markdown, and stop wiping messages still waiting to be read
Two things, both about the transcript telling the truth about itself. Markdown is rendered rather than shown as its source. The parsing is mikepenz/multiplatform-markdown-renderer, not something written here: markdown is somebody else's specification, and a hand-written subset of one disagrees with it at the edges, which is where the bug reports come from. `Markdown.kt` is only the mapping onto this app's palette, so code, links and rules take the Catppuccin values the rest of the app uses rather than the renderer's defaults. The queued-message list was cleared wholesale whenever a turn ended. But the backend holds a queue of its own and takes one message per turn, so a turn ending is precisely the moment the *rest* are still waiting -- the bubbles vanished while the messages were on their way, which reads as everything after the first having been dropped. Now a held message leaves the list exactly two ways: the session reads it, which arrives as a UserMessage, or its send failed and there is nothing to wait for. Measured first, because the report was that the backend dropped them: three messages sent behind one long turn were all delivered in order (ONE, TWO, THREE) against current main, so the loss was in the display. Verified on the emulator: headings, emphasis, inline code, nested lists, a quote bar, a fenced block, a rule and a link all render, and the three queued messages sit through their turn. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
9791afcfd6 |
Hold a queued message below the indicator until the turn takes it
The backend records a message the moment it is sent, so one sent into a running turn landed in the transcript at the time *we* spoke -- above the working indicator, in among things the session had already read. It had not read it. Showing it there says otherwise. Messages sent while a turn is in flight are now held below the indicator, drawn quieter, and take their place in the conversation when the turn ends. That is an approximation and worth naming: the CLI injects a queued message at a tool boundary, and tells nobody when it does, so the end of the turn is the first moment anything here can honestly say the message was taken. It errs toward "not yet read", which is the direction that cannot mislead. Also in this change, from the same pass over the screen: the app draws above the gesture strip rather than under it, and the three status colours that were literals in two other files -- an amber, a green and a red off Material's defaults -- are now Catppuccin members in Theme.kt beside the rest of the scheme. The ordering is verified by construction rather than photographed: the list is bottom-anchored, so the first item emitted is the lowest on screen, and the queued block is emitted before the indicator. Staging a real long-running turn to photograph cost four model turns and never produced one, because the model kept declining to sleep -- which is its own finding, and the reason the next change is a test command in the echo driver. |
||
|
|
31135e3f22 |
Wear Catppuccin Mocha, and move Usage to where the provider is
Two changes to the app, plus the one they turned up. **The theme.** Catppuccin Mocha, copied from dev-updater rather than shared: wg-app-link is the *link* -- the tunnel, the pinned CA, enrollment -- and a palette is not that. The two apps looking alike is a preference rather than a contract, and the moment one wants a different accent a shared version becomes a thing to fight. dev-updater's ActionTone and its ANSI table did not come across; nothing here draws a log or a destructive button yet, and copying a vocabulary with no speakers is how a file starts lying about what the app does. **Usage is no longer a global button.** It belongs to the provider, and the session view is the only place a provider is currently named, so that is where the control sits -- beside the line that names it, rather than collected with the app-wide controls where its scope had to be guessed. It carries the session back with it, so Back returns to that session rather than dumping the reader on the list. Its real home is that provider's own settings, which do not exist yet. **And the bit that only running it could find.** I first subtitled the usage screen with the session's provider, which on an echo session put "echo" directly above a card reading "claude" -- Claude's account-wide numbers labelled as echo's, a claim about echo that nothing measured. The subtitle is gone; each card names the service that answered, which is the true scope, and the reason is written where the subtitle was so it does not get re-added. Looked at on the emulator rather than read: the palette, the session header, the usage screen, and Back landing on the session it came from. ktfmt, compile and Lint clean. |