react-native-gesture-handler 2.19.0 → 2.20.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. package/android/build.gradle +7 -12
  2. package/android/paper/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
  3. package/android/src/main/java/com/swmansion/gesturehandler/core/GestureUtils.kt +1 -0
  4. package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +11 -0
  5. package/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +8 -0
  6. package/android/src/main/java/com/swmansion/gesturehandler/core/StylusData.kt +103 -0
  7. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +24 -15
  8. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/HoverGestureHandlerEventDataBuilder.kt +7 -0
  9. package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/PanGestureHandlerEventDataBuilder.kt +7 -0
  10. package/android/src/main/jni/CMakeLists.txt +18 -9
  11. package/apple/Handlers/RNLongPressHandler.m +2 -0
  12. package/apple/Handlers/RNPanHandler.m +57 -7
  13. package/apple/Handlers/RNRotationHandler.m +1 -1
  14. package/apple/RNGHStylusData.h +77 -0
  15. package/apple/RNGHStylusData.m +37 -0
  16. package/apple/RNGestureHandlerButtonComponentView.mm +35 -0
  17. package/apple/RNGestureHandlerEvents.h +3 -1
  18. package/apple/RNGestureHandlerEvents.m +11 -3
  19. package/lib/commonjs/components/GestureButtons.js +5 -1
  20. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  21. package/lib/commonjs/components/GestureComponents.js.map +1 -1
  22. package/lib/commonjs/components/Pressable/Pressable.js +5 -14
  23. package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
  24. package/lib/commonjs/components/Pressable/utils.js +1 -23
  25. package/lib/commonjs/components/Pressable/utils.js.map +1 -1
  26. package/lib/commonjs/handlers/GestureHandlerEventPayload.js +4 -0
  27. package/lib/commonjs/handlers/createHandler.js +2 -1
  28. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  29. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  30. package/lib/commonjs/handlers/gestures/hoverGesture.js.map +1 -1
  31. package/lib/commonjs/jestUtils/jestUtils.js +12 -4
  32. package/lib/commonjs/jestUtils/jestUtils.js.map +1 -1
  33. package/lib/commonjs/web/handlers/GestureHandler.js +1 -3
  34. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  35. package/lib/commonjs/web/handlers/HoverGestureHandler.js +18 -1
  36. package/lib/commonjs/web/handlers/HoverGestureHandler.js.map +1 -1
  37. package/lib/commonjs/web/handlers/PanGestureHandler.js +8 -1
  38. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  39. package/lib/commonjs/web/interfaces.js.map +1 -1
  40. package/lib/commonjs/web/tools/EventManager.js.map +1 -1
  41. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +0 -3
  42. package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  43. package/lib/commonjs/web/tools/PointerEventManager.js +3 -37
  44. package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
  45. package/lib/commonjs/web/utils.js +173 -0
  46. package/lib/commonjs/web/utils.js.map +1 -1
  47. package/lib/module/components/GestureButtons.js +5 -1
  48. package/lib/module/components/GestureButtons.js.map +1 -1
  49. package/lib/module/components/GestureComponents.js.map +1 -1
  50. package/lib/module/components/Pressable/Pressable.js +7 -14
  51. package/lib/module/components/Pressable/Pressable.js.map +1 -1
  52. package/lib/module/components/Pressable/utils.js +1 -22
  53. package/lib/module/components/Pressable/utils.js.map +1 -1
  54. package/lib/module/handlers/GestureHandlerEventPayload.js +1 -1
  55. package/lib/module/handlers/createHandler.js +2 -1
  56. package/lib/module/handlers/createHandler.js.map +1 -1
  57. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  58. package/lib/module/handlers/gestures/hoverGesture.js.map +1 -1
  59. package/lib/module/jestUtils/jestUtils.js +12 -4
  60. package/lib/module/jestUtils/jestUtils.js.map +1 -1
  61. package/lib/module/web/handlers/GestureHandler.js +1 -3
  62. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  63. package/lib/module/web/handlers/HoverGestureHandler.js +18 -1
  64. package/lib/module/web/handlers/HoverGestureHandler.js.map +1 -1
  65. package/lib/module/web/handlers/PanGestureHandler.js +8 -1
  66. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  67. package/lib/module/web/interfaces.js.map +1 -1
  68. package/lib/module/web/tools/EventManager.js.map +1 -1
  69. package/lib/module/web/tools/GestureHandlerWebDelegate.js +0 -2
  70. package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
  71. package/lib/module/web/tools/PointerEventManager.js +4 -38
  72. package/lib/module/web/tools/PointerEventManager.js.map +1 -1
  73. package/lib/module/web/utils.js +170 -0
  74. package/lib/module/web/utils.js.map +1 -1
  75. package/lib/typescript/components/GestureComponents.d.ts +1 -1
  76. package/lib/typescript/components/Pressable/utils.d.ts +3 -5
  77. package/lib/typescript/handlers/GestureHandlerEventPayload.d.ts +35 -0
  78. package/lib/typescript/handlers/gestures/gesture.d.ts +2 -2
  79. package/lib/typescript/handlers/gestures/hoverGesture.d.ts +1 -6
  80. package/lib/typescript/handlers/handlersRegistry.d.ts +1 -1
  81. package/lib/typescript/jestUtils/jestUtils.d.ts +1 -1
  82. package/lib/typescript/web/handlers/HoverGestureHandler.d.ts +2 -0
  83. package/lib/typescript/web/handlers/PanGestureHandler.d.ts +3 -1
  84. package/lib/typescript/web/interfaces.d.ts +8 -3
  85. package/lib/typescript/web/tools/EventManager.d.ts +2 -2
  86. package/lib/typescript/web/utils.d.ts +2 -1
  87. package/package.json +1 -1
  88. package/src/components/GestureButtons.tsx +2 -1
  89. package/src/components/GestureComponents.tsx +1 -1
  90. package/src/components/Pressable/Pressable.tsx +16 -29
  91. package/src/components/Pressable/utils.ts +5 -49
  92. package/src/handlers/GestureHandlerEventPayload.ts +42 -0
  93. package/src/handlers/createHandler.tsx +1 -0
  94. package/src/handlers/gestures/gesture.ts +3 -1
  95. package/src/handlers/gestures/hoverGesture.ts +1 -7
  96. package/src/jestUtils/jestUtils.ts +9 -1
  97. package/src/web/handlers/GestureHandler.ts +1 -1
  98. package/src/web/handlers/HoverGestureHandler.ts +16 -2
  99. package/src/web/handlers/PanGestureHandler.ts +10 -1
  100. package/src/web/interfaces.ts +9 -3
  101. package/src/web/tools/EventManager.ts +2 -4
  102. package/src/web/tools/GestureHandlerWebDelegate.ts +0 -2
  103. package/src/web/tools/PointerEventManager.ts +2 -38
  104. package/src/web/utils.ts +174 -1
  105. package/lib/commonjs/web/tools/TouchEventManager.js +0 -164
  106. package/lib/commonjs/web/tools/TouchEventManager.js.map +0 -1
  107. package/lib/module/web/tools/TouchEventManager.js +0 -149
  108. package/lib/module/web/tools/TouchEventManager.js.map +0 -1
  109. package/lib/typescript/web/tools/TouchEventManager.d.ts +0 -11
  110. package/src/web/tools/TouchEventManager.ts +0 -175
@@ -33,16 +33,10 @@ def resolveReactNativeDirectory() {
33
33
  return file(reactNativeLocation)
34
34
  }
35
35
 
36
- // monorepo workaround
37
- // react-native can be hoisted or in project's own node_modules
38
- def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native")
39
- if (reactNativeFromProjectNodeModules.exists()) {
40
- return reactNativeFromProjectNodeModules
41
- }
42
-
43
- def reactNativeFromNodeModulesWithReanimated = file("${projectDir}/../../react-native")
44
- if (reactNativeFromNodeModulesWithReanimated.exists()) {
45
- 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
46
40
  }
47
41
 
48
42
  throw new Exception(
@@ -124,8 +118,7 @@ android {
124
118
  externalNativeBuild {
125
119
  cmake {
126
120
  cppFlags "-O2", "-frtti", "-fexceptions", "-Wall", "-Werror", "-std=c++20", "-DANDROID"
127
- arguments "-DAPP_BUILD_DIR=${appProject.buildDir}",
128
- "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
121
+ arguments "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
129
122
  "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}",
130
123
  "-DANDROID_STL=c++_shared"
131
124
  abiFilters (*reactNativeArchitectures())
@@ -153,6 +146,8 @@ android {
153
146
  // only the ones that make the build fail (ideally we should only include libgesturehandler but we
154
147
  // are only allowed to specify exclude patterns)
155
148
  exclude "**/libreact_render*.so"
149
+ exclude "**/libreactnative.so"
150
+ exclude "**/libjsi.so"
156
151
  }
157
152
 
158
153
  sourceSets.main {
@@ -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
  }
@@ -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
  }
@@ -11,6 +11,8 @@ import com.swmansion.gesturehandler.react.RNViewConfigurationHelper
11
11
  class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
12
12
  private var handler: Handler? = null
13
13
  private var finishRunnable = Runnable { finish() }
14
+ var stylusData: StylusData = StylusData()
15
+ private set
14
16
 
15
17
  private infix fun isAncestorOf(other: GestureHandler<*>): Boolean {
16
18
  var current: View? = other.view
@@ -103,6 +105,10 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
103
105
  finish()
104
106
  }
105
107
 
108
+ this.state == STATE_ACTIVE && event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS -> {
109
+ stylusData = StylusData.fromEvent(event)
110
+ }
111
+
106
112
  this.state == STATE_UNDETERMINED &&
107
113
  (event.action == MotionEvent.ACTION_HOVER_MOVE || event.action == MotionEvent.ACTION_HOVER_ENTER) -> {
108
114
  begin()
@@ -111,6 +117,11 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
111
117
  }
112
118
  }
113
119
 
120
+ override fun onReset() {
121
+ super.onReset()
122
+ stylusData = StylusData()
123
+ }
124
+
114
125
  private fun finish() {
115
126
  when (this.state) {
116
127
  STATE_UNDETERMINED -> cancel()
@@ -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() {
@@ -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
+ }
@@ -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? {
@@ -3,18 +3,21 @@ package com.swmansion.gesturehandler.react.eventbuilders
3
3
  import com.facebook.react.bridge.WritableMap
4
4
  import com.facebook.react.uimanager.PixelUtil
5
5
  import com.swmansion.gesturehandler.core.HoverGestureHandler
6
+ import com.swmansion.gesturehandler.core.StylusData
6
7
 
7
8
  class HoverGestureHandlerEventDataBuilder(handler: HoverGestureHandler) : GestureHandlerEventDataBuilder<HoverGestureHandler>(handler) {
8
9
  private val x: Float
9
10
  private val y: Float
10
11
  private val absoluteX: Float
11
12
  private val absoluteY: Float
13
+ private val stylusData: StylusData
12
14
 
13
15
  init {
14
16
  x = handler.lastRelativePositionX
15
17
  y = handler.lastRelativePositionY
16
18
  absoluteX = handler.lastPositionInWindowX
17
19
  absoluteY = handler.lastPositionInWindowY
20
+ stylusData = handler.stylusData
18
21
  }
19
22
 
20
23
  override fun buildEventData(eventData: WritableMap) {
@@ -25,6 +28,10 @@ class HoverGestureHandlerEventDataBuilder(handler: HoverGestureHandler) : Gestur
25
28
  putDouble("y", PixelUtil.toDIPFromPixel(y).toDouble())
26
29
  putDouble("absoluteX", PixelUtil.toDIPFromPixel(absoluteX).toDouble())
27
30
  putDouble("absoluteY", PixelUtil.toDIPFromPixel(absoluteY).toDouble())
31
+
32
+ if (stylusData.pressure != -1.0) {
33
+ putMap("stylusData", stylusData.toReadableMap())
34
+ }
28
35
  }
29
36
  }
30
37
  }
@@ -3,6 +3,7 @@ package com.swmansion.gesturehandler.react.eventbuilders
3
3
  import com.facebook.react.bridge.WritableMap
4
4
  import com.facebook.react.uimanager.PixelUtil
5
5
  import com.swmansion.gesturehandler.core.PanGestureHandler
6
+ import com.swmansion.gesturehandler.core.StylusData
6
7
 
7
8
  class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHandlerEventDataBuilder<PanGestureHandler>(handler) {
8
9
  private val x: Float
@@ -13,6 +14,7 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
13
14
  private val translationY: Float
14
15
  private val velocityX: Float
15
16
  private val velocityY: Float
17
+ private val stylusData: StylusData
16
18
 
17
19
  init {
18
20
  x = handler.lastRelativePositionX
@@ -23,6 +25,7 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
23
25
  translationY = handler.translationY
24
26
  velocityX = handler.velocityX
25
27
  velocityY = handler.velocityY
28
+ stylusData = handler.stylusData
26
29
  }
27
30
 
28
31
  override fun buildEventData(eventData: WritableMap) {
@@ -37,6 +40,10 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
37
40
  putDouble("translationY", PixelUtil.toDIPFromPixel(translationY).toDouble())
38
41
  putDouble("velocityX", PixelUtil.toDIPFromPixel(velocityX).toDouble())
39
42
  putDouble("velocityY", PixelUtil.toDIPFromPixel(velocityY).toDouble())
43
+
44
+ if (stylusData.pressure != -1.0) {
45
+ putMap("stylusData", stylusData.toReadableMap())
46
+ }
40
47
  }
41
48
  }
42
49
  }
@@ -26,12 +26,21 @@ target_include_directories(
26
26
  )
27
27
 
28
28
  find_package(ReactAndroid REQUIRED CONFIG)
29
-
30
- target_link_libraries(
31
- gesturehandler
32
- ReactAndroid::react_render_core
33
- ReactAndroid::react_render_uimanager
34
- ReactAndroid::react_render_graphics
35
- ReactAndroid::jsi
36
- ReactAndroid::react_nativemodule_core
37
- )
29
+ if (ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
30
+ target_link_libraries(
31
+ ${PACKAGE_NAME}
32
+ ReactAndroid::reactnative
33
+ ReactAndroid::jsi
34
+ )
35
+ elseif (ReactAndroid_VERSION_MINOR GREATER_EQUAL 75)
36
+ target_link_libraries(
37
+ ${PACKAGE_NAME}
38
+ ReactAndroid::react_render_core
39
+ ReactAndroid::react_render_uimanager
40
+ ReactAndroid::react_render_graphics
41
+ ReactAndroid::jsi
42
+ ReactAndroid::react_nativemodule_core
43
+ )
44
+ else ()
45
+ message(FATAL_ERROR "react-native-gesture-handler on the New Architecture requires react-native 0.75 or newer.")
46
+ endif ()
@@ -233,10 +233,12 @@
233
233
  recognizer.allowableMovement = [RCTConvert CGFloat:prop];
234
234
  }
235
235
 
236
+ #if !TARGET_OS_TV
236
237
  prop = config[@"numberOfPointers"];
237
238
  if (prop != nil) {
238
239
  recognizer.numberOfTouchesRequired = [RCTConvert CGFloat:prop];
239
240
  }
241
+ #endif
240
242
  }
241
243
 
242
244
  #if !TARGET_OS_OSX
@@ -7,6 +7,7 @@
7
7
  //
8
8
 
9
9
  #import "RNPanHandler.h"
10
+ #import "RNGHStylusData.h"
10
11
 
11
12
  #if TARGET_OS_OSX
12
13
 
@@ -31,6 +32,10 @@
31
32
  @property (nonatomic) CGFloat failOffsetYEnd;
32
33
  @property (nonatomic) CGFloat activateAfterLongPress;
33
34
 
35
+ #if !TARGET_OS_OSX && !TARGET_OS_TV
36
+ @property (atomic, readonly, strong) RNGHStylusData *stylusData;
37
+ #endif
38
+
34
39
  - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler;
35
40
 
36
41
  @end
@@ -80,6 +85,28 @@
80
85
  }
81
86
  #endif
82
87
 
88
+ #if !TARGET_OS_OSX && !TARGET_OS_TV
89
+ - (void)tryUpdateStylusData:(UIEvent *)event
90
+ {
91
+ UITouch *touch = [[event allTouches] anyObject];
92
+
93
+ if (touch.type != UITouchTypePencil) {
94
+ return;
95
+ } else if (_stylusData == nil) {
96
+ _stylusData = [[RNGHStylusData alloc] init];
97
+ }
98
+
99
+ _stylusData.altitudeAngle = touch.altitudeAngle;
100
+ _stylusData.azimuthAngle = [touch azimuthAngleInView:nil];
101
+ _stylusData.pressure = touch.force / touch.maximumPossibleForce;
102
+
103
+ CGPoint tilts = ghSpherical2tilt(_stylusData.altitudeAngle, _stylusData.azimuthAngle);
104
+
105
+ _stylusData.tiltX = tilts.x;
106
+ _stylusData.tiltY = tilts.y;
107
+ }
108
+ #endif
109
+
83
110
  - (void)activateAfterLongPress
84
111
  {
85
112
  self.state = UIGestureRecognizerStateBegan;
@@ -102,6 +129,8 @@
102
129
  } else {
103
130
  super.minimumNumberOfTouches = _realMinimumNumberOfTouches;
104
131
  }
132
+
133
+ [self tryUpdateStylusData:event];
105
134
  #endif
106
135
 
107
136
  #if TARGET_OS_OSX
@@ -150,17 +179,28 @@
150
179
  [self setTranslation:CGPointMake(0, 0) inView:self.view];
151
180
  }
152
181
  }
182
+
183
+ [self tryUpdateStylusData:event];
153
184
  #endif
154
185
  }
155
186
 
156
187
  - (void)interactionsEnded:(NSSet *)touches withEvent:(UIEvent *)event
157
188
  {
158
189
  [_gestureHandler.pointerTracker touchesEnded:touches withEvent:event];
190
+
191
+ #if !TARGET_OS_TV && !TARGET_OS_OSX
192
+ [self tryUpdateStylusData:event];
193
+ #endif
159
194
  }
160
195
 
161
196
  - (void)interactionsCancelled:(NSSet *)touches withEvent:(UIEvent *)event
162
197
  {
163
198
  [_gestureHandler.pointerTracker touchesCancelled:touches withEvent:event];
199
+
200
+ #if !TARGET_OS_TV && !TARGET_OS_OSX
201
+ [self tryUpdateStylusData:event];
202
+ #endif
203
+
164
204
  [self reset];
165
205
  }
166
206
 
@@ -224,6 +264,10 @@
224
264
  self.enabled = YES;
225
265
  [super reset];
226
266
  [_gestureHandler reset];
267
+
268
+ #if !TARGET_OS_TV && !TARGET_OS_OSX
269
+ _stylusData = nil;
270
+ #endif
227
271
  }
228
272
 
229
273
  - (void)updateHasCustomActivationCriteria
@@ -405,17 +449,23 @@
405
449
  withTranslation:[recognizer translationInView:recognizer.view.window.contentView]
406
450
  withVelocity:[recognizer velocityInView:recognizer.view.window.contentView]
407
451
  withNumberOfTouches:1
408
- withPointerType:RNGestureHandlerMouse];
452
+ withPointerType:RNGestureHandlerMouse
453
+ withStylusData:nil];
409
454
  }
410
455
  #else
411
456
  - (RNGestureHandlerEventExtraData *)eventExtraData:(UIPanGestureRecognizer *)recognizer
412
457
  {
413
- return [RNGestureHandlerEventExtraData forPan:[recognizer locationInView:recognizer.view]
414
- withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
415
- withTranslation:[recognizer translationInView:recognizer.view.window]
416
- withVelocity:[recognizer velocityInView:recognizer.view.window]
417
- withNumberOfTouches:recognizer.numberOfTouches
418
- withPointerType:_pointerType];
458
+ RNBetterPanGestureRecognizer *panRecognizer = (RNBetterPanGestureRecognizer *)recognizer;
459
+
460
+ return [RNGestureHandlerEventExtraData
461
+ forPan:[recognizer locationInView:recognizer.view]
462
+ withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
463
+ withTranslation:[recognizer translationInView:recognizer.view.window]
464
+ withVelocity:[recognizer velocityInView:recognizer.view.window]
465
+ withNumberOfTouches:recognizer.numberOfTouches
466
+ withPointerType:_pointerType
467
+ withStylusData:[panRecognizer.stylusData toDictionary]]; // In Objective-C calling method on nil returns
468
+ // nil, therefore this line does not crash.
419
469
  }
420
470
  #endif
421
471
 
@@ -149,7 +149,7 @@
149
149
  #if TARGET_OS_OSX
150
150
  - (RNGestureHandlerEventExtraData *)eventExtraData:(NSRotationGestureRecognizer *)recognizer
151
151
  {
152
- return [RNGestureHandlerEventExtraData forRotation:recognizer.rotation
152
+ return [RNGestureHandlerEventExtraData forRotation:-recognizer.rotation
153
153
  withAnchorPoint:[recognizer locationInView:recognizer.view]
154
154
  withVelocity:((RNBetterRotationRecognizer *)recognizer).velocity
155
155
  withNumberOfTouches:2
@@ -0,0 +1,77 @@
1
+ //
2
+ // RNGHStylusData.h
3
+ // Pods
4
+ //
5
+ // Created by Michał Bert on 18/09/2024.
6
+ //
7
+
8
+ #ifndef RNGHStylusData_h
9
+ #define RNGHStylusData_h
10
+
11
+ @interface RNGHStylusData : NSObject
12
+
13
+ @property (atomic, assign) double tiltX;
14
+ @property (atomic, assign) double tiltY;
15
+ @property (atomic, assign) double altitudeAngle;
16
+ @property (atomic, assign) double azimuthAngle;
17
+ @property (atomic, assign) double pressure;
18
+
19
+ - (NSDictionary *)toDictionary;
20
+
21
+ @end
22
+
23
+ static CGPoint ghSpherical2tilt(double altitudeAngle, double azimuthAngle)
24
+ {
25
+ CGPoint tilts = {.x = 0.0, .y = 0.0};
26
+
27
+ const double radToDeg = 180 / M_PI;
28
+ const double eps = 0.000000001;
29
+
30
+ if (altitudeAngle < eps) {
31
+ // the pen is in the X-Y plane
32
+ if (azimuthAngle < eps || fabs(azimuthAngle - 2 * M_PI) < eps) {
33
+ // pen is on positive X axis
34
+ tilts.x = M_PI_2;
35
+ }
36
+ if (fabs(azimuthAngle - M_PI_2) < eps) {
37
+ // pen is on positive Y axis
38
+ tilts.y = M_PI_2;
39
+ }
40
+ if (fabs(azimuthAngle - M_PI) < eps) {
41
+ // pen is on negative X axis
42
+ tilts.x = -M_PI_2;
43
+ }
44
+ if (fabs(azimuthAngle - 3 * M_PI_2) < eps) {
45
+ // pen is on negative Y axis
46
+ tilts.y = -M_PI_2;
47
+ }
48
+ if (azimuthAngle > eps && fabs(azimuthAngle - M_PI_2) < eps) {
49
+ tilts.x = M_PI_2;
50
+ tilts.y = M_PI_2;
51
+ }
52
+ if (fabs(azimuthAngle - M_PI_2) > eps && fabs(azimuthAngle - M_PI) < eps) {
53
+ tilts.x = -M_PI_2;
54
+ tilts.y = M_PI_2;
55
+ }
56
+ if (azimuthAngle - M_PI > eps && fabs(azimuthAngle - 3 * M_PI_2) < eps) {
57
+ tilts.x = -M_PI_2;
58
+ tilts.y = -M_PI_2;
59
+ }
60
+ if (fabs(azimuthAngle - 3 * M_PI_2) > eps && fabs(azimuthAngle - 2 * M_PI) < eps) {
61
+ tilts.x = M_PI_2;
62
+ tilts.y = -M_PI_2;
63
+ }
64
+ } else {
65
+ const double tanAlt = tan(altitudeAngle);
66
+
67
+ tilts.x = atan(cos(azimuthAngle) / tanAlt);
68
+ tilts.y = atan(sin(azimuthAngle) / tanAlt);
69
+ }
70
+
71
+ tilts.x = round(tilts.x * radToDeg);
72
+ tilts.y = round(tilts.y * radToDeg);
73
+
74
+ return tilts;
75
+ }
76
+
77
+ #endif /* RNGHStylusData_h */
@@ -0,0 +1,37 @@
1
+ //
2
+ // RNGHStylusData.m
3
+ // DoubleConversion
4
+ //
5
+ // Created by Michał Bert on 18/09/2024.
6
+ //
7
+
8
+ #import "RNGHStylusData.h"
9
+ #import <Foundation/Foundation.h>
10
+
11
+ @implementation RNGHStylusData
12
+
13
+ - (instancetype)init
14
+ {
15
+ if (self = [super init]) {
16
+ self.tiltX = 0;
17
+ self.tiltY = 0;
18
+ self.altitudeAngle = M_PI_2;
19
+ self.azimuthAngle = 0;
20
+ self.pressure = 0;
21
+ }
22
+
23
+ return self;
24
+ }
25
+
26
+ - (NSDictionary *)toDictionary
27
+ {
28
+ return @{
29
+ @"tiltX" : @(_tiltX),
30
+ @"tiltY" : @(_tiltY),
31
+ @"altitudeAngle" : @(_altitudeAngle),
32
+ @"azimuthAngle" : @(_azimuthAngle),
33
+ @"pressure" : @(_pressure),
34
+ };
35
+ }
36
+
37
+ @end