Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Gesture Handler to TurboModule #2354

Merged
merged 18 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,90 @@
package com.swmansion.gesturehandler

import com.facebook.react.ReactPackage
import com.facebook.react.TurboReactPackage
import com.facebook.react.ViewManagerOnDemandReactPackage
import com.facebook.react.bridge.ModuleSpec
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.module.model.ReactModuleInfo
import com.facebook.react.module.model.ReactModuleInfoProvider
import com.facebook.react.turbomodule.core.interfaces.TurboModule
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
import com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager
import com.swmansion.gesturehandler.react.RNGestureHandlerModule
import com.swmansion.gesturehandler.react.RNGestureHandlerRootViewManager

class RNGestureHandlerPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf<NativeModule>(RNGestureHandlerModule(reactContext))
}
class RNGestureHandlerPackage : TurboReactPackage(), ViewManagerOnDemandReactPackage {
private var _viewManagers: Map<String, ModuleSpec>? = null
private val viewManagers: Map<String, ModuleSpec>
get() {
if (_viewManagers == null) {
_viewManagers = mutableMapOf(
RNGestureHandlerRootViewManager.REACT_CLASS to ModuleSpec.viewManagerSpec {
RNGestureHandlerRootViewManager()
},
RNGestureHandlerButtonViewManager.REACT_CLASS to ModuleSpec.viewManagerSpec {
RNGestureHandlerButtonViewManager()
}
)
}

return _viewManagers!!
}

override fun createViewManagers(reactContext: ReactApplicationContext) =
listOf<ViewManager<*, *>>(
RNGestureHandlerRootViewManager(),
RNGestureHandlerButtonViewManager()
)

override fun getViewManagerNames(reactContext: ReactApplicationContext?) =
viewManagers.keys.toList()

override fun getViewManagers(reactContext: ReactApplicationContext?): MutableList<ModuleSpec> =
viewManagers.values.toMutableList()

override fun createViewManager(
reactContext: ReactApplicationContext?,
viewManagerName: String?
): ViewManager<*, out ReactShadowNode<*>>? {
j-piasecki marked this conversation as resolved.
Show resolved Hide resolved
return viewManagers[viewManagerName]?.provider?.get() as? ViewManager<*, *>
}

override fun getModule(name: String?, reactContext: ReactApplicationContext?): NativeModule? {
return if (name == RNGestureHandlerModule.MODULE_NAME) {
RNGestureHandlerModule(reactContext)
} else {
null
}
}

override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
try {
val reactModuleInfoProviderClass =
Class.forName("com.swmansion.gesturehandler.RNGestureHandlerPackage$\$ReactModuleInfoProvider")
return reactModuleInfoProviderClass.newInstance() as ReactModuleInfoProvider
} catch (e: ClassNotFoundException) {
return ReactModuleInfoProvider {
val reactModule: ReactModule = RNGestureHandlerModule::class.java.getAnnotation(ReactModule::class.java)!!

mutableMapOf(
RNGestureHandlerModule.MODULE_NAME to ReactModuleInfo(
reactModule.name,
RNGestureHandlerModule::class.java.name,
reactModule.canOverrideExistingModule,
reactModule.needsEagerInit,
reactModule.hasConstants,
reactModule.isCxxModule,
TurboModule::class.java.isAssignableFrom(RNGestureHandlerModule::class.java)
)
)
}
} catch (e: InstantiationException) {
throw RuntimeException("No ReactModuleInfoProvider for RNGestureHandlerPackage$\$ReactModuleInfoProvider", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("No ReactModuleInfoProvider for RNGestureHandlerPackage$\$ReactModuleInfoProvider", e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import android.view.MotionEvent
import com.facebook.react.ReactRootView
import com.facebook.react.bridge.JSApplicationIllegalArgumentException
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.ReadableType
import com.facebook.react.bridge.WritableMap
Expand All @@ -17,6 +15,7 @@ import com.facebook.react.uimanager.events.Event
import com.facebook.soloader.SoLoader
import com.swmansion.common.GestureHandlerStateManager
import com.swmansion.gesturehandler.BuildConfig
import com.swmansion.gesturehandler.NativeRNGestureHandlerModuleSpec
import com.swmansion.gesturehandler.ReanimatedEventDispatcher
import com.swmansion.gesturehandler.core.FlingGestureHandler
import com.swmansion.gesturehandler.core.GestureHandler
Expand All @@ -38,7 +37,7 @@ import com.swmansion.gesturehandler.dispatchEvent
@Suppress("DEPRECATION")
@ReactModule(name = RNGestureHandlerModule.MODULE_NAME)
class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
ReactContextBaseJavaModule(reactContext), GestureHandlerStateManager {
NativeRNGestureHandlerModuleSpec(reactContext), GestureHandlerStateManager {
private abstract class HandlerFactory<T : GestureHandler<T>> : RNGestureHandlerEventDataExtractor<T> {
abstract val type: Class<T>
abstract val name: String
Expand Down Expand Up @@ -366,9 +365,7 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
private val reanimatedEventDispatcher = ReanimatedEventDispatcher()
override fun getName() = MODULE_NAME

@ReactMethod
@Suppress("UNCHECKED_CAST")
fun <T : GestureHandler<T>> createGestureHandler(
fun <T : GestureHandler<T>> createGestureHandlerHelper(
handlerName: String,
handlerTag: Int,
config: ReadableMap,
Expand All @@ -388,8 +385,21 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
throw JSApplicationIllegalArgumentException("Invalid handler name $handlerName")
}

@ReactMethod
j-piasecki marked this conversation as resolved.
Show resolved Hide resolved
fun attachGestureHandler(handlerTag: Int, viewTag: Int, actionType: Int) {
@Suppress("UNCHECKED_CAST")
override fun createGestureHandler(
handlerName: String,
handlerTagDouble: Double,
config: ReadableMap,
) {
val handlerTag = handlerTagDouble.toInt()

createGestureHandlerHelper<GestureHandler<*>>(handlerName, handlerTag, config)
}

override fun attachGestureHandler(handlerTagDouble: Double, viewTagDouble: Double, actionTypeDouble: Double) {
val handlerTag = handlerTagDouble.toInt()
val viewTag = viewTagDouble.toInt()
val actionType = actionTypeDouble.toInt()
// We don't have to handle view flattening in any special way since handlers are stored as
// a map: viewTag -> [handler]. If the view with attached handlers was to be flattened
// then that viewTag simply wouldn't be visited when traversing the view hierarchy in the
Expand All @@ -399,9 +409,7 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
}
}

@ReactMethod
@Suppress("UNCHECKED_CAST")
fun <T : GestureHandler<T>> updateGestureHandler(handlerTag: Int, config: ReadableMap) {
private fun <T : GestureHandler<T>> updateGestureHandlerHelper(handlerTag: Int, config: ReadableMap) {
val handler = registry.getHandler(handlerTag) as T?
if (handler != null) {
val factory = findFactoryForHandler(handler)
Expand All @@ -413,20 +421,29 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
}
}

@ReactMethod
fun dropGestureHandler(handlerTag: Int) {
@Suppress("UNCHECKED_CAST")
override fun updateGestureHandler(handlerTagDouble: Double, config: ReadableMap) {
val handlerTag = handlerTagDouble.toInt()

updateGestureHandlerHelper(handlerTag, config)
}

override fun dropGestureHandler(handlerTagDouble: Double) {
val handlerTag = handlerTagDouble.toInt()
interactionManager.dropRelationsForHandlerWithTag(handlerTag)
registry.dropHandler(handlerTag)
}

@ReactMethod
fun handleSetJSResponder(viewTag: Int, blockNativeResponder: Boolean) {
override fun handleSetJSResponder(viewTagDouble: Double, blockNativeResponder: Boolean) {
val viewTag = viewTagDouble.toInt()
val rootView = findRootHelperForViewAncestor(viewTag)
rootView?.handleSetJSResponder(viewTag, blockNativeResponder)
}

@ReactMethod
fun handleClearJSResponder() {
override fun handleClearJSResponder() {
}

override fun flushOperations() {
}

override fun setGestureHandlerState(handlerTag: Int, newState: Int) {
Expand All @@ -441,16 +458,13 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
}
}

@ReactMethod(isBlockingSynchronousMethod = true)
fun install(): Boolean {
return try {
override fun install() {
try {
SoLoader.loadLibrary("gesturehandler")
val jsContext = reactApplicationContext.javaScriptContextHolder
decorateRuntime(jsContext.get())
true
// decorateRuntime(jsContext.get())
} catch (exception: Exception) {
Log.w("[RNGestureHandler]", "Could not install JSI bindings.")
false
}
}

Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@
],
"codegenConfig": {
"name": "rngesturehandler_codegen",
j-piasecki marked this conversation as resolved.
Show resolved Hide resolved
"type": "components",
"jsSrcsDir": "./src/fabric"
"type": "all",
"jsSrcsDir": "./src/fabric",
"android": {
"javaPackageName": "com.swmansion.gesturehandler"
}
}
}
95 changes: 50 additions & 45 deletions src/RNGestureHandlerModule.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,55 @@
import { NativeModules } from 'react-native';
import { ActionType } from './ActionType';
import { tagMessage } from './utils';
const { RNGestureHandlerModule } = NativeModules;
// import { NativeModules } from 'react-native';
// import { ActionType } from './ActionType';
// import { tagMessage } from './utils';
// const { RNGestureHandlerModule } = NativeModules;

if (RNGestureHandlerModule == null) {
console.error(
tagMessage(
`react-native-gesture-handler module was not found. Make sure you're running your app on the native platform and your code is linked properly (cd ios && pod install && cd ..).
// if (RNGestureHandlerModule == null) {
// console.error(
// tagMessage(
// `react-native-gesture-handler module was not found. Make sure you're running your app on the native platform and your code is linked properly (cd ios && pod install && cd ..).

For installation instructions, please refer to https://docs.swmansion.com/react-native-gesture-handler/docs/#installation`
.split('\n')
.map((line) => line.trim())
.join('\n')
)
);
}
// For installation instructions, please refer to https://docs.swmansion.com/react-native-gesture-handler/docs/#installation`
// .split('\n')
// .map((line) => line.trim())
// .join('\n')
// )
// );
// }

if (
RNGestureHandlerModule &&
RNGestureHandlerModule.flushOperations === undefined
) {
RNGestureHandlerModule.flushOperations = () => {
// NO-OP if not defined
};
}
// if (
// RNGestureHandlerModule &&
// RNGestureHandlerModule.flushOperations === undefined
// ) {
// RNGestureHandlerModule.flushOperations = () => {
// // NO-OP if not defined
// };
// }

export type RNGestureHandlerModuleProps = {
handleSetJSResponder: (tag: number, blockNativeResponder: boolean) => void;
handleClearJSResponder: () => void;
createGestureHandler: (
handlerName: string,
handlerTag: number,
config: Readonly<Record<string, unknown>>
) => void;
attachGestureHandler: (
handlerTag: number,
newView: number,
actionType: ActionType
) => void;
updateGestureHandler: (
handlerTag: number,
newConfig: Readonly<Record<string, unknown>>
) => void;
dropGestureHandler: (handlerTag: number) => void;
install: () => void;
flushOperations: () => void;
};
// export type RNGestureHandlerModuleProps = {
// handleSetJSResponder: (tag: number, blockNativeResponder: boolean) => void;
// handleClearJSResponder: () => void;
// createGestureHandler: (
// handlerName: string,
// handlerTag: number,
// config: Readonly<Record<string, unknown>>
// ) => void;
// attachGestureHandler: (
// handlerTag: number,
// newView: number,
// actionType: ActionType
// ) => void;
// updateGestureHandler: (
// handlerTag: number,
// newConfig: Readonly<Record<string, unknown>>
// ) => void;
// dropGestureHandler: (handlerTag: number) => void;
// install: () => void;
// flushOperations: () => void;
// };

export default RNGestureHandlerModule as RNGestureHandlerModuleProps;
// export default RNGestureHandlerModule as RNGestureHandlerModuleProps;

// TODO: do this the right way

import Module from './fabric/NativeRNGestureHandlerModule';
export default Module;
26 changes: 26 additions & 0 deletions src/fabric/NativeRNGestureHandlerModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { TurboModuleRegistry, TurboModule } from 'react-native';
import { Int32 } from 'react-native/Libraries/Types/CodegenTypes';

export interface Spec extends TurboModule {
handleSetJSResponder: (tag: Int32, blockNativeResponder: boolean) => void;
handleClearJSResponder: () => void;
createGestureHandler: (
handlerName: string,
handlerTag: Int32,
// Record<> is not supported by codegen
// eslint-disable-next-line @typescript-eslint/ban-types
j-piasecki marked this conversation as resolved.
Show resolved Hide resolved
config: Object
) => void;
attachGestureHandler: (
handlerTag: Int32,
newView: Int32,
actionType: Int32
) => void;
// eslint-disable-next-line @typescript-eslint/ban-types
updateGestureHandler: (handlerTag: Int32, newConfig: Object) => void;
dropGestureHandler: (handlerTag: Int32) => void;
install: () => void;
flushOperations: () => void;
}

export default TurboModuleRegistry.getEnforcing<Spec>('RNGestureHandlerModule');
2 changes: 1 addition & 1 deletion src/handlers/gestures/GestureDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ export const GestureDetector = (props: GestureDetectorProps) => {
//@ts-ignore Just setting the ref
viewRef.current = ref;

if (isFabric()) {
if (isFabric() && global.isFormsStackingContext) {
const node = getShadowNodeFromRef(ref);
if (global.isFormsStackingContext(node) === false) {
console.error(
Expand Down