Files
Paul Lipscomb 3425ec69de Android tablet remote UI: styling pass, color picker, arrange mode indicator, connection gating
- Button styling standardization with green ring state indicators (Connect, Rescan, Log, Clear Layout, Reset ALL)
- Input field labels with proper DP-based padding and spacing
- Feedback & title widget color picker with 7-color palette and persistence layer
- Font weight selection for text widgets (deferred visual implementation)
- Hide/Show and Reset Size buttons in context menu
- Flashing pink border around entire app when Arrange mode is ON (500ms fade in/out cycle)
- Arrange button disabled until connected to desktop app, with alpha indicator
- WidgetLayoutState now persists color and fontWeight properties
- Arrange mode visual debugging with smooth fade animation instead of harsh strobe

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-30 18:47:07 -05:00

51 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# iOS Feature Parity Tracker
Tracks what `remote-client-ios` (source of truth) actually does vs. what
`remote-client-android` has built, so gaps get found by checking this list
against the iOS source, not by surprise mid-conversation.
**Status:** ✅ Matched · ⚠️ Partial/Different (deliberate or otherwise) · ❌ Not built · ❓ iOS behavior not yet verified against source
## Top button row
- ✅ Single horizontal row, natural (not stretched) size, iOS's chained trailing/leading order
-`tabletIdField` — iOS has a live editable field; Android hardcodes `TABLET_DEST_ID = 1`
-`autoSwitchButton` — auto preset-switching toggle, not built
-`gridButton` — visual grid-overlay toggle, not built (no grid overlay exists at all)
-`cancelChangesButton` — revert unsaved Arrange-mode edits, not built
- ❌ Preset-switch confirmation alert (`isLocked==false && isNewPreset` → "Save & Switch"/"Discard & Switch") — Android just always re-renders silently
## Networking / protocol
- ✅ WebSocket connect/dispatch, Bonjour discovery, `control`/`control_f` sends
- ⚠️ `save_layout` — iOS **never sends this over the wire**, it's 100% local (`UserDefaults`) only. Android sends `save_layout` to the desktop on every drag/resize. Known, deliberate-at-the-time divergence, not yet reconciled.
-`widget_visibility` on Hide — iOS sends `{"event":"widget_visibility","uid":...,"dest_id":0}` on hide, telling the desktop to un-route that widget (unchecks its remote checkbox there). Android's Hide is local-only, desktop has no idea.
## Widgets — regular (preset-routed)
- ⚠️ `FaderWidget` — confirmed against source: iOS's regular fader has the same `modeButton` (REL/ABS) and 90dp top/bottom `padHeight` dead zone as `FocusFaderWidget`, both fit inside the same 540dp total (not additive) — ported to Android's `FaderWidgetView` (now `FrameLayout`-based, mirroring `FocusFaderWidgetView`'s structure). Android's total height is 540+180=720dp (not iOS's literal 540) to keep the active drag range unshrunk — deliberate, pre-existing divergence, not a bug. Android's regular fader also got a **FINE** button, which iOS's regular `FaderWidget` does NOT have (FINE is Focus-only on iOS) — added by direct request, an intentional Android-only addition beyond parity.
-`ToggleWidget`/`TransportWidget` — 75×75dp, matched
-`FeedbackWidget` — 220×100dp, matched. (Verified 2026-07-29: this is really "matched by both being unused" — `FeedbackWidget.swift` exists on iOS but is never instantiated, and Android has no regular-feedback view or model. The 220×100 constant only ever applied to the *Focus* feedback widget.)
-`TitleWidget` — confirmed against source: iOS hardcodes a single `uid = "title-big"` instance too (`idx` in `defaultFrame(idx:)` is unused for title — leftover grid-placement signature shared with faders/toggles/feedbacks). Android's one-title-per-preset binding matches.
## Widgets — Channel Focus
-`FocusFaderWidget` — REL/ABS + FINE buttons, dead-zone touch math
- ✅ Focus Fader length rescale context-menu options ("50% Longer" / "70% Longer" / "Reset Length") — height-only, bottom-edge anchored, multiplier applied to default (not current) height.
-`FocusToggleWidget` — momentary mode + Gray/White non-darkenable color quirk
-`FocusFeedbackWidget` — chrome-less (transparent background, no resting card border, no caption view, 8dp padding), 32sp monospace semibold at `#EBEBEB`, single line. Box is a pure function of (font size, text) via `fittedSize`, re-fit center-anchored on every `widget_feedback`. Pinch drives **font size**, not the box; "Reset size" restores 32sp; min 12sp. Font size is not persisted — it's back-derived from the saved height on load, matching iOS exactly (see "Networking" note: no schema change). Two knowing approximations: iOS's `.semibold` (weight 600) is only expressible from API 28, so API 2427 falls back to BOLD; and Android still flashes the activity ring green on incoming `widget_feedback` where iOS's `applyFeedbackText` doesn't flash at all.
- Perf note (2026-07-29): re-fitting calls `setLayoutParams()`, which on Android `requestLayout()`s up the tree — unlike iOS's `bounds.size`, which costs siblings nothing. This was briefly suspected of causing fader stutter and reverted; the stutter turned out to persist without this code, so it was reinstated. The unproven suspect is instead the faders' own `setLayerType(LAYER_TYPE_SOFTWARE)` plus per-`onDraw` `LinearGradient` allocation. If this widget ever *does* need optimizing, the cheap fix is skipping the re-fit when the newly measured size equals the current one — monospace means most readout updates measure identical.
- ⚠️ `LogWidget` — iOS is a draggable, pinch-resizable floating console with **In/Out/Local category tabs**, only rebuilding its TextView when the visible category matches what's being logged (the actual reason it doesn't have Android's perf problem). Android's log panel is a fixed bottom overlay, single combined stream, no categories, no drag/resize.
## Context menu (long-press, Arrange mode only)
- ❌ Align Left/Center/Right (`TextAlignableWidget`) — not built
- ❌ Text Color (`TextColorableWidget`, from the named palette matching desktop's `palette.py`) — not built, local-only styling on iOS (no wire event)
- ⚠️ Hide — present on Android but wrong semantics (see "Networking" above: no `widget_visibility` send)
- ✅ Reset Size — box dimensions for regular widgets, font size for `FocusFeedbackWidget` (matching iOS, which means two different things by the same menu item).
- ✅ Focus Fader length rescale (see above) — `remote-client-android/.../arrange/{ArrangeCardView,ArrangeUILayout,ArrangeFunctionsAlerts}.java`
## Arrange mode / layout
- ✅ Free 2D drag, pinch-resize (generic, top-left anchored)
- ✅ Per-preset + Channel Focus separate layout persistence
- ✅ Clear Layout (per-mode) + Reset ALL Layouts (Android-only addition, flagged as an iOS backlog item in memory)
- ⚠️ Default placement: iOS uses `defaultFrame(idx:)` per-type grids at fixed screen-relative coordinates (with real overlap between types by iOS's own design). Android stacks everything at `(0,0)` — simpler, deliberately chosen over Android's earlier over-engineered fit-to-screen algorithm.
---
**When picking something off this list to build:** re-read the actual iOS source file first (don't assume from this doc alone — it's a snapshot, not guaranteed current), confirm the ❓ items against source before treating them as gaps.