Skip to content

Android app on the shared Rust mobile core (Material 3 Expressive) - #148

Draft
katulevskiy wants to merge 13 commits into
mirror/upstream-mainfrom
mirror/upstream-pr/609
Draft

katulevskiy wants to merge 13 commits into
mirror/upstream-mainfrom
mirror/upstream-pr/609

Conversation

@katulevskiy

Copy link
Copy Markdown
Owner

Upstream mirror

Source: zeronsh#609
Original author: @wingleeio
Original revision: 6f1b698c90db830ed0b6911167ced8d0dbedcaaa

This PR is an isolated Contribution Manager pilot mirror. Its reviews, checks and merge state are separate from upstream. An empty [skip ci] commit suppresses automatic bulk CI; the code tree matches the imported upstream revision.


Draft: the Android app, built on the same Rust mobile core (crates/mobile) as iOS.

What's shared with iOS

  • Text measurement and layout — Android links zeron-mobile through UniFFI (Kotlin/JNA). TranscriptView runs the same layout thread, incremental markdown parsing, zeron-text measurement on the bundled Geist bytes (read from the iOS Fonts/ folder), and prefix-sum LayoutFrames.
  • Virtualization — rowsIn binary search over the frame, with only the rows in the viewport band composed. Rows paint the Rust display list on a Skia canvas at Rust coordinates, so measurement and drawing can't disagree. Glyphs Geist lacks (CJK, emoji) are measured by an AndroidMeasurer (Minikin getTextRunAdvances), the counterpart of the CoreText measurer.
  • Painter parity with iOS RowModel: boxes and hairlines, decorations, overflow fades (DST_OUT ramps), horizontal code/table scrollers, the streaming veil, and widgets (copy, disclosures, tool rail, shimmer, images, tool status, working trailer).

Design

Material 3 Expressive components throughout, themed with Zeron's palette, Geist type and Zeron's own icon set (the desktop icons in crates/ui/assets/icons and the iOS tab and tool glyphs, compiled to VectorDrawables by scripts/android/svg2vd.py; no Material icons):

  • Shell: display-weight Geist headers, filter pills with live counts, SegmentedListItem rows with harness marks and Done/Input/Failed labels, a floating nav (Sessions / Settings) with a round search button, and the New session bar with the live summary (iOS accessory parity); pull to refresh uses LoadingIndicator.
  • Session: round tonal back and more buttons around a centred title; the header takes the container tone when content scrolls under it; the transcript ends at the composer; a small FAB jumps to the latest message; streamed text fades in chunk by chunk.
  • New session: composer-first ("What are we building?"); the project chip opens a bottom sheet grouped by machine, and model and effort open expressive menus.
  • Composer: a resting capsule that expands into a card with chips; shape-morphing send/stop; a Queue/Steer chip while the agent works.
  • Wallpaper: the iOS chat wallpaper hero behind the sessions list and new session, with contrast-guarded opacity and effects from wallpaper_render in the core.

Core changes

  • crates/mobile/uniffi.toml: Kotlin-only renames (CoreError.*.message → reason, TranscriptView.close → shutdown) to avoid clashes with Throwable.message and AutoCloseable.close. Swift output is unchanged.
  • scripts/android/build-core.sh: ABIs configurable via ZERON_ANDROID_ABIS; now run by Gradle.
  • scripts/android/gen-icons.sh + svg2vd.py: shared line icons → VectorDrawables; multi-colour file icons → PNG.

Screenshots (current UI — Pixel 9 emulator, API 36, demo workspace)

Every screenshot was recaptured from the latest build.

Home, search, settings

Sessions Scrolled Search Search results Settings

New session

New session Project sheet

Transcript and composer

Transcript Scrolled (jump FAB) Composer focused Photo staged Upload ring Runway Streaming

Queue and mentions

Queued Queue menu Editing Edited @ suggestions Mention sent

Dark

Sessions Transcript New session

Wallpaper (the Frieren artwork used for iOS testing)

Sessions New session Halftone Settings Effect menu Dark: sessions Dark: new session

Emulator frame stats while flinging a 600-turn transcript (software GPU, not representative of devices): 650 frames, 1.08% janky.

Still to do

  • Own-turn runway and fold/row-reveal animations
  • Attachments (picker + upload ring), @ mentions, queued-message editing
  • Push notifications (FCM)
  • Release profile: strip the debug .so (the debug APK is 120 MB)
  • CI job

🤖 Generated with Claude Code

wingleeio and others added 12 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>
@contribution-manager-katulevskiy contribution-manager-katulevskiy Bot added the review:needs-triage Managed by Contribution Manager label Oct 6, 2026
@contribution-manager-katulevskiy

contribution-manager-katulevskiy Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Contribution Manager

needs triage · medium risk · untriaged

Open review workspace · Revision fcf2b710

Next actions:

  • Direction decision needed
  • Scope, risk, and platform triage needed
  • Author has marked this PR as draft
  • Independent code review needed
  • Required check: core-tests (missing)

This summary is maintained by the review app. Decisions and test evidence are recorded in the workspace; the app does not merge PRs.

@contribution-manager-katulevskiy contribution-manager-katulevskiy Bot added cm:inbox Contribution Manager: waiting for triage and removed review:needs-triage Managed by Contribution Manager labels Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cm:inbox Contribution Manager: waiting for triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants