react-native-gesture-handler 2.18.1 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +1 -0
  2. package/android/build.gradle +11 -29
  3. package/android/fabric/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  4. package/android/paper/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  5. package/android/src/main/AndroidManifest.xml +1 -3
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +21 -21
  7. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +2 -2
  8. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureUtils.kt +1 -0
  9. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +16 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt +80 -4
  11. package/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +8 -0
  12. package/android/src/main/java/com/swmansion/gesturehandler/core/PinchGestureHandler.kt +2 -1
  13. package/android/src/main/java/com/swmansion/gesturehandler/core/ScaleGestureDetector.java +10 -0
  14. package/android/src/main/java/com/swmansion/gesturehandler/core/StylusData.kt +103 -0
  15. package/android/src/main/java/com/swmansion/gesturehandler/core/Vector.kt +2 -2
  16. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +24 -15
  17. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +3 -0
  18. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/HoverGestureHandlerEventDataBuilder.kt +7 -0
  19. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/PanGestureHandlerEventDataBuilder.kt +7 -0
  20. package/android/src/main/jni/CMakeLists.txt +18 -9
  21. package/apple/Handlers/RNFlingHandler.h +1 -0
  22. package/apple/Handlers/RNFlingHandler.m +153 -19
  23. package/apple/Handlers/RNHoverHandler.m +44 -2
  24. package/apple/Handlers/RNLongPressHandler.m +111 -20
  25. package/apple/Handlers/RNManualHandler.m +53 -29
  26. package/apple/Handlers/RNNativeViewHandler.mm +22 -15
  27. package/apple/Handlers/RNPanHandler.m +57 -7
  28. package/apple/Handlers/RNRotationHandler.m +1 -1
  29. package/apple/RNGHStylusData.h +77 -0
  30. package/apple/RNGHStylusData.m +37 -0
  31. package/apple/RNGHUIKit.h +2 -0
  32. package/apple/RNGHVector.h +31 -0
  33. package/apple/RNGHVector.m +67 -0
  34. package/apple/RNGestureHandler.h +7 -0
  35. package/apple/{RNGestureHandler.m → RNGestureHandler.mm} +63 -1
  36. package/apple/RNGestureHandlerButtonComponentView.mm +41 -0
  37. package/apple/RNGestureHandlerDirection.h +25 -0
  38. package/apple/RNGestureHandlerEvents.h +3 -1
  39. package/apple/RNGestureHandlerEvents.m +11 -3
  40. package/lib/commonjs/PointerType.js +2 -1
  41. package/lib/commonjs/PointerType.js.map +1 -1
  42. package/lib/commonjs/components/GestureButtons.js +5 -1
  43. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  44. package/lib/commonjs/components/GestureComponents.js.map +1 -1
  45. package/lib/commonjs/components/Pressable/Pressable.js +66 -78
  46. package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
  47. package/lib/commonjs/components/Pressable/index.js +0 -8
  48. package/lib/commonjs/components/Pressable/index.js.map +1 -1
  49. package/lib/commonjs/components/Pressable/utils.js +1 -23
  50. package/lib/commonjs/components/Pressable/utils.js.map +1 -1
  51. package/lib/commonjs/components/ReanimatedSwipeable.js +60 -41
  52. package/lib/commonjs/components/ReanimatedSwipeable.js.map +1 -1
  53. package/lib/commonjs/handlers/GestureHandlerEventPayload.js +4 -0
  54. package/lib/commonjs/handlers/LongPressGestureHandler.js +1 -1
  55. package/lib/commonjs/handlers/LongPressGestureHandler.js.map +1 -1
  56. package/lib/commonjs/handlers/createHandler.js +2 -1
  57. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  58. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js +1 -1
  59. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js.map +1 -1
  60. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  61. package/lib/commonjs/handlers/gestures/hoverGesture.js.map +1 -1
  62. package/lib/commonjs/handlers/gestures/longPressGesture.js +10 -0
  63. package/lib/commonjs/handlers/gestures/longPressGesture.js.map +1 -1
  64. package/lib/commonjs/jestUtils/jestUtils.js +12 -4
  65. package/lib/commonjs/jestUtils/jestUtils.js.map +1 -1
  66. package/lib/commonjs/mocks.js +16 -3
  67. package/lib/commonjs/mocks.js.map +1 -1
  68. package/lib/commonjs/utils.js +4 -0
  69. package/lib/commonjs/utils.js.map +1 -1
  70. package/lib/commonjs/web/constants.js +3 -3
  71. package/lib/commonjs/web/constants.js.map +1 -1
  72. package/lib/commonjs/web/handlers/GestureHandler.js +2 -3
  73. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  74. package/lib/commonjs/web/handlers/HoverGestureHandler.js +18 -1
  75. package/lib/commonjs/web/handlers/HoverGestureHandler.js.map +1 -1
  76. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +43 -9
  77. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  78. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +14 -3
  79. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  80. package/lib/commonjs/web/handlers/PanGestureHandler.js +12 -1
  81. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  82. package/lib/commonjs/web/interfaces.js.map +1 -1
  83. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  84. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +55 -11
  85. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  86. package/lib/commonjs/web/tools/KeyboardEventManager.js +110 -0
  87. package/lib/commonjs/web/tools/KeyboardEventManager.js.map +1 -0
  88. package/lib/commonjs/web/tools/PointerEventManager.js +3 -37
  89. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  90. package/lib/commonjs/web/tools/Vector.js +4 -2
  91. package/lib/commonjs/web/tools/Vector.js.map +1 -1
  92. package/lib/commonjs/web/utils.js +187 -13
  93. package/lib/commonjs/web/utils.js.map +1 -1
  94. package/lib/module/PointerType.js +2 -1
  95. package/lib/module/PointerType.js.map +1 -1
  96. package/lib/module/components/GestureButtons.js +5 -1
  97. package/lib/module/components/GestureButtons.js.map +1 -1
  98. package/lib/module/components/GestureComponents.js.map +1 -1
  99. package/lib/module/components/Pressable/Pressable.js +67 -78
  100. package/lib/module/components/Pressable/Pressable.js.map +1 -1
  101. package/lib/module/components/Pressable/index.js +0 -1
  102. package/lib/module/components/Pressable/index.js.map +1 -1
  103. package/lib/module/components/Pressable/utils.js +1 -22
  104. package/lib/module/components/Pressable/utils.js.map +1 -1
  105. package/lib/module/components/ReanimatedSwipeable.js +58 -37
  106. package/lib/module/components/ReanimatedSwipeable.js.map +1 -1
  107. package/lib/module/handlers/GestureHandlerEventPayload.js +1 -1
  108. package/lib/module/handlers/LongPressGestureHandler.js +1 -1
  109. package/lib/module/handlers/LongPressGestureHandler.js.map +1 -1
  110. package/lib/module/handlers/createHandler.js +2 -1
  111. package/lib/module/handlers/createHandler.js.map +1 -1
  112. package/lib/module/handlers/gestures/GestureDetector/utils.js +2 -2
  113. package/lib/module/handlers/gestures/GestureDetector/utils.js.map +1 -1
  114. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  115. package/lib/module/handlers/gestures/hoverGesture.js.map +1 -1
  116. package/lib/module/handlers/gestures/longPressGesture.js +10 -0
  117. package/lib/module/handlers/gestures/longPressGesture.js.map +1 -1
  118. package/lib/module/jestUtils/jestUtils.js +12 -4
  119. package/lib/module/jestUtils/jestUtils.js.map +1 -1
  120. package/lib/module/mocks.js +13 -3
  121. package/lib/module/mocks.js.map +1 -1
  122. package/lib/module/utils.js +1 -0
  123. package/lib/module/utils.js.map +1 -1
  124. package/lib/module/web/constants.js +1 -1
  125. package/lib/module/web/constants.js.map +1 -1
  126. package/lib/module/web/handlers/GestureHandler.js +2 -3
  127. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  128. package/lib/module/web/handlers/HoverGestureHandler.js +18 -1
  129. package/lib/module/web/handlers/HoverGestureHandler.js.map +1 -1
  130. package/lib/module/web/handlers/LongPressGestureHandler.js +43 -9
  131. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  132. package/lib/module/web/handlers/NativeViewGestureHandler.js +14 -3
  133. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  134. package/lib/module/web/handlers/PanGestureHandler.js +12 -1
  135. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  136. package/lib/module/web/interfaces.js.map +1 -1
  137. package/lib/module/web/tools/EventManager.js.map +1 -1
  138. package/lib/module/web/tools/GestureHandlerWebDelegate.js +54 -10
  139. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  140. package/lib/module/web/tools/KeyboardEventManager.js +96 -0
  141. package/lib/module/web/tools/KeyboardEventManager.js.map +1 -0
  142. package/lib/module/web/tools/PointerEventManager.js +4 -38
  143. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  144. package/lib/module/web/tools/Vector.js +5 -3
  145. package/lib/module/web/tools/Vector.js.map +1 -1
  146. package/lib/module/web/utils.js +184 -13
  147. package/lib/module/web/utils.js.map +1 -1
  148. package/lib/typescript/PointerType.d.ts +2 -1
  149. package/lib/typescript/components/GestureComponents.d.ts +1 -1
  150. package/lib/typescript/components/Pressable/index.d.ts +1 -1
  151. package/lib/typescript/components/Pressable/utils.d.ts +3 -5
  152. package/lib/typescript/handlers/GestureHandlerEventPayload.d.ts +35 -0
  153. package/lib/typescript/handlers/LongPressGestureHandler.d.ts +5 -1
  154. package/lib/typescript/handlers/gestures/gesture.d.ts +2 -2
  155. package/lib/typescript/handlers/gestures/hoverGesture.d.ts +1 -6
  156. package/lib/typescript/handlers/gestures/longPressGesture.d.ts +5 -0
  157. package/lib/typescript/handlers/handlersRegistry.d.ts +1 -1
  158. package/lib/typescript/jestUtils/jestUtils.d.ts +1 -1
  159. package/lib/typescript/mocks.d.ts +4 -3
  160. package/lib/typescript/utils.d.ts +1 -0
  161. package/lib/typescript/web/constants.d.ts +1 -1
  162. package/lib/typescript/web/handlers/GestureHandler.d.ts +1 -1
  163. package/lib/typescript/web/handlers/HoverGestureHandler.d.ts +2 -0
  164. package/lib/typescript/web/handlers/LongPressGestureHandler.d.ts +3 -0
  165. package/lib/typescript/web/handlers/NativeViewGestureHandler.d.ts +1 -0
  166. package/lib/typescript/web/handlers/PanGestureHandler.d.ts +3 -1
  167. package/lib/typescript/web/interfaces.d.ts +9 -4
  168. package/lib/typescript/web/tools/EventManager.d.ts +2 -2
  169. package/lib/typescript/web/tools/GestureHandlerDelegate.d.ts +1 -0
  170. package/lib/typescript/web/tools/GestureHandlerWebDelegate.d.ts +6 -0
  171. package/lib/typescript/web/tools/KeyboardEventManager.d.ts +13 -0
  172. package/lib/typescript/web/utils.d.ts +2 -1
  173. package/package.json +3 -3
  174. package/src/PointerType.ts +1 -0
  175. package/src/components/GestureButtons.tsx +2 -1
  176. package/src/components/GestureComponents.tsx +1 -1
  177. package/src/components/Pressable/Pressable.tsx +77 -70
  178. package/src/components/Pressable/index.ts +1 -1
  179. package/src/components/Pressable/utils.ts +5 -49
  180. package/src/components/ReanimatedSwipeable.tsx +70 -47
  181. package/src/handlers/GestureHandlerEventPayload.ts +42 -0
  182. package/src/handlers/LongPressGestureHandler.ts +6 -0
  183. package/src/handlers/createHandler.tsx +1 -0
  184. package/src/handlers/gestures/GestureDetector/utils.ts +2 -2
  185. package/src/handlers/gestures/gesture.ts +3 -1
  186. package/src/handlers/gestures/hoverGesture.ts +1 -7
  187. package/src/handlers/gestures/longPressGesture.ts +9 -0
  188. package/src/jestUtils/jestUtils.ts +9 -1
  189. package/src/{mocks.ts → mocks.tsx} +8 -3
  190. package/src/utils.ts +2 -0
  191. package/src/web/constants.ts +1 -1
  192. package/src/web/handlers/GestureHandler.ts +4 -2
  193. package/src/web/handlers/HoverGestureHandler.ts +16 -2
  194. package/src/web/handlers/LongPressGestureHandler.ts +49 -10
  195. package/src/web/handlers/NativeViewGestureHandler.ts +14 -4
  196. package/src/web/handlers/PanGestureHandler.ts +14 -1
  197. package/src/web/interfaces.ts +10 -4
  198. package/src/web/tools/EventManager.ts +2 -4
  199. package/src/web/tools/GestureHandlerDelegate.ts +1 -0
  200. package/src/web/tools/GestureHandlerWebDelegate.ts +67 -10
  201. package/src/web/tools/KeyboardEventManager.ts +91 -0
  202. package/src/web/tools/PointerEventManager.ts +2 -38
  203. package/src/web/tools/Vector.ts +4 -3
  204. package/src/web/utils.ts +188 -13
  205. package/lib/commonjs/web/tools/TouchEventManager.js +0 -164
  206. package/lib/commonjs/web/tools/TouchEventManager.js.map +0 -1
  207. package/lib/module/web/tools/TouchEventManager.js +0 -149
  208. package/lib/module/web/tools/TouchEventManager.js.map +0 -1
  209. package/lib/typescript/web/tools/TouchEventManager.d.ts +0 -11
  210. package/src/web/tools/TouchEventManager.ts +0 -175
package/README.md CHANGED
@@ -37,6 +37,7 @@ You will need to have an Android or iOS device or emulator connected.
37
37
 
38
38
  | version | react-native version |
39
39
  | ------- | -------------------- |
40
+ | 2.18.0+ | 0.73.0+ |
40
41
  | 2.16.0+ | 0.68.0+ |
41
42
  | 2.14.0+ | 0.67.0+ |
42
43
  | 2.10.0+ | 0.64.0+ |
@@ -1,8 +1,5 @@
1
1
  import groovy.json.JsonSlurper
2
2
 
3
- import javax.inject.Inject
4
- import java.nio.file.Files
5
-
6
3
  buildscript {
7
4
  def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['RNGH_kotlinVersion']
8
5
 
@@ -36,16 +33,10 @@ def resolveReactNativeDirectory() {
36
33
  return file(reactNativeLocation)
37
34
  }
38
35
 
39
- // monorepo workaround
40
- // react-native can be hoisted or in project's own node_modules
41
- def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native")
42
- if (reactNativeFromProjectNodeModules.exists()) {
43
- return reactNativeFromProjectNodeModules
44
- }
45
-
46
- def reactNativeFromNodeModulesWithReanimated = file("${projectDir}/../../react-native")
47
- if (reactNativeFromNodeModulesWithReanimated.exists()) {
48
- return reactNativeFromNodeModulesWithReanimated
36
+ // Fallback to node resolver for custom directory structures like monorepos.
37
+ def reactNativePackage = file(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim())
38
+ if (reactNativePackage.exists()) {
39
+ return reactNativePackage.parentFile
49
40
  }
50
41
 
51
42
  throw new Exception(
@@ -98,15 +89,11 @@ repositories {
98
89
 
99
90
  android {
100
91
  compileSdkVersion safeExtGet("compileSdkVersion", 33)
101
- def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
102
- if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
103
- namespace "com.swmansion.gesturehandler"
104
- }
105
92
 
106
- if (agpVersion.tokenize('.')[0].toInteger() >= 8) {
107
- buildFeatures {
108
- buildConfig = true
109
- }
93
+ namespace "com.swmansion.gesturehandler"
94
+ buildFeatures {
95
+ buildConfig = true
96
+ prefab = true
110
97
  }
111
98
 
112
99
  // Used to override the NDK path/version on internal CI or by allowing
@@ -118,12 +105,6 @@ android {
118
105
  ndkVersion rootProject.ext.ndkVersion
119
106
  }
120
107
 
121
- if (REACT_NATIVE_MINOR_VERSION >= 71) {
122
- buildFeatures {
123
- prefab true
124
- }
125
- }
126
-
127
108
  defaultConfig {
128
109
  minSdkVersion safeExtGet('minSdkVersion', 21)
129
110
  targetSdkVersion safeExtGet('targetSdkVersion', 33)
@@ -137,8 +118,7 @@ android {
137
118
  externalNativeBuild {
138
119
  cmake {
139
120
  cppFlags "-O2", "-frtti", "-fexceptions", "-Wall", "-Werror", "-std=c++20", "-DANDROID"
140
- arguments "-DAPP_BUILD_DIR=${appProject.buildDir}",
141
- "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
121
+ arguments "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
142
122
  "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}",
143
123
  "-DANDROID_STL=c++_shared"
144
124
  abiFilters (*reactNativeArchitectures())
@@ -166,6 +146,8 @@ android {
166
146
  // only the ones that make the build fail (ideally we should only include libgesturehandler but we
167
147
  // are only allowed to specify exclude patterns)
168
148
  exclude "**/libreact_render*.so"
149
+ exclude "**/libreactnative.so"
150
+ exclude "**/libjsi.so"
169
151
  }
170
152
 
171
153
  sourceSets.main {
@@ -8,5 +8,5 @@ import com.facebook.react.uimanager.events.Event
8
8
 
9
9
  fun ReactContext.dispatchEvent(event: Event<*>) {
10
10
  val fabricUIManager = UIManagerHelper.getUIManager(this, UIManagerType.FABRIC) as FabricUIManager
11
- fabricUIManager.eventDispatcher.dispatchEvent(event)
11
+ fabricUIManager.getEventDispatcher().dispatchEvent(event)
12
12
  }
@@ -6,7 +6,7 @@ import com.facebook.react.uimanager.events.Event
6
6
 
7
7
  fun ReactContext.dispatchEvent(event: Event<*>) {
8
8
  try {
9
- this.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher.dispatchEvent(event)
9
+ this.getNativeModule(UIManagerModule::class.java)!!.getEventDispatcher().dispatchEvent(event)
10
10
  } catch (e: NullPointerException) {
11
11
  throw Exception("Couldn't get an instance of UIManagerModule. Gesture Handler is unable to send an event.", e)
12
12
  }
@@ -1,3 +1 @@
1
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
- package="com.swmansion.gesturehandler">
3
- </manifest>
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" />
@@ -397,19 +397,19 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
397
397
  }
398
398
  }
399
399
 
400
- private fun dispatchTouchDownEvent(event: MotionEvent) {
400
+ private fun dispatchTouchDownEvent(event: MotionEvent, sourceEvent: MotionEvent) {
401
401
  changedTouchesPayload = null
402
402
  touchEventType = RNGestureHandlerTouchEvent.EVENT_TOUCH_DOWN
403
403
  val pointerId = event.getPointerId(event.actionIndex)
404
- val offsetX = event.rawX - event.x
405
- val offsetY = event.rawY - event.y
404
+ val offsetX = sourceEvent.rawX - sourceEvent.x
405
+ val offsetY = sourceEvent.rawY - sourceEvent.y
406
406
 
407
407
  trackedPointers[pointerId] = PointerData(
408
408
  pointerId,
409
409
  event.getX(event.actionIndex),
410
410
  event.getY(event.actionIndex),
411
- event.getX(event.actionIndex) + offsetX - windowOffset[0],
412
- event.getY(event.actionIndex) + offsetY - windowOffset[1],
411
+ sourceEvent.getX(event.actionIndex) + offsetX - windowOffset[0],
412
+ sourceEvent.getY(event.actionIndex) + offsetY - windowOffset[1],
413
413
  )
414
414
  trackedPointersCount++
415
415
  addChangedPointer(trackedPointers[pointerId]!!)
@@ -418,20 +418,20 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
418
418
  dispatchTouchEvent()
419
419
  }
420
420
 
421
- private fun dispatchTouchUpEvent(event: MotionEvent) {
421
+ private fun dispatchTouchUpEvent(event: MotionEvent, sourceEvent: MotionEvent) {
422
422
  extractAllPointersData()
423
423
  changedTouchesPayload = null
424
424
  touchEventType = RNGestureHandlerTouchEvent.EVENT_TOUCH_UP
425
425
  val pointerId = event.getPointerId(event.actionIndex)
426
- val offsetX = event.rawX - event.x
427
- val offsetY = event.rawY - event.y
426
+ val offsetX = sourceEvent.rawX - sourceEvent.x
427
+ val offsetY = sourceEvent.rawY - sourceEvent.y
428
428
 
429
429
  trackedPointers[pointerId] = PointerData(
430
430
  pointerId,
431
431
  event.getX(event.actionIndex),
432
432
  event.getY(event.actionIndex),
433
- event.getX(event.actionIndex) + offsetX - windowOffset[0],
434
- event.getY(event.actionIndex) + offsetY - windowOffset[1],
433
+ sourceEvent.getX(event.actionIndex) + offsetX - windowOffset[0],
434
+ sourceEvent.getY(event.actionIndex) + offsetY - windowOffset[1],
435
435
  )
436
436
  addChangedPointer(trackedPointers[pointerId]!!)
437
437
  trackedPointers[pointerId] = null
@@ -440,11 +440,11 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
440
440
  dispatchTouchEvent()
441
441
  }
442
442
 
443
- private fun dispatchTouchMoveEvent(event: MotionEvent) {
443
+ private fun dispatchTouchMoveEvent(event: MotionEvent, sourceEvent: MotionEvent) {
444
444
  changedTouchesPayload = null
445
445
  touchEventType = RNGestureHandlerTouchEvent.EVENT_TOUCH_MOVE
446
- val offsetX = event.rawX - event.x
447
- val offsetY = event.rawY - event.y
446
+ val offsetX = sourceEvent.rawX - sourceEvent.x
447
+ val offsetY = sourceEvent.rawY - sourceEvent.y
448
448
  var pointersAdded = 0
449
449
 
450
450
  for (i in 0 until event.pointerCount) {
@@ -454,8 +454,8 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
454
454
  if (pointer.x != event.getX(i) || pointer.y != event.getY(i)) {
455
455
  pointer.x = event.getX(i)
456
456
  pointer.y = event.getY(i)
457
- pointer.absoluteX = event.getX(i) + offsetX - windowOffset[0]
458
- pointer.absoluteY = event.getY(i) + offsetY - windowOffset[1]
457
+ pointer.absoluteX = sourceEvent.getX(i) + offsetX - windowOffset[0]
458
+ pointer.absoluteY = sourceEvent.getY(i) + offsetY - windowOffset[1]
459
459
 
460
460
  addChangedPointer(pointer)
461
461
  pointersAdded++
@@ -471,15 +471,15 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
471
471
  }
472
472
  }
473
473
 
474
- fun updatePointerData(event: MotionEvent) {
474
+ fun updatePointerData(event: MotionEvent, sourceEvent: MotionEvent) {
475
475
  if (event.actionMasked == MotionEvent.ACTION_DOWN || event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
476
- dispatchTouchDownEvent(event)
477
- dispatchTouchMoveEvent(event)
476
+ dispatchTouchDownEvent(event, sourceEvent)
477
+ dispatchTouchMoveEvent(event, sourceEvent)
478
478
  } else if (event.actionMasked == MotionEvent.ACTION_UP || event.actionMasked == MotionEvent.ACTION_POINTER_UP) {
479
- dispatchTouchMoveEvent(event)
480
- dispatchTouchUpEvent(event)
479
+ dispatchTouchMoveEvent(event, sourceEvent)
480
+ dispatchTouchUpEvent(event, sourceEvent)
481
481
  } else if (event.actionMasked == MotionEvent.ACTION_MOVE) {
482
- dispatchTouchMoveEvent(event)
482
+ dispatchTouchMoveEvent(event, sourceEvent)
483
483
  }
484
484
  }
485
485
 
@@ -270,7 +270,7 @@ class GestureHandlerOrchestrator(
270
270
  // the first `onTouchesDown` event after the handler processes it and changes state
271
271
  // to `BEGAN`.
272
272
  if (handler.needsPointerData && handler.state != 0) {
273
- handler.updatePointerData(event)
273
+ handler.updatePointerData(event, sourceEvent)
274
274
  }
275
275
 
276
276
  if (!handler.isAwaiting || action != MotionEvent.ACTION_MOVE) {
@@ -292,7 +292,7 @@ class GestureHandlerOrchestrator(
292
292
  }
293
293
 
294
294
  if (handler.needsPointerData && isFirstEvent) {
295
- handler.updatePointerData(event)
295
+ handler.updatePointerData(event, sourceEvent)
296
296
  }
297
297
 
298
298
  // if event was of type UP or POINTER_UP we request handler to stop tracking now that
@@ -45,6 +45,7 @@ object GestureUtils {
45
45
  event.getY(lastPointerIdx)
46
46
  }
47
47
  }
48
+
48
49
  fun coneToDeviation(angle: Double): Double =
49
50
  cos(Math.toRadians(angle / 2.0))
50
51
  }
@@ -5,11 +5,14 @@ import android.os.Looper
5
5
  import android.view.MotionEvent
6
6
  import android.view.View
7
7
  import android.view.ViewGroup
8
+ import com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper
8
9
  import com.swmansion.gesturehandler.react.RNViewConfigurationHelper
9
10
 
10
11
  class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
11
12
  private var handler: Handler? = null
12
13
  private var finishRunnable = Runnable { finish() }
14
+ var stylusData: StylusData = StylusData()
15
+ private set
13
16
 
14
17
  private infix fun isAncestorOf(other: GestureHandler<*>): Boolean {
15
18
  var current: View? = other.view
@@ -70,6 +73,10 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
70
73
  return true
71
74
  }
72
75
 
76
+ if (handler is RNGestureHandlerRootHelper.RootViewGestureHandler) {
77
+ return true
78
+ }
79
+
73
80
  return super.shouldRecognizeSimultaneously(handler)
74
81
  }
75
82
 
@@ -98,6 +105,10 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
98
105
  finish()
99
106
  }
100
107
 
108
+ this.state == STATE_ACTIVE && event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS -> {
109
+ stylusData = StylusData.fromEvent(event)
110
+ }
111
+
101
112
  this.state == STATE_UNDETERMINED &&
102
113
  (event.action == MotionEvent.ACTION_HOVER_MOVE || event.action == MotionEvent.ACTION_HOVER_ENTER) -> {
103
114
  begin()
@@ -106,6 +117,11 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
106
117
  }
107
118
  }
108
119
 
120
+ override fun onReset() {
121
+ super.onReset()
122
+ stylusData = StylusData()
123
+ }
124
+
109
125
  private fun finish() {
110
126
  when (this.state) {
111
127
  STATE_UNDETERMINED -> cancel()
@@ -12,11 +12,13 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
12
12
  get() = (previousTime - startTime).toInt()
13
13
  private val defaultMaxDistSq: Float
14
14
  private var maxDistSq: Float
15
+ private var numberOfPointersRequired: Int
15
16
  private var startX = 0f
16
17
  private var startY = 0f
17
18
  private var startTime: Long = 0
18
19
  private var previousTime: Long = 0
19
20
  private var handler: Handler? = null
21
+ private var currentPointers = 0
20
22
 
21
23
  init {
22
24
  setShouldCancelWhenOutside(true)
@@ -24,6 +26,7 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
24
26
  val defaultMaxDist = DEFAULT_MAX_DIST_DP * context.resources.displayMetrics.density
25
27
  defaultMaxDistSq = defaultMaxDist * defaultMaxDist
26
28
  maxDistSq = defaultMaxDistSq
29
+ numberOfPointersRequired = 1
27
30
  }
28
31
 
29
32
  override fun resetConfig() {
@@ -37,6 +40,37 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
37
40
  return this
38
41
  }
39
42
 
43
+ fun setNumberOfPointers(numberOfPointers: Int): LongPressGestureHandler {
44
+ numberOfPointersRequired = numberOfPointers
45
+ return this
46
+ }
47
+
48
+ private fun getAverageCoords(ev: MotionEvent, excludePointer: Boolean = false): Pair<Float, Float> {
49
+ if (!excludePointer) {
50
+ val x = (0 until ev.pointerCount).map { ev.getX(it) }.average().toFloat()
51
+ val y = (0 until ev.pointerCount).map { ev.getY(it) }.average().toFloat()
52
+
53
+ return Pair(x, y)
54
+ }
55
+
56
+ var sumX = 0f
57
+ var sumY = 0f
58
+
59
+ for (i in 0 until ev.pointerCount) {
60
+ if (i == ev.actionIndex) {
61
+ continue
62
+ }
63
+
64
+ sumX += ev.getX(i)
65
+ sumY += ev.getY(i)
66
+ }
67
+
68
+ val x = sumX / (ev.pointerCount - 1)
69
+ val y = sumY / (ev.pointerCount - 1)
70
+
71
+ return Pair(x, y)
72
+ }
73
+
40
74
  override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
41
75
  if (!shouldActivateWithMouse(sourceEvent)) {
42
76
  return
@@ -46,8 +80,28 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
46
80
  previousTime = SystemClock.uptimeMillis()
47
81
  startTime = previousTime
48
82
  begin()
49
- startX = sourceEvent.rawX
50
- startY = sourceEvent.rawY
83
+
84
+ val (x, y) = getAverageCoords(sourceEvent)
85
+ startX = x
86
+ startY = y
87
+
88
+ currentPointers++
89
+ }
90
+
91
+ if (sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
92
+ currentPointers++
93
+
94
+ val (x, y) = getAverageCoords(sourceEvent)
95
+ startX = x
96
+ startY = y
97
+
98
+ if (currentPointers > numberOfPointersRequired) {
99
+ fail()
100
+ currentPointers = 0
101
+ }
102
+ }
103
+
104
+ if (state == STATE_BEGAN && currentPointers == numberOfPointersRequired && (sourceEvent.actionMasked == MotionEvent.ACTION_DOWN || sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_DOWN)) {
51
105
  handler = Handler(Looper.getMainLooper())
52
106
  if (minDurationMs > 0) {
53
107
  handler!!.postDelayed({ activate() }, minDurationMs)
@@ -56,20 +110,37 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
56
110
  }
57
111
  }
58
112
  if (sourceEvent.actionMasked == MotionEvent.ACTION_UP || sourceEvent.actionMasked == MotionEvent.ACTION_BUTTON_RELEASE) {
113
+ currentPointers--
114
+
59
115
  handler?.let {
60
116
  it.removeCallbacksAndMessages(null)
61
117
  handler = null
62
118
  }
119
+
63
120
  if (state == STATE_ACTIVE) {
64
121
  end()
65
122
  } else {
66
123
  fail()
67
124
  }
125
+ } else if (sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_UP) {
126
+ currentPointers--
127
+
128
+ if (currentPointers < numberOfPointersRequired && state != STATE_ACTIVE) {
129
+ fail()
130
+ currentPointers = 0
131
+ } else {
132
+ val (x, y) = getAverageCoords(sourceEvent, true)
133
+ startX = x
134
+ startY = y
135
+ }
68
136
  } else {
69
137
  // calculate distance from start
70
- val deltaX = sourceEvent.rawX - startX
71
- val deltaY = sourceEvent.rawY - startY
138
+ val (x, y) = getAverageCoords(sourceEvent)
139
+
140
+ val deltaX = x - startX
141
+ val deltaY = y - startY
72
142
  val distSq = deltaX * deltaX + deltaY * deltaY
143
+
73
144
  if (distSq > maxDistSq) {
74
145
  if (state == STATE_ACTIVE) {
75
146
  cancel()
@@ -97,6 +168,11 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
97
168
  super.dispatchHandlerUpdate(event)
98
169
  }
99
170
 
171
+ override fun onReset() {
172
+ super.onReset()
173
+ currentPointers = 0
174
+ }
175
+
100
176
  companion object {
101
177
  private const val DEFAULT_MIN_DURATION_MS: Long = 500
102
178
  private const val DEFAULT_MAX_DIST_DP = 10f
@@ -45,6 +45,8 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
45
45
  private var activateAfterLongPress = DEFAULT_ACTIVATE_AFTER_LONG_PRESS
46
46
  private val activateDelayed = Runnable { activate() }
47
47
  private var handler: Handler? = null
48
+ var stylusData: StylusData = StylusData()
49
+ private set
48
50
 
49
51
  /**
50
52
  * On Android when there are multiple pointers on the screen pan gestures most often just consider
@@ -212,6 +214,10 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
212
214
  return
213
215
  }
214
216
 
217
+ if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
218
+ stylusData = StylusData.fromEvent(event)
219
+ }
220
+
215
221
  val state = state
216
222
  val action = sourceEvent.actionMasked
217
223
  if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) {
@@ -295,6 +301,8 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
295
301
  it.recycle()
296
302
  velocityTracker = null
297
303
  }
304
+
305
+ stylusData = StylusData()
298
306
  }
299
307
 
300
308
  override fun resetProgress() {
@@ -23,7 +23,8 @@ class PinchGestureHandler : GestureHandler<PinchGestureHandler>() {
23
23
  override fun onScale(detector: ScaleGestureDetector): Boolean {
24
24
  val prevScaleFactor: Double = scale
25
25
  scale *= detector.scaleFactor.toDouble()
26
- val delta = detector.timeDelta
26
+ val delta = detector.timeDeltaSeconds
27
+
27
28
  if (delta > 0) {
28
29
  velocity = (scale - prevScaleFactor) / delta
29
30
  }
@@ -547,6 +547,16 @@ public class ScaleGestureDetector {
547
547
  return mCurrTime - mPrevTime;
548
548
  }
549
549
 
550
+ /**
551
+ * Return the time difference in seconds between the previous
552
+ * accepted scaling event and the current scaling event.
553
+ *
554
+ * @return Time difference since the last scaling event in seconds.
555
+ */
556
+ public double getTimeDeltaSeconds() {
557
+ return (double)this.getTimeDelta() / 1000;
558
+ }
559
+
550
560
  /**
551
561
  * Return the event time of the current event being processed.
552
562
  *
@@ -0,0 +1,103 @@
1
+ package com.swmansion.gesturehandler.core
2
+
3
+ import android.view.MotionEvent
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.ReadableMap
6
+ import kotlin.math.PI
7
+ import kotlin.math.abs
8
+ import kotlin.math.atan
9
+ import kotlin.math.cos
10
+ import kotlin.math.round
11
+ import kotlin.math.sin
12
+ import kotlin.math.tan
13
+
14
+ data class StylusData(
15
+ val tiltX: Double = 0.0,
16
+ val tiltY: Double = 0.0,
17
+ val altitudeAngle: Double = 0.0,
18
+ val azimuthAngle: Double = 0.0,
19
+ val pressure: Double = -1.0
20
+ ) {
21
+ fun toReadableMap(): ReadableMap {
22
+ val stylusDataObject = Arguments.createMap().apply {
23
+ putDouble("tiltX", tiltX)
24
+ putDouble("tiltY", tiltY)
25
+ putDouble("altitudeAngle", altitudeAngle)
26
+ putDouble("azimuthAngle", azimuthAngle)
27
+ putDouble("pressure", pressure)
28
+ }
29
+
30
+ val readableStylusData: ReadableMap = stylusDataObject
31
+
32
+ return readableStylusData
33
+ }
34
+
35
+ companion object {
36
+ // Source: https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle
37
+ private fun spherical2tilt(altitudeAngle: Double, azimuthAngle: Double): Pair<Double, Double> {
38
+ val eps = 0.000000001
39
+ val radToDeg = 180 / PI
40
+
41
+ var tiltXrad = 0.0
42
+ var tiltYrad = 0.0
43
+
44
+ if (altitudeAngle < eps) {
45
+ // the pen is in the X-Y plane
46
+ if (azimuthAngle < eps || abs(azimuthAngle - 2 * PI) < eps) {
47
+ // pen is on positive X axis
48
+ tiltXrad = PI / 2
49
+ }
50
+ if (abs(azimuthAngle - PI / 2) < eps) {
51
+ // pen is on positive Y axis
52
+ tiltYrad = PI / 2
53
+ }
54
+ if (abs(azimuthAngle - PI) < eps) {
55
+ // pen is on negative X axis
56
+ tiltXrad = -PI / 2
57
+ }
58
+ if (abs(azimuthAngle - (3 * PI) / 2) < eps) {
59
+ // pen is on negative Y axis
60
+ tiltYrad = -PI / 2
61
+ }
62
+ if (azimuthAngle > eps && abs(azimuthAngle - PI / 2) < eps) {
63
+ tiltXrad = PI / 2
64
+ tiltYrad = PI / 2
65
+ }
66
+ if (abs(azimuthAngle - PI / 2) > eps && abs(azimuthAngle - PI) < eps) {
67
+ tiltXrad = -PI / 2
68
+ tiltYrad = PI / 2
69
+ }
70
+ if (abs(azimuthAngle - PI) > eps && abs(azimuthAngle - (3 * PI) / 2) < eps) {
71
+ tiltXrad = -PI / 2
72
+ tiltYrad = -PI / 2
73
+ }
74
+ if (abs(azimuthAngle - (3 * PI) / 2) > eps && abs(azimuthAngle - 2 * PI) < eps) {
75
+ tiltXrad = PI / 2
76
+ tiltYrad = -PI / 2
77
+ }
78
+ } else {
79
+ val tanAlt = tan(altitudeAngle)
80
+
81
+ tiltXrad = atan(cos(azimuthAngle) / tanAlt)
82
+ tiltYrad = atan(sin(azimuthAngle) / tanAlt)
83
+ }
84
+
85
+ val tiltX = round(tiltXrad * radToDeg)
86
+ val tiltY = round(tiltYrad * radToDeg)
87
+
88
+ return Pair(tiltX, tiltY)
89
+ }
90
+
91
+ fun fromEvent(event: MotionEvent): StylusData {
92
+ // On web and iOS 0 degrees means that stylus is parallel to the surface. On android this value will be PI / 2.
93
+ val altitudeAngle = (PI / 2) - event.getAxisValue(MotionEvent.AXIS_TILT).toDouble()
94
+ val pressure = event.getPressure(0).toDouble()
95
+ val orientation = event.getOrientation(0).toDouble()
96
+ // To get azimuth angle, we need to use orientation property (https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features#orientation).
97
+ val azimuthAngle = (orientation + PI / 2).mod(2 * PI)
98
+ val tilts = spherical2tilt(altitudeAngle, azimuthAngle)
99
+
100
+ return StylusData(tilts.first, tilts.second, altitudeAngle, azimuthAngle, pressure)
101
+ }
102
+ }
103
+ }
@@ -13,7 +13,7 @@ class Vector(val x: Double, val y: Double) {
13
13
  val magnitude = hypot(x, y)
14
14
 
15
15
  init {
16
- val isMagnitudeSufficient = magnitude > MINIMAL_MAGNITUDE
16
+ val isMagnitudeSufficient = magnitude > MINIMAL_RECOGNIZABLE_MAGNITUDE
17
17
 
18
18
  unitX = if (isMagnitudeSufficient) x / magnitude else 0.0
19
19
  unitY = if (isMagnitudeSufficient) y / magnitude else 0.0
@@ -39,7 +39,7 @@ class Vector(val x: Double, val y: Double) {
39
39
  private val VECTOR_LEFT_DOWN: Vector = Vector(-1.0, 1.0)
40
40
 
41
41
  private val VECTOR_ZERO: Vector = Vector(0.0, 0.0)
42
- private const val MINIMAL_MAGNITUDE = 0.1
42
+ private const val MINIMAL_RECOGNIZABLE_MAGNITUDE = 0.1
43
43
 
44
44
  fun fromDirection(direction: Int): Vector =
45
45
  when (direction) {
@@ -286,22 +286,11 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
286
286
  return false
287
287
  }
288
288
 
289
- private fun updateBackgroundColor(backgroundColor: Int, selectable: Drawable?) {
289
+ private fun updateBackgroundColor(backgroundColor: Int, borderDrawable: Drawable, selectable: Drawable?) {
290
290
  val colorDrawable = PaintDrawable(backgroundColor)
291
- val borderDrawable = PaintDrawable(Color.TRANSPARENT)
292
291
 
293
292
  if (hasBorderRadii) {
294
293
  colorDrawable.setCornerRadii(buildBorderRadii())
295
- borderDrawable.setCornerRadii(buildBorderRadii())
296
- }
297
-
298
- if (borderWidth > 0f) {
299
- borderDrawable.paint.apply {
300
- style = Paint.Style.STROKE
301
- strokeWidth = borderWidth
302
- color = borderColor ?: Color.BLACK
303
- pathEffect = buildBorderStyle()
304
- }
305
294
  }
306
295
 
307
296
  val layerDrawable = LayerDrawable(if (selectable != null) arrayOf(colorDrawable, selectable, borderDrawable) else arrayOf(colorDrawable, borderDrawable))
@@ -324,6 +313,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
324
313
  }
325
314
 
326
315
  val selectable = createSelectableDrawable()
316
+ val borderDrawable = createBorderDrawable()
327
317
 
328
318
  if (hasBorderRadii && selectable is RippleDrawable) {
329
319
  val mask = PaintDrawable(Color.WHITE)
@@ -334,13 +324,32 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
334
324
  if (useDrawableOnForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
335
325
  foreground = selectable
336
326
  if (_backgroundColor != Color.TRANSPARENT) {
337
- updateBackgroundColor(_backgroundColor, null)
327
+ updateBackgroundColor(_backgroundColor, borderDrawable, null)
338
328
  }
339
329
  } else if (_backgroundColor == Color.TRANSPARENT && rippleColor == null) {
340
- background = selectable
330
+ background = LayerDrawable(arrayOf(selectable, borderDrawable))
341
331
  } else {
342
- updateBackgroundColor(_backgroundColor, selectable)
332
+ updateBackgroundColor(_backgroundColor, borderDrawable, selectable)
333
+ }
334
+ }
335
+
336
+ private fun createBorderDrawable(): Drawable {
337
+ val borderDrawable = PaintDrawable(Color.TRANSPARENT)
338
+
339
+ if (hasBorderRadii) {
340
+ borderDrawable.setCornerRadii(buildBorderRadii())
341
+ }
342
+
343
+ if (borderWidth > 0f) {
344
+ borderDrawable.paint.apply {
345
+ style = Paint.Style.STROKE
346
+ strokeWidth = borderWidth
347
+ color = borderColor ?: Color.BLACK
348
+ pathEffect = buildBorderStyle()
349
+ }
343
350
  }
351
+
352
+ return borderDrawable
344
353
  }
345
354
 
346
355
  private fun createSelectableDrawable(): Drawable? {