Skip to content
Open
Show file tree
Hide file tree
Changes from all 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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this class will be really closely tied to react so my comment from previous PR might be difficult to implement but maybe we can in the future pass this view (part of react impl) to container constructor (native impl) and everything will be nicely separated.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ package com.swmansion.rnscreens.gamma.modals.formsheet

import android.annotation.SuppressLint
import android.content.Context
import android.view.MotionEvent
import android.view.View
import android.view.ViewTreeObserver
import com.facebook.react.bridge.UIManager
import com.facebook.react.bridge.UIManagerListener
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.config.ReactFeatureFlags
import com.facebook.react.uimanager.JSPointerDispatcher
import com.facebook.react.uimanager.JSTouchDispatcher
import com.facebook.react.uimanager.RootView
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.common.UIManagerType
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.views.view.ReactViewGroup
import com.swmansion.rnscreens.gamma.helpers.getFabricUIManagerNotNull

Expand All @@ -17,16 +25,30 @@ class FormSheetContentView(
context: Context,
private val onSizeChangedCallback: (width: Int, height: Int) -> Unit,
) : ReactViewGroup(context),
RootView,
UIManagerListener,
ViewTreeObserver.OnPreDrawListener {
private val themedReactContext = context as? ThemedReactContext
private val themedReactContext: ThemedReactContext
get() = context as ThemedReactContext
private val jsTouchDispatcher = JSTouchDispatcher(this)
private var jsPointerDispatcher: JSPointerDispatcher? = null

// TODO: @t0maboro - refactor in EventEmitter PR
private val eventDispatcher: EventDispatcher?
get() = UIManagerHelper.getEventDispatcher(themedReactContext, UIManagerType.FABRIC)

private var isWaitingForFabricMount = false

init {
if (ReactFeatureFlags.dispatchPointerEvents) {
jsPointerDispatcher = JSPointerDispatcher(this)
}
}

override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewTreeObserver.addOnPreDrawListener(this)
themedReactContext?.let { themedContext ->
themedReactContext.let { themedContext ->
UIManagerHelper
.getFabricUIManagerNotNull(themedContext)
.addUIManagerEventListener(this)
Expand All @@ -36,7 +58,7 @@ class FormSheetContentView(
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
viewTreeObserver.removeOnPreDrawListener(this)
themedReactContext?.let { themedContext ->
themedReactContext.let { themedContext ->
UIManagerHelper
.getFabricUIManagerNotNull(themedContext)
.removeUIManagerEventListener(this)
Expand Down Expand Up @@ -73,4 +95,61 @@ class FormSheetContentView(
override fun didMountItems(uiManager: UIManager) = Unit

override fun didScheduleMountItems(uiManager: UIManager) = Unit

override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
eventDispatcher?.let { eventDispatcher ->
jsTouchDispatcher.handleTouchEvent(event, eventDispatcher, themedReactContext)
jsPointerDispatcher?.handleMotionEvent(event, eventDispatcher, true)
}
return super.onInterceptTouchEvent(event)
}

@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
eventDispatcher?.let { eventDispatcher ->
jsTouchDispatcher.handleTouchEvent(event, eventDispatcher, themedReactContext)
jsPointerDispatcher?.handleMotionEvent(event, eventDispatcher, false)
}
super.onTouchEvent(event)
// In case when there is no children interested in handling touch event, we return true from
// the root view in order to receive subsequent events related to that gesture
return true
}
Comment on lines +107 to +117

override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, true) }
return super.onInterceptHoverEvent(event)
}

override fun onHoverEvent(event: MotionEvent): Boolean {
eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, false) }
return super.onHoverEvent(event)
}

override fun onChildStartedNativeGesture(
childView: View?,
ev: MotionEvent,
) {
eventDispatcher?.let { eventDispatcher ->
jsTouchDispatcher.onChildStartedNativeGesture(ev, eventDispatcher, themedReactContext)
jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
}
}

override fun onChildEndedNativeGesture(
childView: View,
ev: MotionEvent,
) {
eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
jsPointerDispatcher?.onChildEndedNativeGesture()
}

override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
// No-op - override in order to still receive events to onInterceptTouchEvent
// even when some other view disallow that
}

override fun handleException(t: Throwable) {
themedReactContext.reactApplicationContext.handleException(RuntimeException(t))
}
Comment on lines +152 to +154
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import android.content.Context
import android.view.View
import android.view.ViewGroup
import com.facebook.react.bridge.ReactContext
import com.facebook.react.uimanager.PointerEvents
import com.facebook.react.uimanager.ReactPointerEventsView
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.swmansion.rnscreens.gamma.common.ShadowStateProxy

class FormSheetHost(
context: Context,
) : ViewGroup(context) {
) : ViewGroup(context),
ReactPointerEventsView {
private val dialogManager = FormSheetDialogManager(context, this)
private var isOpen = false

Expand Down Expand Up @@ -66,6 +69,11 @@ class FormSheetHost(
super.onDetachedFromWindow()
}

// The React children are teleported into the dialog window. This host occupies space in the
// main window, but holds no content there. NONE makes the host subtree invisible to
// hit-testing so touches reach the views behind it.
override val pointerEvents: PointerEvents = PointerEvents.NONE

override fun onLayout(
changed: Boolean,
l: Int,
Expand Down
Loading