Skip to content

fix(ime): docked keyboard was full-screen (LayoutParams stamped over) + Lucide toolbars + no fullscreen extract - #78

Merged
willwade merged 5 commits into
mainfrom
feat/ime-lucide-icons
Oct 28, 2026
Merged

willwade merged 5 commits into
mainfrom
feat/ime-lucide-icons

Conversation

@willwade

Copy link
Copy Markdown
Contributor

Fixes #76 (round 2 — the real mechanism), plus the icon/toolbar overhaul flagged in hands-on testing.

The headline fix: the "docked" keyboard was full-screen and top-anchored on API 35

Found in a pixel-verified E2E sweep on the API 35 emulator: onCreateInputView sets the docked root's FrameLayout.LayoutParams(1007px, Gravity.BOTTOM) before attachment (parent=null) — then the IME framework stamps its own MATCH_PARENT×WRAP_CONTENT params over them when attaching the view to the decor. Measured: root laid out 1080x2272 at [0,0] — toolbar over the status bar, canvas swallowing the app.

That is exactly "I get fullscreen Dasher but I can't see the search field" (hands-on), and is a strong candidate for Heide's entire #73/#76 saga on MuMu: a giant, overlay-looking, untypeable-feeling keyboard. It also explains why #75's Gravity.BOTTOM "verified" on the API 33 emulator — that layout path re-docks on its own, so the stamping bug was invisible there.

Fix: setDockedHeight runs again in the posted handler — post-attachment, post-stamp — where the parent is real and the params stick. Verified: toolbar strip at y1400–1540 (bottom), app visible above it, in portrait and landscape, surviving rotation and IME switches.

Fullscreen extract disabled

onEvaluateFullscreenMode() = false — in landscape the default IMS behavior replaces the whole screen with the IME. The keyboard now docks at the bottom in every orientation, consistent with the product stance and Windows/macOS Dasher.

RFC 0002: Lucide icons + compact toolbars

The IME's View-based toolbars used text labels ("⌫", "Sel", "Cp", "Ps") and default Material pills for Float/Hide ("no icons, looks poor, the dock buttons are massive"):

  • Lucide icons baked as tintable vector drawables (lucide-static v1.62, ISC): arrow-left/right, delete, copy, clipboard-paste, text-select, panel-bottom, picture-in-picture-2, keyboard-off
  • Editing toolbar: 48dp icon targets (56dp delete), 8dp rounded corners (design token rounded.md), contentDescriptions preserved
  • Top bar: compact 48dp icon buttons; the Float⇄Dock toggle swaps icon+description+action via setFloatDockButton; emoji toggle keeps its "😀"/"Abc" state label in a compact pill
  • Pressed states (design tokens: highlight-light/dark fills) — the flat borders gave zero touch feedback
  • Long-press tooltips (API 26+) on every icon — note: tooltip rendering inside IME windows is unverified; press feedback + TalkBack confirmed working

Also

  • onConfigurationChanged re-pushes setSystemAppearance (RFC 0007: mid-session dark/light flips now re-derive the palette for System-palette users instead of waiting for engine recreation)
  • Diagnostics: setDockedHeight/after-layout/flush Log.d breadcrumbs

E2E verification (API 35 emulator, pixel + logcat verified)

Scenario Result
Docked portrait / landscape ✓ app visible above a bottom-docked keyboard
Text commits → target field ✓ (real typing; engine→coalescer→batched flush→InputConnection)
Float→Dock cycle incl. persistence ✓ overlay window lifecycle + reasons logged
IME switch cycle ✓ clean recreate, canvas alive
Rotation mid-typing (same-instance recreate) ✓ canvas alive
Cold start ✓ 2.7s to engine ready
Dark mode ✓ toolbar switches; canvas follows the palette setting per RFC 0007

Known-open: tooltip popups may not render inside the IME window (needs eyes; press states and TalkBack cover the affordance), mechanical synthetic typing can't zoom deep enough to re-verify ⌫-on-text (code path unchanged since #71's review).

The IME's View-based toolbars used text labels ('⌫', 'Sel', 'Cp', 'Ps')
and default Material text pills for Float/Hide — 'no icons, looks poor,
the dock buttons are massive' against the design guide and the main app
(which already renders Lucide via Compose).

- Lucide icons baked as tintable vector drawables (lucide-static v1.62,
  ISC), generated for: arrow-left/right, delete, copy, clipboard-paste,
  text-select, panel-bottom, picture-in-picture-2, keyboard-off
- EditingToolbar: 48dp icon targets (56dp delete), 8dp rounded corners
  (design token rounded.md), contentDescriptions preserved
- Top bar: compact 48dp icon buttons for Float (picture-in-picture-2),
  Hide (keyboard-off); FloatDock toggle swaps icon+description+action
  via setFloatDockButton; emoji toggle keeps its '😀'/'Abc' state label
  in a compact pill
- LucideIcons: mutate()+tint bridge for the classic-View layer

Signed-off-by: will wade <willwade@gmail.com>
…n tooltips

Feedback from the first hands-on pass on the Lucide toolbars:

- 'I get fullscreen Dasher but I can't see the search field': Android's
  default extract mode takes the whole screen in landscape and hides the
  app behind the IME. onEvaluateFullscreenMode() now returns false — the
  keyboard docks at the bottom in every orientation, matching the
  product stance (Heide: 'start it directly as docked') and how
  Windows/macOS Dasher behave.
- 'Can't tell what the icons mean / no hover state': the border-only
  button backgrounds had no state list — zero touch feedback. Both
  toolbars now use a bordered pill with a pressed fill (design tokens:
  rounded.md 8dp, border-light/dark, highlight-light/dark), and every
  icon carries a long-press tooltip (API 26+) alongside its existing
  contentDescription — the touch equivalent of the Windows/macOS hover
  labels.

Signed-off-by: will wade <willwade@gmail.com>
… LayoutParams — the real full-screen IME bug

E2E sweep finding (API 35, pixel-verified): onCreateInputView sets the
docked root's FrameLayout.LayoutParams(1007px, Gravity.BOTTOM) BEFORE
attachment (parent=null) — then the IME framework STAMPS its own
MATCH_PARENT×WRAP_CONTENT params over them when attaching the view to
the decor. Measured: root laid out 1080x2272 at [0,0] — toolbar over
the status bar, canvas swallowing the app: 'fullscreen Dasher, can't
see the search field'. #75's Gravity.BOTTOM never actually applied;
its API-33 'verification' passed because that layout path re-docks.

Fix: setDockedHeight runs again in the posted handler — post-attachment,
post-stamp — where the parent is real and the params stick. Verified:
toolbar strip at y1400-1540 (bottom), app visible above, in portrait
AND landscape, surviving rotation and IME switches.

Also: re-push setSystemAppearance on uiMode config changes (RFC 0007 —
mid-session dark flips now re-derive the palette for System-palette
users instead of waiting for engine recreation), plus setDockedHeight/
after-layout Log.d diagnostics from the sweep.

Signed-off-by: will wade <willwade@gmail.com>
…e icon geometry, 48dp emoji target, stamp defense-in-depth

Addresses the #78 review (5/10):

- C1: the flush instrumentation consumed the pending edit even when
  the InputConnection was null (takeFlush resets the coalescer) —
  silent text loss, introduced for a log line, contradicting the
  contract documented three lines above. Consumption now gated on the
  connection; the log only fires when there is something to flush
  (also fixes the per-frame Log.d spam, M3).
- C2: the SVG→vector generator dropped every <rect> — 4 of 9 icons
  (copy, panel-bottom, picture-in-picture-2, clipboard-paste) rendered
  as broken glyphs; the Dock button was a single horizontal line.
  Generator converts rects to rounded-rect stroke paths; all 9
  regenerated (verified counts: paste 5 parts, copy/pip2/panel 2 each).
- I1: emoji toggle back to a 48dp minimum target (compact pill
  rendering, full-size hit area).
- I2: setDockedHeight re-asserted in onStartInputView — belt to the
  posted-handler re-apply for OEM re-attach paths.
- I3: emoji tooltip swaps with mode (was stale 'Switch to emoji
  keyboard' while in emoji mode).
- M1: pillBackground doc no longer claims the border hexes are the
  border token (they are a darkened variant — the token doubles as the
  strip background); ImeToolbarPalette extracted as the single
  definition (M4); dead duplicate listener removed (M2); misplaced
  @Suppress dropped (M5).

Signed-off-by: will wade <willwade@gmail.com>
…tor checked in, cleanups

- The third emoji-label site (createEngine's process-death restore) now
  updates tooltipText with the label/description (loop-2 M2 — same
  class as loop-1 I3).
- scripts/gen_lucide_icons.py checked in — provenance for the 9 IME
  icon drawables; fails loudly on zero-geometry parses. The generator
  that dropped <rect>s was never in the repo; the next icon would have
  re-broken it.
- pillBackground's never-overridden cornerRadiusDp inlined; the FQNs
  from the icon import purge restored to imports in EditingToolbar.
- Night-mode mid-show flip verified in the E2E sweep (toolbar strip
  went to the dark token after 'cmd uimode night yes' with the keyboard
  up — the input view IS recreated on uiMode changes, so the
  construction-time palette vals re-derive).

Signed-off-by: will wade <willwade@gmail.com>
@willwade
willwade merged commit 5a08a07 into main Oct 28, 2026
2 checks passed
@willwade
willwade deleted the feat/ime-lucide-icons branch October 28, 2026 07:34
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.

IME: stuck 'Preparing Dasher' overlay after view recreation — the 'big float-like window you can't type on' (Heide, v0.1.24, MuMu)

1 participant