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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: restore backward compat for new & old architecture #2730

Merged
merged 7 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from 6 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
7 changes: 7 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ android {
} else {
srcDirs += "src/versioned/backgroundcolor/latest"
}

// Native only classes that use PointerEvents
if (REACT_NATIVE_MINOR_VERSION <= 77) {
srcDirs += "src/versioned/pointerevents/77"
} else {
srcDirs += "src/versioned/pointerevents/latest"
}
}
res {
if (safeExtGet(['compileSdkVersion', 'compileSdk'], rnsDefaultCompileSdkVersion) >= 33) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.WindowInsetsCompat
import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.PointerEvents
import com.facebook.react.uimanager.ReactPointerEventsView
import com.facebook.react.uimanager.UIManagerHelper
import com.google.android.material.appbar.AppBarLayout
Expand Down Expand Up @@ -722,9 +721,16 @@ class ScreenStackFragment :
private class ScreensCoordinatorLayout(
context: Context,
private val fragment: ScreenStackFragment,
private val pointerEventsImpl: ReactPointerEventsView,
// ) : CoordinatorLayout(context), ReactCompoundViewGroup, ReactHitSlopView {
) : CoordinatorLayout(context),
ReactPointerEventsView {
ReactPointerEventsView by pointerEventsImpl {
constructor(context: Context, fragment: ScreenStackFragment) : this(
context,
fragment,
ScreensCoordinatorLayoutPointerEventsImpl(),
)

override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets = super.onApplyWindowInsets(insets)

private val animationListener: Animation.AnimationListener =
Expand Down Expand Up @@ -801,11 +807,6 @@ class ScreenStackFragment :
// // bottom – The Y coordinate of the bottom of the rectangle
// return Rect(screen.x.toInt(), -screen.y.toInt(), screen.x.toInt() + screen.width, screen.y.toInt() + screen.height)
// }

// We set pointer events to BOX_NONE, because we don't want the ScreensCoordinatorLayout
// to be target of react gestures and effectively prevent interaction with screens
// underneath the current screen (useful in `modal` & `formSheet` presentation).
override val pointerEvents: PointerEvents = PointerEvents.BOX_NONE
}

private class ScreensAnimation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import android.content.Context
import android.graphics.Color
import android.view.MotionEvent
import android.view.ViewGroup
import com.facebook.react.uimanager.PointerEvents
import com.facebook.react.uimanager.ReactCompoundViewGroup
import com.facebook.react.uimanager.ReactPointerEventsView
import com.swmansion.rnscreens.ext.equalWithRespectToEps
Expand All @@ -17,13 +16,24 @@ import com.swmansion.rnscreens.ext.equalWithRespectToEps
* This dimming view has one more additional feature: it blocks gestures if its alpha > 0.
*/
@SuppressLint("ViewConstructor") // Only we instantiate this view
class DimmingView(
internal class DimmingView(
context: Context,
initialAlpha: Float = 0.6F,
private val pointerEventsProxy: DimmingViewPointerEventsProxy
) : ViewGroup(context),
ReactCompoundViewGroup,
ReactPointerEventsView {
private val blockGestures
ReactPointerEventsView by pointerEventsProxy {

constructor(context: Context, initialAlpha: Float = 0.6F) : this(
context, initialAlpha,
DimmingViewPointerEventsProxy(null)
)
Comment on lines +19 to +30
Copy link
Member Author

Choose a reason for hiding this comment

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

Doing it it such convoluted way, because I want the interface implementation to be delegated, but the implementation requires reference to this@DimmingView which can not be passed while calling other constructor.

This should not cause any timing problems since I'm initialising the implementation field just below in the init block.

Delegation of the interface implementation allows me to not put whole logic under versioning but rather only its fragments related to pointer events.


init {
pointerEventsProxy.pointerEventsImpl = DimmingViewPointerEventsImpl(this)
}

internal val blockGestures
get() = !alpha.equalWithRespectToEps(0F)

init {
Expand Down Expand Up @@ -59,8 +69,12 @@ class DimmingView(
y: Float,
) = blockGestures

override val pointerEvents: PointerEvents
get() = if (blockGestures) PointerEvents.AUTO else PointerEvents.NONE
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()

// Break reference cycle, since the pointerEventsImpl strongly retains this.
pointerEventsProxy.pointerEventsImpl = null
}

companion object {
const val TAG = "DimmingView"
Expand Down
Copy link
Member Author

Choose a reason for hiding this comment

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

Unused code that would required to be adjusted similarly to DimmingView & ScreensCoordinatorLayout.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
package com.facebook.react.viewmanagers;

import android.view.View;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSScreenContainerManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSScreenContainerManagerInterface<T extends View> {
// No props
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
package com.facebook.react.viewmanagers;

import android.view.View;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSScreenContentWrapperManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSScreenContentWrapperManagerInterface<T extends View> {
// No props
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
package com.facebook.react.viewmanagers;

import android.view.View;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSScreenFooterManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSScreenFooterManagerInterface<T extends View> {
// No props
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSScreenManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSScreenManagerInterface<T extends View> {
void setSheetAllowedDetents(T view, @Nullable ReadableArray value);
void setSheetLargestUndimmedDetent(T view, int value);
void setSheetGrabberVisible(T view, boolean value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSScreenStackHeaderConfigManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSScreenStackHeaderConfigManagerInterface<T extends View> {
void setBackgroundColor(T view, @Nullable Integer value);
void setBackTitle(T view, @Nullable String value);
void setBackTitleFontFamily(T view, @Nullable String value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSScreenStackHeaderSubviewManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSScreenStackHeaderSubviewManagerInterface<T extends View> {
void setType(T view, @Nullable String value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
package com.facebook.react.viewmanagers;

import android.view.View;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSScreenStackManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSScreenStackManagerInterface<T extends View> {
// No props
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;

public interface RNSSearchBarManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {

public interface RNSSearchBarManagerInterface<T extends View> {
void setHideWhenScrolling(T view, boolean value);
void setAutoCapitalize(T view, @Nullable String value);
void setPlaceholder(T view, @Nullable String value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.swmansion.rnscreens

import com.facebook.react.uimanager.PointerEvents
import com.facebook.react.uimanager.ReactPointerEventsView

internal class ScreensCoordinatorLayoutPointerEventsImpl : ReactPointerEventsView {
// We set pointer events to BOX_NONE, because we don't want the ScreensCoordinatorLayout
// to be target of react gestures and effectively prevent interaction with screens
// underneath the current screen (useful in `modal` & `formSheet` presentation).
override fun getPointerEvents(): PointerEvents = PointerEvents.BOX_NONE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.swmansion.rnscreens.bottomsheet

import com.facebook.react.uimanager.PointerEvents
import com.facebook.react.uimanager.ReactPointerEventsView
import com.swmansion.rnscreens.bottomsheet.DimmingView


internal class DimmingViewPointerEventsImpl(val dimmingView: DimmingView) : ReactPointerEventsView {
override fun getPointerEvents(): PointerEvents = if (dimmingView.blockGestures == false) PointerEvents.AUTO else PointerEvents.NONE
}

internal class DimmingViewPointerEventsProxy(var pointerEventsImpl: DimmingViewPointerEventsImpl?) :
ReactPointerEventsView {
override fun getPointerEvents(): PointerEvents = pointerEventsImpl?.pointerEvents ?: PointerEvents.NONE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.swmansion.rnscreens

import com.facebook.react.uimanager.PointerEvents
import com.facebook.react.uimanager.ReactPointerEventsView

internal class ScreensCoordinatorLayoutPointerEventsImpl() : ReactPointerEventsView {
// We set pointer events to BOX_NONE, because we don't want the ScreensCoordinatorLayout
// to be target of react gestures and effectively prevent interaction with screens
// underneath the current screen (useful in `modal` & `formSheet` presentation).
override val pointerEvents: PointerEvents = PointerEvents.BOX_NONE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.swmansion.rnscreens.bottomsheet

import com.facebook.react.uimanager.PointerEvents
import com.facebook.react.uimanager.ReactPointerEventsView


internal class DimmingViewPointerEventsImpl(val dimmingView: DimmingView) : ReactPointerEventsView {
override val pointerEvents: PointerEvents
get() = if (dimmingView.blockGestures == false) PointerEvents.AUTO else PointerEvents.NONE
}

internal class DimmingViewPointerEventsProxy(var pointerEventsImpl: DimmingViewPointerEventsImpl?) :
ReactPointerEventsView {
override val pointerEvents: PointerEvents
get() = pointerEventsImpl?.pointerEvents ?: PointerEvents.NONE
}
3 changes: 2 additions & 1 deletion ios/RNSScreenStack.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#import <React/RCTMountingTransactionObserving.h>
#import <React/RCTSurfaceTouchHandler.h>
#import <React/RCTSurfaceView.h>
#import <React/RCTVersion.h>
#import <React/UIView+React.h>
#import <react/renderer/components/rnscreens/ComponentDescriptors.h>
#import <react/renderer/components/rnscreens/EventEmitters.h>
Expand Down Expand Up @@ -1232,7 +1233,7 @@ - (void)mountingTransactionDidMount:(const facebook::react::MountingTransaction
withSurfaceTelemetry:(const facebook::react::SurfaceTelemetry &)surfaceTelemetry
{
for (const auto &mutation : transaction.getMutations()) {
if (mutation.parentTag == self.tag &&
if (MUTATION_PARENT_TAG(mutation) == self.tag &&
(mutation.type == react::ShadowViewMutation::Type::Insert ||
mutation.type == react::ShadowViewMutation::Type::Remove)) {
// we need to wait until children have their layout set. At this point they don't have the layout
Expand Down
17 changes: 17 additions & 0 deletions ios/utils/RNSDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,20 @@
_Pragma("clang diagnostic ignored \"-Wobjc-missing-super-calls\"")

#define RNS_IGNORE_SUPER_CALL_END _Pragma("clang diagnostic pop")

#import <React-RCTAppDelegate/RCTReactNativeFactory.h>

#if defined __has_include
#if __has_include( \
<React-RCTAppDelegate/RCTReactNativeFactory.h>) // added in 78
#define RNS_REACT_NATIVE_VERSION_MINOR_BELOW_78 0
#else
#define RNS_REACT_NATIVE_VERSION_MINOR_BELOW_78 1
#endif
#endif
Comment on lines +9 to +16
Copy link
Member Author

Choose a reason for hiding this comment

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

This is not pretty, but good enough for now.

If we need to have more RN version dependent code in the future we should define RNS_REACT_NATIVE_VERSION_MINOR during compilation or something.

I've also seen that REACT_NATIVE_VERSION_MINOR macro is defined in ReactNativeVersion.h since RN 0.79.


#if RNS_REACT_NATIVE_VERSION_MINOR_BELOW_78
#define MUTATION_PARENT_TAG(mutation) mutation.parentShadowView.tag
#else
#define MUTATION_PARENT_TAG(mutation) mutation.parentTag
#endif
Loading
Loading