Files
ai-app/app/build-icon-font.sh
T
irisandClaude Opus 5 6154cb1949 Stop and start a session's process from the composer
The composer's second button now says what pressing it would do to the
process behind the session, in one place that is always there: an orange
pause while a turn is running (interrupt, the process stays), a red stop
when it is not (end the process), a green play when it has exited (start it
again on the same conversation). Send is disabled while there is nothing to
send, rather than pressable and silent.

Behind it, two routes. `stop` signals the recorded process and says nothing
else -- the driver's own reader already reports a death correctly, and
announcing it here would be a guess ahead of the measurement. `start`
replaces the driver and nothing else, so the transcript, the pump and every
open phone's stream stay where they were and there is still one writer of
the transcript; it is refused unless the session is known to have exited,
since starting on `Unknown` is the two-CLIs-on-one-conversation fault.

That last rule found a bug in the launch path: a relaunched session took its
status from the transcript, so one whose process had died before a backend
restart reported `exited` while the launch had just started a new process --
which refuses every command and offers a phone the chance to start a second
CLI on a live conversation. A launch that leaves a process running now says
idle.

The icon font moves to the Mono face, where every glyph is one em square, so
two icon buttons are the same width without either being told one; the
proportional advances ran 0.46 to 0.92 em and Send came out visibly wider
than Stop. GLYPH_SIZE comes down to match, since a glyph that fills its em
draws bigger at the same point size.

Verified against a stand-in CLI on the emulator: idle -> stop -> exited ->
start -> idle, a turn interrupted from the pause button, and both buttons
measured at 171x105 device pixels.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:41:36 -04:00

77 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Rebuilds androidApp/src/main/res/font/nerd_icons.ttf.
#
# The app draws a handful of icons -- a cog, a refresh arrow, send, stop --
# as text in a Nerd Fonts glyph rather than as vector assets or as ordinary
# Unicode. Unicode has no character for most of these, and the ones it does
# have are not reliably in an Android system font, so they land as tofu
# boxes on somebody's phone. Shipping the subset removes the hope: the
# glyph is in the APK.
#
# The whole symbols font is 3 MB for the handful below, so what is
# committed is a subset. Add a codepoint to GLYPHS below and to NerdIcons.kt
# (the two lists have to agree -- a codepoint in the Kotlin but not here is
# a glyph that silently doesn't exist), then run this and commit the result.
#
# Needs python3 and network access; fontTools is fetched into a temporary
# venv, so nothing has to be installed on the machine.
#
# Copied from dev-updater's script of the same name rather than shared
# through wg-app-link, for the reason Theme.kt gives about the palette: the
# link is the tunnel, the pinned CA and enrollment, and an icon set is a
# preference rather than part of that contract.
set -euo pipefail
# Codepoint, then the Nerd Fonts glyph name it came from. Material Design
# Icons bar one, so they read as one family -- and the first two are
# deliberately the same two dev-updater uses, since a cog and a refresh
# arrow mean the same thing in both apps. The exception is noted on its
# own line, as dev-updater's script does with its two.
GLYPHS=(
U+F0493 # md-cog
U+F0450 # md-refresh
U+F048A # md-send
U+F04DB # md-stop
U+F03E4 # md-pause
U+F040A # md-play
U+F1163 # md-send_clock
U+F0156 # md-close
U+F004D # md-arrow_left
U+F201 # fa-line_chart -- Font Awesome's, asked for by name
)
url=https://github.com/ryanoasis/nerd-fonts/releases/latest/download/NerdFontsSymbolsOnly.zip
out="$(cd "$(dirname "$0")" && pwd)/androidApp/src/main/res/font/nerd_icons.ttf"
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
echo "Fetching $url"
curl -fsSL -o "$work/nf.zip" "$url"
python3 -c 'import sys,zipfile; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])' "$work/nf.zip" "$work"
python3 -m venv "$work/venv"
"$work/venv/bin/pip" -q install fonttools
unicodes="$(IFS=,; echo "${GLYPHS[*]}")"
mkdir -p "$(dirname "$out")"
# The Mono face rather than the proportional one, which this used until
# 2026-08-30. Every glyph in it is one em wide and one em tall, so two
# icons drawn at the same size are the same size -- which is what makes two
# icon buttons beside each other match without either of them being told a
# width. In the proportional face the advances run from 0.46 em (play) to
# 0.92 em (line chart), so the composer's Send button came out visibly wider
# than the Stop button next to it, and any fix at the call site would have
# been one measurement hardcoded per pair.
#
# The trade is the one the old comment named: an icon inline beside text is
# padded out to a cell. That is worth it, and it is also why GLYPH_SIZE in
# NerdIcons.kt came down when this changed -- a glyph that fills its em
# draws bigger at the same point size than one that does not.
"$work/venv/bin/pyftsubset" "$work/SymbolsNerdFontMono-Regular.ttf" \
--unicodes="$unicodes" \
--layout-features= \
--drop-tables+=DSIG \
--output-file="$out"
echo "Wrote $out ($(stat -c %s "$out") bytes) with ${#GLYPHS[@]} glyphs"