Skip to content

refactor(ios): gesture-response factory + performGesture wrapper#659

Merged
thymikee merged 1 commit into
mainfrom
refactor/ios-runner-gesture-response
Jun 2, 2026
Merged

refactor(ios): gesture-response factory + performGesture wrapper#659
thymikee merged 1 commit into
mainfrom
refactor/ios-runner-gesture-response

Conversation

@thymikee
Copy link
Copy Markdown
Member

@thymikee thymikee commented Jun 2, 2026

What

Collapse the repeated gesture-command boilerplate in CommandExecution.swift's executeOnMain switch behind two small seams:

  • performGesture(app, idleTimeout:) → (timing, outcome) — folds measureGesture + the scroll idle-timeout/quiescence-skip wrap. Parameterized: touch gestures wrap (default); synthesis gestures (pinch/rotate/transform) pass idleTimeout: false because RunnerSynthesizedGesture governs its own timing (this distinction was previously implicit/easy to get wrong).
  • gestureResponse(message:timing:frame:) over a GestureFrame (none/touch/drag) — one factory for the success DataPayload (message + gesture timing + optional visualization frame).

13 gesture cases now use the seams; ~120 lines of the repeated quartet (measureGesture + idle-wrap + unsupportedResponse + 8-field DataPayload) collapse. CommandExecution.swift 949 → 867.

Why

Each new gesture command re-derived the same 8-field payload + timing/idle quartet by hand — drift-prone and ~9× of the file's bulk. One factory + one wrapper make the switch far cheaper to read and make the timing/idle distinction explicit.

Behavior-preserving

Identical outcomes, timing capture, DataPayload fields/messages, and the same touch-wrapped vs synthesis-unwrapped distinction. No wire change — the factory emits the already wire-locked DataPayload. mouseClick (throws) and swipe (optional frame) keep their bespoke measure/wrap but route the success payload through gestureResponse.

Verification

  • xcodebuild build-for-testingTEST BUILD SUCCEEDED (no warnings).
  • Pure refactor (field-for-field preserved). Gesture execution is exercised by examples/test-app/replays/gesture-lab.ad (pinch/rotate/pan/fling) — happy to run it on a sim for extra confidence if wanted; the gesture-payload shape is unchanged by construction.

Scope

This was the #1 candidate from the post-merge refactor re-scan (verified deep: complexity concentrates behind two seams serving every gesture). Steers clear of the gesture synthesis (already consolidated in #645) and the Command/DataPayload wire-lock.

…ommandExecution

Collapse the gesture-command boilerplate in the executeOnMain switch behind two seams:
- performGesture(app, idleTimeout:) -> (timing, outcome): folds measureGesture + the scroll
  idle-timeout/quiescence-skip wrap. Parameterized: touch gestures wrap (idleTimeout: true,
  default); synthesis gestures (pinch/rotate/transform) pass idleTimeout: false because
  RunnerSynthesizedGesture governs its own timing — a distinction that was previously implicit.
- gestureResponse(message:timing:frame:) over a GestureFrame (none/touch/drag): one factory for
  the success DataPayload (message + gesture timing + optional touch/drag visualization frame).

The 13 gesture cases (tap x3, tapSeries x2, longPress, drag, dragSeries, swipe, mouseClick, pinch,
rotateGesture, transformGesture) now use the seams; ~120 lines of repeated quartet (measureGesture +
idle-wrap + unsupported check + 8-field DataPayload) collapse. CommandExecution.swift 949 -> 867.

Behavior-preserving: identical outcomes, timing capture, DataPayload fields/messages, and the same
touch-wrapped vs synthesis-unwrapped distinction. No wire change (the factory emits the already
wire-locked DataPayload internally). mouseClick (throws) and swipe (returns an optional frame) keep
their bespoke measure/wrap but route the success payload through gestureResponse.

Verified: xcodebuild build-for-testing -> TEST BUILD SUCCEEDED (no warnings).
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

Size Report

Metric Base Current Diff
JS raw 1.1 MB 1.1 MB 0 B
JS gzip 360.7 kB 360.7 kB 0 B
npm tarball 462.0 kB 462.4 kB +369 B
npm unpacked 1.5 MB 1.5 MB -2.0 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 28.1 ms 28.5 ms +0.4 ms
CLI --help 43.7 ms 44.6 ms +1.0 ms

Top changed chunks: no changes in the largest emitted chunks.

@thymikee thymikee merged commit cbe725d into main Jun 2, 2026
18 checks passed
@thymikee thymikee deleted the refactor/ios-runner-gesture-response branch June 2, 2026 01:32
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-06-02 01:32 UTC

@thymikee
Copy link
Copy Markdown
Member Author

thymikee commented Jun 2, 2026

Thanks — applied the doc nits (7… follow-up commit), all comment-only:

  • idleTimeout: false guardrail — added a NOTE to the performGesture doc: a new synthesis gesture must pass idleTimeout: false; the default true would wrap it in the scroll idle-timeout and change runtime behavior.
  • swipe / mouseClick bypass — added a one-line comment on each explaining why they keep raw measureGesture (swipe returns an optional frame; mouseClick throws — neither produces a RunnerInteractionOutcome), and that both still route the success payload through gestureResponse.

On the gesture-lab recommendation: agreed it's the residual risk. This is a field-for-field preserving refactor (timing window, idle-wrap on/off, unsupportedResponse paths, messages, and DataPayload fields all match), so I verified by compile + diff. I'm happy to run examples/test-app/replays/gesture-lab.ad on an iOS sim before merge for empirical confirmation (pinch/rotate/pan/fling) — it needs the test-app Metro bring-up on the default port. Want me to run it, or are you good merging on field-for-field + green CI?

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.

1 participant