react-native-gesture-handler 2.18.1 → 2.20.0

Sign up to get free protection for your applications and to get access to all the features.
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? {