Skip to content

Commit 52a747d

Browse files
committed
fix: align iOS fling provider fixture
1 parent 2d8d8dc commit 52a747d

3 files changed

Lines changed: 122 additions & 80 deletions

File tree

src/core/dispatch-interactions.ts

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -653,22 +653,7 @@ export async function handleRotateGestureCommand(
653653
);
654654
}
655655

656-
const degrees = Number(positionals[0]);
657-
const x = positionals[1] ? Number(positionals[1]) : undefined;
658-
const y = positionals[2] ? Number(positionals[2]) : undefined;
659-
const velocity = positionals[3] ? Number(positionals[3]) : degrees >= 0 ? 1 : -1;
660-
if (!Number.isFinite(degrees)) {
661-
throw new AppError('INVALID_ARGS', 'rotate-gesture requires degrees [x] [y] [velocity]');
662-
}
663-
if ((x === undefined) !== (y === undefined)) {
664-
throw new AppError('INVALID_ARGS', 'rotate-gesture center requires both x and y');
665-
}
666-
if (x !== undefined && (!Number.isFinite(x) || !Number.isFinite(y))) {
667-
throw new AppError('INVALID_ARGS', 'rotate-gesture center requires finite x and y');
668-
}
669-
if (!Number.isFinite(velocity) || velocity === 0) {
670-
throw new AppError('INVALID_ARGS', 'rotate-gesture velocity must be a non-zero number');
671-
}
656+
const { degrees, x, y, velocity } = parseRotateGestureParams(positionals);
672657

673658
await interactor.rotateGesture(degrees, x, y, velocity);
674659
return {
@@ -681,6 +666,45 @@ export async function handleRotateGestureCommand(
681666

682667
type GestureDirection = 'up' | 'down' | 'left' | 'right';
683668

669+
type RotateGestureParams = {
670+
degrees: number;
671+
x?: number;
672+
y?: number;
673+
velocity: number;
674+
};
675+
676+
function parseRotateGestureParams(positionals: string[]): RotateGestureParams {
677+
const degrees = Number(positionals[0]);
678+
if (!Number.isFinite(degrees)) {
679+
throw new AppError('INVALID_ARGS', 'rotate-gesture requires degrees [x] [y] [velocity]');
680+
}
681+
682+
const center = parseOptionalGestureCenter(positionals[1], positionals[2]);
683+
const velocity = Number(positionals[3] ?? (degrees >= 0 ? 1 : -1));
684+
if (!Number.isFinite(velocity) || velocity === 0) {
685+
throw new AppError('INVALID_ARGS', 'rotate-gesture velocity must be a non-zero number');
686+
}
687+
688+
return { degrees, ...center, velocity };
689+
}
690+
691+
function parseOptionalGestureCenter(
692+
xInput: string | undefined,
693+
yInput: string | undefined,
694+
): Pick<RotateGestureParams, 'x' | 'y'> {
695+
if (xInput === undefined && yInput === undefined) return {};
696+
if (xInput === undefined || yInput === undefined) {
697+
throw new AppError('INVALID_ARGS', 'rotate-gesture center requires both x and y');
698+
}
699+
700+
const x = Number(xInput);
701+
const y = Number(yInput);
702+
if (!Number.isFinite(x) || !Number.isFinite(y)) {
703+
throw new AppError('INVALID_ARGS', 'rotate-gesture center requires finite x and y');
704+
}
705+
return { x, y };
706+
}
707+
684708
function parseGestureDirection(input: string | undefined, field: string): GestureDirection {
685709
if (input === 'up' || input === 'down' || input === 'left' || input === 'right') {
686710
return input;

src/daemon/recording-gestures.ts

Lines changed: 80 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -165,32 +165,39 @@ function buildGestureEvents(
165165
gestureDurationMs: number,
166166
referenceFrame?: ReferenceFrame,
167167
): RecordingGestureEvent[] {
168-
switch (command) {
169-
case 'click':
170-
case 'press':
171-
return buildPressEvents(positionals, result, tMs, referenceFrame);
172-
case 'react-native':
173-
return positionals[0] === 'dismiss-overlay'
174-
? buildPressEvents(positionals, result, tMs, referenceFrame)
175-
: [];
176-
case 'fill':
177-
case 'focus':
178-
return buildFocusEvents(positionals, result, tMs, referenceFrame);
179-
case 'longpress':
180-
return buildLongPressEvents(positionals, result, tMs, gestureDurationMs, referenceFrame);
181-
case 'scroll':
182-
return buildScrollEvents(positionals, result, tMs, gestureDurationMs, referenceFrame);
183-
case 'pan':
184-
case 'fling':
185-
case 'swipe':
186-
return buildSwipeEvents(positionals, result, tMs, gestureDurationMs, referenceFrame);
187-
case 'pinch':
188-
return buildPinchEvents(positionals, result, tMs, gestureDurationMs, referenceFrame);
189-
default:
190-
return [];
191-
}
168+
const builder = gestureEventBuilders[command];
169+
return builder?.(positionals, result, tMs, gestureDurationMs, referenceFrame) ?? [];
192170
}
193171

172+
type GestureEventBuilder = (
173+
positionals: string[],
174+
result: Record<string, unknown>,
175+
tMs: number,
176+
gestureDurationMs: number,
177+
referenceFrame?: ReferenceFrame,
178+
) => RecordingGestureEvent[];
179+
180+
const gestureEventBuilders: Record<string, GestureEventBuilder> = {
181+
click: (positionals, result, tMs, _durationMs, referenceFrame) =>
182+
buildPressEvents(positionals, result, tMs, referenceFrame),
183+
press: (positionals, result, tMs, _durationMs, referenceFrame) =>
184+
buildPressEvents(positionals, result, tMs, referenceFrame),
185+
'react-native': (positionals, result, tMs, _durationMs, referenceFrame) =>
186+
positionals[0] === 'dismiss-overlay'
187+
? buildPressEvents(positionals, result, tMs, referenceFrame)
188+
: [],
189+
fill: (positionals, result, tMs, _durationMs, referenceFrame) =>
190+
buildFocusEvents(positionals, result, tMs, referenceFrame),
191+
focus: (positionals, result, tMs, _durationMs, referenceFrame) =>
192+
buildFocusEvents(positionals, result, tMs, referenceFrame),
193+
longpress: buildLongPressEvents,
194+
scroll: buildScrollEvents,
195+
pan: buildSwipeEvents,
196+
fling: buildSwipeEvents,
197+
swipe: buildSwipeEvents,
198+
pinch: buildPinchEvents,
199+
};
200+
194201
function shouldAnchorTapVisualizationNearCompletion(
195202
command: string,
196203
result: Record<string, unknown>,
@@ -296,43 +303,51 @@ function buildSwipeEvents(
296303
const count = clampInt(readNumber(result.count), 1) ?? 1;
297304
const pauseMs = clampInt(readNumber(result.pauseMs), 0) ?? 0;
298305
const pattern = result.pattern === 'ping-pong' ? 'ping-pong' : 'one-way';
299-
const events: RecordingGestureEvent[] = [];
300-
301-
for (let index = 0; index < count; index += 1) {
302-
const reverse = pattern === 'ping-pong' && index % 2 === 1;
303-
const startX = reverse ? x2 : x1;
304-
const startY = reverse ? y2 : y1;
305-
const endX = reverse ? x1 : x2;
306-
const endY = reverse ? y1 : y2;
306+
return Array.from({ length: count }, (_, index) => {
307+
const { startX, startY, endX, endY } = resolveSwipePathForIndex(index, pattern, x1, y1, x2, y2);
307308
const startTime = tMs + index * (durationMs + pauseMs);
308-
const kind = classifySwipeKind(startX, startY, endX, endY, referenceFrame);
309-
if (kind === 'back-swipe') {
310-
events.push({
311-
kind: 'back-swipe',
312-
tMs: startTime,
313-
x: startX,
314-
y: startY,
315-
x2: endX,
316-
y2: endY,
317-
...referenceFrame,
318-
durationMs,
319-
edge: resolveBackSwipeEdge(startX, endX, referenceFrame),
320-
});
321-
continue;
322-
}
323-
events.push({
324-
kind: 'swipe',
325-
tMs: startTime,
326-
x: startX,
327-
y: startY,
328-
x2: endX,
329-
y2: endY,
309+
return buildSwipeTravelEvent(startTime, startX, startY, endX, endY, durationMs, referenceFrame);
310+
});
311+
}
312+
313+
function resolveSwipePathForIndex(
314+
index: number,
315+
pattern: 'one-way' | 'ping-pong',
316+
x1: number,
317+
y1: number,
318+
x2: number,
319+
y2: number,
320+
): { startX: number; startY: number; endX: number; endY: number } {
321+
const reverse = pattern === 'ping-pong' && index % 2 === 1;
322+
return reverse
323+
? { startX: x2, startY: y2, endX: x1, endY: y1 }
324+
: { startX: x1, startY: y1, endX: x2, endY: y2 };
325+
}
326+
327+
function buildSwipeTravelEvent(
328+
tMs: number,
329+
x: number,
330+
y: number,
331+
x2: number,
332+
y2: number,
333+
durationMs: number,
334+
referenceFrame?: ReferenceFrame,
335+
): RecordingGestureEvent {
336+
const kind = classifySwipeKind(x, y, x2, y2, referenceFrame);
337+
if (kind === 'back-swipe') {
338+
return {
339+
kind,
340+
tMs,
341+
x,
342+
y,
343+
x2,
344+
y2,
330345
...referenceFrame,
331346
durationMs,
332-
});
347+
edge: resolveBackSwipeEdge(x, x2, referenceFrame),
348+
};
333349
}
334-
335-
return events;
350+
return { kind, tMs, x, y, x2, y2, ...referenceFrame, durationMs };
336351
}
337352

338353
function buildScrollEvents(
@@ -506,16 +521,20 @@ function readTravelCoordinates(
506521
result: Record<string, unknown>,
507522
positionals: string[],
508523
): { x1: number; y1: number; x2: number; y2: number } | undefined {
509-
const x1 = readNumber(result.x1) ?? readNumber(result.x) ?? readNumber(positionals[0]);
510-
const y1 = readNumber(result.y1) ?? readNumber(result.y) ?? readNumber(positionals[1]);
511-
const x2 = readNumber(result.x2) ?? readNumber(positionals[2]);
512-
const y2 = readNumber(result.y2) ?? readNumber(positionals[3]);
524+
const x1 = readFirstNumber(result.x1, result.x, positionals[0]);
525+
const y1 = readFirstNumber(result.y1, result.y, positionals[1]);
526+
const x2 = readFirstNumber(result.x2, positionals[2]);
527+
const y2 = readFirstNumber(result.y2, positionals[3]);
513528
if (x1 === undefined || y1 === undefined || x2 === undefined || y2 === undefined) {
514529
return undefined;
515530
}
516531
return { x1, y1, x2, y2 };
517532
}
518533

534+
function readFirstNumber(...values: unknown[]): number | undefined {
535+
return values.map(readNumber).find((value) => value !== undefined);
536+
}
537+
519538
function resolveDurationMs(
520539
gestureDurationMs: number,
521540
candidates: Array<number | undefined>,

test/integration/provider-scenarios/ios-world.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,11 @@ export async function createIosSettingsWorld(): Promise<IosSettingsWorld> {
6767
result: { dragged: true },
6868
},
6969
{
70-
command: 'ios.runner.fling',
70+
command: 'ios.runner.drag',
7171
deviceId: PROVIDER_SCENARIO_IOS_SIMULATOR.id,
7272
platform: 'ios',
7373
request: {
74-
command: 'fling',
75-
direction: 'right',
74+
command: 'drag',
7675
x: 196,
7776
y: 122,
7877
x2: 376,

0 commit comments

Comments
 (0)