Skip to content

Commit 66390ab

Browse files
committed
android
1 parent 6f45a33 commit 66390ab

File tree

11 files changed

+397
-25
lines changed

11 files changed

+397
-25
lines changed

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ open class GestureHandler {
3131
var tag = 0
3232
var view: View? = null
3333
private set
34+
35+
// parent view is used for logicDetector
36+
var parentView: RNGestureHandlerDetectorView? = null
37+
3438
val viewForEvents: RNGestureHandlerDetectorView
3539
get() {
36-
assert(actionType == ACTION_TYPE_NATIVE_DETECTOR) {
40+
assert(actionType == ACTION_TYPE_NATIVE_DETECTOR || actionType == ACTION_TYPE_LOGIC_DETECTOR) {
3741
"[react-native-gesture-handler] `viewForEvents` can only be used with NativeDetector."
3842
}
3943

@@ -996,6 +1000,8 @@ open class GestureHandler {
9961000
const val ACTION_TYPE_JS_FUNCTION_OLD_API = 3
9971001
const val ACTION_TYPE_JS_FUNCTION_NEW_API = 4
9981002
const val ACTION_TYPE_NATIVE_DETECTOR = 5
1003+
1004+
const val ACTION_TYPE_LOGIC_DETECTOR = 6
9991005
const val POINTER_TYPE_TOUCH = 0
10001006
const val POINTER_TYPE_STYLUS = 1
10011007
const val POINTER_TYPE_MOUSE = 2

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
1616
private var nativeHandlers: MutableSet<Int> = mutableSetOf()
1717
private var attachedHandlers: MutableSet<Int> = mutableSetOf()
1818
private var moduleId: Int = -1
19+
private var logicChildren: HashMap<Int, LogicChild> = hashMapOf()
20+
21+
class LogicChild {
22+
var handlerTags: List<Int>? = null
23+
var attachedHandlers: MutableSet<Int> = mutableSetOf()
24+
}
25+
26+
data class LogicProps(val handlerTags: List<Int>, val moduleId: Int, val viewTag: Int)
1927

2028
fun setHandlerTags(handlerTags: ReadableArray?) {
2129
val newHandlers = handlerTags?.toArrayList()?.map { (it as Double).toInt() } ?: emptyList()
@@ -26,17 +34,58 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
2634
return
2735
}
2836

29-
attachHandlers(newHandlers)
37+
attachHandlers(newHandlers, this.id, false, attachedHandlers)
3038
}
3139

3240
fun setModuleId(id: Int) {
3341
assert(this.moduleId == -1) { "Tried to change moduleId of a native detector" }
3442

3543
this.moduleId = id
36-
this.attachHandlers(handlersToAttach ?: return)
44+
this.attachHandlers(handlersToAttach ?: return, this.id, false, attachedHandlers)
3745
handlersToAttach = null
3846
}
3947

48+
fun setLogicChildren(newLogicChildren: ReadableArray?) {
49+
val shouldKeepLogicChild = HashMap<Int, Boolean>()
50+
for (child in logicChildren) {
51+
shouldKeepLogicChild[child.key] = false
52+
}
53+
val mappedChildren = mutableListOf<LogicProps>()
54+
55+
for (i in 0 until newLogicChildren!!.size()) {
56+
val child = newLogicChildren.getMap(i) // Each element should be a ReadableMap
57+
58+
val handlerTagsArray = child!!.getArray("handlerTags")
59+
val handlerTags = mutableListOf<Int>()
60+
for (j in 0 until handlerTagsArray!!.size()) {
61+
handlerTags.add(handlerTagsArray.getInt(j))
62+
}
63+
64+
val moduleId = child.getInt("moduleId")
65+
val viewTag = child.getInt("viewTag")
66+
67+
mappedChildren.add(
68+
LogicProps(
69+
handlerTags = handlerTags,
70+
moduleId = moduleId,
71+
viewTag = viewTag,
72+
),
73+
)
74+
}
75+
76+
for (child in logicChildren) {
77+
shouldKeepLogicChild[child.key] = false
78+
}
79+
80+
for (child in mappedChildren) {
81+
if (!logicChildren.containsKey(child.viewTag)) {
82+
logicChildren.put(child.viewTag, LogicChild())
83+
}
84+
shouldKeepLogicChild[child.viewTag] = true
85+
attachHandlers(child.handlerTags, child.viewTag, true, logicChildren[child.viewTag]!!.attachedHandlers)
86+
}
87+
}
88+
4089
private fun shouldAttachGestureToChildView(tag: Int): Boolean {
4190
val registry = RNGestureHandlerModule.registries[moduleId]
4291
?: throw Exception("Tried to access a non-existent registry")
@@ -57,7 +106,12 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
57106
super.removeViewAt(index)
58107
}
59108

60-
private fun attachHandlers(newHandlers: List<Int>) {
109+
private fun attachHandlers(
110+
newHandlers: List<Int>,
111+
viewTag: Int,
112+
isLogic: Boolean,
113+
attachedHandlers: MutableSet<Int>,
114+
) {
61115
val registry = RNGestureHandlerModule.registries[moduleId]
62116
?: throw Exception("Tried to access a non-existent registry")
63117

@@ -71,6 +125,12 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
71125
changes[tag] = if (changes.containsKey(tag)) GestureHandlerMutation.Keep else GestureHandlerMutation.Attach
72126
}
73127

128+
val actionType = if (isLogic) {
129+
GestureHandler.ACTION_TYPE_LOGIC_DETECTOR
130+
} else {
131+
GestureHandler.ACTION_TYPE_NATIVE_DETECTOR
132+
}
133+
74134
for (entry in changes) {
75135
val tag = entry.key
76136

@@ -80,7 +140,10 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
80140
// attach `NativeViewGestureHandlers` here and we have to do it in `addView` method.
81141
nativeHandlers.add(tag)
82142
} else {
83-
registry.attachHandlerToView(tag, this.id, GestureHandler.ACTION_TYPE_NATIVE_DETECTOR)
143+
registry.attachHandlerToView(tag, viewTag, actionType)
144+
if (isLogic) {
145+
registry.getHandler(tag)?.parentView = this
146+
}
84147
attachedHandlers.add(tag)
85148
}
86149
} else if (entry.value == GestureHandlerMutation.Detach) {
@@ -132,6 +195,13 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
132195
registry.detachHandler(tag)
133196
attachedHandlers.remove(tag)
134197
}
198+
199+
for (child in logicChildren) {
200+
for (tag in child.value.attachedHandlers) {
201+
registry.detachHandler(tag)
202+
}
203+
child.value.attachedHandlers.clear()
204+
}
135205
}
136206

137207
companion object {

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorViewManager.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class RNGestureHandlerDetectorViewManager :
3737
view.setModuleId(value)
3838
}
3939

40+
override fun setLogicChildren(view: RNGestureHandlerDetectorView?, value: ReadableArray?) {
41+
view?.setLogicChildren(value)
42+
}
43+
4044
override fun onDropViewInstance(view: RNGestureHandlerDetectorView) {
4145
view.onViewDrop()
4246
super.onDropViewInstance(view)

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEventDispatcher.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ class RNGestureHandlerEventDispatcher(private val reactApplicationContext: React
8686

8787
handler.viewForEvents!!.dispatchEvent(event)
8888
}
89+
GestureHandler.ACTION_TYPE_LOGIC_DETECTOR -> {
90+
val event = RNGestureHandlerEvent.obtain(
91+
handler,
92+
handler.actionType,
93+
handlerFactory.createEventBuilder(handler),
94+
)
95+
96+
handler.parentView?.dispatchEvent(event)
97+
}
8998
}
9099
}
91100

@@ -142,6 +151,17 @@ class RNGestureHandlerEventDispatcher(private val reactApplicationContext: React
142151

143152
handler.viewForEvents!!.dispatchEvent(event)
144153
}
154+
155+
GestureHandler.ACTION_TYPE_LOGIC_DETECTOR -> {
156+
val event = RNGestureHandlerLogicStateChangeEvent.obtain(
157+
handler,
158+
newState,
159+
oldState,
160+
handler.actionType,
161+
handlerFactory.createEventBuilder(handler),
162+
)
163+
handler.parentView?.dispatchEvent(event)
164+
}
145165
}
146166
}
147167

@@ -177,6 +197,11 @@ class RNGestureHandlerEventDispatcher(private val reactApplicationContext: React
177197

178198
handler.viewForEvents!!.dispatchEvent(event)
179199
}
200+
GestureHandler.ACTION_TYPE_LOGIC_DETECTOR -> {
201+
val event = RNGestureHandlerLogicTouchEvent.obtain(handler, handler.actionType)
202+
203+
handler.parentView?.dispatchEvent(event)
204+
}
180205
}
181206
}
182207

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// 1. RCTEventEmitter was deprecated in favor of RCTModernEventEmitter interface
2+
// 2. Event#init() with only viewTag was deprecated in favor of two arg c-tor
3+
// 3. Event#receiveEvent() with 3 args was deprecated in favor of 4 args version
4+
// ref: https://github.com/facebook/react-native/commit/2fbbdbb2ce897e8da3f471b08b93f167d566db1d
5+
@file:Suppress("DEPRECATION")
6+
7+
package com.swmansion.gesturehandler.react
8+
9+
import androidx.core.util.Pools
10+
import com.facebook.react.bridge.Arguments
11+
import com.facebook.react.bridge.WritableMap
12+
import com.facebook.react.uimanager.UIManagerHelper
13+
import com.facebook.react.uimanager.events.Event
14+
import com.swmansion.gesturehandler.core.GestureHandler
15+
import com.swmansion.gesturehandler.react.eventbuilders.GestureHandlerEventDataBuilder
16+
17+
class RNGestureHandlerLogicEvent private constructor() : Event<RNGestureHandlerLogicEvent>() {
18+
private var dataBuilder: GestureHandlerEventDataBuilder<*>? = null
19+
private var coalescingKey: Short = 0
20+
private var actionType: Int = GestureHandler.ACTION_TYPE_LOGIC_DETECTOR
21+
private var childTag: Int? = null
22+
23+
private fun <T : GestureHandler> init(handler: T, actionType: Int, dataBuilder: GestureHandlerEventDataBuilder<T>) {
24+
val view = handler.parentView!!
25+
26+
super.init(UIManagerHelper.getSurfaceId(view), view.id)
27+
28+
this.dataBuilder = dataBuilder
29+
coalescingKey = handler.eventCoalescingKey
30+
this.actionType = actionType
31+
32+
this.childTag = handler.view!!.id
33+
}
34+
35+
override fun onDispose() {
36+
dataBuilder = null
37+
EVENTS_POOL.release(this)
38+
}
39+
40+
override fun getEventName() = EVENT_NAME
41+
42+
override fun canCoalesce() = true
43+
44+
override fun getCoalescingKey() = coalescingKey
45+
46+
override fun getEventData(): WritableMap = createNativeEventData(dataBuilder!!, childTag)
47+
48+
companion object {
49+
const val EVENT_NAME = "onGestureHandlerLogicEvent"
50+
private const val TOUCH_EVENTS_POOL_SIZE = 7 // magic
51+
private val EVENTS_POOL = Pools.SynchronizedPool<RNGestureHandlerLogicEvent>(TOUCH_EVENTS_POOL_SIZE)
52+
53+
fun <T : GestureHandler> obtain(
54+
handler: T,
55+
actionType: Int,
56+
dataBuilder: GestureHandlerEventDataBuilder<T>,
57+
): RNGestureHandlerLogicEvent = (EVENTS_POOL.acquire() ?: RNGestureHandlerLogicEvent()).apply {
58+
init(handler, actionType, dataBuilder)
59+
}
60+
61+
fun createNativeEventData(dataBuilder: GestureHandlerEventDataBuilder<*>, childTag: Int?): WritableMap =
62+
Arguments.createMap().apply {
63+
putMap(
64+
"handlerData",
65+
Arguments.createMap().apply {
66+
dataBuilder.buildEventData(this)
67+
},
68+
)
69+
putInt("handlerTag", dataBuilder.handlerTag)
70+
putInt("state", dataBuilder.state)
71+
if (childTag != null) {
72+
putInt("childTag", childTag)
73+
}
74+
}
75+
}
76+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// 1. RCTEventEmitter was deprecated in favor of RCTModernEventEmitter interface
2+
// 2. Event#init() with only viewTag was deprecated in favor of two arg c-tor
3+
// 3. Event#receiveEvent() with 3 args was deprecated in favor of 4 args version
4+
// ref: https://github.com/facebook/react-native/commit/2fbbdbb2ce897e8da3f471b08b93f167d566db1d
5+
@file:Suppress("DEPRECATION")
6+
7+
package com.swmansion.gesturehandler.react
8+
9+
import androidx.core.util.Pools
10+
import com.facebook.react.bridge.Arguments
11+
import com.facebook.react.bridge.WritableMap
12+
import com.facebook.react.uimanager.UIManagerHelper
13+
import com.facebook.react.uimanager.events.Event
14+
import com.swmansion.gesturehandler.core.GestureHandler
15+
import com.swmansion.gesturehandler.react.eventbuilders.GestureHandlerEventDataBuilder
16+
17+
class RNGestureHandlerLogicStateChangeEvent private constructor() : Event<RNGestureHandlerLogicStateChangeEvent>() {
18+
private var dataBuilder: GestureHandlerEventDataBuilder<*>? = null
19+
private var newState: Int = GestureHandler.STATE_UNDETERMINED
20+
private var oldState: Int = GestureHandler.STATE_UNDETERMINED
21+
private var actionType: Int = GestureHandler.ACTION_TYPE_LOGIC_DETECTOR
22+
private var childTag: Int? = null
23+
private fun <T : GestureHandler> init(
24+
handler: T,
25+
newState: Int,
26+
oldState: Int,
27+
actionType: Int,
28+
dataBuilder: GestureHandlerEventDataBuilder<T>,
29+
) {
30+
val view = handler.parentView!!
31+
32+
super.init(UIManagerHelper.getSurfaceId(view), view.id)
33+
34+
this.dataBuilder = dataBuilder
35+
this.newState = newState
36+
this.oldState = oldState
37+
this.actionType = actionType
38+
39+
this.childTag = handler.view!!.id
40+
}
41+
42+
override fun onDispose() {
43+
dataBuilder = null
44+
newState = GestureHandler.STATE_UNDETERMINED
45+
oldState = GestureHandler.STATE_UNDETERMINED
46+
EVENTS_POOL.release(this)
47+
}
48+
49+
override fun getEventName() = EVENT_NAME
50+
51+
// TODO: coalescing
52+
override fun canCoalesce() = false
53+
54+
// TODO: coalescing
55+
override fun getCoalescingKey(): Short = 0
56+
57+
override fun getEventData(): WritableMap = createNativeEventData(dataBuilder!!, newState, oldState, childTag)
58+
59+
companion object {
60+
const val EVENT_NAME = "onGestureHandlerLogicStateChange"
61+
private const val TOUCH_EVENTS_POOL_SIZE = 7 // magic
62+
private val EVENTS_POOL = Pools.SynchronizedPool<RNGestureHandlerLogicStateChangeEvent>(
63+
TOUCH_EVENTS_POOL_SIZE,
64+
)
65+
66+
fun <T : GestureHandler> obtain(
67+
handler: T,
68+
newState: Int,
69+
oldState: Int,
70+
actionType: Int,
71+
dataBuilder: GestureHandlerEventDataBuilder<T>,
72+
): RNGestureHandlerLogicStateChangeEvent = (
73+
EVENTS_POOL.acquire()
74+
?: RNGestureHandlerLogicStateChangeEvent()
75+
).apply {
76+
init(handler, newState, oldState, actionType, dataBuilder)
77+
}
78+
79+
fun createNativeEventData(
80+
dataBuilder: GestureHandlerEventDataBuilder<*>,
81+
newState: Int,
82+
oldState: Int,
83+
childTag: Int?,
84+
): WritableMap = Arguments.createMap().apply {
85+
putMap(
86+
"handlerData",
87+
Arguments.createMap().apply {
88+
dataBuilder.buildEventData(this)
89+
},
90+
)
91+
putInt("handlerTag", dataBuilder.handlerTag)
92+
putInt("state", newState)
93+
putInt("oldState", oldState)
94+
if (childTag != null) {
95+
putInt("childTag", childTag)
96+
}
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)