Files
onekey-monorepo/patches/react-native-screens+3.26.0.patch

275 lines
12 KiB
Diff

diff --git a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt
index 401d57e..fc18e6a 100644
--- a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt
+++ b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt
@@ -14,6 +14,7 @@ import com.facebook.react.ReactRootView
import com.facebook.react.bridge.ReactContext
import com.facebook.react.modules.core.ChoreographerCompat
import com.facebook.react.modules.core.ReactChoreographer
+import com.facebook.react.views.view.ReactViewGroup
import com.swmansion.rnscreens.Screen.ActivityState
open class ScreenContainer(context: Context?) : ViewGroup(context) {
@@ -35,6 +36,7 @@ open class ScreenContainer(context: Context?) : ViewGroup(context) {
}
}
private var mParentScreenFragment: ScreenFragmentWrapper? = null
+ private var shouldBreakJSUpdateCount = 0;
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var i = 0
@@ -214,6 +216,49 @@ open class ScreenContainer(context: Context?) : ViewGroup(context) {
super.onAttachedToWindow()
mIsAttached = true
setupFragmentManager()
+
+
+ mScreenFragments.find { it.screen.activityState == ActivityState.ON_TOP }
+ ?: return
+
+ val parentView = parent as? ViewGroup
+ if (parentView == null || parentView.childCount != 2) {
+ return
+ }
+
+ val tabBar = (parentView.getChildAt(1) as? ViewGroup)?.getChildAt(0) as? ViewGroup ?: return
+
+ for (index in 0 until tabBar.childCount) {
+ val tabBarItem = tabBar.getChildAt(index) as? ReactViewGroup ?: return
+
+ tabBarItem.setOnInterceptTouchEventListener { viewGroup, motionEvent ->
+ if (mScreenFragments[index].screen.activityState == ActivityState.ON_TOP) {
+ false
+ }
+ mScreenFragments.forEach {
+ it.screen.setActivityState(ActivityState.INACTIVE)
+ }
+ mScreenFragments[index].screen.setActivityState(ActivityState.ON_TOP)
+
+ for (itemIndex in 0 until tabBar.childCount) {
+ var item = tabBar.getChildAt(itemIndex) as? ViewGroup
+ if (item == null || item.childCount != 2) {
+ item = (tabBar.getChildAt(itemIndex) as? ViewGroup)?.getChildAt(0) as? ViewGroup
+ if (item == null || item.childCount != 2) {
+ continue
+ }
+ }
+ (item.getChildAt(0) as? ReactViewGroup)?.setOpacityIfPossible(if (itemIndex == index) 0f else 1f)
+ (item.getChildAt(1) as? ReactViewGroup)?.setOpacityIfPossible(if (itemIndex == index) 1f else 0f)
+ }
+ shouldBreakJSUpdateCount += 1;
+ createTransaction().let {
+ topScreen?.fragment?.let { fragment -> detachScreen(it, fragment) }
+ attachScreen(it, mScreenFragments[index].fragment)
+ }
+ true
+ }
+ }
}
/** Removes fragments from fragment manager that are attached to this container */
@@ -312,6 +357,10 @@ open class ScreenContainer(context: Context?) : ViewGroup(context) {
}
open fun onUpdate() {
+ // if (shouldBreakJSUpdateCount > 0) {
+ // shouldBreakJSUpdateCount = 0
+ // return
+ // }
createTransaction().let {
// detach screens that are no longer active
val orphaned: MutableSet<Fragment> = HashSet(
diff --git a/node_modules/react-native-screens/ios/RNSFullWindowOverlay.mm b/node_modules/react-native-screens/ios/RNSFullWindowOverlay.mm
index 74f1804..aebed6e 100644
--- a/node_modules/react-native-screens/ios/RNSFullWindowOverlay.mm
+++ b/node_modules/react-native-screens/ios/RNSFullWindowOverlay.mm
@@ -33,6 +33,29 @@ - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
return NO;
}
+// Here is just copied from UIView+React, but we have modified `self.reactSubviews` to `self.subviews`
+// because `RNSFullWindowOverlayContainer` is just a simple UIView without the `reactSubviews` property.
+- (NSArray<UIView *> *)reactZIndexSortedSubviews
+{
+ // Check if sorting is required - in most cases it won't be.
+ BOOL sortingRequired = NO;
+ for (UIView *subview in self.subviews) {
+ if (subview.reactZIndex != 0) {
+ sortingRequired = YES;
+ break;
+ }
+ }
+ return sortingRequired ? [self.subviews sortedArrayUsingComparator:^NSComparisonResult(UIView *a, UIView *b) {
+ if (a.reactZIndex > b.reactZIndex) {
+ return NSOrderedDescending;
+ } else {
+ // Ensure sorting is stable by treating equal zIndex as ascending so
+ // that original order is preserved.
+ return NSOrderedAscending;
+ }
+ }] : self.subviews;
+}
+
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL canReceiveTouchEvents = ([self isUserInteractionEnabled] && ![self isHidden]);
diff --git a/node_modules/react-native-screens/ios/RNSScreen.mm b/node_modules/react-native-screens/ios/RNSScreen.mm
index 1ed4914..e1252b0 100644
--- a/node_modules/react-native-screens/ios/RNSScreen.mm
+++ b/node_modules/react-native-screens/ios/RNSScreen.mm
@@ -2,6 +2,7 @@
#import "RNSScreen.h"
#import "RNSScreenContainer.h"
+#import "RNSScreenNavigationContainer.h"
#import "RNSScreenWindowTraits.h"
#ifdef RCT_NEW_ARCH_ENABLED
@@ -456,8 +457,83 @@ - (BOOL)isMountedUnderScreenOrReactRoot
#undef RNS_EXPECTED_VIEW
}
+- (void)addGestureToTabBarItem {
+ UIView *superview = self.superview.superview.superview.superview.superview;
+ if (superview.subviews.count == 2) {
+ UIView *tabBarView = [[superview.subviews[1] subviews] firstObject];
+ for (UIView *view in tabBarView.subviews) {
+ for (UIGestureRecognizer *gestureRecognizer in view.gestureRecognizers) {
+ [view removeGestureRecognizer:gestureRecognizer];
+ }
+ UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(switchTabFromGesture:)];
+ [view addGestureRecognizer:tapGestureRecognizer];
+ }
+ }
+}
+
+- (void)switchTabFromGesture:(UITapGestureRecognizer *)gesture {
+ NSInteger index = [gesture.view.superview.subviews indexOfObject:gesture.view];
+ if (index == NSNotFound) {
+ return;
+ }
+
+ id _containerView = [gesture.view.superview.superview.superview.subviews firstObject];
+ if (![_containerView isKindOfClass:[RNSScreenNavigationContainerView class]]) {
+ return;
+ }
+ RNSScreenNavigationContainerView *containerView = (RNSScreenNavigationContainerView *)_containerView;
+
+ id _navigationController = containerView.subviews.firstObject.nextResponder;
+ if (![_navigationController isKindOfClass:[UINavigationController class]]) {
+ return;
+ }
+
+ UINavigationController *navigationController = (UINavigationController *)_navigationController;
+ id _subviews = navigationController.view.superview.reactSubviews;
+ if (![[_subviews firstObject] isKindOfClass:[RNSScreenView class]]) {
+ return;
+ }
+ NSArray<RNSScreenView *> *screenViews = (NSArray<RNSScreenView *> *)_subviews;
+
+ if (index < 0 || index >= screenViews.count) {
+ return;
+ }
+
+ if (screenViews[index].activityState == RNSActivityStateOnTop) {
+ return;
+ }
+
+
+ [screenViews enumerateObjectsUsingBlock:^(RNSScreenView *obj, NSUInteger idx, BOOL *stop) {
+ obj.activityState = (idx == index) ? RNSActivityStateOnTop : RNSActivityStateInactive;
+ }];
+ containerView.shouldBreakJSUpdateCount += 1;
+ UIViewController *controller = screenViews[index].controller;
+ [navigationController setViewControllers:@[controller] animated:NO];
+
+ [gesture.view.superview.subviews enumerateObjectsUsingBlock:^(__kindof UIView *obj, NSUInteger idx, BOOL *stop) {
+ NSArray<UIView *> *opacityViewList = obj.subviews;
+ if ([opacityViewList count] != 2) {
+ opacityViewList = [opacityViewList firstObject].subviews;
+ if ([opacityViewList count] != 2) {
+ return;
+ }
+ }
+ if (index == idx) {
+ opacityViewList[0].alpha = 0;
+ opacityViewList[1].alpha = 1;
+ } else {
+ opacityViewList[0].alpha = 1;
+ opacityViewList[1].alpha = 0;
+ }
+ }];
+}
+
- (void)didMoveToWindow
{
+ if (self.activityState == 2) {
+ [self addGestureToTabBarItem];
+ }
// For RN touches to work we need to instantiate and connect RCTTouchHandler. This only applies
// for screens that aren't mounted under RCTRootView e.g., modals that are mounted directly to
// root application window.
diff --git a/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.h b/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.h
index defd0d5..f6521f5 100644
--- a/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.h
+++ b/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.h
@@ -9,6 +9,8 @@
@interface RNSScreenNavigationContainerView : RNSScreenContainerView
+@property (nonatomic, assign) NSInteger shouldBreakJSUpdateCount;
+
@end
@interface RNSScreenNavigationContainerManager : RNSScreenContainerManager
diff --git a/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.mm b/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.mm
index f10671e..20e0d45 100644
--- a/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.mm
+++ b/node_modules/react-native-screens/ios/RNSScreenNavigationContainer.mm
@@ -29,7 +29,11 @@ - (void)updateContainer
if (screen.activityState == RNSActivityStateOnTop) {
// there should never be more than one screen with `RNSActivityStateOnTop`
// since this component should be used for `tabs` and `drawer` navigators
- [(RNSContainerNavigationController *)self.controller setViewControllers:@[ screen.controller ] animated:NO];
+ if (self.shouldBreakJSUpdateCount > 0) {
+ self.shouldBreakJSUpdateCount = 0;
+ } else {
+ [(RNSContainerNavigationController *)self.controller setViewControllers:@[ screen.controller ] animated:NO];
+ }
[screen notifyFinishTransitioning];
}
}
diff --git a/node_modules/react-native-screens/ios/RNSSearchBar.mm b/node_modules/react-native-screens/ios/RNSSearchBar.mm
index 94475b7..862f904 100644
--- a/node_modules/react-native-screens/ios/RNSSearchBar.mm
+++ b/node_modules/react-native-screens/ios/RNSSearchBar.mm
@@ -195,6 +195,9 @@ - (void)hideCancelButton
if (@available(iOS 13, *)) {
// On iOS 13+ UISearchController automatically shows/hides cancel button
// https://developer.apple.com/documentation/uikit/uisearchcontroller/3152926-automaticallyshowscancelbutton?language=objc
+
+ // But when we use `keyboardDismissMode` to dismiss the search bar, we should manually hide the cancel button with the following code.
+ _controller.active = NO;
} else {
[_controller.searchBar setShowsCancelButton:NO animated:YES];
}
@@ -304,6 +307,18 @@ - (void)setText:(NSString *)text
[_controller.searchBar setText:text];
}
+// Set the color of the `searchIcon` and `searchPlaceholder` by `textColor`
+- (void)didSetProps:(NSArray<NSString *> *)changedProps {
+ if (@available(iOS 13.0, *)) {
+ UIColor *placeholderColor = [_controller.searchBar.searchTextField.textColor colorWithAlphaComponent:0.5];
+ _controller.searchBar.searchTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:_controller.searchBar.placeholder attributes:@{
+ NSForegroundColorAttributeName: placeholderColor,
+ }];
+ [_controller.searchBar.searchTextField.leftView setTintColor:placeholderColor];
+ [_controller.searchBar.searchTextField.rightView setTintColor:placeholderColor];
+ }
+}
+
#pragma mark-- Fabric specific
#ifdef RCT_NEW_ARCH_ENABLED