Skip to content

Android: swipe from the left edge for chat history - #888

Open
Gratenes wants to merge 18 commits into
zeronsh:mainfrom
Gratenes:android-history-drawer
Open

Gratenes wants to merge 18 commits into
zeronsh:mainfrom
Gratenes:android-history-drawer

Conversation

@Gratenes

@Gratenes Gratenes commented Oct 13, 2026 •

Copy link
Copy Markdown

Stacked on #609; I'll retarget to main once that lands.

Getting between chats on Android right now means backing out to Sessions, scrolling, and tapping back in. This adds a history drawer so you can jump between chats, or start a new one, from wherever you are.

Swipe right from the left edge (or tap the new menu button in a chat's header) and the drawer slides in under your finger:

  • New chat at the top
  • A project picker to narrow the list to one project
  • All / Needs you / Working / Pinned filters, as one segmented control with a sliding pill
  • Recent chats, newest first, each with a status dot (working, needs you, failed), the project badge and how long ago it was active. The chat you're in is highlighted.
  • Settings at the bottom
Chat header Drawer open
Chat header with the menu button History drawer open

Notes

  • In a chat, the header's back button becomes the menu button. Back still works through the system back gesture.
  • With gesture navigation, a swipe from the left edge normally means back, and Android only lets an app reserve about 200dp of that edge. The drawer reserves the middle band, where the grip is, so swipes above or below it still go back. The menu button always works.
  • The Sessions page filters now use the same segmented control as the drawer, so the two match (counts stay, inside the track). The old Pill component is removed since nothing else used it.
  • Tablets and unfolded foldables are unchanged, since they already show the session list next to the chat.
  • Kotlin/Compose only, no changes to the Rust core. It reuses the same session rows as the Sessions screen.

Testing

Checked on an emulator with the demo workspace: edge swipe, the menu button in a chat, tap outside to close, picking a chat, and the filters in both the drawer and on the Sessions page.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

wingleeio and others added 18 commits September 28, 2026 01:18
A Jetpack Compose app (apps/android) that links crates/mobile through
UniFFI — the same transcript layout engine, text measurement and
virtualization as iOS. The painter draws Rust display lists on a Skia
canvas at Rust coordinates with the same Geist bytes; Minikin backs the
fallback measurer. UI is Material 3 Expressive with Zeron's palette.

Kotlin-only renames in crates/mobile/uniffi.toml avoid clashes with
Throwable.message and AutoCloseable.close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… more screenshots

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sion rows

- New session is the iOS/desktop canvas: harness mark + "What are we
  building?" over a composer card whose chips (project, branch or host,
  model, effort) open Material 3 Expressive grouped menus.
- One shared composer: a resting one-line capsule that becomes a card
  with context chips when focused; no drop shadow; shape-morphing
  send/stop; a Queue/Steer delivery chip while the agent works.
- Session rows show the harness brand mark, project + branch subline,
  Done/Input/Failed status and state-tinted PR badges; small extended FAB.
- Harness brand marks ported from the shared SVG path data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every glyph is Zeron's own: the desktop icon set (crates/ui/assets/icons)
  plus the iOS tab/tool icons, compiled to VectorDrawables at build time
  (scripts/android/svg2vd.py) — no Material icons left in the UI.
- Expressive shell: display-weight Geist headers (emphasized type scale),
  filter pills with live counts, SegmentedListItem rows with project-toned
  harness tiles, a floating nav capsule + round search button, and the
  New session bar with the live summary (iOS accessory parity).
- Round tonal chrome on the session screen, expressive action menus for
  row / transcript / overflow actions, rebuilt settings and search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…diting

- Own-turn runway (desktop OwnTurnAnchor): an immediate send glides the
  prompt to the top and holds a viewport of room for the reply; a message
  queued behind the live turn takes the runway once its bubble lands.
- Row motion: fold toggles tween 140 ms ease-out, a growing tool group
  reveals over 360 ms expo; rows interpolate from the previous frame.
- Attachments: Photos / Files / Paste image via the system pickers,
  staged as JPEG (long side <= 2560, <= 24 MB, up to 8) with removable
  thumbnails; pending thumbnails in the transcript show a wavy upload
  ring driven by the escort progress.
- @ mentions: file suggestions above the composer; tokens become
  zeron-file links on send (session + new session).
- Queue editing: host lease with renewal, the user's draft stashed and
  restored, only the visible text committed.
- Project picker is a bottom sheet grouped by machine; choice menus are
  one group with a trailing check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wallpaper hero behind the sessions list and the new-session page:
aspect-filled artwork fading out downward at the opacity the Rust
contrast guard allows (wallpaper_safe_opacity), the new-session composer
softening it, and the list fading it as it scrolls. Effects (dither,
ASCII, halftone, scanlines) run in the shared core (wallpaper_render).
Settings has choose / effect / remove; --es wallpaper <path> and
--es wallpaper-effect set it at launch, like iOS -wallpaper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The transcript ends where the composer begins: no gradient scrim, no
  text streaming behind the composer (the runway's viewport was the full
  height, so reply tails ran under it, faded and cramped).
- Header is a flat Material top app bar that takes the container tone
  once content scrolls under it, instead of a gradient cut-off.
- Jump to latest is a small FAB floating over the transcript.
- Streaming veil: each inserted chunk fades on its own clock, found by a
  prefix+suffix diff (list rows carry their bullet after the item text,
  so the old prefix check skipped the veil and words popped in); chunks
  are recorded during composition so new text is never drawn opaque
  first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m nav

Two destinations don't take a navigation bar in Material 3 (it's for
three to five), and a floating capsule isn't a Material component. Home
now follows the search-led Material pattern: AppBarWithSearch with the
account avatar (→ Settings, now its own screen with a large top app
bar), ExpandedFullScreenSearchBar for search, FilterChips, and an
ExtendedFloatingActionButton for New session that collapses on scroll.
Session and new-session headers are standard TopAppBars with icon
buttons. Removes the custom floating nav, pills, and tonal circle
buttons. All screenshots recaptured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings back the Sessions header, floating nav with the New session bar,
Settings as a tab, the search screen, and the round header buttons.
Keeps the flat transcript/composer layout, jump FAB, streaming veil,
filter pills and white send arrow, and adds a status-bar scrim on
scrolled home and settings. Screenshots recaptured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…archive

- Question panel: one page per question, auto-advance, "Other…" text,
  Pi input/editor prompts (prefill + multiline) answerable; replaces the
  composer while open.
- Sessions: Group by Project (git identity, Home per device), options
  menu (New section, Collapse all, Group by project, Archived), swipe
  right to pin, Move to section, section rename/delete, pinned reorder,
  Archived screen, Undo snackbar from every archive, iOS row precedence.
- New session: project picker grouped by repository with a host chip
  for checkouts, New project folder browser, text/options/images kept
  when closed unsent.
- Session: per-chat drafts, open failures return to Sessions with a
  note, image viewer (thumbnails and image chips), chip icons, "Sending
  to host…" and reconnect countdown, PR chip Open/Copy link, take photo,
  Ctrl+Enter sends, markSeen on leave.
- App: sends get 25s to deliver after backgrounding (short FGS), an
  expired session keeps its local store, OAuth state checked, tokens
  sealed with Android Keystore, sign-out confirmation, list/detail
  layout on large screens, Ctrl+N / Ctrl+Shift+F.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds sh.zeron.android.voice, the Android side of the Codex voice
orchestrator call: audio on the phone, Codex and its tools on a
registered execution host advertising voiceHostCapability().

- VoiceController (iOS RemoteVoiceController): host eligibility and the
  remote-voice dev override, start/stop/mute, end reasons with messages
  and Retry/Settings, per-user/org remembered host and style, call
  sounds, proximity (earpiece + screen off at the ear), one call at a
  time, no auto reconnect, the scripted preview and a WebRTC self-test.
- VoicePeer + VoiceMedia (CodexVoicePeer/NativeVoiceMedia): Google WebRTC
  M150 (io.github.webrtc-sdk:android, the iOS pin's milestone), audio
  only; Prepare/Offer/ApplyAnswer/SetMuted/Levels/Close completed through
  VoiceCall.completeMedia exactly as iOS; manual audio until the host
  confirms, focus loss ends the call, speaker/earpiece/headset routing.
- VoiceCallService: microphone foreground service with a CallStyle call
  notification (host, call clock, Mute, Hang Up; tap opens the stage).
- Compose UI: the core orb on a Canvas, the core caption fader, the call
  stage, voice settings, the New session bar button / live call strip,
  the session header button and VoiceHost (mic prompt, keep-awake,
  off-stage failure snackbar).
- Call sounds from the iOS app in res/raw.

Wiring into AppModel, navigation and the existing screens is left to
the integrating change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The call lives on AppModel (stopped on any sign-out). The New session
bar carries the voice button and the live call strip; sessions get a
header voice button; Settings gets a Voice row; the call stage and
voice settings are routes (also from the call notification and
zeron://voice). Launch extras: voice-preview, voice-stage, remote-voice,
voice-selftest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A history drawer that follows the finger: new chat, a project picker,
All / Needs you / Working / Pinned filters and recent chats. In a chat
the header's back button becomes a menu button that opens it; back stays
on the system gesture. Wide layouts keep the side-by-side list.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants