@react-native-oh-tpl/react-native-gesture-handler 2.12.6-1 → 2.12.6-2
Sign up to get free protection for your applications and to get access to all the features.
- package/harmony/gesture_handler/LICENSE +21 -0
- package/harmony/gesture_handler/OAT.xml +44 -0
- package/harmony/gesture_handler/README.OpenSource +11 -0
- package/harmony/gesture_handler/README.md +1 -0
- package/harmony/gesture_handler/build-profile.json5 +7 -7
- package/harmony/gesture_handler/hvigorfile.ts +2 -2
- package/harmony/gesture_handler/index.ets +2 -2
- package/harmony/gesture_handler/oh-package.json5 +13 -11
- package/harmony/gesture_handler/src/main/cpp/CMakeLists.txt +8 -8
- package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.cpp +33 -33
- package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.h +14 -14
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerButtonComponentDescriptor.h +60 -60
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.cpp +17 -17
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerModule.h +11 -11
- package/harmony/gesture_handler/src/main/cpp/RNGestureHandlerRootViewComponentDescriptor.h +60 -60
- package/harmony/gesture_handler/src/main/ets/CircularBuffer.ts +42 -42
- package/harmony/gesture_handler/src/main/ets/Event.ts +67 -67
- package/harmony/gesture_handler/src/main/ets/EventDispatcher.ts +37 -37
- package/harmony/gesture_handler/src/main/ets/GestureHandler.ts +663 -663
- package/harmony/gesture_handler/src/main/ets/GestureHandlerArkUIAdapter.ets +201 -201
- package/harmony/gesture_handler/src/main/ets/GestureHandlerFactory.ts +44 -44
- package/harmony/gesture_handler/src/main/ets/GestureHandlerOrchestrator.ts +280 -280
- package/harmony/gesture_handler/src/main/ets/GestureHandlerPackage.ts +22 -22
- package/harmony/gesture_handler/src/main/ets/GestureHandlerRegistry.ts +27 -27
- package/harmony/gesture_handler/src/main/ets/InteractionManager.ts +108 -108
- package/harmony/gesture_handler/src/main/ets/LeastSquareSolver.ts +182 -182
- package/harmony/gesture_handler/src/main/ets/NativeViewGestureHandler.ts +114 -114
- package/harmony/gesture_handler/src/main/ets/OutgoingEvent.ts +33 -33
- package/harmony/gesture_handler/src/main/ets/PanGestureHandler.ts +327 -327
- package/harmony/gesture_handler/src/main/ets/PointerTracker.ts +239 -239
- package/harmony/gesture_handler/src/main/ets/RNGHError.ts +4 -4
- package/harmony/gesture_handler/src/main/ets/RNGHLogger.ts +28 -28
- package/harmony/gesture_handler/src/main/ets/RNGHRootTouchHandler.ets +57 -57
- package/harmony/gesture_handler/src/main/ets/RNGestureHandlerButton.ets +36 -36
- package/harmony/gesture_handler/src/main/ets/RNGestureHandlerModule.ts +125 -125
- package/harmony/gesture_handler/src/main/ets/RNGestureHandlerRootView.ets +56 -55
- package/harmony/gesture_handler/src/main/ets/RNOHScrollLocker.ts +10 -10
- package/harmony/gesture_handler/src/main/ets/State.ts +46 -46
- package/harmony/gesture_handler/src/main/ets/TapGestureHandler.ts +205 -205
- package/harmony/gesture_handler/src/main/ets/Vector2D.ts +36 -36
- package/harmony/gesture_handler/src/main/ets/VelocityTracker.ts +98 -98
- package/harmony/gesture_handler/src/main/ets/View.ts +70 -70
- package/harmony/gesture_handler/src/main/ets/ViewRegistry.ts +42 -42
- package/harmony/gesture_handler/src/main/ets/pages/Index.ets +16 -16
- package/harmony/gesture_handler/src/main/ets/webviewability/WebviewAbility.ts +41 -41
- package/harmony/gesture_handler/src/main/module.json5 +6 -6
- package/harmony/gesture_handler/src/main/resources/base/element/color.json +7 -7
- package/harmony/gesture_handler/src/main/resources/base/element/string.json +15 -15
- package/harmony/gesture_handler/src/main/resources/base/profile/main_pages.json +5 -5
- package/harmony/gesture_handler/src/main/resources/en_US/element/string.json +15 -15
- package/harmony/gesture_handler/src/main/resources/zh_CN/element/string.json +15 -15
- package/harmony/gesture_handler.har +0 -0
- package/lib/commonjs/components/touchables/GenericTouchable.js +9 -9
- package/lib/commonjs/components/touchables/TouchableOpacity.js +2 -2
- package/lib/commonjs/handlers/createNativeWrapper.js +6 -6
- package/lib/commonjs/handlers/gestures/GestureDetector.js +3 -3
- package/lib/module/components/touchables/GenericTouchable.js +9 -9
- package/lib/module/components/touchables/TouchableOpacity.js +2 -2
- package/lib/module/handlers/createNativeWrapper.js +6 -6
- package/lib/module/handlers/gestures/GestureDetector.js +3 -3
- package/package.json +70 -70
- package/src/RNGestureHandlerModule.ts +6 -6
- package/src/components/GestureButtons.tsx +334 -334
- package/src/components/GestureHandlerButton.tsx +5 -5
- package/src/components/GestureHandlerRootView.tsx +34 -34
- package/src/components/RNGestureHandlerButton.tsx +23 -23
- package/src/components/touchables/GenericTouchable.tsx +301 -301
- package/src/components/touchables/TouchableOpacity.tsx +76 -76
- package/src/components/touchables/TouchableWithoutFeedback.tsx +14 -14
- package/src/components/touchables/index.ts +7 -7
- package/src/handlers/NativeViewGestureHandler.ts +55 -55
- package/src/handlers/PanGestureHandler.ts +327 -327
- package/src/handlers/TapGestureHandler.ts +95 -95
- package/src/handlers/createHandler.tsx +535 -535
- package/src/handlers/createNativeWrapper.tsx +81 -81
- package/src/handlers/gestureHandlerCommon.ts +15 -15
- package/src/handlers/gestures/GestureDetector.tsx +823 -823
- package/src/index.ts +172 -172
- package/src/init.ts +18 -18
@@ -1,280 +1,280 @@
|
|
1
|
-
import { GestureHandler } from "./GestureHandler"
|
2
|
-
import { State } from "./State"
|
3
|
-
import { PointerType } from "./Event"
|
4
|
-
import { RNGHLogger } from "./RNGHLogger"
|
5
|
-
|
6
|
-
export class GestureHandlerOrchestrator {
|
7
|
-
private awaitingHandlers: Set<GestureHandler> = new Set()
|
8
|
-
private gestureHandlers: GestureHandler[] = []
|
9
|
-
private handlersToCancel: GestureHandler[] = []
|
10
|
-
private activationIndex: number = 0
|
11
|
-
|
12
|
-
constructor(private logger: RNGHLogger) {
|
13
|
-
}
|
14
|
-
|
15
|
-
public onHandlerStateChange(handler: GestureHandler, newState: State, oldState: State, sendIfDisabled?: boolean) {
|
16
|
-
this.logger.info("onHandlerStateChange")
|
17
|
-
if (this.shouldCancelStateChange(handler, sendIfDisabled)) return;
|
18
|
-
if (this.isFinishedState(newState)) {
|
19
|
-
this.handleChangingToFinishedState(handler, newState)
|
20
|
-
}
|
21
|
-
if (newState === State.ACTIVE) {
|
22
|
-
this.tryActivate(handler)
|
23
|
-
} else if (oldState === State.ACTIVE || oldState === State.END) {
|
24
|
-
if (handler.isActive()) {
|
25
|
-
handler.sendEvent({ newState, oldState })
|
26
|
-
} else if (oldState === State.ACTIVE && (newState === State.CANCELLED || newState === State.FAILED)) {
|
27
|
-
// Handle edge case where handler awaiting for another one tries to activate but finishes
|
28
|
-
// before the other would not send state change event upon ending. Note that we only want
|
29
|
-
// to do this if the newState is either CANCELLED or FAILED, if it is END we still want to
|
30
|
-
// wait for the other handler to finish as in that case synthetic events will be sent by the
|
31
|
-
// makeActive method.
|
32
|
-
handler.sendEvent({ newState, oldState: State.BEGAN })
|
33
|
-
}
|
34
|
-
} else if (newState !== State.CANCELLED || oldState !== State.UNDETERMINED) {
|
35
|
-
// If handler is changing state from UNDETERMINED to CANCELLED, the state change event shouldn't
|
36
|
-
// be sent. Handler hasn't yet began so it may not be initialized which results in crashes.
|
37
|
-
// If it doesn't crash, there may be some weird behavior on JS side, as `onFinalize` will be
|
38
|
-
// called without calling `onBegin` first.
|
39
|
-
handler.sendEvent({ newState, oldState })
|
40
|
-
}
|
41
|
-
this.cleanUpHandlers(handler)
|
42
|
-
}
|
43
|
-
|
44
|
-
private isFinishedState(state: State) {
|
45
|
-
return [State.END, State.FAILED, State.CANCELLED].includes(state)
|
46
|
-
}
|
47
|
-
|
48
|
-
private shouldCancelStateChange(handler: GestureHandler, sendIfDisabled?: boolean) {
|
49
|
-
const isHandlerDisabled = !handler.isEnabled()
|
50
|
-
return!sendIfDisabled && isHandlerDisabled
|
51
|
-
}
|
52
|
-
|
53
|
-
private handleChangingToFinishedState(handler: GestureHandler, newState: State) {
|
54
|
-
this.awaitingHandlers.forEach(awaitingHandler => {
|
55
|
-
if (handler.shouldWaitFor(awaitingHandler)) {
|
56
|
-
if (newState === State.END) {
|
57
|
-
awaitingHandler.cancel()
|
58
|
-
if (awaitingHandler.getState() === State.END) {
|
59
|
-
// Handle edge case, where discrete gestures end immediately after activation thus
|
60
|
-
// their state is set to END and when the gesture they are waiting for activates they
|
61
|
-
// should be cancelled, however `cancel` was never sent as gestures were already in the END state.
|
62
|
-
// Send synthetic BEGAN -> CANCELLED to properly handle JS logic
|
63
|
-
awaitingHandler.sendEvent({ newState: State.CANCELLED, oldState: State.BEGAN })
|
64
|
-
}
|
65
|
-
awaitingHandler.setAwaiting(false)
|
66
|
-
} else {
|
67
|
-
this.tryActivate(awaitingHandler)
|
68
|
-
}
|
69
|
-
}
|
70
|
-
})
|
71
|
-
}
|
72
|
-
|
73
|
-
private tryActivate(handler: GestureHandler): void {
|
74
|
-
if (this.hasOtherHandlerToWaitFor(handler)) {
|
75
|
-
this.addAwaitingHandler(handler)
|
76
|
-
} else if (handler.getState() !== State.CANCELLED && handler.getState() !== State.FAILED) {
|
77
|
-
if (this.shouldActivate(handler)) {
|
78
|
-
this.makeActive(handler);
|
79
|
-
} else {
|
80
|
-
switch (handler.getState()) {
|
81
|
-
case State.ACTIVE:
|
82
|
-
handler.fail();
|
83
|
-
break;
|
84
|
-
case State.BEGAN:
|
85
|
-
handler.cancel();
|
86
|
-
break;
|
87
|
-
}
|
88
|
-
}
|
89
|
-
}
|
90
|
-
}
|
91
|
-
|
92
|
-
private hasOtherHandlerToWaitFor(handler: GestureHandler): boolean {
|
93
|
-
for (const otherHandler of this.gestureHandlers) {
|
94
|
-
if (!this.isFinishedState(otherHandler.getState()) && otherHandler.shouldWaitFor(handler)) {
|
95
|
-
return true
|
96
|
-
}
|
97
|
-
}
|
98
|
-
return false;
|
99
|
-
}
|
100
|
-
|
101
|
-
private addAwaitingHandler(handler: GestureHandler) {
|
102
|
-
if (!this.awaitingHandlers.has(handler)) {
|
103
|
-
this.awaitingHandlers.add(handler)
|
104
|
-
handler.setAwaiting(true)
|
105
|
-
handler.setActivationIndex(this.activationIndex++)
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
private shouldActivate(handler: GestureHandler) {
|
110
|
-
for (const otherHandler of this.gestureHandlers) {
|
111
|
-
if (this.shouldHandlerBeCancelledByOtherHandler({ handler, otherHandler })) {
|
112
|
-
return false
|
113
|
-
}
|
114
|
-
}
|
115
|
-
return true
|
116
|
-
}
|
117
|
-
|
118
|
-
private shouldHandlerBeCancelledByOtherHandler({handler, otherHandler}: {
|
119
|
-
handler: GestureHandler,
|
120
|
-
otherHandler: GestureHandler
|
121
|
-
}): boolean {
|
122
|
-
if (this.canRunSimultaneously(handler, otherHandler))
|
123
|
-
return false;
|
124
|
-
if (handler !== otherHandler && (handler.isAwaiting() || handler.getState() === State.ACTIVE))
|
125
|
-
return handler.shouldBeCancelledByOther(otherHandler)
|
126
|
-
return this.checkOverlap(handler, otherHandler)
|
127
|
-
}
|
128
|
-
|
129
|
-
private canRunSimultaneously(handlerA: GestureHandler, handlerB: GestureHandler) {
|
130
|
-
return handlerA === handlerB
|
131
|
-
|| handlerA.shouldRecognizeSimultaneously(handlerB)
|
132
|
-
|| handlerB.shouldRecognizeSimultaneously(handlerA)
|
133
|
-
}
|
134
|
-
|
135
|
-
private checkOverlap(
|
136
|
-
handler: GestureHandler,
|
137
|
-
otherHandler: GestureHandler
|
138
|
-
): boolean {
|
139
|
-
// If handlers don't have common pointers, default return value is false.
|
140
|
-
// However, if at least on pointer overlaps with both handlers, we return true
|
141
|
-
// This solves issue in overlapping parents example
|
142
|
-
|
143
|
-
// TODO: Find better way to handle that issue, for example by activation order and handler cancelling
|
144
|
-
|
145
|
-
const handlerPointers: number[] = handler.getTrackedPointersID();
|
146
|
-
const otherPointers: number[] = otherHandler.getTrackedPointersID();
|
147
|
-
let overlap = false;
|
148
|
-
handlerPointers.forEach((pointer: number) => {
|
149
|
-
const handlerX: number = handler.getTracker().getLastX(pointer);
|
150
|
-
const handlerY: number = handler.getTracker().getLastY(pointer);
|
151
|
-
if (
|
152
|
-
handler.getView().isPositionInBounds({ x: handlerX, y: handlerY }) &&
|
153
|
-
otherHandler.getView().isPositionInBounds({ x: handlerX, y: handlerY })
|
154
|
-
) {
|
155
|
-
overlap = true;
|
156
|
-
}
|
157
|
-
});
|
158
|
-
otherPointers.forEach((pointer: number) => {
|
159
|
-
const otherX: number = otherHandler.getTracker().getLastX(pointer);
|
160
|
-
const otherY: number = otherHandler.getTracker().getLastY(pointer);
|
161
|
-
if (
|
162
|
-
handler.getView().isPositionInBounds({ x: otherX, y: otherY }) &&
|
163
|
-
otherHandler.getView().isPositionInBounds({ x: otherX, y: otherY })
|
164
|
-
) {
|
165
|
-
overlap = true;
|
166
|
-
}
|
167
|
-
});
|
168
|
-
return overlap;
|
169
|
-
}
|
170
|
-
|
171
|
-
private makeActive(handler: GestureHandler): void {
|
172
|
-
handler.setActive(true)
|
173
|
-
handler.setShouldResetProgress(true)
|
174
|
-
handler.setActivationIndex(this.activationIndex++)
|
175
|
-
for (const otherHandler of this.gestureHandlers) {
|
176
|
-
if (this.shouldHandlerBeCancelledByOtherHandler({ handler: otherHandler, otherHandler: handler })) {
|
177
|
-
this.handlersToCancel.push(otherHandler)
|
178
|
-
}
|
179
|
-
}
|
180
|
-
for (let i = this.handlersToCancel.length - 1; i >= 0; --i) {
|
181
|
-
this.handlersToCancel[i]?.cancel();
|
182
|
-
}
|
183
|
-
this.handlersToCancel = []
|
184
|
-
for (const awaitingHandler of this.awaitingHandlers) {
|
185
|
-
if (this.shouldHandlerBeCancelledByOtherHandler({ handler: awaitingHandler, otherHandler: handler })) {
|
186
|
-
awaitingHandler.cancel();
|
187
|
-
awaitingHandler.setAwaiting(true);
|
188
|
-
}
|
189
|
-
}
|
190
|
-
const currentState = handler.getState()
|
191
|
-
handler.sendEvent({ newState: State.ACTIVE, oldState: State.BEGAN })
|
192
|
-
if (currentState !== State.ACTIVE) {
|
193
|
-
handler.sendEvent({ newState: State.END, oldState: State.ACTIVE })
|
194
|
-
if (currentState !== State.END) {
|
195
|
-
handler.sendEvent({ newState: State.UNDETERMINED, oldState: State.END })
|
196
|
-
}
|
197
|
-
}
|
198
|
-
if (handler.isAwaiting()) {
|
199
|
-
handler.setAwaiting(false)
|
200
|
-
this.awaitingHandlers.delete(handler)
|
201
|
-
}
|
202
|
-
}
|
203
|
-
|
204
|
-
private cleanUpHandlers(handler: GestureHandler) {
|
205
|
-
this.cleanUpFinishedHandlers()
|
206
|
-
if (this.awaitingHandlers.has(handler)) {
|
207
|
-
this.cleanupAwaitingHandlers(handler);
|
208
|
-
}
|
209
|
-
}
|
210
|
-
|
211
|
-
private cleanUpFinishedHandlers(): void {
|
212
|
-
for (let i = this.gestureHandlers.length - 1; i >= 0; --i) {
|
213
|
-
const handler = this.gestureHandlers[i];
|
214
|
-
if (!handler) {
|
215
|
-
continue;
|
216
|
-
}
|
217
|
-
if (this.isFinishedState(handler.getState()) && !handler.isAwaiting()) {
|
218
|
-
this.gestureHandlers.splice(i, 1);
|
219
|
-
this.cleanUpHandler(handler);
|
220
|
-
}
|
221
|
-
}
|
222
|
-
}
|
223
|
-
|
224
|
-
private cleanupAwaitingHandlers(handler: GestureHandler): void {
|
225
|
-
for (const awaitingHandler of this.awaitingHandlers) {
|
226
|
-
if (
|
227
|
-
awaitingHandler.isAwaiting() &&
|
228
|
-
awaitingHandler.shouldWaitFor(handler)
|
229
|
-
) {
|
230
|
-
this.cleanUpHandler(awaitingHandler);
|
231
|
-
this.awaitingHandlers.delete(awaitingHandler)
|
232
|
-
}
|
233
|
-
}
|
234
|
-
}
|
235
|
-
|
236
|
-
private cleanUpHandler(handler: GestureHandler) {
|
237
|
-
handler.reset();
|
238
|
-
handler.setActive(false);
|
239
|
-
handler.setAwaiting(false);
|
240
|
-
handler.setActivationIndex(Number.MAX_VALUE);
|
241
|
-
}
|
242
|
-
|
243
|
-
public registerHandlerIfNotPresent(handler: GestureHandler) {
|
244
|
-
this.logger.info("registerHandlerIfNotPresent")
|
245
|
-
if (this.gestureHandlers.includes(handler)) return;
|
246
|
-
this.gestureHandlers.push(handler);
|
247
|
-
handler.setActive(false);
|
248
|
-
handler.setAwaiting(false);
|
249
|
-
handler.setActivationIndex(Number.MAX_SAFE_INTEGER);
|
250
|
-
}
|
251
|
-
|
252
|
-
/**
|
253
|
-
This function is called when handler receives touchdown event
|
254
|
-
If handler is using mouse or pen as a pointer and any handler receives touch event,
|
255
|
-
mouse/pen event disappears - it doesn't send onPointerCancel nor onPointerUp (and others)
|
256
|
-
This became a problem because handler was left at active state without any signal to end or fail
|
257
|
-
To handle this, when new touch event is received, we loop through active handlers and check which type of
|
258
|
-
pointer they're using. If there are any handler with mouse/pen as a pointer, we cancel them
|
259
|
-
*/
|
260
|
-
public cancelMouseAndPenGestures(currentHandler: GestureHandler): void {
|
261
|
-
this.logger.info("cancelMouseAndPenGestures")
|
262
|
-
this.gestureHandlers.forEach((handler: GestureHandler) => {
|
263
|
-
if (handler.getPointerType() !== PointerType.MOUSE && handler.getPointerType() !== PointerType.PEN) return;
|
264
|
-
|
265
|
-
if (handler !== currentHandler) {
|
266
|
-
handler.cancel();
|
267
|
-
} else {
|
268
|
-
// Handler that received touch event should have its pointer tracker reset
|
269
|
-
// This allows handler to smoothly change from mouse/pen to touch
|
270
|
-
// The drawback is, that when we try to use mouse/pen one more time, it doesn't send onPointerDown at the first time
|
271
|
-
// so it is required to click two times to get handler to work
|
272
|
-
//
|
273
|
-
// However, handler will receive manually created onPointerEnter that is triggered in EventManager in onPointerMove method.
|
274
|
-
// There may be possibility to use that fact to make handler respond properly to first mouse click
|
275
|
-
handler.getTracker().resetTracker();
|
276
|
-
}
|
277
|
-
});
|
278
|
-
}
|
279
|
-
}
|
280
|
-
|
1
|
+
import { GestureHandler } from "./GestureHandler"
|
2
|
+
import { State } from "./State"
|
3
|
+
import { PointerType } from "./Event"
|
4
|
+
import { RNGHLogger } from "./RNGHLogger"
|
5
|
+
|
6
|
+
export class GestureHandlerOrchestrator {
|
7
|
+
private awaitingHandlers: Set<GestureHandler> = new Set()
|
8
|
+
private gestureHandlers: GestureHandler[] = []
|
9
|
+
private handlersToCancel: GestureHandler[] = []
|
10
|
+
private activationIndex: number = 0
|
11
|
+
|
12
|
+
constructor(private logger: RNGHLogger) {
|
13
|
+
}
|
14
|
+
|
15
|
+
public onHandlerStateChange(handler: GestureHandler, newState: State, oldState: State, sendIfDisabled?: boolean) {
|
16
|
+
this.logger.info("onHandlerStateChange")
|
17
|
+
if (this.shouldCancelStateChange(handler, sendIfDisabled)) return;
|
18
|
+
if (this.isFinishedState(newState)) {
|
19
|
+
this.handleChangingToFinishedState(handler, newState)
|
20
|
+
}
|
21
|
+
if (newState === State.ACTIVE) {
|
22
|
+
this.tryActivate(handler)
|
23
|
+
} else if (oldState === State.ACTIVE || oldState === State.END) {
|
24
|
+
if (handler.isActive()) {
|
25
|
+
handler.sendEvent({ newState, oldState })
|
26
|
+
} else if (oldState === State.ACTIVE && (newState === State.CANCELLED || newState === State.FAILED)) {
|
27
|
+
// Handle edge case where handler awaiting for another one tries to activate but finishes
|
28
|
+
// before the other would not send state change event upon ending. Note that we only want
|
29
|
+
// to do this if the newState is either CANCELLED or FAILED, if it is END we still want to
|
30
|
+
// wait for the other handler to finish as in that case synthetic events will be sent by the
|
31
|
+
// makeActive method.
|
32
|
+
handler.sendEvent({ newState, oldState: State.BEGAN })
|
33
|
+
}
|
34
|
+
} else if (newState !== State.CANCELLED || oldState !== State.UNDETERMINED) {
|
35
|
+
// If handler is changing state from UNDETERMINED to CANCELLED, the state change event shouldn't
|
36
|
+
// be sent. Handler hasn't yet began so it may not be initialized which results in crashes.
|
37
|
+
// If it doesn't crash, there may be some weird behavior on JS side, as `onFinalize` will be
|
38
|
+
// called without calling `onBegin` first.
|
39
|
+
handler.sendEvent({ newState, oldState })
|
40
|
+
}
|
41
|
+
this.cleanUpHandlers(handler)
|
42
|
+
}
|
43
|
+
|
44
|
+
private isFinishedState(state: State) {
|
45
|
+
return [State.END, State.FAILED, State.CANCELLED].includes(state)
|
46
|
+
}
|
47
|
+
|
48
|
+
private shouldCancelStateChange(handler: GestureHandler, sendIfDisabled?: boolean) {
|
49
|
+
const isHandlerDisabled = !handler.isEnabled()
|
50
|
+
return!sendIfDisabled && isHandlerDisabled
|
51
|
+
}
|
52
|
+
|
53
|
+
private handleChangingToFinishedState(handler: GestureHandler, newState: State) {
|
54
|
+
this.awaitingHandlers.forEach(awaitingHandler => {
|
55
|
+
if (handler.shouldWaitFor(awaitingHandler)) {
|
56
|
+
if (newState === State.END) {
|
57
|
+
awaitingHandler.cancel()
|
58
|
+
if (awaitingHandler.getState() === State.END) {
|
59
|
+
// Handle edge case, where discrete gestures end immediately after activation thus
|
60
|
+
// their state is set to END and when the gesture they are waiting for activates they
|
61
|
+
// should be cancelled, however `cancel` was never sent as gestures were already in the END state.
|
62
|
+
// Send synthetic BEGAN -> CANCELLED to properly handle JS logic
|
63
|
+
awaitingHandler.sendEvent({ newState: State.CANCELLED, oldState: State.BEGAN })
|
64
|
+
}
|
65
|
+
awaitingHandler.setAwaiting(false)
|
66
|
+
} else {
|
67
|
+
this.tryActivate(awaitingHandler)
|
68
|
+
}
|
69
|
+
}
|
70
|
+
})
|
71
|
+
}
|
72
|
+
|
73
|
+
private tryActivate(handler: GestureHandler): void {
|
74
|
+
if (this.hasOtherHandlerToWaitFor(handler)) {
|
75
|
+
this.addAwaitingHandler(handler)
|
76
|
+
} else if (handler.getState() !== State.CANCELLED && handler.getState() !== State.FAILED) {
|
77
|
+
if (this.shouldActivate(handler)) {
|
78
|
+
this.makeActive(handler);
|
79
|
+
} else {
|
80
|
+
switch (handler.getState()) {
|
81
|
+
case State.ACTIVE:
|
82
|
+
handler.fail();
|
83
|
+
break;
|
84
|
+
case State.BEGAN:
|
85
|
+
handler.cancel();
|
86
|
+
break;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
private hasOtherHandlerToWaitFor(handler: GestureHandler): boolean {
|
93
|
+
for (const otherHandler of this.gestureHandlers) {
|
94
|
+
if (!this.isFinishedState(otherHandler.getState()) && otherHandler.shouldWaitFor(handler)) {
|
95
|
+
return true
|
96
|
+
}
|
97
|
+
}
|
98
|
+
return false;
|
99
|
+
}
|
100
|
+
|
101
|
+
private addAwaitingHandler(handler: GestureHandler) {
|
102
|
+
if (!this.awaitingHandlers.has(handler)) {
|
103
|
+
this.awaitingHandlers.add(handler)
|
104
|
+
handler.setAwaiting(true)
|
105
|
+
handler.setActivationIndex(this.activationIndex++)
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
private shouldActivate(handler: GestureHandler) {
|
110
|
+
for (const otherHandler of this.gestureHandlers) {
|
111
|
+
if (this.shouldHandlerBeCancelledByOtherHandler({ handler, otherHandler })) {
|
112
|
+
return false
|
113
|
+
}
|
114
|
+
}
|
115
|
+
return true
|
116
|
+
}
|
117
|
+
|
118
|
+
private shouldHandlerBeCancelledByOtherHandler({handler, otherHandler}: {
|
119
|
+
handler: GestureHandler,
|
120
|
+
otherHandler: GestureHandler
|
121
|
+
}): boolean {
|
122
|
+
if (this.canRunSimultaneously(handler, otherHandler))
|
123
|
+
return false;
|
124
|
+
if (handler !== otherHandler && (handler.isAwaiting() || handler.getState() === State.ACTIVE))
|
125
|
+
return handler.shouldBeCancelledByOther(otherHandler)
|
126
|
+
return this.checkOverlap(handler, otherHandler)
|
127
|
+
}
|
128
|
+
|
129
|
+
private canRunSimultaneously(handlerA: GestureHandler, handlerB: GestureHandler) {
|
130
|
+
return handlerA === handlerB
|
131
|
+
|| handlerA.shouldRecognizeSimultaneously(handlerB)
|
132
|
+
|| handlerB.shouldRecognizeSimultaneously(handlerA)
|
133
|
+
}
|
134
|
+
|
135
|
+
private checkOverlap(
|
136
|
+
handler: GestureHandler,
|
137
|
+
otherHandler: GestureHandler
|
138
|
+
): boolean {
|
139
|
+
// If handlers don't have common pointers, default return value is false.
|
140
|
+
// However, if at least on pointer overlaps with both handlers, we return true
|
141
|
+
// This solves issue in overlapping parents example
|
142
|
+
|
143
|
+
// TODO: Find better way to handle that issue, for example by activation order and handler cancelling
|
144
|
+
|
145
|
+
const handlerPointers: number[] = handler.getTrackedPointersID();
|
146
|
+
const otherPointers: number[] = otherHandler.getTrackedPointersID();
|
147
|
+
let overlap = false;
|
148
|
+
handlerPointers.forEach((pointer: number) => {
|
149
|
+
const handlerX: number = handler.getTracker().getLastX(pointer);
|
150
|
+
const handlerY: number = handler.getTracker().getLastY(pointer);
|
151
|
+
if (
|
152
|
+
handler.getView().isPositionInBounds({ x: handlerX, y: handlerY }) &&
|
153
|
+
otherHandler.getView().isPositionInBounds({ x: handlerX, y: handlerY })
|
154
|
+
) {
|
155
|
+
overlap = true;
|
156
|
+
}
|
157
|
+
});
|
158
|
+
otherPointers.forEach((pointer: number) => {
|
159
|
+
const otherX: number = otherHandler.getTracker().getLastX(pointer);
|
160
|
+
const otherY: number = otherHandler.getTracker().getLastY(pointer);
|
161
|
+
if (
|
162
|
+
handler.getView().isPositionInBounds({ x: otherX, y: otherY }) &&
|
163
|
+
otherHandler.getView().isPositionInBounds({ x: otherX, y: otherY })
|
164
|
+
) {
|
165
|
+
overlap = true;
|
166
|
+
}
|
167
|
+
});
|
168
|
+
return overlap;
|
169
|
+
}
|
170
|
+
|
171
|
+
private makeActive(handler: GestureHandler): void {
|
172
|
+
handler.setActive(true)
|
173
|
+
handler.setShouldResetProgress(true)
|
174
|
+
handler.setActivationIndex(this.activationIndex++)
|
175
|
+
for (const otherHandler of this.gestureHandlers) {
|
176
|
+
if (this.shouldHandlerBeCancelledByOtherHandler({ handler: otherHandler, otherHandler: handler })) {
|
177
|
+
this.handlersToCancel.push(otherHandler)
|
178
|
+
}
|
179
|
+
}
|
180
|
+
for (let i = this.handlersToCancel.length - 1; i >= 0; --i) {
|
181
|
+
this.handlersToCancel[i]?.cancel();
|
182
|
+
}
|
183
|
+
this.handlersToCancel = []
|
184
|
+
for (const awaitingHandler of this.awaitingHandlers) {
|
185
|
+
if (this.shouldHandlerBeCancelledByOtherHandler({ handler: awaitingHandler, otherHandler: handler })) {
|
186
|
+
awaitingHandler.cancel();
|
187
|
+
awaitingHandler.setAwaiting(true);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
const currentState = handler.getState()
|
191
|
+
handler.sendEvent({ newState: State.ACTIVE, oldState: State.BEGAN })
|
192
|
+
if (currentState !== State.ACTIVE) {
|
193
|
+
handler.sendEvent({ newState: State.END, oldState: State.ACTIVE })
|
194
|
+
if (currentState !== State.END) {
|
195
|
+
handler.sendEvent({ newState: State.UNDETERMINED, oldState: State.END })
|
196
|
+
}
|
197
|
+
}
|
198
|
+
if (handler.isAwaiting()) {
|
199
|
+
handler.setAwaiting(false)
|
200
|
+
this.awaitingHandlers.delete(handler)
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
private cleanUpHandlers(handler: GestureHandler) {
|
205
|
+
this.cleanUpFinishedHandlers()
|
206
|
+
if (this.awaitingHandlers.has(handler)) {
|
207
|
+
this.cleanupAwaitingHandlers(handler);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
private cleanUpFinishedHandlers(): void {
|
212
|
+
for (let i = this.gestureHandlers.length - 1; i >= 0; --i) {
|
213
|
+
const handler = this.gestureHandlers[i];
|
214
|
+
if (!handler) {
|
215
|
+
continue;
|
216
|
+
}
|
217
|
+
if (this.isFinishedState(handler.getState()) && !handler.isAwaiting()) {
|
218
|
+
this.gestureHandlers.splice(i, 1);
|
219
|
+
this.cleanUpHandler(handler);
|
220
|
+
}
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
private cleanupAwaitingHandlers(handler: GestureHandler): void {
|
225
|
+
for (const awaitingHandler of this.awaitingHandlers) {
|
226
|
+
if (
|
227
|
+
awaitingHandler.isAwaiting() &&
|
228
|
+
awaitingHandler.shouldWaitFor(handler)
|
229
|
+
) {
|
230
|
+
this.cleanUpHandler(awaitingHandler);
|
231
|
+
this.awaitingHandlers.delete(awaitingHandler)
|
232
|
+
}
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
private cleanUpHandler(handler: GestureHandler) {
|
237
|
+
handler.reset();
|
238
|
+
handler.setActive(false);
|
239
|
+
handler.setAwaiting(false);
|
240
|
+
handler.setActivationIndex(Number.MAX_VALUE);
|
241
|
+
}
|
242
|
+
|
243
|
+
public registerHandlerIfNotPresent(handler: GestureHandler) {
|
244
|
+
this.logger.info("registerHandlerIfNotPresent")
|
245
|
+
if (this.gestureHandlers.includes(handler)) return;
|
246
|
+
this.gestureHandlers.push(handler);
|
247
|
+
handler.setActive(false);
|
248
|
+
handler.setAwaiting(false);
|
249
|
+
handler.setActivationIndex(Number.MAX_SAFE_INTEGER);
|
250
|
+
}
|
251
|
+
|
252
|
+
/**
|
253
|
+
This function is called when handler receives touchdown event
|
254
|
+
If handler is using mouse or pen as a pointer and any handler receives touch event,
|
255
|
+
mouse/pen event disappears - it doesn't send onPointerCancel nor onPointerUp (and others)
|
256
|
+
This became a problem because handler was left at active state without any signal to end or fail
|
257
|
+
To handle this, when new touch event is received, we loop through active handlers and check which type of
|
258
|
+
pointer they're using. If there are any handler with mouse/pen as a pointer, we cancel them
|
259
|
+
*/
|
260
|
+
public cancelMouseAndPenGestures(currentHandler: GestureHandler): void {
|
261
|
+
this.logger.info("cancelMouseAndPenGestures")
|
262
|
+
this.gestureHandlers.forEach((handler: GestureHandler) => {
|
263
|
+
if (handler.getPointerType() !== PointerType.MOUSE && handler.getPointerType() !== PointerType.PEN) return;
|
264
|
+
|
265
|
+
if (handler !== currentHandler) {
|
266
|
+
handler.cancel();
|
267
|
+
} else {
|
268
|
+
// Handler that received touch event should have its pointer tracker reset
|
269
|
+
// This allows handler to smoothly change from mouse/pen to touch
|
270
|
+
// The drawback is, that when we try to use mouse/pen one more time, it doesn't send onPointerDown at the first time
|
271
|
+
// so it is required to click two times to get handler to work
|
272
|
+
//
|
273
|
+
// However, handler will receive manually created onPointerEnter that is triggered in EventManager in onPointerMove method.
|
274
|
+
// There may be possibility to use that fact to make handler respond properly to first mouse click
|
275
|
+
handler.getTracker().resetTracker();
|
276
|
+
}
|
277
|
+
});
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
@@ -1,22 +1,22 @@
|
|
1
|
-
import {RNPackage, TurboModuleContext, TurboModulesFactory} from 'rnoh/ts';
|
2
|
-
import type {TurboModule} from 'rnoh/ts';
|
3
|
-
import {RNGestureHandlerModule} from './RNGestureHandlerModule';
|
4
|
-
|
5
|
-
class GestureHandlerTurboModulesFactory extends TurboModulesFactory {
|
6
|
-
createTurboModule(name: string): TurboModule | null {
|
7
|
-
if (name === RNGestureHandlerModule.NAME) {
|
8
|
-
return new RNGestureHandlerModule(this.ctx);
|
9
|
-
}
|
10
|
-
return null;
|
11
|
-
}
|
12
|
-
|
13
|
-
hasTurboModule(name: string): boolean {
|
14
|
-
return name === 'RNGestureHandlerModule';
|
15
|
-
}
|
16
|
-
}
|
17
|
-
|
18
|
-
export class GestureHandlerPackage extends RNPackage {
|
19
|
-
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
20
|
-
return new GestureHandlerTurboModulesFactory(ctx);
|
21
|
-
}
|
22
|
-
}
|
1
|
+
import {RNPackage, TurboModuleContext, TurboModulesFactory} from 'rnoh/ts';
|
2
|
+
import type {TurboModule} from 'rnoh/ts';
|
3
|
+
import {RNGestureHandlerModule} from './RNGestureHandlerModule';
|
4
|
+
|
5
|
+
class GestureHandlerTurboModulesFactory extends TurboModulesFactory {
|
6
|
+
createTurboModule(name: string): TurboModule | null {
|
7
|
+
if (name === RNGestureHandlerModule.NAME) {
|
8
|
+
return new RNGestureHandlerModule(this.ctx);
|
9
|
+
}
|
10
|
+
return null;
|
11
|
+
}
|
12
|
+
|
13
|
+
hasTurboModule(name: string): boolean {
|
14
|
+
return name === 'RNGestureHandlerModule';
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
export class GestureHandlerPackage extends RNPackage {
|
19
|
+
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
20
|
+
return new GestureHandlerTurboModulesFactory(ctx);
|
21
|
+
}
|
22
|
+
}
|
@@ -1,28 +1,28 @@
|
|
1
|
-
import { GestureHandler } from "./GestureHandler"
|
2
|
-
import { View } from "./View"
|
3
|
-
|
4
|
-
export class GestureHandlerRegistry {
|
5
|
-
private gestureHandlerByHandlerTag: Map<number, GestureHandler> = new Map()
|
6
|
-
private gestureHandlersByViewTag: Map<number, Set<GestureHandler>> = new Map()
|
7
|
-
|
8
|
-
public addGestureHandler(gestureHandler: GestureHandler) {
|
9
|
-
this.gestureHandlerByHandlerTag.set(gestureHandler.getTag(), gestureHandler)
|
10
|
-
}
|
11
|
-
|
12
|
-
public bindGestureHandlerWithView(gestureHandlerTag: number, view: View) {
|
13
|
-
const viewTag = view.getTag()
|
14
|
-
if (!this.gestureHandlersByViewTag.has(viewTag))
|
15
|
-
this.gestureHandlersByViewTag.set(viewTag, new Set())
|
16
|
-
const gestureHandler = this.gestureHandlerByHandlerTag.get(gestureHandlerTag)
|
17
|
-
this.gestureHandlersByViewTag.get(viewTag).add(gestureHandler)
|
18
|
-
gestureHandler.onViewAttached(view)
|
19
|
-
}
|
20
|
-
|
21
|
-
public getGestureHandlersByViewTag(viewTag: number): GestureHandler[] {
|
22
|
-
return Array.from(this.gestureHandlersByViewTag.get(viewTag) ?? [])
|
23
|
-
}
|
24
|
-
|
25
|
-
public getGestureHandlerByHandlerTag(handlerTag: number): GestureHandler {
|
26
|
-
return this.gestureHandlerByHandlerTag.get(handlerTag)
|
27
|
-
}
|
1
|
+
import { GestureHandler } from "./GestureHandler"
|
2
|
+
import { View } from "./View"
|
3
|
+
|
4
|
+
export class GestureHandlerRegistry {
|
5
|
+
private gestureHandlerByHandlerTag: Map<number, GestureHandler> = new Map()
|
6
|
+
private gestureHandlersByViewTag: Map<number, Set<GestureHandler>> = new Map()
|
7
|
+
|
8
|
+
public addGestureHandler(gestureHandler: GestureHandler) {
|
9
|
+
this.gestureHandlerByHandlerTag.set(gestureHandler.getTag(), gestureHandler)
|
10
|
+
}
|
11
|
+
|
12
|
+
public bindGestureHandlerWithView(gestureHandlerTag: number, view: View) {
|
13
|
+
const viewTag = view.getTag()
|
14
|
+
if (!this.gestureHandlersByViewTag.has(viewTag))
|
15
|
+
this.gestureHandlersByViewTag.set(viewTag, new Set())
|
16
|
+
const gestureHandler = this.gestureHandlerByHandlerTag.get(gestureHandlerTag)
|
17
|
+
this.gestureHandlersByViewTag.get(viewTag).add(gestureHandler)
|
18
|
+
gestureHandler.onViewAttached(view)
|
19
|
+
}
|
20
|
+
|
21
|
+
public getGestureHandlersByViewTag(viewTag: number): GestureHandler[] {
|
22
|
+
return Array.from(this.gestureHandlersByViewTag.get(viewTag) ?? [])
|
23
|
+
}
|
24
|
+
|
25
|
+
public getGestureHandlerByHandlerTag(handlerTag: number): GestureHandler {
|
26
|
+
return this.gestureHandlerByHandlerTag.get(handlerTag)
|
27
|
+
}
|
28
28
|
}
|