react-native-gesture-handler 2.18.0 → 2.19.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 (141) hide show
  1. package/README.md +1 -0
  2. package/android/build.gradle +4 -17
  3. package/android/src/main/AndroidManifest.xml +1 -3
  4. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +21 -21
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +2 -2
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +5 -0
  7. package/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt +80 -4
  8. package/android/src/main/java/com/swmansion/gesturehandler/core/PinchGestureHandler.kt +2 -1
  9. package/android/src/main/java/com/swmansion/gesturehandler/core/ScaleGestureDetector.java +10 -0
  10. package/android/src/main/java/com/swmansion/gesturehandler/core/Vector.kt +2 -2
  11. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +3 -0
  12. package/android/src/main/jni/cpp-adapter.cpp +2 -4
  13. package/apple/Handlers/RNFlingHandler.h +1 -0
  14. package/apple/Handlers/RNFlingHandler.m +153 -19
  15. package/apple/Handlers/RNHoverHandler.m +44 -2
  16. package/apple/Handlers/RNLongPressHandler.m +109 -20
  17. package/apple/Handlers/RNManualHandler.m +53 -29
  18. package/apple/Handlers/RNNativeViewHandler.mm +22 -15
  19. package/apple/RNGHUIKit.h +2 -0
  20. package/apple/RNGHVector.h +31 -0
  21. package/apple/RNGHVector.m +67 -0
  22. package/apple/RNGestureHandler.h +7 -0
  23. package/apple/{RNGestureHandler.m → RNGestureHandler.mm} +63 -1
  24. package/apple/RNGestureHandlerButtonComponentView.mm +6 -0
  25. package/apple/RNGestureHandlerDirection.h +25 -0
  26. package/apple/RNGestureHandlerModule.mm +2 -4
  27. package/lib/commonjs/PointerType.js +2 -1
  28. package/lib/commonjs/PointerType.js.map +1 -1
  29. package/lib/commonjs/components/Pressable/Pressable.js +67 -70
  30. package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
  31. package/lib/commonjs/components/Pressable/index.js +0 -8
  32. package/lib/commonjs/components/Pressable/index.js.map +1 -1
  33. package/lib/commonjs/components/ReanimatedSwipeable.js +60 -41
  34. package/lib/commonjs/components/ReanimatedSwipeable.js.map +1 -1
  35. package/lib/commonjs/components/Swipeable.js +5 -0
  36. package/lib/commonjs/components/Swipeable.js.map +1 -1
  37. package/lib/commonjs/handlers/LongPressGestureHandler.js +1 -1
  38. package/lib/commonjs/handlers/LongPressGestureHandler.js.map +1 -1
  39. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js +1 -1
  40. package/lib/commonjs/handlers/gestures/GestureDetector/utils.js.map +1 -1
  41. package/lib/commonjs/handlers/gestures/longPressGesture.js +10 -0
  42. package/lib/commonjs/handlers/gestures/longPressGesture.js.map +1 -1
  43. package/lib/commonjs/mocks.js +16 -3
  44. package/lib/commonjs/mocks.js.map +1 -1
  45. package/lib/commonjs/utils.js +4 -0
  46. package/lib/commonjs/utils.js.map +1 -1
  47. package/lib/commonjs/web/constants.js +3 -3
  48. package/lib/commonjs/web/constants.js.map +1 -1
  49. package/lib/commonjs/web/handlers/GestureHandler.js +1 -0
  50. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  51. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +43 -9
  52. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  53. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +14 -3
  54. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  55. package/lib/commonjs/web/handlers/PanGestureHandler.js +4 -0
  56. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  57. package/lib/commonjs/web/interfaces.js.map +1 -1
  58. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +55 -8
  59. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  60. package/lib/commonjs/web/tools/KeyboardEventManager.js +110 -0
  61. package/lib/commonjs/web/tools/KeyboardEventManager.js.map +1 -0
  62. package/lib/commonjs/web/tools/Vector.js +4 -2
  63. package/lib/commonjs/web/tools/Vector.js.map +1 -1
  64. package/lib/commonjs/web/utils.js +14 -13
  65. package/lib/commonjs/web/utils.js.map +1 -1
  66. package/lib/module/PointerType.js +2 -1
  67. package/lib/module/PointerType.js.map +1 -1
  68. package/lib/module/components/Pressable/Pressable.js +66 -70
  69. package/lib/module/components/Pressable/Pressable.js.map +1 -1
  70. package/lib/module/components/Pressable/index.js +0 -1
  71. package/lib/module/components/Pressable/index.js.map +1 -1
  72. package/lib/module/components/ReanimatedSwipeable.js +58 -37
  73. package/lib/module/components/ReanimatedSwipeable.js.map +1 -1
  74. package/lib/module/components/Swipeable.js +6 -0
  75. package/lib/module/components/Swipeable.js.map +1 -1
  76. package/lib/module/handlers/LongPressGestureHandler.js +1 -1
  77. package/lib/module/handlers/LongPressGestureHandler.js.map +1 -1
  78. package/lib/module/handlers/gestures/GestureDetector/utils.js +2 -2
  79. package/lib/module/handlers/gestures/GestureDetector/utils.js.map +1 -1
  80. package/lib/module/handlers/gestures/longPressGesture.js +10 -0
  81. package/lib/module/handlers/gestures/longPressGesture.js.map +1 -1
  82. package/lib/module/mocks.js +13 -3
  83. package/lib/module/mocks.js.map +1 -1
  84. package/lib/module/utils.js +1 -0
  85. package/lib/module/utils.js.map +1 -1
  86. package/lib/module/web/constants.js +1 -1
  87. package/lib/module/web/constants.js.map +1 -1
  88. package/lib/module/web/handlers/GestureHandler.js +1 -0
  89. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  90. package/lib/module/web/handlers/LongPressGestureHandler.js +43 -9
  91. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  92. package/lib/module/web/handlers/NativeViewGestureHandler.js +14 -3
  93. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  94. package/lib/module/web/handlers/PanGestureHandler.js +4 -0
  95. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  96. package/lib/module/web/interfaces.js.map +1 -1
  97. package/lib/module/web/tools/GestureHandlerWebDelegate.js +54 -8
  98. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  99. package/lib/module/web/tools/KeyboardEventManager.js +96 -0
  100. package/lib/module/web/tools/KeyboardEventManager.js.map +1 -0
  101. package/lib/module/web/tools/Vector.js +5 -3
  102. package/lib/module/web/tools/Vector.js.map +1 -1
  103. package/lib/module/web/utils.js +14 -13
  104. package/lib/module/web/utils.js.map +1 -1
  105. package/lib/typescript/PointerType.d.ts +2 -1
  106. package/lib/typescript/components/Pressable/index.d.ts +1 -1
  107. package/lib/typescript/components/Swipeable.d.ts +5 -0
  108. package/lib/typescript/handlers/LongPressGestureHandler.d.ts +5 -1
  109. package/lib/typescript/handlers/gestures/longPressGesture.d.ts +5 -0
  110. package/lib/typescript/mocks.d.ts +4 -3
  111. package/lib/typescript/utils.d.ts +1 -0
  112. package/lib/typescript/web/constants.d.ts +1 -1
  113. package/lib/typescript/web/handlers/GestureHandler.d.ts +1 -1
  114. package/lib/typescript/web/handlers/LongPressGestureHandler.d.ts +3 -0
  115. package/lib/typescript/web/handlers/NativeViewGestureHandler.d.ts +1 -0
  116. package/lib/typescript/web/interfaces.d.ts +1 -1
  117. package/lib/typescript/web/tools/GestureHandlerDelegate.d.ts +1 -0
  118. package/lib/typescript/web/tools/GestureHandlerWebDelegate.d.ts +6 -0
  119. package/lib/typescript/web/tools/KeyboardEventManager.d.ts +13 -0
  120. package/package.json +3 -3
  121. package/src/PointerType.ts +1 -0
  122. package/src/components/Pressable/Pressable.tsx +70 -50
  123. package/src/components/Pressable/index.ts +1 -1
  124. package/src/components/ReanimatedSwipeable.tsx +70 -47
  125. package/src/components/Swipeable.tsx +6 -0
  126. package/src/handlers/LongPressGestureHandler.ts +6 -0
  127. package/src/handlers/gestures/GestureDetector/utils.ts +2 -2
  128. package/src/handlers/gestures/longPressGesture.ts +9 -0
  129. package/src/{mocks.ts → mocks.tsx} +8 -3
  130. package/src/utils.ts +2 -0
  131. package/src/web/constants.ts +1 -1
  132. package/src/web/handlers/GestureHandler.ts +3 -1
  133. package/src/web/handlers/LongPressGestureHandler.ts +49 -10
  134. package/src/web/handlers/NativeViewGestureHandler.ts +14 -4
  135. package/src/web/handlers/PanGestureHandler.ts +4 -0
  136. package/src/web/interfaces.ts +1 -1
  137. package/src/web/tools/GestureHandlerDelegate.ts +1 -0
  138. package/src/web/tools/GestureHandlerWebDelegate.ts +67 -8
  139. package/src/web/tools/KeyboardEventManager.ts +91 -0
  140. package/src/web/tools/Vector.ts +4 -3
  141. package/src/web/utils.ts +15 -13
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
 
@@ -98,15 +95,11 @@ repositories {
98
95
 
99
96
  android {
100
97
  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
98
 
106
- if (agpVersion.tokenize('.')[0].toInteger() >= 8) {
107
- buildFeatures {
108
- buildConfig = true
109
- }
99
+ namespace "com.swmansion.gesturehandler"
100
+ buildFeatures {
101
+ buildConfig = true
102
+ prefab = true
110
103
  }
111
104
 
112
105
  // Used to override the NDK path/version on internal CI or by allowing
@@ -118,12 +111,6 @@ android {
118
111
  ndkVersion rootProject.ext.ndkVersion
119
112
  }
120
113
 
121
- if (REACT_NATIVE_MINOR_VERSION >= 71) {
122
- buildFeatures {
123
- prefab true
124
- }
125
- }
126
-
127
114
  defaultConfig {
128
115
  minSdkVersion safeExtGet('minSdkVersion', 21)
129
116
  targetSdkVersion safeExtGet('targetSdkVersion', 33)
@@ -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
@@ -5,6 +5,7 @@ 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>() {
@@ -70,6 +71,10 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
70
71
  return true
71
72
  }
72
73
 
74
+ if (handler is RNGestureHandlerRootHelper.RootViewGestureHandler) {
75
+ return true
76
+ }
77
+
73
78
  return super.shouldRecognizeSimultaneously(handler)
74
79
  }
75
80
 
@@ -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
@@ -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
  *
@@ -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) {
@@ -154,6 +154,9 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
154
154
  if (config.hasKey(KEY_LONG_PRESS_MAX_DIST)) {
155
155
  handler.setMaxDist(PixelUtil.toPixelFromDIP(config.getDouble(KEY_LONG_PRESS_MAX_DIST)))
156
156
  }
157
+ if (config.hasKey(KEY_NUMBER_OF_POINTERS)) {
158
+ handler.setNumberOfPointers(config.getInt(KEY_NUMBER_OF_POINTERS))
159
+ }
157
160
  }
158
161
 
159
162
  override fun createEventBuilder(handler: LongPressGestureHandler) = LongPressGestureHandlerEventDataBuilder(handler)
@@ -19,10 +19,8 @@ void decorateRuntime(jsi::Runtime &runtime) {
19
19
  return jsi::Value::null();
20
20
  }
21
21
 
22
- auto shadowNodeWrapper = arguments[0]
23
- .asObject(runtime).getNativeState<ShadowNodeWrapper>(runtime);
24
- bool isFormsStackingContext = shadowNodeWrapper->shadowNode->getTraits()
25
- .check(ShadowNodeTraits::FormsStackingContext);
22
+ auto shadowNode = shadowNodeFromValue(runtime, arguments[0]);
23
+ bool isFormsStackingContext = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext);
26
24
 
27
25
  return jsi::Value(isFormsStackingContext);
28
26
  });
@@ -1,3 +1,4 @@
1
+ #import "../RNGHVector.h"
1
2
  #import "RNGestureHandler.h"
2
3
 
3
4
  @interface RNFlingGestureHandler : RNGestureHandler
@@ -87,6 +87,154 @@
87
87
 
88
88
  @end
89
89
 
90
+ #else
91
+
92
+ @interface RNBetterSwipeGestureRecognizer : NSGestureRecognizer {
93
+ dispatch_block_t failFlingAction;
94
+ int maxDuration;
95
+ int minVelocity;
96
+ double defaultAlignmentCone;
97
+ double axialDeviationCosine;
98
+ double diagonalDeviationCosine;
99
+ }
100
+
101
+ @property (atomic, assign) RNGestureHandlerDirection direction;
102
+ @property (atomic, assign) int numberOfTouchesRequired;
103
+
104
+ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler;
105
+
106
+ @end
107
+
108
+ @implementation RNBetterSwipeGestureRecognizer {
109
+ __weak RNGestureHandler *_gestureHandler;
110
+
111
+ NSPoint startPosition;
112
+ double startTime;
113
+ }
114
+
115
+ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler
116
+ {
117
+ if ((self = [super initWithTarget:self action:@selector(handleGesture:)])) {
118
+ _gestureHandler = gestureHandler;
119
+
120
+ maxDuration = 1.0;
121
+ minVelocity = 700;
122
+
123
+ defaultAlignmentCone = 30;
124
+ axialDeviationCosine = [self coneToDeviation:defaultAlignmentCone];
125
+ diagonalDeviationCosine = [self coneToDeviation:(90 - defaultAlignmentCone)];
126
+ }
127
+ return self;
128
+ }
129
+
130
+ - (void)handleGesture:(NSPanGestureRecognizer *)gestureRecognizer
131
+ {
132
+ [_gestureHandler handleGesture:self];
133
+ }
134
+
135
+ - (void)mouseDown:(NSEvent *)event
136
+ {
137
+ [super mouseDown:event];
138
+
139
+ startPosition = [self locationInView:self.view];
140
+ startTime = CACurrentMediaTime();
141
+
142
+ self.state = NSGestureRecognizerStatePossible;
143
+
144
+ __weak typeof(self) weakSelf = self;
145
+
146
+ failFlingAction = dispatch_block_create(0, ^{
147
+ __strong typeof(self) strongSelf = weakSelf;
148
+
149
+ if (strongSelf) {
150
+ strongSelf.state = NSGestureRecognizerStateFailed;
151
+ }
152
+ });
153
+
154
+ dispatch_after(
155
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(maxDuration * NSEC_PER_SEC)),
156
+ dispatch_get_main_queue(),
157
+ failFlingAction);
158
+ }
159
+
160
+ - (void)mouseDragged:(NSEvent *)event
161
+ {
162
+ [super mouseDragged:event];
163
+
164
+ NSPoint currentPosition = [self locationInView:self.view];
165
+ double currentTime = CACurrentMediaTime();
166
+
167
+ NSPoint distance;
168
+ distance.x = currentPosition.x - startPosition.x;
169
+ distance.y = startPosition.y - currentPosition.y;
170
+
171
+ double timeDelta = currentTime - startTime;
172
+
173
+ Vector *velocityVector = [Vector fromVelocityX:(distance.x / timeDelta) withVelocityY:(distance.y / timeDelta)];
174
+
175
+ [self tryActivate:velocityVector];
176
+ }
177
+
178
+ - (void)mouseUp:(NSEvent *)event
179
+ {
180
+ [super mouseUp:event];
181
+
182
+ dispatch_block_cancel(failFlingAction);
183
+
184
+ self.state =
185
+ self.state == NSGestureRecognizerStateChanged ? NSGestureRecognizerStateEnded : NSGestureRecognizerStateFailed;
186
+ }
187
+
188
+ - (void)tryActivate:(Vector *)velocityVector
189
+ {
190
+ bool isAligned = NO;
191
+
192
+ for (int i = 0; i < directionsSize; ++i) {
193
+ if ([self getAlignment:axialDirections[i]
194
+ withMinimalAlignmentCosine:axialDeviationCosine
195
+ withVelocityVector:velocityVector]) {
196
+ isAligned = YES;
197
+ break;
198
+ }
199
+ }
200
+
201
+ if (!isAligned) {
202
+ for (int i = 0; i < directionsSize; ++i) {
203
+ if ([self getAlignment:diagonalDirections[i]
204
+ withMinimalAlignmentCosine:diagonalDeviationCosine
205
+ withVelocityVector:velocityVector]) {
206
+ isAligned = YES;
207
+ break;
208
+ }
209
+ }
210
+ }
211
+
212
+ bool isFastEnough = velocityVector.magnitude >= minVelocity;
213
+
214
+ if (isAligned && isFastEnough) {
215
+ self.state = NSGestureRecognizerStateChanged;
216
+ }
217
+ }
218
+
219
+ - (BOOL)getAlignment:(RNGestureHandlerDirection)direction
220
+ withMinimalAlignmentCosine:(double)minimalAlignmentCosine
221
+ withVelocityVector:(Vector *)velocityVector
222
+ {
223
+ Vector *directionVector = [Vector fromDirection:direction];
224
+ return ((self.direction & direction) == direction) &&
225
+ [velocityVector isSimilar:directionVector withThreshold:minimalAlignmentCosine];
226
+ }
227
+
228
+ - (double)coneToDeviation:(double)degrees
229
+ {
230
+ double radians = (degrees * M_PI) / 180;
231
+ return cos(radians / 2);
232
+ }
233
+
234
+ @end
235
+
236
+ #endif
237
+
90
238
  @implementation RNFlingGestureHandler
91
239
 
92
240
  - (instancetype)initWithTag:(NSNumber *)tag
@@ -100,8 +248,8 @@
100
248
  - (void)resetConfig
101
249
  {
102
250
  [super resetConfig];
103
- UISwipeGestureRecognizer *recognizer = (UISwipeGestureRecognizer *)_recognizer;
104
- recognizer.direction = UISwipeGestureRecognizerDirectionRight;
251
+ RNBetterSwipeGestureRecognizer *recognizer = (RNBetterSwipeGestureRecognizer *)_recognizer;
252
+ recognizer.direction = RNGestureHandlerDirectionRight;
105
253
  #if !TARGET_OS_TV
106
254
  recognizer.numberOfTouchesRequired = 1;
107
255
  #endif
@@ -110,7 +258,7 @@
110
258
  - (void)configure:(NSDictionary *)config
111
259
  {
112
260
  [super configure:config];
113
- UISwipeGestureRecognizer *recognizer = (UISwipeGestureRecognizer *)_recognizer;
261
+ RNBetterSwipeGestureRecognizer *recognizer = (RNBetterSwipeGestureRecognizer *)_recognizer;
114
262
 
115
263
  id prop = config[@"direction"];
116
264
  if (prop != nil) {
@@ -125,6 +273,7 @@
125
273
  #endif
126
274
  }
127
275
 
276
+ #if !TARGET_OS_OSX
128
277
  - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
129
278
  {
130
279
  RNGestureHandlerState savedState = _lastState;
@@ -154,21 +303,6 @@
154
303
  withNumberOfTouches:recognizer.numberOfTouches
155
304
  withPointerType:_pointerType];
156
305
  }
157
- @end
158
-
159
- #else
160
-
161
- @implementation RNFlingGestureHandler
162
-
163
- - (instancetype)initWithTag:(NSNumber *)tag
164
- {
165
- RCTLogWarn(@"FlingGestureHandler is not supported on macOS");
166
- if ((self = [super initWithTag:tag])) {
167
- _recognizer = [NSGestureRecognizer alloc];
168
- }
169
- return self;
170
- }
306
+ #endif
171
307
 
172
308
  @end
173
-
174
- #endif
@@ -6,6 +6,7 @@
6
6
  //
7
7
 
8
8
  #import "RNHoverHandler.h"
9
+ #import <React/UIView+React.h>
9
10
 
10
11
  #if !TARGET_OS_OSX
11
12
 
@@ -163,17 +164,58 @@ API_AVAILABLE(ios(13.4))
163
164
 
164
165
  #else
165
166
 
166
- @implementation RNHoverGestureHandler
167
+ @implementation RNHoverGestureHandler {
168
+ NSTrackingArea *trackingArea;
169
+ RNGHUIView *_view;
170
+ }
167
171
 
168
172
  - (instancetype)initWithTag:(NSNumber *)tag
169
173
  {
170
- RCTLogWarn(@"HoverGestureHandler is not supported on macOS");
171
174
  if ((self = [super initWithTag:tag])) {
172
175
  _recognizer = [NSGestureRecognizer alloc];
173
176
  }
177
+
174
178
  return self;
175
179
  }
176
180
 
181
+ - (void)bindToView:(RNGHUIView *)view
182
+ {
183
+ _view = view;
184
+
185
+ NSTrackingAreaOptions options =
186
+ NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp | NSTrackingInVisibleRect;
187
+
188
+ trackingArea = [[NSTrackingArea alloc] initWithRect:_view.bounds options:options owner:self userInfo:nil];
189
+ [_view addTrackingArea:trackingArea];
190
+ }
191
+
192
+ - (void)unbindFromView
193
+ {
194
+ [_view removeTrackingArea:trackingArea];
195
+ _view = nil;
196
+ }
197
+
198
+ - (void)mouseEntered:(NSEvent *)event
199
+ {
200
+ [self sendEventsInState:RNGestureHandlerStateBegan
201
+ forViewWithTag:_view.reactTag
202
+ withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]];
203
+ [self sendEventsInState:RNGestureHandlerStateActive
204
+ forViewWithTag:_view.reactTag
205
+ withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]];
206
+ }
207
+
208
+ - (void)mouseExited:(NSEvent *)theEvent
209
+ {
210
+ [self sendEventsInState:RNGestureHandlerStateEnd
211
+ forViewWithTag:_view.reactTag
212
+ withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]];
213
+
214
+ [self sendEventsInState:RNGestureHandlerStateUndetermined
215
+ forViewWithTag:_view.reactTag
216
+ withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]];
217
+ }
218
+
177
219
  @end
178
220
 
179
221
  #endif