@react-native-oh-tpl/react-native-gesture-handler 2.14.8-rc.1 → 2.14.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. package/DrawerLayout/index.ts +2 -2
  2. package/Swipeable/index.ts +2 -2
  3. package/harmony/gesture_handler/BuildProfile.ets +17 -0
  4. package/harmony/gesture_handler/build-profile.json5 +19 -0
  5. package/harmony/gesture_handler/hvigorfile.ts +2 -0
  6. package/harmony/gesture_handler/index.ets +2 -0
  7. package/harmony/gesture_handler/oh-package-lock.json5 +18 -0
  8. package/harmony/gesture_handler/oh-package.json5 +12 -0
  9. package/harmony/gesture_handler/src/main/cpp/CMakeLists.txt +8 -0
  10. package/harmony/gesture_handler/src/main/cpp/GestureHandlerPackage.h +12 -0
  11. package/harmony/gesture_handler/src/main/cpp/RnohReactNativeHarmonyGestureHandlerPackage.cpp +123 -0
  12. package/harmony/gesture_handler/src/main/cpp/RnohReactNativeHarmonyGestureHandlerPackage.h +15 -0
  13. package/harmony/gesture_handler/src/main/cpp/componentInstances/RNGestureHandlerButtonComponentInstance.h +27 -0
  14. package/harmony/gesture_handler/src/main/cpp/componentInstances/RNGestureHandlerRootViewComponentInstance.h +245 -0
  15. package/harmony/gesture_handler/src/main/ets/RNOHPackage.ets +17 -0
  16. package/harmony/gesture_handler/src/main/ets/core/CircularBuffer.ts +42 -0
  17. package/harmony/gesture_handler/src/main/ets/core/GestureHandler.ts +739 -0
  18. package/harmony/gesture_handler/src/main/ets/core/GestureHandlerOrchestrator.ts +344 -0
  19. package/harmony/gesture_handler/src/main/ets/core/GestureHandlerRegistry.ts +63 -0
  20. package/harmony/gesture_handler/src/main/ets/core/IncomingEvent.ts +78 -0
  21. package/harmony/gesture_handler/src/main/ets/core/InteractionManager.ts +144 -0
  22. package/harmony/gesture_handler/src/main/ets/core/LeastSquareSolver.ts +182 -0
  23. package/harmony/gesture_handler/src/main/ets/core/Multiset.ts +26 -0
  24. package/harmony/gesture_handler/src/main/ets/core/OutgoingEvent.ts +34 -0
  25. package/harmony/gesture_handler/src/main/ets/core/OutgoingEventDispatcher.ts +12 -0
  26. package/harmony/gesture_handler/src/main/ets/core/PointerTracker.ts +239 -0
  27. package/harmony/gesture_handler/src/main/ets/core/RNGHError.ts +5 -0
  28. package/harmony/gesture_handler/src/main/ets/core/RNGHLogger.ts +16 -0
  29. package/harmony/gesture_handler/src/main/ets/core/State.ts +47 -0
  30. package/harmony/gesture_handler/src/main/ets/core/Vector2D.ts +80 -0
  31. package/harmony/gesture_handler/src/main/ets/core/VelocityTracker.ts +106 -0
  32. package/harmony/gesture_handler/src/main/ets/core/View.ts +21 -0
  33. package/harmony/gesture_handler/src/main/ets/core/ViewRegistry.ts +7 -0
  34. package/harmony/gesture_handler/src/main/ets/core/index.ts +15 -0
  35. package/harmony/gesture_handler/src/main/ets/detectors/ScaleGestureDetector.ts +169 -0
  36. package/harmony/gesture_handler/src/main/ets/gesture-handlers/FlingGestureHandler.ts +219 -0
  37. package/harmony/gesture_handler/src/main/ets/gesture-handlers/GestureHandlerFactory.ts +67 -0
  38. package/harmony/gesture_handler/src/main/ets/gesture-handlers/LongPressGestureHandler.ts +139 -0
  39. package/harmony/gesture_handler/src/main/ets/gesture-handlers/ManualGestureHandler.ts +50 -0
  40. package/harmony/gesture_handler/src/main/ets/gesture-handlers/NativeViewGestureHandler.ts +124 -0
  41. package/harmony/gesture_handler/src/main/ets/gesture-handlers/PanGestureHandler.ts +361 -0
  42. package/harmony/gesture_handler/src/main/ets/gesture-handlers/PinchGestureHandler.ts +174 -0
  43. package/harmony/gesture_handler/src/main/ets/gesture-handlers/RotationGestureHandler.ts +172 -0
  44. package/harmony/gesture_handler/src/main/ets/gesture-handlers/TapGestureHandler.ts +216 -0
  45. package/harmony/gesture_handler/src/main/ets/gesture-handlers/detectors/RotationGestureDetector.ts +167 -0
  46. package/harmony/gesture_handler/src/main/ets/gesture-handlers/index.ts +1 -0
  47. package/harmony/gesture_handler/src/main/ets/rnoh/GestureHandlerPackage.ts +25 -0
  48. package/harmony/gesture_handler/src/main/ets/rnoh/Logger.ts +107 -0
  49. package/harmony/gesture_handler/src/main/ets/rnoh/OutgoingEventDispatchers.ts +94 -0
  50. package/harmony/gesture_handler/src/main/ets/rnoh/RNGHRootViewController.ts +182 -0
  51. package/harmony/gesture_handler/src/main/ets/rnoh/RNGHView.ts +62 -0
  52. package/harmony/gesture_handler/src/main/ets/rnoh/RNGHViewController.ts +262 -0
  53. package/harmony/gesture_handler/src/main/ets/rnoh/RNGHViewRegistry.ts +19 -0
  54. package/harmony/gesture_handler/src/main/ets/rnoh/RNGestureHandlerModule.ts +267 -0
  55. package/harmony/gesture_handler/src/main/ets/rnoh/RNOHGestureResponder.ts +15 -0
  56. package/harmony/gesture_handler/src/main/ets/rnoh/RNOHScrollLocker.ts +25 -0
  57. package/harmony/gesture_handler/src/main/ets/rnoh/types.ts +25 -0
  58. package/harmony/gesture_handler/src/main/module.json5 +9 -0
  59. package/harmony/gesture_handler/src/main/resources/base/element/color.json +8 -0
  60. package/harmony/gesture_handler/src/main/resources/base/element/string.json +16 -0
  61. package/harmony/gesture_handler/src/main/resources/base/media/icon.png +0 -0
  62. package/harmony/gesture_handler/src/main/resources/base/profile/main_pages.json +5 -0
  63. package/harmony/gesture_handler/src/main/resources/en_US/element/string.json +16 -0
  64. package/harmony/gesture_handler/src/main/resources/zh_CN/element/string.json +16 -0
  65. package/harmony/gesture_handler/ts.ts +2 -0
  66. package/harmony/gesture_handler.har +0 -0
  67. package/lib/commonjs/RNGestureHandlerModule.js +3 -2
  68. package/lib/commonjs/RNGestureHandlerModule.js.map +1 -1
  69. package/lib/commonjs/components/GestureHandlerRootView.js +3 -3
  70. package/lib/commonjs/components/GestureHandlerRootView.js.map +1 -1
  71. package/lib/commonjs/handlers/createHandler.js +18 -15
  72. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  73. package/lib/commonjs/index.js +36 -8
  74. package/lib/commonjs/index.js.map +1 -1
  75. package/lib/commonjs/specs/NativeRNGestureHandlerModule.js +2 -1
  76. package/lib/commonjs/specs/NativeRNGestureHandlerModule.js.map +1 -1
  77. package/lib/commonjs/specs/RNGestureHandlerButtonNativeComponent.js +3 -2
  78. package/lib/commonjs/specs/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  79. package/lib/commonjs/specs/RNGestureHandlerRootViewNativeComponent.js +3 -2
  80. package/lib/commonjs/specs/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
  81. package/lib/module/RNGestureHandlerModule.js.map +1 -1
  82. package/lib/module/components/GestureHandlerRootView.js.map +1 -1
  83. package/lib/module/handlers/createHandler.js +15 -12
  84. package/lib/module/handlers/createHandler.js.map +1 -1
  85. package/lib/module/index.js +5 -7
  86. package/lib/module/index.js.map +1 -1
  87. package/lib/module/specs/NativeRNGestureHandlerModule.js.map +1 -1
  88. package/lib/module/specs/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  89. package/lib/module/specs/RNGestureHandlerRootViewNativeComponent.js.map +1 -1
  90. package/lib/typescript/RNGestureHandlerModule.d.ts +2 -2
  91. package/lib/typescript/components/GestureHandlerRootView.d.ts +6 -6
  92. package/lib/typescript/handlers/createHandler.d.ts +11 -11
  93. package/lib/typescript/index.d.ts +47 -42
  94. package/lib/typescript/index.d.ts.map +1 -1
  95. package/lib/typescript/specs/NativeRNGestureHandlerModule.d.ts +14 -14
  96. package/lib/typescript/specs/RNGestureHandlerButtonNativeComponent.d.ts +14 -14
  97. package/lib/typescript/specs/RNGestureHandlerRootViewNativeComponent.d.ts +6 -6
  98. package/package.json +78 -70
  99. package/src/RNGestureHandlerModule.ts +4 -4
  100. package/src/components/GestureHandlerRootView.tsx +23 -23
  101. package/src/handlers/createHandler.tsx +534 -534
  102. package/src/index.ts +172 -172
  103. package/src/specs/NativeRNGestureHandlerModule.ts +26 -26
  104. package/src/specs/RNGestureHandlerButtonNativeComponent.ts +18 -18
  105. package/src/specs/RNGestureHandlerRootViewNativeComponent.ts +6 -6
@@ -0,0 +1,167 @@
1
+ import { PointerTracker, IncomingEvent, EventType } from '../../core';
2
+
3
+ export interface RotationGestureListener {
4
+ onRotationBegin: (detector: RotationGestureDetector) => boolean;
5
+ onRotation: (detector: RotationGestureDetector) => boolean;
6
+ onRotationEnd: (detector: RotationGestureDetector) => void;
7
+ }
8
+
9
+ export default class RotationGestureDetector
10
+ implements RotationGestureListener
11
+ {
12
+ onRotationBegin: (detector: RotationGestureDetector) => boolean;
13
+ onRotation: (detector: RotationGestureDetector) => boolean;
14
+ onRotationEnd: (detector: RotationGestureDetector) => void;
15
+
16
+ private currentTime = 0;
17
+ private previousTime = 0;
18
+
19
+ private previousAngle = 0;
20
+ private rotation = 0;
21
+
22
+ private anchorX = 0;
23
+ private anchorY = 0;
24
+
25
+ private isInProgress = false;
26
+
27
+ private keyPointers: number[] = [NaN, NaN];
28
+
29
+ constructor(callbacks: RotationGestureListener) {
30
+ this.onRotationBegin = callbacks.onRotationBegin;
31
+ this.onRotation = callbacks.onRotation;
32
+ this.onRotationEnd = callbacks.onRotationEnd;
33
+ }
34
+
35
+ private updateCurrent(event: IncomingEvent, tracker: PointerTracker): void {
36
+ this.previousTime = this.currentTime;
37
+ this.currentTime = event.time;
38
+
39
+ const [firstPointerID, secondPointerID] = this.keyPointers;
40
+
41
+ const firstPointerX: number = tracker.getLastX(firstPointerID);
42
+ const firstPointerY: number = tracker.getLastY(firstPointerID);
43
+ const secondPointerX: number = tracker.getLastX(secondPointerID);
44
+ const secondPointerY: number = tracker.getLastY(secondPointerID);
45
+
46
+ const vectorX: number = secondPointerX - firstPointerX;
47
+ const vectorY: number = secondPointerY - firstPointerY;
48
+
49
+ this.anchorX = (firstPointerX + secondPointerX) / 2;
50
+ this.anchorY = (firstPointerY + secondPointerY) / 2;
51
+
52
+ //Angle diff should be positive when rotating in clockwise direction
53
+ const angle: number = -Math.atan2(vectorY, vectorX);
54
+
55
+ this.rotation = Number.isNaN(this.previousAngle)
56
+ ? 0
57
+ : this.previousAngle - angle;
58
+
59
+ this.previousAngle = angle;
60
+
61
+ if (this.rotation > Math.PI) {
62
+ this.rotation -= Math.PI;
63
+ } else if (this.rotation < -Math.PI) {
64
+ this.rotation += Math.PI;
65
+ }
66
+
67
+ if (this.rotation > Math.PI / 2) {
68
+ this.rotation -= Math.PI;
69
+ } else if (this.rotation < -Math.PI / 2) {
70
+ this.rotation += Math.PI;
71
+ }
72
+ }
73
+
74
+ private finish(): void {
75
+ if (!this.isInProgress) {
76
+ return;
77
+ }
78
+
79
+ this.isInProgress = false;
80
+ this.keyPointers = [NaN, NaN];
81
+ this.onRotationEnd(this);
82
+ }
83
+
84
+ private setKeyPointers(tracker: PointerTracker): void {
85
+ if (this.keyPointers[0] && this.keyPointers[1]) {
86
+ return;
87
+ }
88
+
89
+ const pointerIDs: IterableIterator<number> = tracker.getData().keys();
90
+
91
+ this.keyPointers[0] = pointerIDs.next().value as number;
92
+ this.keyPointers[1] = pointerIDs.next().value as number;
93
+ }
94
+
95
+ public onTouchEvent(event: IncomingEvent, tracker: PointerTracker): boolean {
96
+ switch (event.eventType) {
97
+ case EventType.DOWN:
98
+ this.isInProgress = false;
99
+ break;
100
+
101
+ case EventType.ADDITIONAL_POINTER_DOWN:
102
+ if (this.isInProgress) {
103
+ break;
104
+ }
105
+ this.isInProgress = true;
106
+
107
+ this.previousTime = event.time;
108
+ this.previousAngle = NaN;
109
+
110
+ this.setKeyPointers(tracker);
111
+
112
+ this.updateCurrent(event, tracker);
113
+ this.onRotationBegin(this);
114
+ break;
115
+
116
+ case EventType.MOVE:
117
+ if (!this.isInProgress) {
118
+ break;
119
+ }
120
+
121
+ this.updateCurrent(event, tracker);
122
+ this.onRotation(this);
123
+
124
+ break;
125
+
126
+ case EventType.ADDITIONAL_POINTER_UP:
127
+ if (!this.isInProgress) {
128
+ break;
129
+ }
130
+
131
+ if (this.keyPointers.indexOf(event.pointerId) >= 0) {
132
+ this.finish();
133
+ }
134
+
135
+ break;
136
+
137
+ case EventType.UP:
138
+ if (this.isInProgress) {
139
+ this.finish();
140
+ }
141
+ break;
142
+ }
143
+
144
+ return true;
145
+ }
146
+
147
+ public getTimeDelta(): number {
148
+ return this.currentTime + this.previousTime;
149
+ }
150
+
151
+ public getAnchorX(): number {
152
+ return this.anchorX;
153
+ }
154
+
155
+ public getAnchorY(): number {
156
+ return this.anchorY;
157
+ }
158
+
159
+ public getRotation(): number {
160
+ return this.rotation;
161
+ }
162
+
163
+ public reset(): void {
164
+ this.keyPointers = [NaN, NaN];
165
+ this.isInProgress = false;
166
+ }
167
+ }
@@ -0,0 +1 @@
1
+ export * from "./GestureHandlerFactory"
@@ -0,0 +1,25 @@
1
+ import {RNPackage, TurboModulesFactory} from "@rnoh/react-native-openharmony/ts";
2
+ import type {TurboModule, TurboModuleContext} from "@rnoh/react-native-openharmony/ts";
3
+ import {RNGestureHandlerModule} from './RNGestureHandlerModule';
4
+
5
+ class GestureHandlerTurboModuleFactory 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.NAME;
15
+ }
16
+ }
17
+
18
+ /**
19
+ * @deprecated: Use the package class exported from ../RNOHPackage.ets (2024-10-10)
20
+ */
21
+ export class GestureHandlerPackage extends RNPackage {
22
+ createUITurboModuleFactory(ctx: TurboModuleContext): TurboModulesFactory {
23
+ return new GestureHandlerTurboModuleFactory(ctx);
24
+ }
25
+ }
@@ -0,0 +1,107 @@
1
+ import { RNOHContext } from '@rnoh/react-native-openharmony/ts';
2
+ import { RNGHLogger, RNGHLoggerMessage } from "../core"
3
+ import hiTrace from "@ohos.hiTraceMeter"
4
+
5
+ class Tracer {
6
+ private activeTracesCount: number = 0
7
+
8
+ public startTrace(name: string) {
9
+ /**
10
+ * hiTrace.startTrace creates a new lane which makes the traces useless
11
+ */
12
+ hiTrace.startTrace(name, 0)
13
+ this.activeTracesCount++
14
+ return () => {
15
+ hiTrace.finishTrace(name, 0)
16
+ this.activeTracesCount--
17
+ }
18
+ }
19
+
20
+ public getActiveTracesCount(): number {
21
+ return this.activeTracesCount
22
+ }
23
+ }
24
+
25
+ export class DevelopmentRNGHLogger implements RNGHLogger {
26
+ constructor(
27
+ protected rnohLogger: RNOHContext['logger'],
28
+ protected prefix: string,
29
+ protected tracer: Tracer = new Tracer(),
30
+ ) {
31
+ }
32
+
33
+ error(msg: string) {
34
+ this.log("error", msg);
35
+ }
36
+
37
+ warn(msg: string) {
38
+ this.log("warn", msg);
39
+ }
40
+
41
+ info(msg: string) {
42
+ this.log("info", msg);
43
+ }
44
+
45
+ debug(msg: RNGHLoggerMessage) {
46
+ this.log("debug", typeof msg === "string" ? msg : JSON.stringify(msg));
47
+ }
48
+
49
+ protected log(type: "debug" | "info" | "warn" | "error", msg: string, offset: number | undefined = undefined) {
50
+ this.rnohLogger[type](" ".repeat(offset ?? this.tracer.getActiveTracesCount() * 2),
51
+ `${this.prefix}: ${this.stringifyMsg(msg)}`)
52
+ }
53
+
54
+ startTracing(): () => void {
55
+ const startTime = Date.now()
56
+ const currentOffset = this.tracer.getActiveTracesCount() * 2
57
+ this.log("debug", "START", currentOffset)
58
+ const stopTrace = this.tracer.startTrace(this.prefix)
59
+ return () => {
60
+ stopTrace()
61
+ const stopTime = Date.now()
62
+ const durationInMs = stopTime - startTime
63
+ if (durationInMs < 16) {
64
+ this.log("debug", "STOP", currentOffset)
65
+ } else {
66
+ this.log("debug", `STOP (${durationInMs} ms)`, currentOffset)
67
+ }
68
+ }
69
+ }
70
+
71
+ private stringifyMsg(msg: RNGHLoggerMessage): string {
72
+ if (typeof msg === "string") {
73
+ return msg
74
+ } else {
75
+ return JSON.stringify(msg)
76
+ }
77
+ }
78
+
79
+ cloneAndJoinPrefix(prefix: string) {
80
+ return new DevelopmentRNGHLogger(this.rnohLogger, `${this.prefix}::${prefix}`, this.tracer);
81
+ }
82
+ }
83
+
84
+ export class ProductionRNGHLogger extends DevelopmentRNGHLogger {
85
+ override debug(msg: string) {
86
+ // NOOP
87
+ }
88
+
89
+ override cloneAndJoinPrefix(prefix: string) {
90
+ return new ProductionRNGHLogger(this.rnohLogger, `${this.prefix}::${prefix}`, this.tracer);
91
+ }
92
+
93
+ override startTracing(): () => void {
94
+ const startTime = Date.now()
95
+ const currentOffset = this.tracer.getActiveTracesCount() * 2
96
+
97
+ const stopTrace = this.tracer.startTrace(this.prefix)
98
+ return () => {
99
+ stopTrace()
100
+ const stopTime = Date.now()
101
+ const durationInMs = stopTime - startTime
102
+ if (durationInMs > 16) {
103
+ this.log("warn", `STOP (${durationInMs} ms)`, currentOffset)
104
+ }
105
+ }
106
+ }
107
+ }
@@ -0,0 +1,94 @@
1
+ import { RNInstance } from '@rnoh/react-native-openharmony/ts';
2
+ import {
3
+ OutgoingEventDispatcher,
4
+ GestureStateChangeEvent,
5
+ GestureUpdateEvent,
6
+ GestureTouchEvent,
7
+ RNGHLogger
8
+ } from "../core"
9
+
10
+ export class JSEventDispatcher implements OutgoingEventDispatcher {
11
+ private logger: RNGHLogger
12
+
13
+ constructor(private rnInstance: RNInstance, logger: RNGHLogger) {
14
+ this.logger = logger.cloneAndJoinPrefix("JSEventDispatcher")
15
+ }
16
+
17
+ public onGestureHandlerStateChange(event: GestureStateChangeEvent) {
18
+ const stopTracing = this.logger.cloneAndJoinPrefix(`onGestureHandlerStateChange`).startTracing();
19
+ this.rnInstance.emitDeviceEvent('onGestureHandlerStateChange', event);
20
+ stopTracing()
21
+ }
22
+
23
+ public onGestureHandlerEvent(
24
+ event: GestureStateChangeEvent | GestureUpdateEvent | GestureTouchEvent,
25
+ ) {
26
+ const stopTracing = this.logger.cloneAndJoinPrefix(`onGestureHandlerEvent`).startTracing();
27
+ this.rnInstance.emitDeviceEvent('onGestureHandlerEvent', event);
28
+ stopTracing()
29
+ }
30
+ }
31
+
32
+ export class AnimatedEventDispatcher implements OutgoingEventDispatcher {
33
+ private logger: RNGHLogger
34
+
35
+ constructor(
36
+ private rnInstance: RNInstance,
37
+ logger: RNGHLogger,
38
+ private viewTag: number,
39
+ ) {
40
+ this.logger = logger.cloneAndJoinPrefix("AnimatedEventDispatcher")
41
+ }
42
+
43
+ public onGestureHandlerStateChange(event: GestureStateChangeEvent) {
44
+ const stopTracing = this.logger.cloneAndJoinPrefix(`onGestureHandlerStateChange`).startTracing()
45
+ this.rnInstance.emitDeviceEvent('onGestureHandlerStateChange', event);
46
+ stopTracing()
47
+ }
48
+
49
+ public onGestureHandlerEvent(
50
+ event: GestureStateChangeEvent | GestureUpdateEvent | GestureTouchEvent,
51
+ ) {
52
+ const stopTracing = this.logger.cloneAndJoinPrefix(`onGestureHandlerEvent`).startTracing();
53
+ this.rnInstance.emitComponentEvent(
54
+ this.viewTag,
55
+ 'onGestureHandlerEvent',
56
+ event,
57
+ );
58
+ stopTracing()
59
+ }
60
+ }
61
+
62
+ export class ReanimatedEventDispatcher implements OutgoingEventDispatcher {
63
+ private logger: RNGHLogger
64
+
65
+ constructor(
66
+ private rnInstance: RNInstance,
67
+ logger: RNGHLogger,
68
+ private viewTag: number,
69
+ ) {
70
+ this.logger = logger.cloneAndJoinPrefix("ReanimatedEventDispatcher")
71
+ }
72
+
73
+ public onGestureHandlerStateChange(event: GestureStateChangeEvent) {
74
+ const stopTracing = this.logger.cloneAndJoinPrefix(`onGestureHandlerStateChange`).startTracing();
75
+ this.rnInstance.emitComponentEvent(
76
+ this.viewTag,
77
+ 'onGestureHandlerStateChange',
78
+ event,
79
+ );
80
+ stopTracing()
81
+ }
82
+
83
+ public onGestureHandlerEvent(
84
+ event: GestureStateChangeEvent | GestureUpdateEvent | GestureTouchEvent,
85
+ ) {
86
+ const stopTracing = this.logger.cloneAndJoinPrefix(`onGestureHandlerEvent`).startTracing();
87
+ this.rnInstance.emitComponentEvent(
88
+ this.viewTag,
89
+ 'onGestureHandlerEvent',
90
+ event,
91
+ );
92
+ stopTracing()
93
+ }
94
+ }
@@ -0,0 +1,182 @@
1
+ import { TouchEvent as TouchEventArkTS, TouchType, TouchObject } from './types';
2
+ import { RNGHLogger, View, Multiset, GestureHandlerRegistry } from '../core';
3
+ import { RawTouchableView } from "./RNGHView"
4
+ import { RNGHViewController } from './RNGHViewController';
5
+
6
+ type RawTouchPoint = {
7
+ pointerId: number;
8
+ windowX: number;
9
+ windowY: number;
10
+ };
11
+
12
+ export type RawTouchEvent = {
13
+ action: number;
14
+ actionTouch: RawTouchPoint;
15
+ touchPoints: RawTouchPoint[];
16
+ sourceType: number;
17
+ timestamp: number;
18
+ /** TouchableViews is a list of views from the root to the leaf which contain within their boundaries the touch point specified by `actionTouch`. */
19
+ touchableViews: RawTouchableView[]
20
+ };
21
+
22
+
23
+ const areRawTouchPointsEqual = (a: RawTouchPoint, b: RawTouchPoint) =>
24
+ a.pointerId === b.pointerId &&
25
+ a.windowX === b.windowX &&
26
+ a.windowY === b.windowY;
27
+
28
+
29
+ export class RNGHRootViewController {
30
+ private logger: RNGHLogger;
31
+ // This multiset keeps track of touchable views that were detected
32
+ // at the beginning of the gesture to ensure they aren't overridden
33
+ // during move touch events, which could prevent the gesture handler
34
+ // from updating its state correctly.
35
+ private touchableViewsMultiset: Multiset<View> = new Multiset();
36
+ private viewControllerByViewTag: Map<number, RNGHViewController> =
37
+ new Map(); // TODO: remove entry when view is removed
38
+ /**
39
+ * A view is ACTIVE, if it recently received POINTER_DOWN event
40
+ */
41
+ private activeViewTags = new Set<number>();
42
+
43
+ constructor(
44
+ logger: RNGHLogger,
45
+ private gestureHandlerRegistry: GestureHandlerRegistry
46
+ ) {
47
+ this.logger = logger.cloneAndJoinPrefix('RNGHRootTouchHandlerCAPI');
48
+ }
49
+
50
+ handleTouch(rawTouchEvent: RawTouchEvent, touchableViews: View[]) {
51
+ /**
52
+ * NOTE: TouchEventArkTS was used in ArkTS RNOH architecture. Currently only C-API architecture is supported.
53
+ */
54
+ const touchEvent = rawTouchEventToTouchEventArkTS(rawTouchEvent);
55
+ if (touchEvent.type === TouchType.Down) {
56
+ touchableViews.forEach(view => this.touchableViewsMultiset.add(view));
57
+ }
58
+ const e = touchEvent;
59
+ if (e.type === TouchType.Down) {
60
+ this.activeViewTags.clear();
61
+ }
62
+ const views = touchableViews
63
+ for (const view of views) {
64
+ for (const handler of this.gestureHandlerRegistry.getGestureHandlersByViewTag(
65
+ view.getTag(),
66
+ )) {
67
+ this.logger.info(
68
+ `Found GestureHandler ${handler.getTag()} for view ${view.getTag()}`,
69
+ );
70
+
71
+ // create view touch handler if necessary
72
+ if (!this.viewControllerByViewTag.has(view.getTag())) {
73
+ this.viewControllerByViewTag.set(
74
+ view.getTag(),
75
+ new RNGHViewController(
76
+ view,
77
+ this.logger,
78
+ ),
79
+ );
80
+ }
81
+
82
+ // attach handler (there might be multiple handlers per view)
83
+ this.viewControllerByViewTag.get(view.getTag())!.attachGestureHandler(handler) // TODO: detachGestureHandler
84
+
85
+ // register active view tag
86
+ if (e.type === TouchType.Down) {
87
+ this.activeViewTags.add(view.getTag());
88
+ }
89
+ }
90
+ }
91
+
92
+ // send touch to gesture handlers, prioritize handling touch events for child components
93
+ if (this.activeViewTags.size > 0) {
94
+ const tags = Array.from(this.activeViewTags);
95
+ for (let i = tags.length - 1; i >= 0; i--) {
96
+ const tag = tags[i];
97
+ const viewController = this.viewControllerByViewTag.get(tag);
98
+ if (viewController) {
99
+ viewController.handleTouch(e);
100
+ }
101
+ }
102
+ }
103
+
104
+
105
+ if (touchEvent.type === TouchType.Up || touchEvent.type === TouchType.Cancel) {
106
+ touchableViews.forEach(view => this.touchableViewsMultiset.remove(view));
107
+ }
108
+ }
109
+
110
+ cancelTouches() {
111
+ for (const activeViewTag of this.activeViewTags) {
112
+ this.gestureHandlerRegistry.getGestureHandlersByViewTag(activeViewTag).forEach(gh => {
113
+ gh.cancel()
114
+ gh.reset()
115
+ })
116
+ }
117
+ }
118
+ }
119
+
120
+
121
+ const CACHED_RAW_TOUCH_POINT_BY_POINTER_ID = new Map<number, RawTouchPoint>();
122
+ let LAST_CHANGED_POINTER_ID: number | null = null;
123
+ const MAX_CACHE_SIZE = 10;
124
+
125
+ function rawTouchEventToTouchEventArkTS(raw: RawTouchEvent): TouchEventArkTS {
126
+ const touchType = touchTypeFromAction(raw.action);
127
+ const actionTouch = raw.actionTouch;
128
+
129
+ let lastChangedTouch: RawTouchPoint = actionTouch;
130
+ if (CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.has(actionTouch.pointerId)) {
131
+ if (!areRawTouchPointsEqual(actionTouch,
132
+ CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.get(actionTouch.pointerId) as RawTouchPoint)) {
133
+ LAST_CHANGED_POINTER_ID = actionTouch.pointerId;
134
+ CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.set(actionTouch.pointerId, actionTouch);
135
+ }
136
+ } else {
137
+ // remove first element if the cache is full
138
+ if (CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.size >= MAX_CACHE_SIZE) {
139
+ CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.delete(CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.keys().next().value);
140
+ }
141
+ LAST_CHANGED_POINTER_ID = actionTouch.pointerId;
142
+ CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.set(actionTouch.pointerId, actionTouch);
143
+ }
144
+ lastChangedTouch = CACHED_RAW_TOUCH_POINT_BY_POINTER_ID.get(LAST_CHANGED_POINTER_ID as number) as RawTouchPoint
145
+ return {
146
+ type: touchTypeFromAction(raw.action),
147
+ touches: raw.touchPoints.map(tp =>
148
+ touchObjectFromTouchPoint(tp, touchType),
149
+ ),
150
+ changedTouches: [
151
+ touchObjectFromTouchPoint(lastChangedTouch, touchType),
152
+ ],
153
+ timestamp: raw.timestamp / Math.pow(10, 6),
154
+ };
155
+ }
156
+
157
+ function touchTypeFromAction(action: number): TouchType {
158
+ switch (action) {
159
+ case 1:
160
+ return TouchType.Down;
161
+ case 2:
162
+ return TouchType.Move;
163
+ case 3:
164
+ return TouchType.Up;
165
+ default:
166
+ return TouchType.Cancel;
167
+ }
168
+ }
169
+
170
+ function touchObjectFromTouchPoint(
171
+ touchPoint: RawTouchPoint,
172
+ touchType: TouchType,
173
+ ): TouchObject {
174
+ return {
175
+ id: touchPoint.pointerId,
176
+ windowX: touchPoint.windowX,
177
+ windowY: touchPoint.windowY,
178
+ x: touchPoint.windowX,
179
+ y: touchPoint.windowY,
180
+ type: touchType,
181
+ };
182
+ }
@@ -0,0 +1,62 @@
1
+ import { View, BoundingBox } from "../core"
2
+
3
+
4
+ export type RawTouchableView = {
5
+ tag: number,
6
+ /**
7
+ * Relative to application window.
8
+ */
9
+ x: number,
10
+ /**
11
+ * Relative to application window.
12
+ */
13
+ y: number,
14
+ width: number,
15
+ height: number,
16
+ buttonRole: boolean,
17
+ }
18
+
19
+ export class RNGHView implements View {
20
+ private tag: number
21
+ private buttonRole: boolean
22
+ private boundingBox: BoundingBox
23
+
24
+ constructor({ tag, buttonRole, ...boundingBox }: RawTouchableView) {
25
+ this.tag = tag
26
+ this.buttonRole = buttonRole
27
+ this.boundingBox = boundingBox
28
+ }
29
+
30
+ getTag(): number {
31
+ return this.tag
32
+ }
33
+
34
+ getBoundingRect(): BoundingBox {
35
+ return { ...this.boundingBox }
36
+ }
37
+
38
+ isPositionInBounds({ x, y }: {
39
+ x: number;
40
+ y: number
41
+ }): boolean {
42
+ const rect = this.getBoundingRect();
43
+ return (
44
+ x >= rect.x &&
45
+ x <= rect.x + rect.width &&
46
+ y >= rect.y &&
47
+ y <= rect.y + rect.height
48
+ );
49
+ }
50
+
51
+ updateBoundingBox(boundingBox: BoundingBox) {
52
+ this.boundingBox = boundingBox
53
+ }
54
+
55
+ setButtonRole(buttonRole: boolean) {
56
+ this.buttonRole = buttonRole
57
+ }
58
+
59
+ hasButtonRole(): boolean {
60
+ return this.buttonRole
61
+ }
62
+ }