3425ec69de
- 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>
6.5 KiB
6.5 KiB
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 hardcodesTABLET_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_fsends - ⚠️
save_layout— iOS never sends this over the wire, it's 100% local (UserDefaults) only. Android sendssave_layoutto the desktop on every drag/resize. Known, deliberate-at-the-time divergence, not yet reconciled. - ❌
widget_visibilityon 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 samemodeButton(REL/ABS) and 90dp top/bottompadHeightdead zone asFocusFaderWidget, both fit inside the same 540dp total (not additive) — ported to Android'sFaderWidgetView(nowFrameLayout-based, mirroringFocusFaderWidgetView'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 regularFaderWidgetdoes 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.swiftexists 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 singleuid = "title-big"instance too (idxindefaultFrame(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) viafittedSize, re-fit center-anchored on everywidget_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 24–27 falls back to BOLD; and Android still flashes the activity ring green on incomingwidget_feedbackwhere iOS'sapplyFeedbackTextdoesn't flash at all.- Perf note (2026-07-29): re-fitting calls
setLayoutParams(), which on AndroidrequestLayout()s up the tree — unlike iOS'sbounds.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' ownsetLayerType(LAYER_TYPE_SOFTWARE)plus per-onDrawLinearGradientallocation. 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.
- Perf note (2026-07-29): re-fitting calls
- ⚠️
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'spalette.py) — not built, local-only styling on iOS (no wire event) - ⚠️ Hide — present on Android but wrong semantics (see "Networking" above: no
widget_visibilitysend) - ✅ 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.