From 6f2121ab9dc81ebebaa4991946596be54bac2f62 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 7 Apr 2022 09:44:44 +0200 Subject: [PATCH 001/105] chore: Set RN_FABRIC_ENABLED compiler flag when fabric is enabled --- RNScreens.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNScreens.podspec b/RNScreens.podspec index ab37cb9404..b224c31341 100644 --- a/RNScreens.podspec +++ b/RNScreens.podspec @@ -29,7 +29,7 @@ Pod::Spec.new do |s| "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", } s.platforms = { ios: '11.0', tvos: '11.0' } - s.compiler_flags = folly_compiler_flags + s.compiler_flags = folly_compiler_flags + '-DRN_FABRIC_ENABLED' s.source_files = 'ios/**/*.{h,m,mm,cpp}' s.requires_arc = true From 00fc6db94ce964fd754594f267de2875a69e6bfa Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 8 Apr 2022 14:59:51 +0200 Subject: [PATCH 002/105] refract: Move RNSScreenComponentView implementation to RNSScreenView && RNSScreenController to RNSScreen --- ios/RNSScreen.h | 79 +++-- ios/{RNSScreen.m => RNSScreen.mm} | 501 ++++++++++++++++++++++++++++-- ios/RNSScreenComponentView.h | 57 ---- ios/RNSScreenComponentView.mm | 485 ----------------------------- ios/RNSScreenController.h | 12 - ios/RNSScreenController.mm | 198 ------------ 6 files changed, 541 insertions(+), 791 deletions(-) rename ios/{RNSScreen.m => RNSScreen.mm} (65%) delete mode 100644 ios/RNSScreenComponentView.h delete mode 100644 ios/RNSScreenComponentView.mm delete mode 100644 ios/RNSScreenController.h delete mode 100644 ios/RNSScreenController.mm diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index a3a07075df..4c59f9a334 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -1,10 +1,15 @@ #import -#import #import #import "RNSEnums.h" #import "RNSScreenContainer.h" +#if RN_FABRIC_ENABLED +#import +#else +#import +#endif + @interface RCTConvert (RNSScreen) + (RNSScreenStackPresentation)RNSScreenStackPresentation:(id)json; @@ -12,6 +17,7 @@ #if !TARGET_OS_TV + (RNSStatusBarStyle)RNSStatusBarStyle:(id)json; ++ (UIStatusBarAnimation)UIStatusBarAnimation:(id)json; + (UIInterfaceOrientationMask)UIInterfaceOrientationMask:(id)json; #endif @@ -20,8 +26,13 @@ @interface RNSScreen : UIViewController - (instancetype)initWithView:(UIView *)view; -- (void)notifyFinishTransitioning; - (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals; +#ifdef RN_FABRIC_ENABLED +- (void)setViewToSnapshot:(UIView *)snapshot; +- (void)resetViewToScreen; +#else +- (void)notifyFinishTransitioning; +#endif @end @@ -29,8 +40,39 @@ @end -@interface RNSScreenView : RCTView +#ifdef RN_FABRIC_ENABLED +#define BASE_VIEW RCTViewComponentView +#else +#define BASE_VIEW RCTView +#endif + +@interface RNSScreenView : BASE_VIEW + +@property (nonatomic) BOOL fullScreenSwipeEnabled; +@property (nonatomic) BOOL gestureEnabled; +@property (nonatomic) BOOL hasStatusBarHiddenSet; +@property (nonatomic) BOOL hasStatusBarStyleSet; +@property (nonatomic) BOOL hasStatusBarAnimationSet; +@property (nonatomic) BOOL hasHomeIndicatorHiddenSet; +@property (nonatomic) BOOL hasOrientationSet; +@property (nonatomic) RNSScreenStackAnimation stackAnimation; +@property (nonatomic) RNSScreenStackPresentation stackPresentation; +@property (nonatomic) RNSScreenSwipeDirection swipeDirection; +@property (nonatomic, retain) NSNumber *transitionDuration; + +#if !TARGET_OS_TV +@property (nonatomic) RNSStatusBarStyle statusBarStyle; +@property (nonatomic) UIStatusBarAnimation statusBarAnimation; +@property (nonatomic) UIInterfaceOrientationMask screenOrientation; +@property (nonatomic) BOOL statusBarHidden; +@property (nonatomic) BOOL homeIndicatorHidden; +#endif +#ifdef RN_FABRIC_ENABLED +@property (weak, nonatomic) UIView *config; +@property (weak, nonatomic) UIView *reactSuperview; +@property (nonatomic, retain) RNSScreen *controller; +#else @property (nonatomic, copy) RCTDirectEventBlock onAppear; @property (nonatomic, copy) RCTDirectEventBlock onDisappear; @property (nonatomic, copy) RCTDirectEventBlock onDismissed; @@ -43,35 +85,30 @@ @property (nonatomic, retain) UIViewController *controller; @property (nonatomic, readonly) BOOL dismissed; @property (nonatomic) int activityState; -@property (nonatomic) BOOL gestureEnabled; -@property (nonatomic) RNSScreenStackAnimation stackAnimation; -@property (nonatomic) RNSScreenStackPresentation stackPresentation; @property (nonatomic) RNSScreenReplaceAnimation replaceAnimation; -@property (nonatomic) RNSScreenSwipeDirection swipeDirection; @property (nonatomic) BOOL preventNativeDismiss; -@property (nonatomic) BOOL hasOrientationSet; -@property (nonatomic) BOOL hasStatusBarStyleSet; -@property (nonatomic) BOOL hasStatusBarAnimationSet; -@property (nonatomic) BOOL hasStatusBarHiddenSet; -@property (nonatomic) BOOL hasHomeIndicatorHiddenSet; @property (nonatomic) BOOL customAnimationOnSwipe; -@property (nonatomic) BOOL fullScreenSwipeEnabled; @property (nonatomic, copy) NSDictionary *gestureResponseDistance; -@property (nonatomic, retain) NSNumber *transitionDuration; - -#if !TARGET_OS_TV -@property (nonatomic) RNSStatusBarStyle statusBarStyle; -@property (nonatomic) UIStatusBarAnimation statusBarAnimation; -@property (nonatomic) BOOL statusBarHidden; -@property (nonatomic) UIInterfaceOrientationMask screenOrientation; -@property (nonatomic) BOOL homeIndicatorHidden; #endif +#ifdef RN_FABRIC_ENABLED +- (void)notifyWillAppear; +- (void)notifyWillDisappear; +- (void)notifyAppear; +- (void)notifyDisappear; +- (void)updateBounds; +- (void)notifyDismissedWithCount:(int)dismissCount; +#else - (void)notifyFinishTransitioning; - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward; +#endif @end +#ifdef RN_FABRIC_ENABLED + +#else @interface UIView (RNSScreen) - (UIViewController *)parentViewController; @end +#endif diff --git a/ios/RNSScreen.m b/ios/RNSScreen.mm similarity index 65% rename from ios/RNSScreen.m rename to ios/RNSScreen.mm index 60423084f9..a2e65881be 100644 --- a/ios/RNSScreen.m +++ b/ios/RNSScreen.mm @@ -6,20 +6,71 @@ #import "RNSScreenStackHeaderConfig.h" #import "RNSScreenWindowTraits.h" -#import +#import + +// TODO: Organize imports +#ifdef RN_FABRIC_ENABLED +#import +#import +#import +#import +#import +#import "RNSConvert.h" +#import "RNSScreenStackHeaderConfigComponentView.h" +#else #import +#endif + +#import #import -@interface RNSScreenView () +#import +#import "RCTFabricComponentsPlugins.h" + +#import +#import + +@interface RNSScreenView () +#ifdef RN_FABRIC_ENABLED + +#else + +#endif @end @implementation RNSScreenView { - __weak RCTBridge *_bridge; RNSScreen *_controller; +#ifdef RN_FABRIC_ENABLED + RCTSurfaceTouchHandler *_touchHandler; + facebook::react::RNSScreenShadowNode::ConcreteState::Shared _state; +#else + __weak RCTBridge *_bridge; RCTTouchHandler *_touchHandler; CGRect _reactFrame; +#endif } +#if RN_FABRIC_ENABLED +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + _controller = [[RNSScreen alloc] initWithView:self]; + // TODO: use default props (?) + _stackAnimation = RNSScreenStackAnimationDefault; + _stackPresentation = RNSScreenStackPresentationPush; + _hasStatusBarHiddenSet = NO; + _hasStatusBarStyleSet = NO; + _gestureEnabled = YES; + _hasStatusBarAnimationSet = NO; + _hasOrientationSet = NO; + _hasHomeIndicatorHiddenSet = NO; + } + + return self; +} +#else - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super init]) { @@ -39,6 +90,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge return self; } +#endif - (void)reactSetFrame:(CGRect)frame { @@ -62,7 +114,16 @@ - (UIViewController *)reactViewController - (void)updateBounds { +#ifdef RN_FABRIC_ENDABLED + if (_state != nullptr) { + auto newState = facebook::react::RNSScreenState{RCTSizeFromCGSize(self.bounds.size)}; + _state->updateState(std::move(newState)); + UINavigationController *navctr = _controller.navigationController; + [navctr.view setNeedsLayout]; + } +#else [_bridge.uiManager setSize:self.bounds.size forView:self]; +#endif } // Nil will be provided when activityState is set as an animated value and we change @@ -237,6 +298,14 @@ - (void)notifyFinishTransitioning - (void)notifyDismissedWithCount:(int)dismissCount { +#ifdef RN_FABRIC_ENABLED + // If screen is already unmounted then there will be no event emitter + // it will be cleaned in prepareForRecycle + if (_eventEmitter != nullptr) { + std::dynamic_pointer_cast(_eventEmitter) + ->onDismissed(facebook::react::RNSScreenEventEmitter::OnDismissed{dismissCount : dismissCount}); + } +#else _dismissed = YES; if (self.onDismissed) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -245,27 +314,55 @@ - (void)notifyDismissedWithCount:(int)dismissCount } }); } +#endif } - (void)notifyWillAppear { +#ifdef RN_FABRIC_ENABLED + // If screen is already unmounted then there will be no event emitter + // it will be cleaned in prepareForRecycle + if (_eventEmitter != nullptr) { + std::dynamic_pointer_cast(_eventEmitter) + ->onWillAppear(facebook::react::RNSScreenEventEmitter::OnWillAppear{}); + } +#else if (self.onWillAppear) { self.onWillAppear(nil); } // we do it here too because at this moment the `parentViewController` is already not nil, // so if the parent is not UINavCtr, the frame will be updated to the correct one. [self reactSetFrame:_reactFrame]; +#endif } - (void)notifyWillDisappear { +#ifdef RN_FABRIC_ENABLED + // If screen is already unmounted then there will be no event emitter + // it will be cleaned in prepareForRecycle + if (_eventEmitter != nullptr) { + std::dynamic_pointer_cast(_eventEmitter) + ->onWillDisappear(facebook::react::RNSScreenEventEmitter::OnWillDisappear{}); + } + +#else if (self.onWillDisappear) { self.onWillDisappear(nil); } +#endif } - (void)notifyAppear { +#ifdef RN_FABRIC_ENABLED + // If screen is already unmounted then there will be no event emitter + // it will be cleaned in prepareForRecycle + if (_eventEmitter != nullptr) { + std::dynamic_pointer_cast(_eventEmitter) + ->onAppear(facebook::react::RNSScreenEventEmitter::OnAppear{}); + } +#else if (self.onAppear) { dispatch_async(dispatch_get_main_queue(), ^{ if (self.onAppear) { @@ -273,13 +370,23 @@ - (void)notifyAppear } }); } +#endif } - (void)notifyDisappear { +#ifdef RN_FABRIC_ENABLED + // If screen is already unmounted then there will be no event emitter + // it will be cleaned in prepareForRecycle + if (_eventEmitter != nullptr) { + std::dynamic_pointer_cast(_eventEmitter) + ->onDisappear(facebook::react::RNSScreenEventEmitter::OnDisappear{}); + } +#else if (self.onDisappear) { self.onDisappear(nil); } +#endif } - (void)notifyDismissCancelledWithDismissCount:(int)dismissCount @@ -302,12 +409,18 @@ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingFor - (BOOL)isMountedUnderScreenOrReactRoot { +#ifdef RN_FABRIC_ENABLED +#define EXPECTED_VIEW RCTRootComponentView +#else +#define EXPECTED_VIEW RCTRootView +#endif for (UIView *parent = self.superview; parent != nil; parent = parent.superview) { - if ([parent isKindOfClass:[RCTRootView class]] || [parent isKindOfClass:[RNSScreenView class]]) { + if ([parent isKindOfClass:[EXPECTED_VIEW class]] || [parent isKindOfClass:[RNSScreenView class]]) { return YES; } } return NO; +#undef EXPECTED_VIEW } - (void)didMoveToWindow @@ -317,7 +430,11 @@ - (void)didMoveToWindow // root application window. if (self.window != nil && ![self isMountedUnderScreenOrReactRoot]) { if (_touchHandler == nil) { +#ifdef RN_FABRIC_ENABLED + _touchHandler = [RCTSurfaceTouchHandler new]; +#else _touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge]; +#endif } [_touchHandler attachToView:self]; } else { @@ -325,6 +442,152 @@ - (void)didMoveToWindow } } +#ifdef RN_FABRIC_ENABLED +- (RCTSurfaceTouchHandler *)touchHandler +#else +- (RCTTouchHandler *)touchHandler +#endif +{ + if (_touchHandler != nil) { + return _touchHandler; + } + UIView *parent = [self superview]; + while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) + parent = parent.superview; + if (parent != nil) { + return [parent performSelector:@selector(touchHandler)]; + } + return nil; +} + +// altough it is fabric specific code ++ (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider +{ + return facebook::react::concreteComponentDescriptorProvider(); +} + +#pragma mark - Fabric specific +#ifdef RN_FABRIC_ENABLED +- (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index +{ + [super mountChildComponentView:childComponentView index:index]; + if ([childComponentView isKindOfClass:[RNSScreenStackHeaderConfigComponentView class]]) { + _config = childComponentView; + ((RNSScreenStackHeaderConfigComponentView *)childComponentView).screenView = self; + } +} + +- (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index +{ + if ([childComponentView isKindOfClass:[RNSScreenStackHeaderConfigComponentView class]]) { + _config = nil; + } + [super unmountChildComponentView:childComponentView index:index]; +} + +#pragma mark - RCTComponentViewProtocol + +- (void)prepareForRecycle +{ + [super prepareForRecycle]; + // TODO: Make sure that there is no edge case when this should be uncommented + // _controller=nil; + _state.reset(); +} + +- (void)updateProps:(facebook::react::Props::Shared const &)props + oldProps:(facebook::react::Props::Shared const &)oldProps +{ + const auto &oldScreenProps = *std::static_pointer_cast(_props); + const auto &newScreenProps = *std::static_pointer_cast(props); + + [self setFullScreenSwipeEnabled:newScreenProps.fullScreenSwipeEnabled]; + + [self setGestureEnabled:newScreenProps.gestureEnabled]; + + [self setTransitionDuration:[NSNumber numberWithInt:newScreenProps.transitionDuration]]; + + if (newScreenProps.statusBarHidden != oldScreenProps.statusBarHidden) { + [self setStatusBarHidden:newScreenProps.statusBarHidden]; + } + + if (newScreenProps.statusBarStyle != oldScreenProps.statusBarStyle) { + [self setStatusBarStyle:[RCTConvert + RNSStatusBarStyle:RCTNSStringFromStringNilIfEmpty(newScreenProps.statusBarStyle)]]; + } + + if (newScreenProps.statusBarAnimation != oldScreenProps.statusBarAnimation) { + [self setStatusBarAnimation:[RCTConvert UIStatusBarAnimation:RCTNSStringFromStringNilIfEmpty( + newScreenProps.statusBarAnimation)]]; + } + + if (newScreenProps.screenOrientation != oldScreenProps.screenOrientation) { + [self setScreenOrientation:[RCTConvert UIInterfaceOrientationMask:RCTNSStringFromStringNilIfEmpty( + newScreenProps.screenOrientation)]]; + } + + if (newScreenProps.stackPresentation != oldScreenProps.stackPresentation) { + [self + setStackPresentation:[RNSConvert RNSScreenStackPresentationFromCppEquivalent:newScreenProps.stackPresentation]]; + } + + if (newScreenProps.stackAnimation != oldScreenProps.stackAnimation) { + [self setStackAnimation:[RNSConvert RNSScreenStackAnimationFromCppEquivalent:newScreenProps.stackAnimation]]; + } + + if (newScreenProps.statusBarColor) { + [self logPropNotAvailable:@"statusBarColor"]; + } + + if (newScreenProps.statusBarTranslucent) { + [self logPropNotAvailable:@"statusBarTranslucent"]; + } + + [self setFullScreenSwipeEnabled:newScreenProps.fullScreenSwipeEnabled]; + + [self setGestureEnabled:newScreenProps.gestureEnabled]; + + if (newScreenProps.statusBarHidden != oldScreenProps.statusBarHidden) { + [self setStatusBarHidden:newScreenProps.statusBarHidden]; + } + + if (newScreenProps.statusBarStyle != oldScreenProps.statusBarStyle) { + [self setStatusBarStyle:[RCTConvert RNSStatusBarStyle:[self stringToPropValue:newScreenProps.statusBarStyle]]]; + } + + if (newScreenProps.statusBarAnimation != oldScreenProps.statusBarAnimation) { + [self setStatusBarAnimation:[RCTConvert + UIStatusBarAnimation:[self stringToPropValue:newScreenProps.statusBarAnimation]]]; + } + + if (newScreenProps.screenOrientation != oldScreenProps.screenOrientation) { + [self + setScreenOrientation:[RCTConvert + UIInterfaceOrientationMask:[self stringToPropValue:newScreenProps.screenOrientation]]]; + } + + if (newScreenProps.statusBarColor) { + [self logPropNotAvailable:@"statusBarColor"]; + } + + if (newScreenProps.statusBarTranslucent) { + [self logPropNotAvailable:@"statusBarTranslucent"]; + } + + [super updateProps:props oldProps:oldProps]; + + _fullScreenSwipeEnabled = newScreenProps.fullScreenSwipeEnabled; + _gestureEnabled = newScreenProps.gestureEnabled; +} + +- (void)updateState:(facebook::react::State::Shared const &)state + oldState:(facebook::react::State::Shared const &)oldState +{ + _state = std::static_pointer_cast(state); +} + +#pragma mark - Paper specific +#else - (void)presentationControllerWillDismiss:(UIPresentationController *)presentationController { // We need to call both "cancel" and "reset" here because RN's gesture recognizer @@ -341,20 +604,6 @@ - (void)presentationControllerWillDismiss:(UIPresentationController *)presentati [_touchHandler reset]; } -- (RCTTouchHandler *)touchHandler -{ - if (_touchHandler != nil) { - return _touchHandler; - } - UIView *parent = [self superview]; - while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) - parent = parent.superview; - if (parent != nil) { - return [parent performSelector:@selector(touchHandler)]; - } - return nil; -} - - (BOOL)presentationControllerShouldDismiss:(UIPresentationController *)presentationController { if (_preventNativeDismiss) { @@ -375,11 +624,215 @@ - (void)invalidate { _controller = nil; } +#endif @end +Class RNSScreenCls(void) +{ + return RNSScreenView.class; +} + #pragma mark - RNSScreen +#ifdef RN_FABRIC_ENABLED + +@implementation RNSScreen { + RNSScreenView *_initialView; +} + +- (instancetype)initWithView:(UIView *)view +{ + if (self = [super init]) { + self.view = view; + if ([view isKindOfClass:[RNSScreenView class]]) { + _initialView = (RNSScreenView *)view; + } else { + RCTLogError(@"ScreenController can only be initialized with ScreenComponentView"); + } + } + return self; +} + +- (void)setViewToSnapshot:(UIView *)snapshot +{ + [self.view removeFromSuperview]; + self.view = snapshot; +} + +- (void)resetViewToScreen +{ + [self.view removeFromSuperview]; + self.view = _initialView; +} + +// TODO: Find out why this is executed when screen is going out +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [RNSScreenWindowTraits updateWindowTraits]; + [_initialView notifyWillAppear]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [_initialView notifyWillDisappear]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + [_initialView notifyAppear]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + [_initialView notifyDisappear]; + if (self.parentViewController == nil && self.presentingViewController == nil) { + // screen dismissed, send event + [_initialView notifyDismissedWithCount:1]; + } +} + +- (void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + BOOL isDisplayedWithinUINavController = [self.parentViewController isKindOfClass:[UINavigationController class]]; + if (isDisplayedWithinUINavController) { + [_initialView updateBounds]; + } +} + +#if !TARGET_OS_TV +// if the returned vc is a child, it means that it can provide config; +// if the returned vc is self, it means that there is no child for config and self has config to provide, +// so we return self which results in asking self for preferredStatusBarStyle/Animation etc.; +// if the returned vc is nil, it means none of children could provide config and self does not have config either, +// so if it was asked by parent, it will fallback to parent's option, or use default option if it is the top Screen +- (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals +{ + UIViewController *lastViewController = [[self childViewControllers] lastObject]; + if ([self.presentedViewController isKindOfClass:[RNSScreen class]]) { + lastViewController = self.presentedViewController; + // we don't want to allow controlling of status bar appearance when we present non-fullScreen modal + // and it is not possible if `modalPresentationCapturesStatusBarAppearance` is not set to YES, so even + // if we went into a modal here and ask it, it wouldn't take any effect. For fullScreen modals, the system + // asks them by itself, so we can stop traversing here. + // for screen orientation, we need to start the search again from that modal + return !includingModals + ? nil + : [(RNSScreen *)lastViewController findChildVCForConfigAndTrait:trait includingModals:includingModals] + ?: lastViewController; + } + + UIViewController *selfOrNil = [self hasTraitSet:trait] ? self : nil; + if (lastViewController == nil) { + return selfOrNil; + } else { + if ([lastViewController conformsToProtocol:@protocol(RNScreensViewControllerDelegate)]) { + // If there is a child (should be VC of ScreenContainer or ScreenStack), that has a child that could provide the + // trait, we recursively go into its findChildVCForConfig, and if one of the children has the trait set, we return + // it, otherwise we return self if this VC has config, and nil if it doesn't we use + // `childViewControllerForStatusBarStyle` for all options since the behavior is the same for all of them + UIViewController *childScreen = [lastViewController childViewControllerForStatusBarStyle]; + if ([childScreen isKindOfClass:[RNSScreen class]]) { + return [(RNSScreen *)childScreen findChildVCForConfigAndTrait:trait includingModals:includingModals] + ?: selfOrNil; + } else { + return selfOrNil; + } + } else { + // child vc is not from this library, so we don't ask it + return selfOrNil; + } + } +} + +- (BOOL)hasTraitSet:(RNSWindowTrait)trait +{ + switch (trait) { + case RNSWindowTraitStyle: { + return ((RNSScreenView *)self.view).hasStatusBarStyleSet; + } + case RNSWindowTraitAnimation: { + return ((RNSScreenView *)self.view).hasStatusBarAnimationSet; + } + case RNSWindowTraitHidden: { + return ((RNSScreenView *)self.view).hasStatusBarHiddenSet; + } + case RNSWindowTraitOrientation: { + return ((RNSScreenView *)self.view).hasOrientationSet; + } + case RNSWindowTraitHomeIndicatorHidden: { + return ((RNSScreenView *)self.view).hasHomeIndicatorHiddenSet; + } + default: { + RCTLogError(@"Unknown trait passed: %d", (int)trait); + } + } + return NO; +} + +- (UIViewController *)childViewControllerForStatusBarHidden +{ + UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHidden includingModals:NO]; + return vc == self ? nil : vc; +} + +- (BOOL)prefersStatusBarHidden +{ + return ((RNSScreenView *)self.view).statusBarHidden; +} + +- (UIViewController *)childViewControllerForStatusBarStyle +{ + UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitStyle includingModals:NO]; + return vc == self ? nil : vc; +} + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return [RNSScreenWindowTraits statusBarStyleForRNSStatusBarStyle:((RNSScreenView *)self.view).statusBarStyle]; +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation +{ + UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitAnimation includingModals:NO]; + + if ([vc isKindOfClass:[RNSScreen class]]) { + return ((RNSScreenView *)vc.view).statusBarAnimation; + } + return UIStatusBarAnimationFade; +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientations +{ + UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitOrientation includingModals:YES]; + + if ([vc isKindOfClass:[RNSScreen class]]) { + return ((RNSScreenView *)vc.view).screenOrientation; + } + return UIInterfaceOrientationMaskAllButUpsideDown; +} + +- (UIViewController *)childViewControllerForHomeIndicatorAutoHidden +{ + UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHomeIndicatorHidden includingModals:YES]; + return vc == self ? nil : vc; +} + +- (BOOL)prefersHomeIndicatorAutoHidden +{ + return ((RNSScreenView *)self.view).homeIndicatorHidden; +} +#endif + +@end + +#else + @implementation RNSScreen { __weak id _previousFirstResponder; CGRect _lastViewFrame; @@ -782,6 +1235,8 @@ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingFor @end +#endif + @implementation RNSScreenManager RCT_EXPORT_MODULE() @@ -824,6 +1279,16 @@ - (UIView *)view @implementation RCTConvert (RNSScreen) +RCT_ENUM_CONVERTER( + UIStatusBarAnimation, + (@{ + @"none" : @(UIStatusBarAnimationNone), + @"fade" : @(UIStatusBarAnimationFade), + @"slide" : @(UIStatusBarAnimationSlide) + }), + UIStatusBarAnimationNone, + integerValue) + RCT_ENUM_CONVERTER( RNSScreenStackPresentation, (@{ diff --git a/ios/RNSScreenComponentView.h b/ios/RNSScreenComponentView.h deleted file mode 100644 index e4a05850bf..0000000000 --- a/ios/RNSScreenComponentView.h +++ /dev/null @@ -1,57 +0,0 @@ -#import - -#import - -#import "RNSEnums.h" -#import "RNSScreenController.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface RCTConvert (RNSScreenComponentView) - -+ (RNSScreenStackPresentation)RNSScreenStackPresentation:(id)json; - -#if !TARGET_OS_TV -+ (RNSStatusBarStyle)RNSStatusBarStyle:(id)json; -+ (UIStatusBarAnimation)UIStatusBarAnimation:(id)json; -+ (UIInterfaceOrientationMask)UIInterfaceOrientationMask:(id)json; -#endif - -@end - -@interface RNSScreenComponentView : RCTViewComponentView - -@property (weak, nonatomic) UIView *reactSuperview; -@property (weak, nonatomic) UIView *config; -@property (nonatomic, retain) RNSScreenController *controller; - -@property (nonatomic) BOOL fullScreenSwipeEnabled; -@property (nonatomic) BOOL gestureEnabled; -@property (nonatomic) BOOL hasStatusBarHiddenSet; -@property (nonatomic) BOOL hasStatusBarStyleSet; -@property (nonatomic) BOOL hasStatusBarAnimationSet; -@property (nonatomic) BOOL hasHomeIndicatorHiddenSet; -@property (nonatomic) BOOL hasOrientationSet; -@property (nonatomic) RNSScreenSwipeDirection swipeDirection; -@property (nonatomic) RNSScreenStackPresentation stackPresentation; -@property (nonatomic) RNSScreenStackAnimation stackAnimation; -@property (nonatomic, retain) NSNumber *transitionDuration; - -#if !TARGET_OS_TV -@property (nonatomic) BOOL statusBarHidden; -@property (nonatomic) BOOL homeIndicatorHidden; -@property (nonatomic) RNSStatusBarStyle statusBarStyle; -@property (nonatomic) UIInterfaceOrientationMask screenOrientation; -@property (nonatomic) UIStatusBarAnimation statusBarAnimation; -#endif - -- (void)notifyWillAppear; -- (void)notifyWillDisappear; -- (void)notifyAppear; -- (void)notifyDisappear; -- (void)updateBounds; -- (void)notifyDismissedWithCount:(int)dismissCount; - -@end - -NS_ASSUME_NONNULL_END diff --git a/ios/RNSScreenComponentView.mm b/ios/RNSScreenComponentView.mm deleted file mode 100644 index c07d7e4b83..0000000000 --- a/ios/RNSScreenComponentView.mm +++ /dev/null @@ -1,485 +0,0 @@ -#import "RNSScreenComponentView.h" -#import "RNSConvert.h" -#import "RNSScreenStackHeaderConfigComponentView.h" -#import "RNSScreenWindowTraits.h" - -#import - -#import -#import -#import -#import - -#import "RCTFabricComponentsPlugins.h" - -#import -#import - -@interface RNSScreenComponentView () -@end - -@implementation RNSScreenComponentView { - RNSScreenController *_controller; - facebook::react::RNSScreenShadowNode::ConcreteState::Shared _state; - RCTSurfaceTouchHandler *_touchHandler; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; - _controller = [[RNSScreenController alloc] initWithView:self]; - // TODO: use default props (?) - _stackAnimation = RNSScreenStackAnimationDefault; - _stackPresentation = RNSScreenStackPresentationPush; - _hasStatusBarHiddenSet = NO; - _hasStatusBarStyleSet = NO; - _gestureEnabled = YES; - _hasStatusBarAnimationSet = NO; - _hasOrientationSet = NO; - _hasHomeIndicatorHiddenSet = NO; - } - - return self; -} - -- (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index -{ - [super mountChildComponentView:childComponentView index:index]; - if ([childComponentView isKindOfClass:[RNSScreenStackHeaderConfigComponentView class]]) { - _config = childComponentView; - ((RNSScreenStackHeaderConfigComponentView *)childComponentView).screenView = self; - } -} - -- (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index -{ - if ([childComponentView isKindOfClass:[RNSScreenStackHeaderConfigComponentView class]]) { - _config = nil; - } - [super unmountChildComponentView:childComponentView index:index]; -} - -- (void)updateBounds -{ - if (_state != nullptr) { - auto newState = facebook::react::RNSScreenState{RCTSizeFromCGSize(self.bounds.size)}; - _state->updateState(std::move(newState)); - UINavigationController *navctr = _controller.navigationController; - [navctr.view setNeedsLayout]; - } -} - -- (UIView *)reactSuperview -{ - return _reactSuperview; -} - -- (UIViewController *)reactViewController -{ - return _controller; -} - -- (void)notifyWillAppear -{ - // If screen is already unmounted then there will be no event emitter - // it will be cleaned in prepareForRecycle - if (_eventEmitter != nullptr) { - std::dynamic_pointer_cast(_eventEmitter) - ->onWillAppear(facebook::react::RNSScreenEventEmitter::OnWillAppear{}); - } -} - -- (void)notifyWillDisappear -{ - // If screen is already unmounted then there will be no event emitter - // it will be cleaned in prepareForRecycle - if (_eventEmitter != nullptr) { - std::dynamic_pointer_cast(_eventEmitter) - ->onWillDisappear(facebook::react::RNSScreenEventEmitter::OnWillDisappear{}); - } -} - -- (void)notifyAppear -{ - // If screen is already unmounted then there will be no event emitter - // it will be cleaned in prepareForRecycle - if (_eventEmitter != nullptr) { - std::dynamic_pointer_cast(_eventEmitter) - ->onAppear(facebook::react::RNSScreenEventEmitter::OnAppear{}); - } -} - -- (void)notifyDismissedWithCount:(int)dismissCount -{ - // If screen is already unmounted then there will be no event emitter - // it will be cleaned in prepareForRecycle - if (_eventEmitter != nullptr) { - std::dynamic_pointer_cast(_eventEmitter) - ->onDismissed(facebook::react::RNSScreenEventEmitter::OnDismissed{dismissCount : dismissCount}); - } -} - -- (void)notifyDisappear -{ - // If screen is already unmounted then there will be no event emitter - // it will be cleaned in prepareForRecycle - if (_eventEmitter != nullptr) { - std::dynamic_pointer_cast(_eventEmitter) - ->onDisappear(facebook::react::RNSScreenEventEmitter::OnDisappear{}); - } -} - -- (void)setStackPresentation:(RNSScreenStackPresentation)stackPresentation -{ - switch (stackPresentation) { - case RNSScreenStackPresentationModal: -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \ - __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 - if (@available(iOS 13.0, tvOS 13.0, *)) { - _controller.modalPresentationStyle = UIModalPresentationAutomatic; - } else { - _controller.modalPresentationStyle = UIModalPresentationFullScreen; - } -#else - _controller.modalPresentationStyle = UIModalPresentationFullScreen; -#endif - break; - case RNSScreenStackPresentationFullScreenModal: - _controller.modalPresentationStyle = UIModalPresentationFullScreen; - break; -#if !TARGET_OS_TV - case RNSScreenStackPresentationFormSheet: - _controller.modalPresentationStyle = UIModalPresentationFormSheet; - break; -#endif - case RNSScreenStackPresentationTransparentModal: - _controller.modalPresentationStyle = UIModalPresentationOverFullScreen; - break; - case RNSScreenStackPresentationContainedModal: - _controller.modalPresentationStyle = UIModalPresentationCurrentContext; - break; - case RNSScreenStackPresentationContainedTransparentModal: - _controller.modalPresentationStyle = UIModalPresentationOverCurrentContext; - break; - case RNSScreenStackPresentationPush: - // ignored, we only need to keep in mind not to set presentation delegate - break; - } - // There is a bug in UIKit which causes retain loop when presentationController is accessed for a - // controller that is not going to be presented modally. We therefore need to avoid setting the - // delegate for screens presented using push. This also means that when controller is updated from - // modal to push type, this may cause memory leak, we warn about that as well. - if (stackPresentation != RNSScreenStackPresentationPush) { - // `modalPresentationStyle` must be set before accessing `presentationController` - // otherwise a default controller will be created and cannot be changed after. - // Documented here: - // https://developer.apple.com/documentation/uikit/uiviewcontroller/1621426-presentationcontroller?language=objc - _controller.presentationController.delegate = self; - } else if (_stackPresentation != RNSScreenStackPresentationPush) { - RCTLogError( - @"Screen presentation updated from modal to push, this may likely result in a screen object leakage. If you need to change presentation style create a new screen object instead"); - } - _stackPresentation = stackPresentation; -} - -- (void)setStackAnimation:(RNSScreenStackAnimation)stackAnimation -{ - _stackAnimation = stackAnimation; - - switch (stackAnimation) { - case RNSScreenStackAnimationFade: - _controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - break; -#if !TARGET_OS_TV - case RNSScreenStackAnimationFlip: - _controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; - break; -#endif - case RNSScreenStackAnimationNone: - case RNSScreenStackAnimationDefault: - case RNSScreenStackAnimationSimplePush: - case RNSScreenStackAnimationSlideFromBottom: - case RNSScreenStackAnimationFadeFromBottom: - // Default - break; - } -} - -- (void)setGestureEnabled:(BOOL)gestureEnabled -{ -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \ - __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 - if (@available(iOS 13.0, tvOS 13.0, *)) { - _controller.modalInPresentation = !gestureEnabled; - } -#endif - _gestureEnabled = gestureEnabled; -} - -#if !TARGET_OS_TV -- (void)setStatusBarHidden:(BOOL)statusBarHidden -{ - _statusBarHidden = statusBarHidden; - _hasStatusBarHiddenSet = YES; - [RNSScreenWindowTraits assertViewControllerBasedStatusBarAppearenceSet]; - [RNSScreenWindowTraits updateStatusBarAppearance]; -} - -- (void)setStatusBarStyle:(RNSStatusBarStyle)statusBarStyle -{ - _hasStatusBarStyleSet = YES; - _statusBarStyle = statusBarStyle; - [RNSScreenWindowTraits assertViewControllerBasedStatusBarAppearenceSet]; - [RNSScreenWindowTraits updateStatusBarAppearance]; -} - -- (void)setStatusBarAnimation:(UIStatusBarAnimation)statusBarAnimation -{ - _hasStatusBarAnimationSet = YES; - _statusBarAnimation = statusBarAnimation; - [RNSScreenWindowTraits assertViewControllerBasedStatusBarAppearenceSet]; -} - -- (void)setScreenOrientation:(UIInterfaceOrientationMask)screenOrientation -{ - _hasOrientationSet = YES; - _screenOrientation = screenOrientation; - [RNSScreenWindowTraits enforceDesiredDeviceOrientation]; -} - -- (void)setHomeIndicatorHidden:(BOOL)homeIndicatorHidden -{ - _hasHomeIndicatorHiddenSet = YES; - _homeIndicatorHidden = homeIndicatorHidden; - [RNSScreenWindowTraits updateHomeIndicatorAutoHidden]; -} -#endif - -- (BOOL)isMountedUnderScreenOrReactRoot -{ - for (UIView *parent = self.superview; parent != nil; parent = parent.superview) { - if ([parent isKindOfClass:[RCTRootComponentView class]] || [parent isKindOfClass:[RNSScreenComponentView class]]) { - return YES; - } - } - return NO; -} - -- (void)didMoveToWindow -{ - if (self.window != nil && ![self isMountedUnderScreenOrReactRoot]) { - if (_touchHandler == nil) { - _touchHandler = [RCTSurfaceTouchHandler new]; - } - [_touchHandler attachToView:self]; - } else { - [_touchHandler detachFromView:self]; - } -} - -- (RCTSurfaceTouchHandler *)touchHandler -{ - if (_touchHandler != nil) { - return _touchHandler; - } - UIView *parent = [self superview]; - while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) - parent = parent.superview; - - if (parent != nil) { - return [parent performSelector:@selector(touchHandler)]; - } - return nil; -} - -#pragma mark - RCTComponentViewProtocol - -- (void)prepareForRecycle -{ - [super prepareForRecycle]; - // TODO: Make sure that there is no edge case when this should be uncommented - // _controller=nil; - _state.reset(); -} - -+ (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider -{ - return facebook::react::concreteComponentDescriptorProvider(); -} - -- (void)updateProps:(facebook::react::Props::Shared const &)props - oldProps:(facebook::react::Props::Shared const &)oldProps -{ - const auto &oldScreenProps = *std::static_pointer_cast(_props); - const auto &newScreenProps = *std::static_pointer_cast(props); - - [self setFullScreenSwipeEnabled:newScreenProps.fullScreenSwipeEnabled]; - - [self setGestureEnabled:newScreenProps.gestureEnabled]; - - [self setTransitionDuration:[NSNumber numberWithInt:newScreenProps.transitionDuration]]; - - if (newScreenProps.statusBarHidden != oldScreenProps.statusBarHidden) { - [self setStatusBarHidden:newScreenProps.statusBarHidden]; - } - - if (newScreenProps.statusBarStyle != oldScreenProps.statusBarStyle) { - [self setStatusBarStyle:[RCTConvert - RNSStatusBarStyle:RCTNSStringFromStringNilIfEmpty(newScreenProps.statusBarStyle)]]; - } - - if (newScreenProps.statusBarAnimation != oldScreenProps.statusBarAnimation) { - [self setStatusBarAnimation:[RCTConvert UIStatusBarAnimation:RCTNSStringFromStringNilIfEmpty( - newScreenProps.statusBarAnimation)]]; - } - - if (newScreenProps.screenOrientation != oldScreenProps.screenOrientation) { - [self setScreenOrientation:[RCTConvert UIInterfaceOrientationMask:RCTNSStringFromStringNilIfEmpty( - newScreenProps.screenOrientation)]]; - } - - if (newScreenProps.stackPresentation != oldScreenProps.stackPresentation) { - [self - setStackPresentation:[RNSConvert RNSScreenStackPresentationFromCppEquivalent:newScreenProps.stackPresentation]]; - } - - if (newScreenProps.stackAnimation != oldScreenProps.stackAnimation) { - [self setStackAnimation:[RNSConvert RNSScreenStackAnimationFromCppEquivalent:newScreenProps.stackAnimation]]; - } - - if (newScreenProps.statusBarColor) { - [self logPropNotAvailable:@"statusBarColor"]; - } - - if (newScreenProps.statusBarTranslucent) { - [self logPropNotAvailable:@"statusBarTranslucent"]; - } - - [self setFullScreenSwipeEnabled:newScreenProps.fullScreenSwipeEnabled]; - - [self setGestureEnabled:newScreenProps.gestureEnabled]; - - if (newScreenProps.statusBarHidden != oldScreenProps.statusBarHidden) { - [self setStatusBarHidden:newScreenProps.statusBarHidden]; - } - - if (newScreenProps.statusBarStyle != oldScreenProps.statusBarStyle) { - [self setStatusBarStyle:[RCTConvert RNSStatusBarStyle:[self stringToPropValue:newScreenProps.statusBarStyle]]]; - } - - if (newScreenProps.statusBarAnimation != oldScreenProps.statusBarAnimation) { - [self setStatusBarAnimation:[RCTConvert - UIStatusBarAnimation:[self stringToPropValue:newScreenProps.statusBarAnimation]]]; - } - - if (newScreenProps.screenOrientation != oldScreenProps.screenOrientation) { - [self - setScreenOrientation:[RCTConvert - UIInterfaceOrientationMask:[self stringToPropValue:newScreenProps.screenOrientation]]]; - } - - if (newScreenProps.statusBarColor) { - [self logPropNotAvailable:@"statusBarColor"]; - } - - if (newScreenProps.statusBarTranslucent) { - [self logPropNotAvailable:@"statusBarTranslucent"]; - } - - [super updateProps:props oldProps:oldProps]; - - _fullScreenSwipeEnabled = newScreenProps.fullScreenSwipeEnabled; - _gestureEnabled = newScreenProps.gestureEnabled; -} - -- (void)updateState:(facebook::react::State::Shared const &)state - oldState:(facebook::react::State::Shared const &)oldState -{ - _state = std::static_pointer_cast(state); -} - -#pragma mark - Util - -- (void)logPropNotAvailable:(NSString *)propName -{ - NSLog(@"%@ prop not available on iOS", propName); -} - -- (NSString *)stringToPropValue:(std::string)value -{ - if (value.empty()) - return nil; - return [[NSString alloc] initWithUTF8String:value.c_str()]; -} -@end - -Class RNSScreenCls(void) -{ - return RNSScreenComponentView.class; -} - -@implementation RCTConvert (RNSScreenComponentView) - -RCT_ENUM_CONVERTER( - UIStatusBarAnimation, - (@{ - @"none" : @(UIStatusBarAnimationNone), - @"fade" : @(UIStatusBarAnimationFade), - @"slide" : @(UIStatusBarAnimationSlide) - }), - UIStatusBarAnimationNone, - integerValue) - -RCT_ENUM_CONVERTER( - RNSScreenStackPresentation, - (@{ - @"push" : @(RNSScreenStackPresentationPush), - @"modal" : @(RNSScreenStackPresentationModal), - @"fullScreenModal" : @(RNSScreenStackPresentationFullScreenModal), - @"formSheet" : @(RNSScreenStackPresentationFormSheet), - @"containedModal" : @(RNSScreenStackPresentationContainedModal), - @"transparentModal" : @(RNSScreenStackPresentationTransparentModal), - @"containedTransparentModal" : @(RNSScreenStackPresentationContainedTransparentModal) - }), - RNSScreenStackPresentationPush, - integerValue) - -#if !TARGET_OS_TV -RCT_ENUM_CONVERTER( - RNSStatusBarStyle, - (@{ - @"auto" : @(RNSStatusBarStyleAuto), - @"inverted" : @(RNSStatusBarStyleInverted), - @"light" : @(RNSStatusBarStyleLight), - @"dark" : @(RNSStatusBarStyleDark), - }), - RNSStatusBarStyleAuto, - integerValue) - -+ (UIInterfaceOrientationMask)UIInterfaceOrientationMask:(id)json -{ - json = [self NSString:json]; - if ([json isEqualToString:@"default"]) { - return UIInterfaceOrientationMaskAllButUpsideDown; - } else if ([json isEqualToString:@"all"]) { - return UIInterfaceOrientationMaskAll; - } else if ([json isEqualToString:@"portrait"]) { - return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; - } else if ([json isEqualToString:@"portrait_up"]) { - return UIInterfaceOrientationMaskPortrait; - } else if ([json isEqualToString:@"portrait_down"]) { - return UIInterfaceOrientationMaskPortraitUpsideDown; - } else if ([json isEqualToString:@"landscape"]) { - return UIInterfaceOrientationMaskLandscape; - } else if ([json isEqualToString:@"landscape_left"]) { - return UIInterfaceOrientationMaskLandscapeLeft; - } else if ([json isEqualToString:@"landscape_right"]) { - return UIInterfaceOrientationMaskLandscapeRight; - } - return UIInterfaceOrientationMaskAllButUpsideDown; -} -#endif - -@end diff --git a/ios/RNSScreenController.h b/ios/RNSScreenController.h deleted file mode 100644 index 6ce38cba82..0000000000 --- a/ios/RNSScreenController.h +++ /dev/null @@ -1,12 +0,0 @@ -#import -#import "RNSScreenContainer.h" - -@interface RNSScreenController : UIViewController - -- (instancetype)initWithView:(UIView *)view; -- (void)setViewToSnapshot:(UIView *)snapshot; -- (void)resetViewToScreen; - -- (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals; - -@end diff --git a/ios/RNSScreenController.mm b/ios/RNSScreenController.mm deleted file mode 100644 index b4f4aaa789..0000000000 --- a/ios/RNSScreenController.mm +++ /dev/null @@ -1,198 +0,0 @@ -#import -#import "RNSScreenComponentView.h" -#import "RNSScreenWindowTraits.h" - -@implementation RNSScreenController { - RNSScreenComponentView *_initialView; -} - -- (instancetype)initWithView:(UIView *)view -{ - if (self = [super init]) { - self.view = view; - if ([view isKindOfClass:[RNSScreenComponentView class]]) { - _initialView = (RNSScreenComponentView *)view; - } else { - RCTLogError(@"ScreenController can only be initialized with ScreenComponentView"); - } - } - return self; -} - -- (void)setViewToSnapshot:(UIView *)snapshot -{ - [self.view removeFromSuperview]; - self.view = snapshot; -} - -- (void)resetViewToScreen -{ - [self.view removeFromSuperview]; - self.view = _initialView; -} - -// TODO: Find out why this is executed when screen is going out -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - [RNSScreenWindowTraits updateWindowTraits]; - [_initialView notifyWillAppear]; -} - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - [_initialView notifyWillDisappear]; -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - [_initialView notifyAppear]; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - [_initialView notifyDisappear]; - if (self.parentViewController == nil && self.presentingViewController == nil) { - // screen dismissed, send event - [_initialView notifyDismissedWithCount:1]; - } -} - -- (void)viewDidLayoutSubviews -{ - [super viewDidLayoutSubviews]; - BOOL isDisplayedWithinUINavController = [self.parentViewController isKindOfClass:[UINavigationController class]]; - if (isDisplayedWithinUINavController) { - [_initialView updateBounds]; - } -} - -#if !TARGET_OS_TV -// if the returned vc is a child, it means that it can provide config; -// if the returned vc is self, it means that there is no child for config and self has config to provide, -// so we return self which results in asking self for preferredStatusBarStyle/Animation etc.; -// if the returned vc is nil, it means none of children could provide config and self does not have config either, -// so if it was asked by parent, it will fallback to parent's option, or use default option if it is the top Screen -- (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals -{ - UIViewController *lastViewController = [[self childViewControllers] lastObject]; - if ([self.presentedViewController isKindOfClass:[RNSScreenController class]]) { - lastViewController = self.presentedViewController; - // we don't want to allow controlling of status bar appearance when we present non-fullScreen modal - // and it is not possible if `modalPresentationCapturesStatusBarAppearance` is not set to YES, so even - // if we went into a modal here and ask it, it wouldn't take any effect. For fullScreen modals, the system - // asks them by itself, so we can stop traversing here. - // for screen orientation, we need to start the search again from that modal - return !includingModals - ? nil - : [(RNSScreenController *)lastViewController findChildVCForConfigAndTrait:trait includingModals:includingModals] - ?: lastViewController; - } - - UIViewController *selfOrNil = [self hasTraitSet:trait] ? self : nil; - if (lastViewController == nil) { - return selfOrNil; - } else { - if ([lastViewController conformsToProtocol:@protocol(RNScreensViewControllerDelegate)]) { - // If there is a child (should be VC of ScreenContainer or ScreenStack), that has a child that could provide the - // trait, we recursively go into its findChildVCForConfig, and if one of the children has the trait set, we return - // it, otherwise we return self if this VC has config, and nil if it doesn't we use - // `childViewControllerForStatusBarStyle` for all options since the behavior is the same for all of them - UIViewController *childScreen = [lastViewController childViewControllerForStatusBarStyle]; - if ([childScreen isKindOfClass:[RNSScreenController class]]) { - return [(RNSScreenController *)childScreen findChildVCForConfigAndTrait:trait includingModals:includingModals] - ?: selfOrNil; - } else { - return selfOrNil; - } - } else { - // child vc is not from this library, so we don't ask it - return selfOrNil; - } - } -} - -- (BOOL)hasTraitSet:(RNSWindowTrait)trait -{ - switch (trait) { - case RNSWindowTraitStyle: { - return ((RNSScreenComponentView *)self.view).hasStatusBarStyleSet; - } - case RNSWindowTraitAnimation: { - return ((RNSScreenComponentView *)self.view).hasStatusBarAnimationSet; - } - case RNSWindowTraitHidden: { - return ((RNSScreenComponentView *)self.view).hasStatusBarHiddenSet; - } - case RNSWindowTraitOrientation: { - return ((RNSScreenComponentView *)self.view).hasOrientationSet; - } - case RNSWindowTraitHomeIndicatorHidden: { - return ((RNSScreenComponentView *)self.view).hasHomeIndicatorHiddenSet; - } - default: { - RCTLogError(@"Unknown trait passed: %d", (int)trait); - } - } - return NO; -} - -- (UIViewController *)childViewControllerForStatusBarHidden -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHidden includingModals:NO]; - return vc == self ? nil : vc; -} - -- (BOOL)prefersStatusBarHidden -{ - return ((RNSScreenComponentView *)self.view).statusBarHidden; -} - -- (UIViewController *)childViewControllerForStatusBarStyle -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitStyle includingModals:NO]; - return vc == self ? nil : vc; -} - -- (UIStatusBarStyle)preferredStatusBarStyle -{ - return - [RNSScreenWindowTraits statusBarStyleForRNSStatusBarStyle:((RNSScreenComponentView *)self.view).statusBarStyle]; -} - -- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitAnimation includingModals:NO]; - - if ([vc isKindOfClass:[RNSScreenController class]]) { - return ((RNSScreenComponentView *)vc.view).statusBarAnimation; - } - return UIStatusBarAnimationFade; -} - -- (UIInterfaceOrientationMask)supportedInterfaceOrientations -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitOrientation includingModals:YES]; - - if ([vc isKindOfClass:[RNSScreenController class]]) { - return ((RNSScreenComponentView *)vc.view).screenOrientation; - } - return UIInterfaceOrientationMaskAllButUpsideDown; -} - -- (UIViewController *)childViewControllerForHomeIndicatorAutoHidden -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHomeIndicatorHidden includingModals:YES]; - return vc == self ? nil : vc; -} - -- (BOOL)prefersHomeIndicatorAutoHidden -{ - return ((RNSScreenComponentView *)self.view).homeIndicatorHidden; -} -#endif - -@end From 6dd5347b1c02adcd952bab9c67a9db09dac27a8a Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 8 Apr 2022 15:05:40 +0200 Subject: [PATCH 003/105] refract: Rename dependencies to make previous change work --- ios/RNSScreenStackAnimator.m | 18 ++---- ios/RNSScreenStackComponentView.mm | 59 ++++++++++++------- ios/RNSScreenStackHeaderConfigComponentView.h | 4 +- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/ios/RNSScreenStackAnimator.m b/ios/RNSScreenStackAnimator.m index fb48a24e79..efc10ff8c5 100644 --- a/ios/RNSScreenStackAnimator.m +++ b/ios/RNSScreenStackAnimator.m @@ -1,13 +1,7 @@ #import "RNSScreenStackAnimator.h" #import "RNSScreenStack.h" -#if RN_FABRIC_ENABLED -#import "RNSScreenComponentView.h" -#define RNSView RNSScreenComponentView -#else #import "RNSScreen.h" -#define RNSView RNSScreenView -#endif // proportions to default transition duration static const float RNSSlideOpenTransitionDurationProportion = 1; @@ -32,15 +26,15 @@ - (instancetype)initWithOperation:(UINavigationControllerOperation)operation - (NSTimeInterval)transitionDuration:(id)transitionContext { - RNSView *screen; + RNSScreenView *screen; if (_operation == UINavigationControllerOperationPush) { UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; - screen = (RNSView *)toViewController.view; + screen = (RNSScreenView *)toViewController.view; } else if (_operation == UINavigationControllerOperationPop) { UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; - screen = (RNSView *)fromViewController.view; + screen = (RNSScreenView *)fromViewController.view; } if (screen != nil && screen.stackAnimation == RNSScreenStackAnimationNone) { @@ -62,11 +56,11 @@ - (void)animateTransition:(id)transitionCo [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; - RNSView *screen; + RNSScreenView *screen; if (_operation == UINavigationControllerOperationPush) { - screen = (RNSView *)toViewController.view; + screen = (RNSScreenView *)toViewController.view; } else if (_operation == UINavigationControllerOperationPop) { - screen = (RNSView *)fromViewController.view; + screen = (RNSScreenView *)fromViewController.view; } if (screen != nil) { diff --git a/ios/RNSScreenStackComponentView.mm b/ios/RNSScreenStackComponentView.mm index 25a371407b..f6635bacf3 100644 --- a/ios/RNSScreenStackComponentView.mm +++ b/ios/RNSScreenStackComponentView.mm @@ -1,5 +1,5 @@ #import "RNSScreenStackComponentView.h" -#import "RNSScreenComponentView.h" +#import "RNSScreen.h" #import "RNSScreenStackAnimator.h" #import "RNSScreenStackHeaderConfigComponentView.h" #import "RNSScreenWindowTraits.h" @@ -49,7 +49,7 @@ @implementation RNSPanGestureRecognizerF @implementation RNSScreenStackComponentView { UINavigationController *_controller; - NSMutableArray *_reactSubviews; + NSMutableArray *_reactSubviews; BOOL _invalidated; UIView *_snapshot; BOOL _isFullWidthSwiping; @@ -76,7 +76,9 @@ - (instancetype)initWithFrame:(CGRect)frame - (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { - if (![childComponentView isKindOfClass:[RNSScreenComponentView class]]) { + // TODO: Remove this if def when merging with RNSScreenStack +#ifdef RN_FABRIC_ENABLED + if (![childComponentView isKindOfClass:[RNSScreenView class]]) { RCTLogError(@"ScreenStack only accepts children of type Screen"); return; } @@ -89,16 +91,19 @@ - (void)mountChildComponentView:(UIView *)childCompone @(index), @([childComponentView.superview tag])); - [_reactSubviews insertObject:(RNSScreenComponentView *)childComponentView atIndex:index]; - ((RNSScreenComponentView *)childComponentView).reactSuperview = self; + [_reactSubviews insertObject:(RNSScreenView *)childComponentView atIndex:index]; + ((RNSScreenView *)childComponentView).reactSuperview = self; dispatch_async(dispatch_get_main_queue(), ^{ [self maybeAddToParentAndUpdateContainer]; }); +#endif } - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { - RNSScreenComponentView *screenChildComponent = (RNSScreenComponentView *)childComponentView; + // TODO: Remove this if def when merging with RNSScreenStack +#ifdef RN_FABRIC_ENABLED + RNSScreenView *screenChildComponent = (RNSScreenView *)childComponentView; // We should only do a snapshot of a screen that is on the top if (screenChildComponent == _controller.topViewController.view) { [screenChildComponent.controller setViewToSnapshot:_snapshot]; @@ -124,6 +129,7 @@ - (void)unmountChildComponentView:(UIView *)childCompo dispatch_async(dispatch_get_main_queue(), ^{ [self maybeAddToParentAndUpdateContainer]; }); +#endif } - (void)takeSnapshot @@ -152,12 +158,16 @@ - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { + // TODO: Remove this if def when merging with RNSScreenStack +#ifdef RN_FABRIC_ENABLED + UIView *view = viewController.view; - if ([view isKindOfClass:RNSScreenComponentView.class]) { + if ([view isKindOfClass:RNSScreenView.class]) { RNSScreenStackHeaderConfigComponentView *config = - (RNSScreenStackHeaderConfigComponentView *)((RNSScreenComponentView *)view).config; + (RNSScreenStackHeaderConfigComponentView *)((RNSScreenView *)view).config; [RNSScreenStackHeaderConfigComponentView willShowViewController:viewController animated:animated withConfig:config]; } +#endif } - (void)maybeAddToParentAndUpdateContainer @@ -208,7 +218,7 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio // We don't directly set presentation delegate but instead rely on the ScreenView's delegate to // forward certain calls to the container (Stack). UIView *screenView = presentationController.presentedViewController.view; - if ([screenView isKindOfClass:[RNSScreenComponentView class]]) { + if ([screenView isKindOfClass:[RNSScreenView class]]) { // we trigger the update of status bar's appearance here because there is no other lifecycle method // that can handle it when dismissing a modal, the same for orientation [RNSScreenWindowTraits updateWindowTraits]; @@ -233,6 +243,9 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio - (void)setPushViewControllers:(NSArray *)controllers { + // TODO: Remove this if def when merging with RNSScreenStack +#ifdef RN_FABRIC_ENABLED + // when there is no change we return immediately if ([_controller.viewControllers isEqualToArray:controllers]) { return; @@ -273,7 +286,7 @@ - (void)setPushViewControllers:(NSArray *)controllers // instance. This is a workaround for header height adjustment bug (see comment // in the init function). Here, we need to detect if the initial empty // controller is still there - BOOL firstTimePush = ![previousTop isKindOfClass:[RNSScreenController class]]; + BOOL firstTimePush = ![previousTop isKindOfClass:[RNSScreen class]]; if (firstTimePush) { // nothing pushed yet @@ -284,7 +297,7 @@ - (void)setPushViewControllers:(NSArray *)controllers // was called, so we check the animation if (![_controller.viewControllers containsObject:top]) { // setting new controllers with animation does `push` animation by default - auto screenController = (RNSScreenController *)top; + auto screenController = (RNSScreen *)top; [screenController resetViewToScreen]; [_controller setViewControllers:controllers animated:YES]; } else { @@ -303,7 +316,7 @@ - (void)setPushViewControllers:(NSArray *)controllers NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; [newControllers removeLastObject]; [_controller setViewControllers:newControllers animated:NO]; - auto screenController = (RNSScreenController *)top; + auto screenController = (RNSScreen *)top; [screenController resetViewToScreen]; [_controller pushViewController:top animated:YES]; } else { @@ -315,6 +328,7 @@ - (void)setPushViewControllers:(NSArray *)controllers // change wasn't on the top of the stack. We don't need animation. [_controller setViewControllers:controllers animated:NO]; } +#endif } - (void)setModalViewControllers:(NSArray *)controllers @@ -413,8 +427,8 @@ - (void)setModalViewControllers:(NSArray *)controllers } #endif - BOOL shouldAnimate = lastModal && [next isKindOfClass:[RNSScreenController class]] && - ((RNSScreenComponentView *)next.view).stackAnimation != RNSScreenStackAnimationNone; + BOOL shouldAnimate = lastModal && [next isKindOfClass:[RNSScreen class]] && + ((RNSScreenView *)next.view).stackAnimation != RNSScreenStackAnimationNone; // if you want to present another modal quick enough after dismissing the previous one, // it will result in wrong changeRootController, see repro in @@ -440,8 +454,8 @@ - (void)setModalViewControllers:(NSArray *)controllers if (changeRootController.presentedViewController != nil && [_presentedModals containsObject:changeRootController.presentedViewController]) { BOOL shouldAnimate = changeRootIndex == controllers.count && - [changeRootController.presentedViewController isKindOfClass:[RNSScreenController class]] && - ((RNSScreenComponentView *)changeRootController.presentedViewController.view).stackAnimation != + [changeRootController.presentedViewController isKindOfClass:[RNSScreen class]] && + ((RNSScreenView *)changeRootController.presentedViewController.view).stackAnimation != RNSScreenStackAnimationNone; [changeRootController dismissViewControllerAnimated:shouldAnimate completion:finish]; } else { @@ -453,7 +467,7 @@ - (void)updateContainer { NSMutableArray *pushControllers = [NSMutableArray new]; NSMutableArray *modalControllers = [NSMutableArray new]; - for (RNSScreenComponentView *screen in _reactSubviews) { + for (RNSScreenView *screen in _reactSubviews) { if (screen.controller != nil) { if (pushControllers.count == 0) { // first screen on the list needs to be places as "push controller" @@ -480,8 +494,11 @@ - (void)layoutSubviews - (void)dismissOnReload { - auto screenController = (RNSScreenController *)_controller.topViewController; + // TODO: Remove this ifdef when merging with RNSScreenStack +#ifdef RN_FABRIC_ENABLED + auto screenController = (RNSScreen *)_controller.topViewController; [screenController resetViewToScreen]; +#endif } #pragma mark - methods connected to transitioning @@ -526,9 +543,9 @@ - (void)cancelTouchesInParent - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { - RNSScreenComponentView *topScreen = (RNSScreenComponentView *)_controller.viewControllers.lastObject.view; + RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; - if (![topScreen isKindOfClass:[RNSScreenComponentView class]] || !topScreen.gestureEnabled || + if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled || _controller.viewControllers.count < 2) { return NO; } @@ -587,7 +604,7 @@ - (void)setupGestureHandlers - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer { - RNSScreenComponentView *topScreen = (RNSScreenComponentView *)_controller.viewControllers.lastObject.view; + RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; float translation; float velocity; diff --git a/ios/RNSScreenStackHeaderConfigComponentView.h b/ios/RNSScreenStackHeaderConfigComponentView.h index 7fd944f643..390023adc8 100644 --- a/ios/RNSScreenStackHeaderConfigComponentView.h +++ b/ios/RNSScreenStackHeaderConfigComponentView.h @@ -2,12 +2,12 @@ #import -#import "RNSScreenComponentView.h" +#import "RNSScreen.h" #import "RNSScreenStackHeaderSubviewComponentView.h" @interface RNSScreenStackHeaderConfigComponentView : RCTViewComponentView -@property (nonatomic, weak) RNSScreenComponentView *screenView; +@property (nonatomic, weak) RNSScreenView *screenView; @property (nonatomic) NSMutableArray *reactSubviews; // Properties from props From 9f78cc080c425c4de9bd7ded2db968dcc2a85f20 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 14 Apr 2022 10:21:11 +0200 Subject: [PATCH 004/105] chore: update Cocoapods to .3 --- FabricExample/ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FabricExample/ios/Podfile.lock b/FabricExample/ios/Podfile.lock index 9d3c7b46ed..3a247691e4 100644 --- a/FabricExample/ios/Podfile.lock +++ b/FabricExample/ios/Podfile.lock @@ -955,11 +955,11 @@ SPEC CHECKSUMS: React-rncore: f16be923fa7927977764ae31c65996f538b7e3b9 React-runtimeexecutor: 482f9d03c0764d4ae3fdf4687f6c975556bf71a2 ReactCommon: e23be08d1b21d8ab0dff24ce1afbe57942e9090f - RNScreens: b29ddf58060cdb2a274a044318a8c78b555f7860 + RNScreens: 2db1ede02cf20c64703931bc41c1ffe360377bfd SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 Yoga: d473a4284ea9eae9e312b38b8a62d9dedc4dd2f0 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: d1692aab6ddf32b03dc03304e2dc04073ec65f35 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 From 9b183753121323b7031be5d9b4ed307c04d955af Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 14 Apr 2022 12:22:28 +0200 Subject: [PATCH 005/105] fix: type in RNSScreen.mm --- ios/RNSScreen.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index a2e65881be..a3ba3f2528 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -50,7 +50,7 @@ @implementation RNSScreenView { #endif } -#if RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { From 4a1c31515d688c39b4ea1dc6708d742cd3488212 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 14 Apr 2022 13:18:26 +0200 Subject: [PATCH 006/105] fix: add missing space to compiler flags in RNScreens.podspec It caused RN_FABRIC_ENABLED flag to be invalid (as it merged with previous flag from the list...) --- RNScreens.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNScreens.podspec b/RNScreens.podspec index b224c31341..fd93a55dcb 100644 --- a/RNScreens.podspec +++ b/RNScreens.podspec @@ -29,7 +29,7 @@ Pod::Spec.new do |s| "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", } s.platforms = { ios: '11.0', tvos: '11.0' } - s.compiler_flags = folly_compiler_flags + '-DRN_FABRIC_ENABLED' + s.compiler_flags = folly_compiler_flags + ' -DRN_FABRIC_ENABLED' s.source_files = 'ios/**/*.{h,m,mm,cpp}' s.requires_arc = true From 76efc1915d7e1c0b15787f02b0d329af38b83023 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:06:31 +0200 Subject: [PATCH 007/105] refact: rename all source .m files to .mm Otherwise C++ standard headers are not visible from .m files -> project fails to build. e.g. Whem=n A.m includes B.h & B.h imports memory header: "#include " -- memory header is not visible & compilation fails --- ios/{RNSFullWindowOverlay.m => RNSFullWindowOverlay.mm} | 0 ios/{RNSScreenContainer.m => RNSScreenContainer.mm} | 0 ...creenNavigationContainer.m => RNSScreenNavigationContainer.mm} | 0 ios/{RNSScreenStack.m => RNSScreenStack.mm} | 0 ios/{RNSScreenStackAnimator.m => RNSScreenStackAnimator.mm} | 0 ...RNSScreenStackHeaderConfig.m => RNSScreenStackHeaderConfig.mm} | 0 ios/{RNSScreenWindowTraits.m => RNSScreenWindowTraits.mm} | 0 ios/{RNSSearchBar.m => RNSSearchBar.mm} | 0 ...UIViewController+RNScreens.m => UIViewController+RNScreens.mm} | 0 ios/{UIWindow+RNScreens.m => UIWindow+RNScreens.mm} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename ios/{RNSFullWindowOverlay.m => RNSFullWindowOverlay.mm} (100%) rename ios/{RNSScreenContainer.m => RNSScreenContainer.mm} (100%) rename ios/{RNSScreenNavigationContainer.m => RNSScreenNavigationContainer.mm} (100%) rename ios/{RNSScreenStack.m => RNSScreenStack.mm} (100%) rename ios/{RNSScreenStackAnimator.m => RNSScreenStackAnimator.mm} (100%) rename ios/{RNSScreenStackHeaderConfig.m => RNSScreenStackHeaderConfig.mm} (100%) rename ios/{RNSScreenWindowTraits.m => RNSScreenWindowTraits.mm} (100%) rename ios/{RNSSearchBar.m => RNSSearchBar.mm} (100%) rename ios/{UIViewController+RNScreens.m => UIViewController+RNScreens.mm} (100%) rename ios/{UIWindow+RNScreens.m => UIWindow+RNScreens.mm} (100%) diff --git a/ios/RNSFullWindowOverlay.m b/ios/RNSFullWindowOverlay.mm similarity index 100% rename from ios/RNSFullWindowOverlay.m rename to ios/RNSFullWindowOverlay.mm diff --git a/ios/RNSScreenContainer.m b/ios/RNSScreenContainer.mm similarity index 100% rename from ios/RNSScreenContainer.m rename to ios/RNSScreenContainer.mm diff --git a/ios/RNSScreenNavigationContainer.m b/ios/RNSScreenNavigationContainer.mm similarity index 100% rename from ios/RNSScreenNavigationContainer.m rename to ios/RNSScreenNavigationContainer.mm diff --git a/ios/RNSScreenStack.m b/ios/RNSScreenStack.mm similarity index 100% rename from ios/RNSScreenStack.m rename to ios/RNSScreenStack.mm diff --git a/ios/RNSScreenStackAnimator.m b/ios/RNSScreenStackAnimator.mm similarity index 100% rename from ios/RNSScreenStackAnimator.m rename to ios/RNSScreenStackAnimator.mm diff --git a/ios/RNSScreenStackHeaderConfig.m b/ios/RNSScreenStackHeaderConfig.mm similarity index 100% rename from ios/RNSScreenStackHeaderConfig.m rename to ios/RNSScreenStackHeaderConfig.mm diff --git a/ios/RNSScreenWindowTraits.m b/ios/RNSScreenWindowTraits.mm similarity index 100% rename from ios/RNSScreenWindowTraits.m rename to ios/RNSScreenWindowTraits.mm diff --git a/ios/RNSSearchBar.m b/ios/RNSSearchBar.mm similarity index 100% rename from ios/RNSSearchBar.m rename to ios/RNSSearchBar.mm diff --git a/ios/UIViewController+RNScreens.m b/ios/UIViewController+RNScreens.mm similarity index 100% rename from ios/UIViewController+RNScreens.m rename to ios/UIViewController+RNScreens.mm diff --git a/ios/UIWindow+RNScreens.m b/ios/UIWindow+RNScreens.mm similarity index 100% rename from ios/UIWindow+RNScreens.m rename to ios/UIWindow+RNScreens.mm From 947ac3d315eab3f090168872213e705879b09b20 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:10:01 +0200 Subject: [PATCH 008/105] chore: update FabricExample's Podfile.lock --- FabricExample/ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FabricExample/ios/Podfile.lock b/FabricExample/ios/Podfile.lock index 3a247691e4..5c225fd1c0 100644 --- a/FabricExample/ios/Podfile.lock +++ b/FabricExample/ios/Podfile.lock @@ -955,7 +955,7 @@ SPEC CHECKSUMS: React-rncore: f16be923fa7927977764ae31c65996f538b7e3b9 React-runtimeexecutor: 482f9d03c0764d4ae3fdf4687f6c975556bf71a2 ReactCommon: e23be08d1b21d8ab0dff24ce1afbe57942e9090f - RNScreens: 2db1ede02cf20c64703931bc41c1ffe360377bfd + RNScreens: 592316e0744de3b640e90c335a45aad13088381a SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 Yoga: d473a4284ea9eae9e312b38b8a62d9dedc4dd2f0 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a From c2e020d0fb6d2e27b14dd13cb76c0945909a7fd3 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:18:37 +0200 Subject: [PATCH 009/105] fix: move reactSetFrame: method to Paper specific section --- ios/RNSScreen.mm | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index a3ba3f2528..2ee0402c15 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -92,20 +92,6 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge } #endif -- (void)reactSetFrame:(CGRect)frame -{ - _reactFrame = frame; - UIViewController *parentVC = self.reactViewController.parentViewController; - if (parentVC != nil && ![parentVC isKindOfClass:[RNScreensNavigationController class]]) { - [super reactSetFrame:frame]; - } - // when screen is mounted under RNScreensNavigationController it's size is controller - // by the navigation controller itself. That is, it is set to fill space of - // the controller. In that case we ignore react layout system from managing - // the screen dimensions and we wait for the screen VC to update and then we - // pass the dimensions to ui view manager to take into account when laying out - // subviews -} - (UIViewController *)reactViewController { @@ -588,6 +574,22 @@ - (void)updateState:(facebook::react::State::Shared const &)state #pragma mark - Paper specific #else + +- (void)reactSetFrame:(CGRect)frame +{ + _reactFrame = frame; + UIViewController *parentVC = self.reactViewController.parentViewController; + if (parentVC != nil && ![parentVC isKindOfClass:[RNScreensNavigationController class]]) { + [super reactSetFrame:frame]; + } + // when screen is mounted under RNScreensNavigationController it's size is controller + // by the navigation controller itself. That is, it is set to fill space of + // the controller. In that case we ignore react layout system from managing + // the screen dimensions and we wait for the screen VC to update and then we + // pass the dimensions to ui view manager to take into account when laying out + // subviews +} + - (void)presentationControllerWillDismiss:(UIPresentationController *)presentationController { // We need to call both "cancel" and "reset" here because RN's gesture recognizer From f0c88c26ae75ca2e5db1f119051dd5c5e5357386 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:20:22 +0200 Subject: [PATCH 010/105] fix: fix typo in ifdef directive --- ios/RNSScreen.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 2ee0402c15..ca7b23558a 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -100,7 +100,7 @@ - (UIViewController *)reactViewController - (void)updateBounds { -#ifdef RN_FABRIC_ENDABLED +#ifdef RN_FABRIC_ENABLED if (_state != nullptr) { auto newState = facebook::react::RNSScreenState{RCTSizeFromCGSize(self.bounds.size)}; _state->updateState(std::move(newState)); From b37a60a7cf331f3dac9ac5845ba29be58e0bd4f3 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:22:21 +0200 Subject: [PATCH 011/105] fix: temporary: move setActivityStateOrNil & setPointerEvents methods to paper specific section --- ios/RNSScreen.mm | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index ca7b23558a..f8c588af0b 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -112,24 +112,6 @@ - (void)updateBounds #endif } -// Nil will be provided when activityState is set as an animated value and we change -// it from JS to be a plain value (non animated). -// In case when nil is received, we want to ignore such value and not make -// any updates as the actual non-nil value will follow immediately. -- (void)setActivityStateOrNil:(NSNumber *)activityStateOrNil -{ - int activityState = [activityStateOrNil intValue]; - if (activityStateOrNil != nil && activityState != _activityState) { - _activityState = activityState; - [_reactSuperview markChildUpdated]; - } -} - -- (void)setPointerEvents:(RCTPointerEvents)pointerEvents -{ - // pointer events settings are managed by the parent screen container, we ignore - // any attempt of setting that via React props -} - (void)setStackPresentation:(RNSScreenStackPresentation)stackPresentation { @@ -575,6 +557,25 @@ - (void)updateState:(facebook::react::State::Shared const &)state #pragma mark - Paper specific #else +// Nil will be provided when activityState is set as an animated value and we change +// it from JS to be a plain value (non animated). +// In case when nil is received, we want to ignore such value and not make +// any updates as the actual non-nil value will follow immediately. +- (void)setActivityStateOrNil:(NSNumber *)activityStateOrNil +{ + int activityState = [activityStateOrNil intValue]; + if (activityStateOrNil != nil && activityState != _activityState) { + _activityState = activityState; + [_reactSuperview markChildUpdated] + } +} + +- (void)setPointerEvents:(RCTPointerEvents)pointerEvents +{ + // pointer events settings are managed by the parent screen container, we ignore + // any attempt of setting that via React props +} + - (void)reactSetFrame:(CGRect)frame { _reactFrame = frame; From 6825875730eea9ebf6c6942d1cd0ef677c62a43e Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:27:28 +0200 Subject: [PATCH 012/105] fix: add missing replaceAnimation prop (NOT TESTED) 1. move the prop to implemented section in JS 2. move the prop to "common" section in RNSScreenView interface --- ios/RNSScreen.h | 2 +- src/fabric/ScreenNativeComponent.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index 4c59f9a334..ee288a03fb 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -58,6 +58,7 @@ @property (nonatomic) RNSScreenStackAnimation stackAnimation; @property (nonatomic) RNSScreenStackPresentation stackPresentation; @property (nonatomic) RNSScreenSwipeDirection swipeDirection; +@property (nonatomic) RNSScreenReplaceAnimation replaceAnimation; @property (nonatomic, retain) NSNumber *transitionDuration; #if !TARGET_OS_TV @@ -85,7 +86,6 @@ @property (nonatomic, retain) UIViewController *controller; @property (nonatomic, readonly) BOOL dismissed; @property (nonatomic) int activityState; -@property (nonatomic) RNSScreenReplaceAnimation replaceAnimation; @property (nonatomic) BOOL preventNativeDismiss; @property (nonatomic) BOOL customAnimationOnSwipe; @property (nonatomic, copy) NSDictionary *gestureResponseDistance; diff --git a/src/fabric/ScreenNativeComponent.js b/src/fabric/ScreenNativeComponent.js index 86cf53b3c2..6e9b416961 100644 --- a/src/fabric/ScreenNativeComponent.js +++ b/src/fabric/ScreenNativeComponent.js @@ -59,8 +59,8 @@ export type NativeProps = $ReadOnly<{| stackPresentation?: WithDefault, stackAnimation?: WithDefault, transitionDuration?: WithDefault, - // TODO: implement these props on iOS replaceAnimation?: WithDefault, + // TODO: implement these props on iOS navigationBarColor?: ColorValue, navigationBarHidden?: boolean, nativeBackButtonDismissalEnabled?: boolean, From ce01586d32448b51052c3f7a0fa5f5055ffa083e Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:47:38 +0200 Subject: [PATCH 013/105] fix: move notifyFinishTransitioning method to Paper specific section --- ios/RNSScreen.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index f8c588af0b..9ff1f7a405 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -259,11 +259,6 @@ - (void)addSubview:(UIView *)view } } -- (void)notifyFinishTransitioning -{ - [_controller notifyFinishTransitioning]; -} - - (void)notifyDismissedWithCount:(int)dismissCount { #ifdef RN_FABRIC_ENABLED @@ -557,6 +552,11 @@ - (void)updateState:(facebook::react::State::Shared const &)state #pragma mark - Paper specific #else +- (void)notifyFinishTransitioning +{ + [_controller notifyFinishTransitioning]; +} + // Nil will be provided when activityState is set as an animated value and we change // it from JS to be a plain value (non animated). // In case when nil is received, we want to ignore such value and not make From 8a1525c20f6b9f39568d16ed7dadc711d598577e Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:51:39 +0200 Subject: [PATCH 014/105] fix: move notifyDismissCancelledWithDismissCount: method to Paper specific section --- ios/RNSScreen.mm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 9ff1f7a405..24e8280655 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -352,13 +352,6 @@ - (void)notifyDisappear #endif } -- (void)notifyDismissCancelledWithDismissCount:(int)dismissCount -{ - if (self.onNativeDismissCancelled) { - self.onNativeDismissCancelled(@{@"dismissCount" : @(dismissCount)}); - } -} - - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward { if (self.onTransitionProgress) { @@ -557,6 +550,13 @@ - (void)notifyFinishTransitioning [_controller notifyFinishTransitioning]; } +- (void)notifyDismissCancelledWithDismissCount:(int)dismissCount +{ + if (self.onNativeDismissCancelled) { + self.onNativeDismissCancelled(@{@"dismissCount" : @(dismissCount)}); + } +} + // Nil will be provided when activityState is set as an animated value and we change // it from JS to be a plain value (non animated). // In case when nil is received, we want to ignore such value and not make From 249d6753802bee96d4df5765238bfdad42229fd4 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:53:01 +0200 Subject: [PATCH 015/105] fix: move notifyTransitionProgress:closing:goingForward: method to Paper specific section Aim: to ake project compile --- ios/RNSScreen.mm | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 24e8280655..a3d1fff373 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -352,17 +352,6 @@ - (void)notifyDisappear #endif } -- (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward -{ - if (self.onTransitionProgress) { - self.onTransitionProgress(@{ - @"progress" : @(progress), - @"closing" : @(closing ? 1 : 0), - @"goingForward" : @(goingForward ? 1 : 0), - }); - } -} - - (BOOL)isMountedUnderScreenOrReactRoot { #ifdef RN_FABRIC_ENABLED @@ -557,6 +546,17 @@ - (void)notifyDismissCancelledWithDismissCount:(int)dismissCount } } +- (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward +{ + if (self.onTransitionProgress) { + self.onTransitionProgress(@{ + @"progress" : @(progress), + @"closing" : @(closing ? 1 : 0), + @"goingForward" : @(goingForward ? 1 : 0), + }); + } +} + // Nil will be provided when activityState is set as an animated value and we change // it from JS to be a plain value (non animated). // In case when nil is received, we want to ignore such value and not make From 5e89e5b3d2540a193eb253784f8992aa8709101f Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:58:00 +0200 Subject: [PATCH 016/105] fix: remove duplication of prop setting most likely some kind of merging artifact --- ios/RNSScreen.mm | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index a3d1fff373..323361f555 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -488,37 +488,6 @@ - (void)updateProps:(facebook::react::Props::Shared const &)props [self logPropNotAvailable:@"statusBarTranslucent"]; } - [self setFullScreenSwipeEnabled:newScreenProps.fullScreenSwipeEnabled]; - - [self setGestureEnabled:newScreenProps.gestureEnabled]; - - if (newScreenProps.statusBarHidden != oldScreenProps.statusBarHidden) { - [self setStatusBarHidden:newScreenProps.statusBarHidden]; - } - - if (newScreenProps.statusBarStyle != oldScreenProps.statusBarStyle) { - [self setStatusBarStyle:[RCTConvert RNSStatusBarStyle:[self stringToPropValue:newScreenProps.statusBarStyle]]]; - } - - if (newScreenProps.statusBarAnimation != oldScreenProps.statusBarAnimation) { - [self setStatusBarAnimation:[RCTConvert - UIStatusBarAnimation:[self stringToPropValue:newScreenProps.statusBarAnimation]]]; - } - - if (newScreenProps.screenOrientation != oldScreenProps.screenOrientation) { - [self - setScreenOrientation:[RCTConvert - UIInterfaceOrientationMask:[self stringToPropValue:newScreenProps.screenOrientation]]]; - } - - if (newScreenProps.statusBarColor) { - [self logPropNotAvailable:@"statusBarColor"]; - } - - if (newScreenProps.statusBarTranslucent) { - [self logPropNotAvailable:@"statusBarTranslucent"]; - } - [super updateProps:props oldProps:oldProps]; _fullScreenSwipeEnabled = newScreenProps.fullScreenSwipeEnabled; From d028f87ce4e3691a4d7294235cfe6d3961ebb5e9 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 12:58:42 +0200 Subject: [PATCH 017/105] chore: change handling of unsupported props to noop --- ios/RNSScreen.mm | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 323361f555..c689288632 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -480,14 +480,6 @@ - (void)updateProps:(facebook::react::Props::Shared const &)props [self setStackAnimation:[RNSConvert RNSScreenStackAnimationFromCppEquivalent:newScreenProps.stackAnimation]]; } - if (newScreenProps.statusBarColor) { - [self logPropNotAvailable:@"statusBarColor"]; - } - - if (newScreenProps.statusBarTranslucent) { - [self logPropNotAvailable:@"statusBarTranslucent"]; - } - [super updateProps:props oldProps:oldProps]; _fullScreenSwipeEnabled = newScreenProps.fullScreenSwipeEnabled; From ebdbafa3ad92e7dc63819aed1eb50b82410baa9e Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 13:04:23 +0200 Subject: [PATCH 018/105] fix: move RNSScreenManager impl & def under !RN_FABRIC_ENABLED condition --- ios/RNSScreen.h | 8 ++++---- ios/RNSScreen.mm | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index ee288a03fb..940cad393a 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -36,10 +36,6 @@ @end -@interface RNSScreenManager : RCTViewManager - -@end - #ifdef RN_FABRIC_ENABLED #define BASE_VIEW RCTViewComponentView #else @@ -110,5 +106,9 @@ #else @interface UIView (RNSScreen) - (UIViewController *)parentViewController; +@end + +@interface RNSScreenManager : RCTViewManager + @end #endif diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index c689288632..5f1d1d289c 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -92,7 +92,6 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge } #endif - - (UIViewController *)reactViewController { return _controller; @@ -112,7 +111,6 @@ - (void)updateBounds #endif } - - (void)setStackPresentation:(RNSScreenStackPresentation)stackPresentation { switch (stackPresentation) { @@ -1199,8 +1197,11 @@ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingFor @end -#endif +#endif // RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED + +#else @implementation RNSScreenManager RCT_EXPORT_MODULE() @@ -1241,6 +1242,8 @@ - (UIView *)view @end +#endif // RN_FABRIC_ENABLED + @implementation RCTConvert (RNSScreen) RCT_ENUM_CONVERTER( From cfd3842c092f4ffd77db2d1cad0b44d25aaafb2b Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 13:11:33 +0200 Subject: [PATCH 019/105] fix: remove duplicated prop update in updateProps method most likely some kind of merge artifact --- ios/RNSScreen.mm | 3 --- 1 file changed, 3 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 5f1d1d289c..754a800d2b 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -479,9 +479,6 @@ - (void)updateProps:(facebook::react::Props::Shared const &)props } [super updateProps:props oldProps:oldProps]; - - _fullScreenSwipeEnabled = newScreenProps.fullScreenSwipeEnabled; - _gestureEnabled = newScreenProps.gestureEnabled; } - (void)updateState:(facebook::react::State::Shared const &)state From 40d438a32f85934f73cc36b2aeb9af71a6cde203 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 15 Apr 2022 13:20:15 +0200 Subject: [PATCH 020/105] fix: temporary: exclude usages of customAnimationOnSwipe from Fabric temporary solution until customAnimationOnSwipe is not added to RNSScreenView on Fabric --- ios/RNSScreenStackAnimator.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ios/RNSScreenStackAnimator.mm b/ios/RNSScreenStackAnimator.mm index efc10ff8c5..4b5f5cab41 100644 --- a/ios/RNSScreenStackAnimator.mm +++ b/ios/RNSScreenStackAnimator.mm @@ -66,12 +66,15 @@ - (void)animateTransition:(id)transitionCo if (screen != nil) { if (screen.fullScreenSwipeEnabled && transitionContext.isInteractive) { // we are swiping with full width gesture +#ifndef RN_FABRIC_ENABLED if (screen.customAnimationOnSwipe) { [self animateTransitionWithStackAnimation:screen.stackAnimation transitionContext:transitionContext toVC:toViewController fromVC:fromViewController]; - } else { + } else +#endif + { // we have to provide an animation when swiping, otherwise the screen will be popped immediately, // so in case of no custom animation on swipe set, we provide the one closest to the default [self animateSimplePushWithTransitionContext:transitionContext toVC:toViewController fromVC:fromViewController]; From e79ae5f49288eb79d943285d2133dcde306604b0 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 09:15:23 +0200 Subject: [PATCH 021/105] fix: make the project compile these directives should be removed once implementations ale fully merged --- ios/RNSScreenContainer.mm | 4 ++++ ios/RNSScreenNavigationContainer.mm | 2 ++ ios/RNSScreenStack.mm | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/ios/RNSScreenContainer.mm b/ios/RNSScreenContainer.mm index ffdf066412..eff360572d 100644 --- a/ios/RNSScreenContainer.mm +++ b/ios/RNSScreenContainer.mm @@ -32,12 +32,14 @@ - (UIViewController *)childViewControllerForHomeIndicatorAutoHidden - (UIViewController *)findActiveChildVC { +#ifndef RN_FABRIC_ENABLED for (UIViewController *childVC in self.childViewControllers) { if ([childVC isKindOfClass:[RNSScreen class]] && ((RNSScreenView *)((RNSScreen *)childVC.view)).activityState == RNSActivityStateOnTop) { return childVC; } } +#endif return [[self childViewControllers] lastObject]; } @@ -139,6 +141,7 @@ - (void)attachScreen:(RNSScreenView *)screen atIndex:(NSInteger)index - (void)updateContainer { +#ifndef RN_FABRIC_ENABLED BOOL screenRemoved = NO; // remove screens that are no longer active NSMutableSet *orphaned = [NSMutableSet setWithSet:_activeScreens]; @@ -188,6 +191,7 @@ - (void)updateContainer if (screenRemoved || screenAdded) { [self maybeDismissVC]; } +#endif } - (void)maybeDismissVC diff --git a/ios/RNSScreenNavigationContainer.mm b/ios/RNSScreenNavigationContainer.mm index 649e41b6d0..1d362d7535 100644 --- a/ios/RNSScreenNavigationContainer.mm +++ b/ios/RNSScreenNavigationContainer.mm @@ -17,6 +17,7 @@ - (void)setupController - (void)updateContainer { +#ifndef RN_FABRIC_ENABLED for (RNSScreenView *screen in self.reactSubviews) { if (screen.activityState == RNSActivityStateOnTop) { // there should never be more than one screen with `RNSActivityStateOnTop` @@ -27,6 +28,7 @@ - (void)updateContainer } [self maybeDismissVC]; +#endif } @end diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 06d13f04a9..e1e3b62834 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -485,6 +485,7 @@ - (void)setPushViewControllers:(NSArray *)controllers - (void)updateContainer { +#ifndef RN_FABRIC_ENABLED NSMutableArray *pushControllers = [NSMutableArray new]; NSMutableArray *modalControllers = [NSMutableArray new]; for (RNSScreenView *screen in _reactSubviews) { @@ -504,6 +505,7 @@ - (void)updateContainer [self setPushViewControllers:pushControllers]; [self setModalViewControllers:modalControllers]; +#endif } // By default, the header buttons that are not inside the native hit area @@ -571,6 +573,7 @@ - (void)dismissOnReload - (BOOL)isInGestureResponseDistance:(UIGestureRecognizer *)gestureRecognizer topScreen:(RNSScreenView *)topScreen { +#ifndef RN_FABRIC_ENABLED NSDictionary *gestureResponseDistanceValues = topScreen.gestureResponseDistance; float x = [gestureRecognizer locationInView:gestureRecognizer.view].x; float y = [gestureRecognizer locationInView:gestureRecognizer.view].y; @@ -584,6 +587,9 @@ - (BOOL)isInGestureResponseDistance:(UIGestureRecognizer *)gestureRecognizer top (gestureResponseDistanceValues[@"end"] && x > [gestureResponseDistanceValues[@"end"] floatValue]) || (gestureResponseDistanceValues[@"top"] && y < [gestureResponseDistanceValues[@"top"] floatValue]) || (gestureResponseDistanceValues[@"bottom"] && y > [gestureResponseDistanceValues[@"bottom"] floatValue])); +#else + return NO; +#endif } - (void)cancelTouchesInParent @@ -627,6 +633,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer return NO; } +#ifndef RN_FABRIC_ENABLED if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) { if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { // if we do not set any explicit `semanticContentAttribute`, it is `UISemanticContentAttributeUnspecified` instead @@ -652,6 +659,18 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer [self cancelTouchesInParent]; return YES; } +#else + if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { + // it should only recognize with `customAnimationOnSwipe` set + return NO; + } else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { + // it should only recognize with `fullScreenSwipeEnabled` set + return NO; + } + [self cancelTouchesInParent]; + return _controller.viewControllers.count >= 2; +#endif + #endif } From a7e3012132f294b5fcb4cd06b69a6808c9970047 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:05 +0200 Subject: [PATCH 022/105] chore: merge ScreenStack headers --- ios/RNSScreenStack.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ios/RNSScreenStack.h b/ios/RNSScreenStack.h index a383cd2265..d340c3c4d5 100644 --- a/ios/RNSScreenStack.h +++ b/ios/RNSScreenStack.h @@ -1,5 +1,10 @@ +#ifdef RN_FABRIC_ENABLED +#import +#import +#else #import #import +#endif #import "RNSScreenContainer.h" @@ -7,15 +12,24 @@ @end -@interface RNSScreenStackView : UIView +@interface RNSScreenStackView : +#ifdef RN_FABRIC_ENABLED + RCTViewComponentView +#else + UIView +#endif +#ifndef RN_FABRIC_ENABLED @property (nonatomic, copy) RCTDirectEventBlock onFinishTransitioning; - (void)markChildUpdated; - (void)didUpdateChildren; +#endif @end +#ifndef RN_FABRIC_ENABLED @interface RNSScreenStackManager : RCTViewManager @end +#endif From 4ea96a79914d58f37f6cbd5a187117cf1de2d4d7 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:07 +0200 Subject: [PATCH 023/105] chore: merge imports in ScreenStack impls --- ios/RNSScreenStack.mm | 50 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index e1e3b62834..fac1e47935 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -1,8 +1,19 @@ -#import "RNSScreenStack.h" -#import "RNSScreen.h" -#import "RNSScreenStackAnimator.h" +#ifdef RN_FABRIC_ENABLED +#import "RNSScreenStackHeaderConfigComponentView.h" + +#import + +#import +#import +#import +#import +#import + +#import "RCTFabricComponentsPlugins.h" + +#import +#else #import "RNSScreenStackHeaderConfig.h" -#import "RNSScreenWindowTraits.h" #import #import @@ -10,12 +21,31 @@ #import #import #import +#endif // RN_FABRIC_ENABLED -@interface RNSScreenStackView () < +#import "RNSScreenStack.h" +#import "RNSScreen.h" +#import "RNSScreenStackAnimator.h" +#import "RNSScreenWindowTraits.h" + +@interface RNSScreenStackView () +#ifdef RN_FABRIC_ENABLED +< + UINavigationControllerDelegate, + UIAdaptivePresentationControllerDelegate, + UIGestureRecognizerDelegate, + UIViewControllerTransitioningDelegate, + RCTMountingTransactionObserving> { + BOOL _updateScheduled; +} +#else +< UINavigationControllerDelegate, UIAdaptivePresentationControllerDelegate, UIGestureRecognizerDelegate, UIViewControllerTransitioningDelegate> +#endif + @property (nonatomic) NSMutableArray *presentedModals; @property (nonatomic) BOOL updatingModals; @@ -71,12 +101,16 @@ @implementation RNSPanGestureRecognizer @implementation RNSScreenStackView { UINavigationController *_controller; NSMutableArray *_reactSubviews; - __weak RNSScreenStackManager *_manager; - BOOL _hasLayout; BOOL _invalidated; + BOOL _isFullWidthSwiping; UIPercentDrivenInteractiveTransition *_interactionController; +#ifdef RN_FABRIC_ENABLED + UIView *_snapshot; +#else + __weak RNSScreenStackManager *_manager; + BOOL _hasLayout; BOOL _updateScheduled; - BOOL _isFullWidthSwiping; +#endif } - (instancetype)initWithManager:(RNSScreenStackManager *)manager From f9160d4e06d625c1043521ac0b5346578328ca3c Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:09 +0200 Subject: [PATCH 024/105] chore: move initWithFrame: method & add sections --- ios/RNSScreenStack.mm | 48 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index fac1e47935..cc99e61c4e 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -113,6 +113,25 @@ @implementation RNSScreenStackView { #endif } +#ifdef RN_FABRIC_ENABLED +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + _reactSubviews = [NSMutableArray new]; + _presentedModals = [NSMutableArray new]; + _controller = [RNScreensNavigationController new]; + _controller.delegate = self; + [_controller setViewControllers:@[ [UIViewController new] ]]; +#if !TARGET_OS_TV + [self setupGestureHandlers]; +#endif + } + + return self; +} +#else - (instancetype)initWithManager:(RNSScreenStackManager *)manager { if (self = [super init]) { @@ -135,17 +154,24 @@ - (instancetype)initWithManager:(RNSScreenStackManager *)manager } return self; } +#endif // RN_FABRIC_ENABLED + +#pragma mark - Common -- (UIViewController *)reactViewController -{ - return _controller; -} - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { UIView *view = viewController.view; + // TODO: Improve this merge when StackHeaderConfig is merged +#ifdef RN_FABRIC_ENABLED + if ([view isKindOfClass:RNSScreenView.class]) { + RNSScreenStackHeaderConfigComponentView *config = + (RNSScreenStackHeaderConfigComponentView *)((RNSScreenView *)view).config; + [RNSScreenStackHeaderConfigComponentView willShowViewController:viewController animated:animated withConfig:config]; + } +#else RNSScreenStackHeaderConfig *config = nil; for (UIView *subview in view.reactSubviews) { if ([subview isKindOfClass:[RNSScreenStackHeaderConfig class]]) { @@ -154,6 +180,7 @@ - (void)navigationController:(UINavigationController *)navigationController } } [RNSScreenStackHeaderConfig willShowViewController:viewController animated:animated withConfig:config]; +#endif } - (void)navigationController:(UINavigationController *)navigationController @@ -826,6 +853,19 @@ - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer return _interactionController; } +#ifdef RN_FABRIC_ENABLED +#pragma mark - Fabric specific + +#else +#pragma mark - Paper specific + +- (UIViewController *)reactViewController +{ + return _controller; +} + +#endif + @end @implementation RNSScreenStackManager { From 22d0484fa84ab5c9012e1d69f60e45ac8c7c2674 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:11 +0200 Subject: [PATCH 025/105] chore: move navigationController:didShowViewController:animated method to Paper specific section This method is not present in RNSScreenStackComponentView, therefore I conclude it is not necessary at least for now --- ios/RNSScreenStack.mm | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index cc99e61c4e..9129fbe6bf 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -183,15 +183,6 @@ - (void)navigationController:(UINavigationController *)navigationController #endif } -- (void)navigationController:(UINavigationController *)navigationController - didShowViewController:(UIViewController *)viewController - animated:(BOOL)animated -{ - if (self.onFinishTransitioning) { - self.onFinishTransitioning(nil); - } - [RNSScreenWindowTraits updateWindowTraits]; -} - (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController { @@ -864,6 +855,17 @@ - (UIViewController *)reactViewController return _controller; } +- (void)navigationController:(UINavigationController *)navigationController + didShowViewController:(UIViewController *)viewController + animated:(BOOL)animated +{ + if (self.onFinishTransitioning) { + self.onFinishTransitioning(nil); + } + [RNSScreenWindowTraits updateWindowTraits]; +} + + #endif @end From 60b9d20e64bb481864a3d8d6136c80f2226aba63 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:13 +0200 Subject: [PATCH 026/105] chore: merge presentationControllerDidDismiss: method --- ios/RNSScreenStack.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 9129fbe6bf..8066467805 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -198,6 +198,8 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio // have tried to push another one during the transition _updatingModals = NO; [self updateContainer]; + // TODO: implement onFinishTransitioning on Fabric +#ifndef RN_FABRIC_ENABLED if (self.onFinishTransitioning) { // instead of directly triggering onFinishTransitioning this time we enqueue the event on the // main queue. We do that because onDismiss event is also enqueued and we want for the transition @@ -208,6 +210,7 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio } }); } +#endif } } From 30b3a1e0774b15b199d73534e9ec52c799d120d5 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:15 +0200 Subject: [PATCH 027/105] chore: move {mount,unmount}ChildComponentView:index: methods --- ios/RNSScreenStack.mm | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 8066467805..6e9822d7de 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -850,6 +850,57 @@ - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer #ifdef RN_FABRIC_ENABLED #pragma mark - Fabric specific +- (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index +{ + if (![childComponentView isKindOfClass:[RNSScreenView class]]) { + RCTLogError(@"ScreenStack only accepts children of type Screen"); + return; + } + + RCTAssert( + childComponentView.reactSuperview == nil, + @"Attempt to mount already mounted component view. (parent: %@, child: %@, index: %@, existing parent: %@)", + self, + childComponentView, + @(index), + @([childComponentView.superview tag])); + + [_reactSubviews insertObject:(RNSScreenView *)childComponentView atIndex:index]; + ((RNSScreenView *)childComponentView).reactSuperview = self; + dispatch_async(dispatch_get_main_queue(), ^{ + [self maybeAddToParentAndUpdateContainer]; + }); +} + +- (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index +{ + RNSScreenView *screenChildComponent = (RNSScreenView *)childComponentView; + // We should only do a snapshot of a screen that is on the top + if (screenChildComponent == _controller.topViewController.view) { + [screenChildComponent.controller setViewToSnapshot:_snapshot]; + } + + RCTAssert( + screenChildComponent.reactSuperview == self, + @"Attempt to unmount a view which is mounted inside different view. (parent: %@, child: %@, index: %@)", + self, + screenChildComponent, + @(index)); + RCTAssert( + (_reactSubviews.count > index) && [_reactSubviews objectAtIndex:index] == childComponentView, + @"Attempt to unmount a view which has a different index. (parent: %@, child: %@, index: %@, actual index: %@, tag at index: %@)", + self, + screenChildComponent, + @(index), + @([_reactSubviews indexOfObject:screenChildComponent]), + @([[_reactSubviews objectAtIndex:index] tag])); + screenChildComponent.reactSuperview = nil; + [_reactSubviews removeObject:screenChildComponent]; + [screenChildComponent removeFromSuperview]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self maybeAddToParentAndUpdateContainer]; + }); +} #else #pragma mark - Paper specific From 384df76872ccbb03a39549c1e6fa9af0f19e7c6f Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:17 +0200 Subject: [PATCH 028/105] chore: move takeSnapshot method --- ios/RNSScreenStack.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 6e9822d7de..1b9b826503 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -901,6 +901,11 @@ - (void)unmountChildComponentView:(UIView *)childCompo [self maybeAddToParentAndUpdateContainer]; }); } + +- (void)takeSnapshot +{ + _snapshot = [_controller.topViewController.view snapshotViewAfterScreenUpdates:NO]; +} #else #pragma mark - Paper specific From 228aa31812c078a3da7dec5fdebd614f83454c4e Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:19 +0200 Subject: [PATCH 029/105] chore: merge didMoveToWindow methods --- ios/RNSScreenStack.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 1b9b826503..f42ea0174d 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -258,6 +258,11 @@ - (void)didUpdateReactSubviews - (void)didMoveToWindow { +#ifdef RN_FABRIC_ENABLED + [super didMoveToWindow]; + // for handling nested stacks + [self maybeAddToParentAndUpdateContainer]; +#else [super didMoveToWindow]; if (!_invalidated) { // We check whether the view has been invalidated before running side-effects in didMoveToWindow @@ -265,6 +270,7 @@ - (void)didMoveToWindow // to a window despite the fact it has been removed from the React Native view hierarchy. [self maybeAddToParentAndUpdateContainer]; } +#endif } - (void)maybeAddToParentAndUpdateContainer From bdd2c243e41fe04ae2e5219141fcddae3bdb0cc2 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:21 +0200 Subject: [PATCH 030/105] chore: move mountingTransactionWillMountWithMetadata: method to Fabric specific section --- ios/RNSScreenStack.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index f42ea0174d..04e1616fea 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -912,6 +912,12 @@ - (void)takeSnapshot { _snapshot = [_controller.topViewController.view snapshotViewAfterScreenUpdates:NO]; } + +- (void)mountingTransactionWillMountWithMetadata:(MountingTransactionMetadata const &)metadata +{ + [self takeSnapshot]; +} + #else #pragma mark - Paper specific From c2464675e732b66339affb0d89f94dce4ace8065 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:22 +0200 Subject: [PATCH 031/105] chore: merge maybeAddToParentAndUpdateContainer methods --- ios/RNSScreenStack.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 04e1616fea..b1362e463e 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -276,7 +276,11 @@ - (void)didMoveToWindow - (void)maybeAddToParentAndUpdateContainer { BOOL wasScreenMounted = _controller.parentViewController != nil; +#ifdef RN_FABRIC_ENABLED + BOOL isScreenReadyForShowing = self.window; +#else BOOL isScreenReadyForShowing = self.window && _hasLayout; +#endif if (!isScreenReadyForShowing && !wasScreenMounted) { // We wait with adding to parent controller until the stack is mounted and has its initial // layout done. From c2c625236fee704ad2cda729c8a01d87090caf31 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:24 +0200 Subject: [PATCH 032/105] chore: move markChildUpdated & didUpdateChildren methods to Paper specific section --- ios/RNSScreenStack.mm | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index b1362e463e..b1c7e7b669 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -158,7 +158,7 @@ - (instancetype)initWithManager:(RNSScreenStackManager *)manager #pragma mark - Common - +// done - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated @@ -183,7 +183,7 @@ - (void)navigationController:(UINavigationController *)navigationController #endif } - +// done - (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController { // We don't directly set presentation delegate but instead rely on the ScreenView's delegate to @@ -214,16 +214,6 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio } } -- (void)markChildUpdated -{ - // do nothing -} - -- (void)didUpdateChildren -{ - // do nothing -} - - (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex { if (![subview isKindOfClass:[RNSScreenView class]]) { @@ -925,6 +915,16 @@ - (void)mountingTransactionWillMountWithMetadata:(MountingTransactionMetadata co #else #pragma mark - Paper specific +- (void)markChildUpdated +{ + // do nothing +} + +- (void)didUpdateChildren +{ + // do nothing +} + - (UIViewController *)reactViewController { return _controller; From c91c43b3e3d61d0072439acdee56a96cea9cb790 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:26 +0200 Subject: [PATCH 033/105] chore: move insertReactSubview:atIndex: method to Paper specific section --- ios/RNSScreenStack.mm | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index b1c7e7b669..1eb450d3f8 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -214,16 +214,6 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio } } -- (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex -{ - if (![subview isKindOfClass:[RNSScreenView class]]) { - RCTLogError(@"ScreenStack only accepts children of type Screen"); - return; - } - subview.reactSuperview = self; - [_reactSubviews insertObject:subview atIndex:atIndex]; -} - - (void)removeReactSubview:(RNSScreenView *)subview { subview.reactSuperview = nil; @@ -940,6 +930,16 @@ - (void)navigationController:(UINavigationController *)navigationController [RNSScreenWindowTraits updateWindowTraits]; } +- (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex +{ + if (![subview isKindOfClass:[RNSScreenView class]]) { + RCTLogError(@"ScreenStack only accepts children of type Screen"); + return; + } + subview.reactSuperview = self; + [_reactSubviews insertObject:subview atIndex:atIndex]; +} + #endif From 16fe33de9509d368f61c5d2d8f75d0f4e9107776 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:28 +0200 Subject: [PATCH 034/105] chore: move removeReactSubview: method to paper specific section --- ios/RNSScreenStack.mm | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 1eb450d3f8..f3ffc1b878 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -214,12 +214,6 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio } } -- (void)removeReactSubview:(RNSScreenView *)subview -{ - subview.reactSuperview = nil; - [_reactSubviews removeObject:subview]; -} - - (NSArray *)reactSubviews { return _reactSubviews; @@ -941,6 +935,13 @@ - (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex } +- (void)removeReactSubview:(RNSScreenView *)subview +{ + subview.reactSuperview = nil; + [_reactSubviews removeObject:subview]; +} + + #endif @end From 906ce0dfc6d5f9606eaf2cdc345f995122700d18 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:30 +0200 Subject: [PATCH 035/105] chore: move didUpdateReactSubviews method to paper specific section --- ios/RNSScreenStack.mm | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index f3ffc1b878..783ab71805 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -214,22 +214,12 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio } } +// done - (NSArray *)reactSubviews { return _reactSubviews; } -- (void)didUpdateReactSubviews -{ - // we need to wait until children have their layout set. At this point they don't have the layout - // set yet, however the layout call is already enqueued on ui thread. Enqueuing update call on the - // ui queue will guarantee that the update will run after layout. - dispatch_async(dispatch_get_main_queue(), ^{ - self->_hasLayout = YES; - [self maybeAddToParentAndUpdateContainer]; - }); -} - - (void)didMoveToWindow { #ifdef RN_FABRIC_ENABLED @@ -934,13 +924,22 @@ - (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex [_reactSubviews insertObject:subview atIndex:atIndex]; } - - (void)removeReactSubview:(RNSScreenView *)subview { subview.reactSuperview = nil; [_reactSubviews removeObject:subview]; } +- (void)didUpdateReactSubviews +{ + // we need to wait until children have their layout set. At this point they don't have the layout + // set yet, however the layout call is already enqueued on ui thread. Enqueuing update call on the + // ui queue will guarantee that the update will run after layout. + dispatch_async(dispatch_get_main_queue(), ^{ + self->_hasLayout = YES; + [self maybeAddToParentAndUpdateContainer]; + }); +} #endif From 8c9585dbcb9535752110c6a94c821342757e1525 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:32 +0200 Subject: [PATCH 036/105] chore: merge reactAddControllerToClosestParent: methods --- ios/RNSScreenStack.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 783ab71805..9897b6d134 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -220,6 +220,7 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio return _reactSubviews; } +// done - (void)didMoveToWindow { #ifdef RN_FABRIC_ENABLED @@ -237,6 +238,7 @@ - (void)didMoveToWindow #endif } +// done - (void)maybeAddToParentAndUpdateContainer { BOOL wasScreenMounted = _controller.parentViewController != nil; @@ -283,7 +285,9 @@ - (void)reactAddControllerToClosestParent:(UIViewController *)controller #if !TARGET_OS_TV _controller.interactivePopGestureRecognizer.delegate = self; #endif +#ifndef RN_FABRIC_ENABLED [controller didMoveToParentViewController:parentView.reactViewController]; +#endif // On iOS pre 12 we observed that `willShowViewController` delegate method does not always // get triggered when the navigation controller is instantiated. As the only thing we do in // that delegate method is ask nav header to update to the current state it does not hurt to @@ -941,7 +945,7 @@ - (void)didUpdateReactSubviews }); } -#endif +#endif // RN_FABRIC_ENABLED @end From 34f8cb3e63aef28cffb432b58f6f7b0b5fbbd94f Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:34 +0200 Subject: [PATCH 037/105] chore: merge setModalViewControllers: methods --- ios/RNSScreenStack.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 9897b6d134..8155e9f9d6 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -274,6 +274,7 @@ - (void)maybeAddToParentAndUpdateContainer } } +// done - (void)reactAddControllerToClosestParent:(UIViewController *)controller { if (!controller.parentViewController) { @@ -301,6 +302,7 @@ - (void)reactAddControllerToClosestParent:(UIViewController *)controller } } +// done - (void)setModalViewControllers:(NSArray *)controllers { // prevent re-entry @@ -351,9 +353,12 @@ - (void)setModalViewControllers:(NSArray *)controllers __weak RNSScreenStackView *weakSelf = self; void (^afterTransitions)(void) = ^{ + // TODO: Implement onFinishTransitioning on Fabric +#ifndef RN_FABRIC_ENABLED if (weakSelf.onFinishTransitioning) { weakSelf.onFinishTransitioning(nil); } +#endif weakSelf.updatingModals = NO; if (weakSelf.scheduleModalsUpdate) { // if modals update was requested during setModalViewControllers we set scheduleModalsUpdate From ee139da061669c9f61dc0e740f81f352913839a8 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:36 +0200 Subject: [PATCH 038/105] chore: WIP: merge setPushViewControllers --- ios/RNSScreenStack.mm | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 8155e9f9d6..ad5302253f 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -437,6 +437,7 @@ - (void)setModalViewControllers:(NSArray *)controllers } } +// done - (void)setPushViewControllers:(NSArray *)controllers { // when there is no change we return immediately @@ -472,6 +473,56 @@ - (void)setPushViewControllers:(NSArray *)controllers } UIViewController *top = controllers.lastObject; +#ifdef RN_FABRIC_ENABLED + UIViewController *previousTop = _controller.topViewController; + + // At the start we set viewControllers to contain a single UIViewController + // instance. This is a workaround for header height adjustment bug (see comment + // in the init function). Here, we need to detect if the initial empty + // controller is still there + BOOL firstTimePush = ![previousTop isKindOfClass:[RNSScreen class]]; + + if (firstTimePush) { + // nothing pushed yet + [_controller setViewControllers:controllers animated:NO]; + } else if (top != previousTop) { + if (![controllers containsObject:previousTop]) { + // if the previous top screen does not exist anymore and the new top was not on the stack before, probably replace + // was called, so we check the animation + if (![_controller.viewControllers containsObject:top]) { + // setting new controllers with animation does `push` animation by default + auto screenController = (RNSScreen *)top; + [screenController resetViewToScreen]; + [_controller setViewControllers:controllers animated:YES]; + } else { + // last top controller is no longer on stack + // in this case we set the controllers stack to the new list with + // added the last top element to it and perform (animated) pop + NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; + [newControllers addObject:previousTop]; + [_controller setViewControllers:newControllers animated:NO]; + [_controller popViewControllerAnimated:YES]; + } + } else if (![_controller.viewControllers containsObject:top]) { + // new top controller is not on the stack + // in such case we update the stack except from the last element with + // no animation and do animated push of the last item + NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; + [newControllers removeLastObject]; + [_controller setViewControllers:newControllers animated:NO]; + auto screenController = (RNSScreen *)top; + [screenController resetViewToScreen]; + [_controller pushViewController:top animated:YES]; + } else { + // don't really know what this case could be, but may need to handle it + // somehow + [_controller setViewControllers:controllers animated:YES]; + } + } else { + // change wasn't on the top of the stack. We don't need animation. + [_controller setViewControllers:controllers animated:NO]; + } +#else UIViewController *lastTop = _controller.viewControllers.lastObject; // at the start we set viewControllers to contain a single UIVIewController @@ -519,6 +570,7 @@ - (void)setPushViewControllers:(NSArray *)controllers // change wasn't on the top of the stack. We don't need animation. [_controller setViewControllers:controllers animated:NO]; } +#endif } - (void)updateContainer From ed24d05f96e09510b9505bfb0f2303948b54eef2 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:38 +0200 Subject: [PATCH 039/105] chore: merge updateContainer methods --- ios/RNSScreenStack.mm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index ad5302253f..b31f10fb88 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -573,13 +573,17 @@ - (void)setPushViewControllers:(NSArray *)controllers #endif } +// done - (void)updateContainer { -#ifndef RN_FABRIC_ENABLED NSMutableArray *pushControllers = [NSMutableArray new]; NSMutableArray *modalControllers = [NSMutableArray new]; for (RNSScreenView *screen in _reactSubviews) { +#ifdef RN_FABRIC_ENABLED + if (screen.controller != nil) { +#else if (!screen.dismissed && screen.controller != nil) { +#endif if (pushControllers.count == 0) { // first screen on the list needs to be places as "push controller" [pushControllers addObject:screen.controller]; @@ -595,7 +599,6 @@ - (void)updateContainer [self setPushViewControllers:pushControllers]; [self setModalViewControllers:modalControllers]; -#endif } // By default, the header buttons that are not inside the native hit area From 8140571dc9840392c3b8e555288c59a87ff07fda Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:40 +0200 Subject: [PATCH 040/105] chore: move hitTest:withEvent: method to paper specific section --- ios/RNSScreenStack.mm | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index b31f10fb88..86645b4e65 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -601,23 +601,6 @@ - (void)updateContainer [self setModalViewControllers:modalControllers]; } -// By default, the header buttons that are not inside the native hit area -// cannot be clicked, so we check it by ourselves -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - if (CGRectContainsPoint(_controller.navigationBar.frame, point)) { - // headerConfig should be the first subview of the topmost screen - UIView *headerConfig = [[_reactSubviews.lastObject reactSubviews] firstObject]; - if ([headerConfig isKindOfClass:[RNSScreenStackHeaderConfig class]]) { - UIView *headerHitTestResult = [headerConfig hitTest:point withEvent:event]; - if (headerHitTestResult != nil) { - return headerHitTestResult; - } - } - } - return [super hitTest:point withEvent:event]; -} - - (void)layoutSubviews { [super layoutSubviews]; @@ -1005,6 +988,22 @@ - (void)didUpdateReactSubviews }); } +// By default, the header buttons that are not inside the native hit area +// cannot be clicked, so we check it by ourselves +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event +{ + if (CGRectContainsPoint(_controller.navigationBar.frame, point)) { + // headerConfig should be the first subview of the topmost screen + UIView *headerConfig = [[_reactSubviews.lastObject reactSubviews] firstObject]; + if ([headerConfig isKindOfClass:[RNSScreenStackHeaderConfig class]]) { + UIView *headerHitTestResult = [headerConfig hitTest:point withEvent:event]; + if (headerHitTestResult != nil) { + return headerHitTestResult; + } + } + } + return [super hitTest:point withEvent:event]; +} #endif // RN_FABRIC_ENABLED @end From 899b2850baf2152964dd8da2a8ca9ce25d1e13de Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:42 +0200 Subject: [PATCH 041/105] refact: fix braces in updateContainer method --- ios/RNSScreenStack.mm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 86645b4e65..c1be185fd0 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -580,10 +580,11 @@ - (void)updateContainer NSMutableArray *modalControllers = [NSMutableArray new]; for (RNSScreenView *screen in _reactSubviews) { #ifdef RN_FABRIC_ENABLED - if (screen.controller != nil) { + if (screen.controller != nil) #else - if (!screen.dismissed && screen.controller != nil) { + if (!screen.dismissed && screen.controller != nil) #endif + { if (pushControllers.count == 0) { // first screen on the list needs to be places as "push controller" [pushControllers addObject:screen.controller]; @@ -601,6 +602,7 @@ - (void)updateContainer [self setModalViewControllers:modalControllers]; } +// done - (void)layoutSubviews { [super layoutSubviews]; From 35fd105ede1954b0452326b02f45d80fd54c79cf Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:44 +0200 Subject: [PATCH 042/105] chore: move invalidate method to paper specific section --- ios/RNSScreenStack.mm | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index c1be185fd0..4adc9df960 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -609,17 +609,6 @@ - (void)layoutSubviews _controller.view.frame = self.bounds; } -- (void)invalidate -{ - _invalidated = YES; - for (UIViewController *controller in _presentedModals) { - [controller dismissViewControllerAnimated:NO completion:nil]; - } - [_presentedModals removeAllObjects]; - [_controller willMoveToParentViewController:nil]; - [_controller removeFromParentViewController]; -} - - (void)dismissOnReload { dispatch_async(dispatch_get_main_queue(), ^{ @@ -1006,6 +995,18 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event } return [super hitTest:point withEvent:event]; } + +- (void)invalidate +{ + _invalidated = YES; + for (UIViewController *controller in _presentedModals) { + [controller dismissViewControllerAnimated:NO completion:nil]; + } + [_presentedModals removeAllObjects]; + [_controller willMoveToParentViewController:nil]; + [_controller removeFromParentViewController]; +} + #endif // RN_FABRIC_ENABLED @end From bc27beb626cc9c02b3f198832ed0550e4a64bebb Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:46 +0200 Subject: [PATCH 043/105] chore: merge dismissOnReload methods --- ios/RNSScreenStack.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 4adc9df960..60322fd1e7 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -609,11 +609,17 @@ - (void)layoutSubviews _controller.view.frame = self.bounds; } +// done - (void)dismissOnReload { +#ifdef RN_FABRIC_ENABLED + auto screenController = (RNSScreen *)_controller.topViewController; + [screenController resetViewToScreen]; +#else dispatch_async(dispatch_get_main_queue(), ^{ [self invalidate]; }); +#endif } #pragma mark methods connected to transitioning From 0c57d95f16396ee443a9da41dfe76da06414ad33 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:48 +0200 Subject: [PATCH 044/105] chore: move isInGestureResponseDistance:topScreen: method to paper specific section --- ios/RNSScreenStack.mm | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 60322fd1e7..0565a23ee6 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -624,6 +624,7 @@ - (void)dismissOnReload #pragma mark methods connected to transitioning +// done - (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC @@ -644,27 +645,6 @@ - (void)dismissOnReload return nil; } -- (BOOL)isInGestureResponseDistance:(UIGestureRecognizer *)gestureRecognizer topScreen:(RNSScreenView *)topScreen -{ -#ifndef RN_FABRIC_ENABLED - NSDictionary *gestureResponseDistanceValues = topScreen.gestureResponseDistance; - float x = [gestureRecognizer locationInView:gestureRecognizer.view].x; - float y = [gestureRecognizer locationInView:gestureRecognizer.view].y; - BOOL isRTL = _controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft; - if (isRTL) { - x = _controller.view.frame.size.width - x; - } - // we check if any of the constraints are violated and return NO if so - return !( - (gestureResponseDistanceValues[@"start"] && x < [gestureResponseDistanceValues[@"start"] floatValue]) || - (gestureResponseDistanceValues[@"end"] && x > [gestureResponseDistanceValues[@"end"] floatValue]) || - (gestureResponseDistanceValues[@"top"] && y < [gestureResponseDistanceValues[@"top"] floatValue]) || - (gestureResponseDistanceValues[@"bottom"] && y > [gestureResponseDistanceValues[@"bottom"] floatValue])); -#else - return NO; -#endif -} - - (void)cancelTouchesInParent { // cancel touches in parent, this is needed to cancel RN touch events. For example when Touchable @@ -1013,6 +993,23 @@ - (void)invalidate [_controller removeFromParentViewController]; } +- (BOOL)isInGestureResponseDistance:(UIGestureRecognizer *)gestureRecognizer topScreen:(RNSScreenView *)topScreen +{ + NSDictionary *gestureResponseDistanceValues = topScreen.gestureResponseDistance; + float x = [gestureRecognizer locationInView:gestureRecognizer.view].x; + float y = [gestureRecognizer locationInView:gestureRecognizer.view].y; + BOOL isRTL = _controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft; + if (isRTL) { + x = _controller.view.frame.size.width - x; + } + // we check if any of the constraints are violated and return NO if so + return !( + (gestureResponseDistanceValues[@"start"] && x < [gestureResponseDistanceValues[@"start"] floatValue]) || + (gestureResponseDistanceValues[@"end"] && x > [gestureResponseDistanceValues[@"end"] floatValue]) || + (gestureResponseDistanceValues[@"top"] && y < [gestureResponseDistanceValues[@"top"] floatValue]) || + (gestureResponseDistanceValues[@"bottom"] && y > [gestureResponseDistanceValues[@"bottom"] floatValue])); + return NO; +} #endif // RN_FABRIC_ENABLED @end From 844820ca3a9078541e68379423783c9d757fee65 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:50 +0200 Subject: [PATCH 045/105] chore: merge cancelTouchesInParent methods --- ios/RNSScreenStack.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 0565a23ee6..3c3b6d0455 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -655,9 +655,16 @@ - (void)cancelTouchesInParent while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) parent = parent.superview; if (parent != nil) { +#ifdef RN_FABRIC_ENABLED + RCTSurfaceTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)]; + [touchHandler setEnabled:NO]; + [touchHandler setEnabled:YES]; + [touchHandler reset]; +#else RCTTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)]; [touchHandler cancel]; [touchHandler reset]; +#endif } } From fa21ff4e81d3d07e18bb47c80e2db0e74956da70 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:52 +0200 Subject: [PATCH 046/105] chore: merge gestureRecognizerShouldBegin: methods --- ios/RNSScreenStack.mm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 3c3b6d0455..83702d1aff 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -645,6 +645,7 @@ - (void)dismissOnReload return nil; } +// done - (void)cancelTouchesInParent { // cancel touches in parent, this is needed to cancel RN touch events. For example when Touchable @@ -668,6 +669,7 @@ - (void)cancelTouchesInParent } } +// done - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; @@ -684,8 +686,13 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer if (topScreen.fullScreenSwipeEnabled) { // we want only `RNSPanGestureRecognizer` to be able to recognize when // `fullScreenSwipeEnabled` is set, and we are in the bounds set by user +#ifdef RN_FABRIC_ENABLED + if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) +#else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] && - [self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) { + [self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) +#endif + { _isFullWidthSwiping = YES; [self cancelTouchesInParent]; return YES; From 159e07a5bc55197735da7fc912d8b9fe07209985 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:54 +0200 Subject: [PATCH 047/105] chore: move isScrollViewPanGestureRecognizer: method to paper specific section temporary -- unitl not implemented on fabric --- ios/RNSScreenStack.mm | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 83702d1aff..a58246f63c 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -741,18 +741,6 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer #endif } -- (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer -{ - // NOTE: This hack is required to restore native behavior of edge swipe (interactive pop gesture) - // without this, on a screen with a scroll view, it's only possible to pop view by panning horizontally - // if even slightly diagonal (or if in motion), scroll view will scroll, and edge swipe will be cancelled - if (![[gestureRecognizer view] isKindOfClass:[UIScrollView class]]) { - return NO; - } - UIScrollView *scrollView = gestureRecognizer.view; - return scrollView.panGestureRecognizer == gestureRecognizer; -} - - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { @@ -1024,6 +1012,19 @@ - (BOOL)isInGestureResponseDistance:(UIGestureRecognizer *)gestureRecognizer top (gestureResponseDistanceValues[@"bottom"] && y > [gestureResponseDistanceValues[@"bottom"] floatValue])); return NO; } + +- (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer +{ + // NOTE: This hack is required to restore native behavior of edge swipe (interactive pop gesture) + // without this, on a screen with a scroll view, it's only possible to pop view by panning horizontally + // if even slightly diagonal (or if in motion), scroll view will scroll, and edge swipe will be cancelled + if (![[gestureRecognizer view] isKindOfClass:[UIScrollView class]]) { + return NO; + } + UIScrollView *scrollView = gestureRecognizer.view; + return scrollView.panGestureRecognizer == gestureRecognizer; +} + #endif // RN_FABRIC_ENABLED @end From c5a30934085e1514cfdf5c640ba22d37dbcd4d32 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:56 +0200 Subject: [PATCH 048/105] chore: move two gestureRecognizer:... methods to paper specific section --- ios/RNSScreenStack.mm | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index a58246f63c..4df5a122b8 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -741,17 +741,6 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer #endif } -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer - shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer -{ - return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]; -} - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer - shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer -{ - return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]; -} #if !TARGET_OS_TV - (void)setupGestureHandlers @@ -1025,6 +1014,17 @@ - (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognize return scrollView.panGestureRecognizer == gestureRecognizer; } +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer + shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer +{ + return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer + shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer +{ + return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]; +} #endif // RN_FABRIC_ENABLED @end From f0d45dc61f452eaac0cecbe29fc68366e8ab31f7 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:57 +0200 Subject: [PATCH 049/105] chore: move two interactionController getters to paper specific section --- ios/RNSScreenStack.mm | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 4df5a122b8..0fb88cae5c 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -743,6 +743,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer #if !TARGET_OS_TV +// done - (void)setupGestureHandlers { // gesture recognizers for custom stack animations @@ -765,6 +766,7 @@ - (void)setupGestureHandlers [self addGestureRecognizer:panRecognizer]; } +// done - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer { RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; @@ -823,19 +825,6 @@ - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer } #endif -- (id)navigationController:(UINavigationController *)navigationController - interactionControllerForAnimationController: - (id)animationController -{ - return _interactionController; -} - -- (id)interactionControllerForDismissal: - (id)animator -{ - return _interactionController; -} - #ifdef RN_FABRIC_ENABLED #pragma mark - Fabric specific @@ -1025,6 +1014,19 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer { return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]; } + +- (id)navigationController:(UINavigationController *)navigationController + interactionControllerForAnimationController: + (id)animationController +{ + return _interactionController; +} + +- (id)interactionControllerForDismissal: + (id)animator +{ + return _interactionController; +} #endif // RN_FABRIC_ENABLED @end From 396d58e1835e6c8191813303cea48519debb5fed Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:24:59 +0200 Subject: [PATCH 050/105] chore: move prepareForRecycle method to fabric specific section & finish merging --- ios/RNSScreenStack.mm | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 0fb88cae5c..1261646276 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -890,6 +890,26 @@ - (void)mountingTransactionWillMountWithMetadata:(MountingTransactionMetadata co [self takeSnapshot]; } +- (void)prepareForRecycle +{ + [super prepareForRecycle]; + _reactSubviews = [NSMutableArray new]; + + for (UIViewController *controller in _presentedModals) { + [controller dismissViewControllerAnimated:NO completion:nil]; + } + + [_presentedModals removeAllObjects]; + [self dismissOnReload]; + [_controller willMoveToParentViewController:nil]; + [_controller removeFromParentViewController]; + [_controller setViewControllers:@[ [UIViewController new] ]]; +} + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} #else #pragma mark - Paper specific @@ -1031,6 +1051,12 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer @end +Class RNSScreenStackCls(void) +{ + return RNSScreenStackView.class; +} + +#ifndef RN_FABRIC_ENABLED @implementation RNSScreenStackManager { NSPointerArray *_stacks; } @@ -1058,3 +1084,4 @@ - (void)invalidate } @end +#endif From 7b6653581607c91dda3d22cd11d0ae4d73c3f0b0 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:25:01 +0200 Subject: [PATCH 051/105] fix: add facebook::react namespace to C++ react types --- ios/RNSScreenStack.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 1261646276..b657da1124 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -117,7 +117,7 @@ @implementation RNSScreenStackView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); + static const auto defaultProps = std::make_shared(); _props = defaultProps; _reactSubviews = [NSMutableArray new]; _presentedModals = [NSMutableArray new]; @@ -885,7 +885,7 @@ - (void)takeSnapshot _snapshot = [_controller.topViewController.view snapshotViewAfterScreenUpdates:NO]; } -- (void)mountingTransactionWillMountWithMetadata:(MountingTransactionMetadata const &)metadata +- (void)mountingTransactionWillMountWithMetadata:(facebook::react::MountingTransactionMetadata const &)metadata { [self takeSnapshot]; } @@ -906,9 +906,9 @@ - (void)prepareForRecycle [_controller setViewControllers:@[ [UIViewController new] ]]; } -+ (ComponentDescriptorProvider)componentDescriptorProvider ++ (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider { - return concreteComponentDescriptorProvider(); + return facebook::react::concreteComponentDescriptorProvider(); } #else #pragma mark - Paper specific From 8b212d35731b546463aa948f7c980b781aa8b711 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:25:03 +0200 Subject: [PATCH 052/105] chore: remove RNSScreenStackComponentView.{h,mm} files --- ios/RNSScreenStackComponentView.h | 15 - ios/RNSScreenStackComponentView.mm | 693 ----------------------------- 2 files changed, 708 deletions(-) delete mode 100644 ios/RNSScreenStackComponentView.h delete mode 100644 ios/RNSScreenStackComponentView.mm diff --git a/ios/RNSScreenStackComponentView.h b/ios/RNSScreenStackComponentView.h deleted file mode 100644 index 03915852ce..0000000000 --- a/ios/RNSScreenStackComponentView.h +++ /dev/null @@ -1,15 +0,0 @@ -#import - -#import -#import "RNSScreenContainer.h" - -NS_ASSUME_NONNULL_BEGIN -@interface RNScreensNavigationController : UINavigationController - -@end - -@interface RNSScreenStackComponentView : RCTViewComponentView - -@end - -NS_ASSUME_NONNULL_END diff --git a/ios/RNSScreenStackComponentView.mm b/ios/RNSScreenStackComponentView.mm deleted file mode 100644 index f6635bacf3..0000000000 --- a/ios/RNSScreenStackComponentView.mm +++ /dev/null @@ -1,693 +0,0 @@ -#import "RNSScreenStackComponentView.h" -#import "RNSScreen.h" -#import "RNSScreenStackAnimator.h" -#import "RNSScreenStackHeaderConfigComponentView.h" -#import "RNSScreenWindowTraits.h" - -#import - -#import -#import -#import -#import -#import - -#import "RCTFabricComponentsPlugins.h" - -#import - -using namespace facebook::react; - -@interface RNSScreenStackComponentView () < - UINavigationControllerDelegate, - UIAdaptivePresentationControllerDelegate, - UIGestureRecognizerDelegate, - UIViewControllerTransitioningDelegate, - RCTMountingTransactionObserving> { - BOOL _updateScheduled; -} - -@property (nonatomic) NSMutableArray *presentedModals; -@property (nonatomic) BOOL updatingModals; -@property (nonatomic) BOOL scheduleModalsUpdate; - -@end - -#if !TARGET_OS_TV -@interface RNSScreenEdgeGestureRecognizerF : UIScreenEdgePanGestureRecognizer -@end - -@implementation RNSScreenEdgeGestureRecognizerF -@end - -@interface RNSPanGestureRecognizerF : UIPanGestureRecognizer -@end - -@implementation RNSPanGestureRecognizerF -@end -#endif - -@implementation RNSScreenStackComponentView { - UINavigationController *_controller; - NSMutableArray *_reactSubviews; - BOOL _invalidated; - UIView *_snapshot; - BOOL _isFullWidthSwiping; - UIPercentDrivenInteractiveTransition *_interactionController; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; - _reactSubviews = [NSMutableArray new]; - _presentedModals = [NSMutableArray new]; - _controller = [RNScreensNavigationController new]; - _controller.delegate = self; - [_controller setViewControllers:@[ [UIViewController new] ]]; -#if !TARGET_OS_TV - [self setupGestureHandlers]; -#endif - } - - return self; -} - -- (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index -{ - // TODO: Remove this if def when merging with RNSScreenStack -#ifdef RN_FABRIC_ENABLED - if (![childComponentView isKindOfClass:[RNSScreenView class]]) { - RCTLogError(@"ScreenStack only accepts children of type Screen"); - return; - } - - RCTAssert( - childComponentView.reactSuperview == nil, - @"Attempt to mount already mounted component view. (parent: %@, child: %@, index: %@, existing parent: %@)", - self, - childComponentView, - @(index), - @([childComponentView.superview tag])); - - [_reactSubviews insertObject:(RNSScreenView *)childComponentView atIndex:index]; - ((RNSScreenView *)childComponentView).reactSuperview = self; - dispatch_async(dispatch_get_main_queue(), ^{ - [self maybeAddToParentAndUpdateContainer]; - }); -#endif -} - -- (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index -{ - // TODO: Remove this if def when merging with RNSScreenStack -#ifdef RN_FABRIC_ENABLED - RNSScreenView *screenChildComponent = (RNSScreenView *)childComponentView; - // We should only do a snapshot of a screen that is on the top - if (screenChildComponent == _controller.topViewController.view) { - [screenChildComponent.controller setViewToSnapshot:_snapshot]; - } - - RCTAssert( - screenChildComponent.reactSuperview == self, - @"Attempt to unmount a view which is mounted inside different view. (parent: %@, child: %@, index: %@)", - self, - screenChildComponent, - @(index)); - RCTAssert( - (_reactSubviews.count > index) && [_reactSubviews objectAtIndex:index] == childComponentView, - @"Attempt to unmount a view which has a different index. (parent: %@, child: %@, index: %@, actual index: %@, tag at index: %@)", - self, - screenChildComponent, - @(index), - @([_reactSubviews indexOfObject:screenChildComponent]), - @([[_reactSubviews objectAtIndex:index] tag])); - screenChildComponent.reactSuperview = nil; - [_reactSubviews removeObject:screenChildComponent]; - [screenChildComponent removeFromSuperview]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self maybeAddToParentAndUpdateContainer]; - }); -#endif -} - -- (void)takeSnapshot -{ - _snapshot = [_controller.topViewController.view snapshotViewAfterScreenUpdates:NO]; -} - -- (void)mountingTransactionWillMountWithMetadata:(MountingTransactionMetadata const &)metadata -{ - [self takeSnapshot]; -} - -- (NSArray *)reactSubviews -{ - return _reactSubviews; -} - -- (void)didMoveToWindow -{ - [super didMoveToWindow]; - // for handling nested stacks - [self maybeAddToParentAndUpdateContainer]; -} - -- (void)navigationController:(UINavigationController *)navigationController - willShowViewController:(UIViewController *)viewController - animated:(BOOL)animated -{ - // TODO: Remove this if def when merging with RNSScreenStack -#ifdef RN_FABRIC_ENABLED - - UIView *view = viewController.view; - if ([view isKindOfClass:RNSScreenView.class]) { - RNSScreenStackHeaderConfigComponentView *config = - (RNSScreenStackHeaderConfigComponentView *)((RNSScreenView *)view).config; - [RNSScreenStackHeaderConfigComponentView willShowViewController:viewController animated:animated withConfig:config]; - } -#endif -} - -- (void)maybeAddToParentAndUpdateContainer -{ - BOOL wasScreenMounted = _controller.parentViewController != nil; - BOOL isScreenReadyForShowing = self.window; - if (!isScreenReadyForShowing && !wasScreenMounted) { - return; - } - [self updateContainer]; - if (!wasScreenMounted) { - // when stack hasn't been added to parent VC yet we do two things: - // 1) we run updateContainer (the one above) – we do this because we want push view controllers to - // be installed before the VC is mounted. If we do that after it is added to parent the push - // updates operations are going to be blocked by UIKit. - // 2) we add navigation VS to parent – this is needed for the VC lifecycle events to be dispatched - // properly - // 3) we again call updateContainer – this time we do this to open modal controllers. Modals - // won't open in (1) because they require navigator to be added to parent. We handle that case - // gracefully in setModalViewControllers and can retry opening at any point. - [self reactAddControllerToClosestParent:_controller]; - [self updateContainer]; - } -} - -- (void)reactAddControllerToClosestParent:(UIViewController *)controller -{ - if (!controller.parentViewController) { - UIView *parentView = (UIView *)self.reactSuperview; - while (parentView) { - if ([parentView reactViewController]) { - [parentView.reactViewController addChildViewController:controller]; - [self addSubview:controller.view]; -#if !TARGET_OS_TV - _controller.interactivePopGestureRecognizer.delegate = self; -#endif - [self navigationController:_controller willShowViewController:_controller.topViewController animated:NO]; - break; - } - parentView = (UIView *)parentView.reactSuperview; - } - return; - } -} - -- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController -{ - // We don't directly set presentation delegate but instead rely on the ScreenView's delegate to - // forward certain calls to the container (Stack). - UIView *screenView = presentationController.presentedViewController.view; - if ([screenView isKindOfClass:[RNSScreenView class]]) { - // we trigger the update of status bar's appearance here because there is no other lifecycle method - // that can handle it when dismissing a modal, the same for orientation - [RNSScreenWindowTraits updateWindowTraits]; - [_presentedModals removeObject:presentationController.presentedViewController]; - // we double check if there are no new controllers pending to be presented since someone could - // have tried to push another one during the transition - _updatingModals = NO; - [self updateContainer]; - // TODO: implement onFinishTransitioning - // if (self.onFinishTransitioning) { - // // instead of directly triggering onFinishTransitioning this time we enqueue the event on the - // // main queue. We do that because onDismiss event is also enqueued and we want for the transition - // // finish event to arrive later than onDismiss (see RNSScreen#notifyDismiss) - // dispatch_async(dispatch_get_main_queue(), ^{ - // if (self.onFinishTransitioning) { - // self.onFinishTransitioning(nil); - // } - // }); - // } - } -} - -- (void)setPushViewControllers:(NSArray *)controllers -{ - // TODO: Remove this if def when merging with RNSScreenStack -#ifdef RN_FABRIC_ENABLED - - // when there is no change we return immediately - if ([_controller.viewControllers isEqualToArray:controllers]) { - return; - } - - // if view controller is not yet attached to window we skip updates now and run them when view - // is attached - if (self.window == nil) { - return; - } - - // when transition is ongoing, any updates made to the controller will not be reflected until the - // transition is complete. In particular, when we push/pop view controllers we expect viewControllers - // property to be updated immediately. Based on that property we then calculate future updates. - // When the transition is ongoing the property won't be updated immediatly. We therefore avoid - // making any updated when transition is ongoing and schedule updates for when the transition - // is complete. - if (_controller.transitionCoordinator != nil) { - if (!_updateScheduled) { - _updateScheduled = YES; - __weak RNSScreenStackComponentView *weakSelf = self; - [_controller.transitionCoordinator - animateAlongsideTransition:^(id _Nonnull context) { - // do nothing here, we only want to be notified when transition is complete - } - completion:^(id _Nonnull context) { - self->_updateScheduled = NO; - [weakSelf updateContainer]; - }]; - } - return; - } - - UIViewController *top = controllers.lastObject; - UIViewController *previousTop = _controller.topViewController; - - // At the start we set viewControllers to contain a single UIViewController - // instance. This is a workaround for header height adjustment bug (see comment - // in the init function). Here, we need to detect if the initial empty - // controller is still there - BOOL firstTimePush = ![previousTop isKindOfClass:[RNSScreen class]]; - - if (firstTimePush) { - // nothing pushed yet - [_controller setViewControllers:controllers animated:NO]; - } else if (top != previousTop) { - if (![controllers containsObject:previousTop]) { - // if the previous top screen does not exist anymore and the new top was not on the stack before, probably replace - // was called, so we check the animation - if (![_controller.viewControllers containsObject:top]) { - // setting new controllers with animation does `push` animation by default - auto screenController = (RNSScreen *)top; - [screenController resetViewToScreen]; - [_controller setViewControllers:controllers animated:YES]; - } else { - // last top controller is no longer on stack - // in this case we set the controllers stack to the new list with - // added the last top element to it and perform (animated) pop - NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; - [newControllers addObject:previousTop]; - [_controller setViewControllers:newControllers animated:NO]; - [_controller popViewControllerAnimated:YES]; - } - } else if (![_controller.viewControllers containsObject:top]) { - // new top controller is not on the stack - // in such case we update the stack except from the last element with - // no animation and do animated push of the last item - NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; - [newControllers removeLastObject]; - [_controller setViewControllers:newControllers animated:NO]; - auto screenController = (RNSScreen *)top; - [screenController resetViewToScreen]; - [_controller pushViewController:top animated:YES]; - } else { - // don't really know what this case could be, but may need to handle it - // somehow - [_controller setViewControllers:controllers animated:YES]; - } - } else { - // change wasn't on the top of the stack. We don't need animation. - [_controller setViewControllers:controllers animated:NO]; - } -#endif -} - -- (void)setModalViewControllers:(NSArray *)controllers -{ - // prevent re-entry - if (_updatingModals) { - _scheduleModalsUpdate = YES; - return; - } - - // when there is no change we return immediately. This check is important because sometime we may - // accidently trigger modal dismiss if we don't verify to run the below code only when an actual - // change in the list of presented modal was made. - if ([_presentedModals isEqualToArray:controllers]) { - return; - } - - // if view controller is not yet attached to window we skip updates now and run them when view - // is attached - if (self.window == nil && _presentedModals.lastObject.view.window == nil) { - return; - } - - _updatingModals = YES; - - NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; - [newControllers removeObjectsInArray:_presentedModals]; - - // find bottom-most controller that should stay on the stack for the duration of transition - NSUInteger changeRootIndex = 0; - UIViewController *changeRootController = _controller; - for (NSUInteger i = 0; i < MIN(_presentedModals.count, controllers.count); i++) { - if (_presentedModals[i] == controllers[i]) { - changeRootController = controllers[i]; - changeRootIndex = i + 1; - } else { - break; - } - } - - // we verify that controllers added on top of changeRootIndex are all new. Unfortunately modal - // VCs cannot be reshuffled (there are some visual glitches when we try to dismiss then show as - // even non-animated dismissal has delay and updates the screen several times) - for (NSUInteger i = changeRootIndex; i < controllers.count; i++) { - if ([_presentedModals containsObject:controllers[i]]) { - RCTAssert(false, @"Modally presented controllers are being reshuffled, this is not allowed"); - } - } - - __weak RNSScreenStackComponentView *weakSelf = self; - - void (^afterTransitions)(void) = ^{ - // TODO: find out how to implement these - // if (weakSelf.onFinishTransitioning) { - // weakSelf.onFinishTransitioning(nil); - // } - weakSelf.updatingModals = NO; - if (weakSelf.scheduleModalsUpdate) { - // if modals update was requested during setModalViewControllers we set scheduleModalsUpdate - // flag in order to perform updates at a later point. Here we are done with all modals - // transitions and check this flag again. If it was set, we reset the flag and execute updates. - weakSelf.scheduleModalsUpdate = NO; - [weakSelf updateContainer]; - } - // we trigger the update of orientation here because, when dismissing the modal from JS, - // neither `viewWillAppear` nor `presentationControllerDidDismiss` are called, same for status bar. - [RNSScreenWindowTraits updateWindowTraits]; - }; - - void (^finish)(void) = ^{ - NSUInteger oldCount = weakSelf.presentedModals.count; - if (changeRootIndex < oldCount) { - [weakSelf.presentedModals removeObjectsInRange:NSMakeRange(changeRootIndex, oldCount - changeRootIndex)]; - } - BOOL isAttached = - changeRootController.parentViewController != nil || changeRootController.presentingViewController != nil; - if (!isAttached || changeRootIndex >= controllers.count) { - // if change controller view is not attached, presenting modals will silently fail on iOS. - // In such a case we trigger controllers update from didMoveToWindow. - // We also don't run any present transitions if changeRootIndex is greater or equal to the size - // of new controllers array. This means that no new controllers should be presented. - afterTransitions(); - return; - } else { - UIViewController *previous = changeRootController; - for (NSUInteger i = changeRootIndex; i < controllers.count; i++) { - UIViewController *next = controllers[i]; - BOOL lastModal = (i == controllers.count - 1); - -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \ - __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 - if (@available(iOS 13.0, tvOS 13.0, *)) { - // Inherit UI style from its parent - solves an issue with incorrect style being applied to some UIKit views - // like date picker or segmented control. - next.overrideUserInterfaceStyle = self->_controller.overrideUserInterfaceStyle; - } -#endif - - BOOL shouldAnimate = lastModal && [next isKindOfClass:[RNSScreen class]] && - ((RNSScreenView *)next.view).stackAnimation != RNSScreenStackAnimationNone; - - // if you want to present another modal quick enough after dismissing the previous one, - // it will result in wrong changeRootController, see repro in - // https://github.com/software-mansion/react-native-screens/issues/1299 We call `updateContainer` again in - // `presentationControllerDidDismiss` to cover this case and present new controller - if (previous.beingDismissed) { - return; - } - - [previous presentViewController:next - animated:shouldAnimate - completion:^{ - [weakSelf.presentedModals addObject:next]; - if (lastModal) { - afterTransitions(); - }; - }]; - previous = next; - } - } - }; - - if (changeRootController.presentedViewController != nil && - [_presentedModals containsObject:changeRootController.presentedViewController]) { - BOOL shouldAnimate = changeRootIndex == controllers.count && - [changeRootController.presentedViewController isKindOfClass:[RNSScreen class]] && - ((RNSScreenView *)changeRootController.presentedViewController.view).stackAnimation != - RNSScreenStackAnimationNone; - [changeRootController dismissViewControllerAnimated:shouldAnimate completion:finish]; - } else { - finish(); - } -} - -- (void)updateContainer -{ - NSMutableArray *pushControllers = [NSMutableArray new]; - NSMutableArray *modalControllers = [NSMutableArray new]; - for (RNSScreenView *screen in _reactSubviews) { - if (screen.controller != nil) { - if (pushControllers.count == 0) { - // first screen on the list needs to be places as "push controller" - [pushControllers addObject:screen.controller]; - } else { - if (screen.stackPresentation == RNSScreenStackPresentationPush) { - [pushControllers addObject:screen.controller]; - } else { - [modalControllers addObject:screen.controller]; - } - } - } - } - - [self setPushViewControllers:pushControllers]; - [self setModalViewControllers:modalControllers]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - _controller.view.frame = self.bounds; -} - -- (void)dismissOnReload -{ - // TODO: Remove this ifdef when merging with RNSScreenStack -#ifdef RN_FABRIC_ENABLED - auto screenController = (RNSScreen *)_controller.topViewController; - [screenController resetViewToScreen]; -#endif -} - -#pragma mark - methods connected to transitioning - -- (id)navigationController:(UINavigationController *)navigationController - animationControllerForOperation:(UINavigationControllerOperation)operation - fromViewController:(UIViewController *)fromVC - toViewController:(UIViewController *)toVC -{ - RNSScreenView *screen; - if (operation == UINavigationControllerOperationPush) { - screen = (RNSScreenView *)toVC.view; - } else if (operation == UINavigationControllerOperationPop) { - screen = (RNSScreenView *)fromVC.view; - } - if (screen != nil && - // we need to return the animator when full width swiping even if the animation is not custom, - // otherwise the screen will be just popped immediately due to no animation - (_isFullWidthSwiping || [RNSScreenStackAnimator isCustomAnimation:screen.stackAnimation])) { - return [[RNSScreenStackAnimator alloc] initWithOperation:operation]; - } - return nil; -} - -- (void)cancelTouchesInParent -{ - // cancel touches in parent, this is needed to cancel RN touch events. For example when Touchable - // item is close to an edge and we start pulling from edge we want the Touchable to be cancelled. - // Without the below code the Touchable will remain active (highlighted) for the duration of back - // gesture and onPress may fire when we release the finger. - UIView *parent = _controller.view; - while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) - parent = parent.superview; - - if (parent != nil) { - RCTSurfaceTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)]; - [touchHandler setEnabled:NO]; - [touchHandler setEnabled:YES]; - [touchHandler reset]; - } -} - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; - - if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled || - _controller.viewControllers.count < 2) { - return NO; - } - -#if TARGET_OS_TV - [self cancelTouchesInPartent]; - return YES; -#else - - if (topScreen.fullScreenSwipeEnabled) { - // we want only `RNSPanGestureRecognizer` to be able to recognize when - // `fullScreenSwipeEnabled` is set - if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizerF class]]) { - _isFullWidthSwiping = YES; - [self cancelTouchesInParent]; - return YES; - } - return NO; - } - - if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizerF class]]) { - // it should only recognize with `customAnimationOnSwipe` set - return NO; - } else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizerF class]]) { - // it should only recognize with `fullScreenSwipeEnabled` set - return NO; - } - [self cancelTouchesInParent]; - return _controller.viewControllers.count >= 2; - - // TODO: add code for customAnimationOnSwipe prop here -#endif -} - -#if !TARGET_OS_TV -- (void)setupGestureHandlers -{ - // gesture recognizers for custom stack animations - RNSScreenEdgeGestureRecognizerF *leftEdgeSwipeGestureRecognizer = - [[RNSScreenEdgeGestureRecognizerF alloc] initWithTarget:self action:@selector(handleSwipe:)]; - leftEdgeSwipeGestureRecognizer.edges = UIRectEdgeLeft; - leftEdgeSwipeGestureRecognizer.delegate = self; - [self addGestureRecognizer:leftEdgeSwipeGestureRecognizer]; - - RNSScreenEdgeGestureRecognizerF *rightEdgeSwipeGestureRecognizer = - [[RNSScreenEdgeGestureRecognizerF alloc] initWithTarget:self action:@selector(handleSwipe:)]; - rightEdgeSwipeGestureRecognizer.edges = UIRectEdgeRight; - rightEdgeSwipeGestureRecognizer.delegate = self; - - // gesture recognizer for full width swipe gesture - RNSPanGestureRecognizerF *panRecognizer = [[RNSPanGestureRecognizerF alloc] initWithTarget:self - action:@selector(handleSwipe:)]; - panRecognizer.delegate = self; - [self addGestureRecognizer:panRecognizer]; -} - -- (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer -{ - RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; - - float translation; - float velocity; - float distance; - - if (topScreen.swipeDirection == RNSScreenSwipeDirectionVertical) { - translation = [gestureRecognizer translationInView:gestureRecognizer.view].y; - velocity = [gestureRecognizer velocityInView:gestureRecognizer.view].y; - distance = gestureRecognizer.view.bounds.size.height; - } else { - translation = [gestureRecognizer translationInView:gestureRecognizer.view].x; - velocity = [gestureRecognizer velocityInView:gestureRecognizer.view].x; - distance = gestureRecognizer.view.bounds.size.width; - BOOL isRTL = _controller.view.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft; - if (isRTL) { - translation = -translation; - velocity = -velocity; - } - } - - float transitionProgress = (translation / distance); - - switch (gestureRecognizer.state) { - case UIGestureRecognizerStateBegan: { - _interactionController = [UIPercentDrivenInteractiveTransition new]; - [_controller popViewControllerAnimated:YES]; - break; - } - - case UIGestureRecognizerStateChanged: { - [_interactionController updateInteractiveTransition:transitionProgress]; - break; - } - - case UIGestureRecognizerStateCancelled: { - [_interactionController cancelInteractiveTransition]; - break; - } - - case UIGestureRecognizerStateEnded: { - // values taken from - // https://github.com/react-navigation/react-navigation/blob/54739828598d7072c1bf7b369659e3682db3edc5/packages/stack/src/views/Stack/Card.tsx#L316 - BOOL shouldFinishTransition = (translation + velocity * 0.3) > (distance / 2); - if (shouldFinishTransition) { - [_interactionController finishInteractiveTransition]; - } else { - [_interactionController cancelInteractiveTransition]; - } - _interactionController = nil; - } - default: { - break; - } - } -} -#endif - -#pragma mark - RCTComponentViewProtocol - -- (void)prepareForRecycle -{ - [super prepareForRecycle]; - _reactSubviews = [NSMutableArray new]; - - for (UIViewController *controller in _presentedModals) { - [controller dismissViewControllerAnimated:NO completion:nil]; - } - - [_presentedModals removeAllObjects]; - [self dismissOnReload]; - [_controller willMoveToParentViewController:nil]; - [_controller removeFromParentViewController]; - [_controller setViewControllers:@[ [UIViewController new] ]]; -} - -+ (ComponentDescriptorProvider)componentDescriptorProvider -{ - return concreteComponentDescriptorProvider(); -} - -@end - -Class RNSScreenStackCls(void) -{ - return RNSScreenStackComponentView.class; -} From 7ea700574fcc0b940dfe057c706f1ab6d41ddccc Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 11:25:05 +0200 Subject: [PATCH 053/105] chore: add TODOs --- ios/RNSScreenStack.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index b657da1124..f4fea2d859 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -1,4 +1,5 @@ #ifdef RN_FABRIC_ENABLED +// TODO: merge this import when StackHeaderConfigComponentView is merged #import "RNSScreenStackHeaderConfigComponentView.h" #import From c5238700ad50aaf9fe22c6bef3ea1654afc033a8 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 15:23:36 +0200 Subject: [PATCH 054/105] chore: restore NS_ASSUME_NONNULL_{BEGIN,END} macros --- ios/RNSScreen.h | 10 ++++++---- ios/RNSScreen.mm | 7 ++----- ios/RNSScreenContainer.h | 4 ++++ ios/RNSScreenStack.h | 4 ++++ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index 940cad393a..423732ff86 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -10,6 +10,8 @@ #import #endif +NS_ASSUME_NONNULL_BEGIN + @interface RCTConvert (RNSScreen) + (RNSScreenStackPresentation)RNSScreenStackPresentation:(id)json; @@ -101,14 +103,14 @@ @end -#ifdef RN_FABRIC_ENABLED - -#else +#ifndef RN_FABRIC_ENABLED @interface UIView (RNSScreen) - (UIViewController *)parentViewController; @end +#endif @interface RNSScreenManager : RCTViewManager @end -#endif + +NS_ASSUME_NONNULL_END diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 754a800d2b..001a4ed867 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -1196,13 +1196,11 @@ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingFor #endif // RN_FABRIC_ENABLED -#ifdef RN_FABRIC_ENABLED - -#else @implementation RNSScreenManager RCT_EXPORT_MODULE() +#ifndef RN_FABRIC_ENABLED // we want to handle the case when activityState is nil RCT_REMAP_VIEW_PROPERTY(activityState, activityStateOrNil, NSNumber) RCT_EXPORT_VIEW_PROPERTY(customAnimationOnSwipe, BOOL); @@ -1236,11 +1234,10 @@ - (UIView *)view { return [[RNSScreenView alloc] initWithBridge:self.bridge]; } +#endif // RN_FABRIC_ENABLED @end -#endif // RN_FABRIC_ENABLED - @implementation RCTConvert (RNSScreen) RCT_ENUM_CONVERTER( diff --git a/ios/RNSScreenContainer.h b/ios/RNSScreenContainer.h index 0493e81aa2..303110720f 100644 --- a/ios/RNSScreenContainer.h +++ b/ios/RNSScreenContainer.h @@ -1,5 +1,7 @@ #import +NS_ASSUME_NONNULL_BEGIN + @protocol RNSScreenContainerDelegate - (void)markChildUpdated; @@ -29,3 +31,5 @@ - (void)maybeDismissVC; @end + +NS_ASSUME_NONNULL_END diff --git a/ios/RNSScreenStack.h b/ios/RNSScreenStack.h index a383cd2265..62fbde928f 100644 --- a/ios/RNSScreenStack.h +++ b/ios/RNSScreenStack.h @@ -3,6 +3,8 @@ #import "RNSScreenContainer.h" +NS_ASSUME_NONNULL_BEGIN + @interface RNScreensNavigationController : UINavigationController @end @@ -19,3 +21,5 @@ @interface RNSScreenStackManager : RCTViewManager @end + +NS_ASSUME_NONNULL_END From bd737032a5c66ca787adfc750557a860520b4b11 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 15:24:21 +0200 Subject: [PATCH 055/105] refact: apply linter suggestions --- ios/RNSScreenStack.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index e1e3b62834..cf39b8a8d9 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -670,7 +670,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer [self cancelTouchesInParent]; return _controller.viewControllers.count >= 2; #endif - + #endif } From a0245cfd889729f43dc1109e935f1ecd97644c4a Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Wed, 20 Apr 2022 15:25:36 +0200 Subject: [PATCH 056/105] fix: restore RNSScreenManager on Fabric --- FabricExample/ios/Podfile.lock | 2 +- ios/RNSScreen.h | 6 +----- ios/RNSScreen.mm | 35 ++++++++++++---------------------- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/FabricExample/ios/Podfile.lock b/FabricExample/ios/Podfile.lock index 5c225fd1c0..5fa1f6c992 100644 --- a/FabricExample/ios/Podfile.lock +++ b/FabricExample/ios/Podfile.lock @@ -962,4 +962,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: d1692aab6ddf32b03dc03304e2dc04073ec65f35 -COCOAPODS: 1.11.3 +COCOAPODS: 1.11.2 diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index 940cad393a..eccbf8cc57 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -56,6 +56,7 @@ @property (nonatomic) RNSScreenSwipeDirection swipeDirection; @property (nonatomic) RNSScreenReplaceAnimation replaceAnimation; @property (nonatomic, retain) NSNumber *transitionDuration; +@property (nonatomic, readonly) BOOL dismissed; #if !TARGET_OS_TV @property (nonatomic) RNSStatusBarStyle statusBarStyle; @@ -80,7 +81,6 @@ @property (weak, nonatomic) UIView *reactSuperview; @property (nonatomic, retain) UIViewController *controller; -@property (nonatomic, readonly) BOOL dismissed; @property (nonatomic) int activityState; @property (nonatomic) BOOL preventNativeDismiss; @property (nonatomic) BOOL customAnimationOnSwipe; @@ -101,9 +101,6 @@ @end -#ifdef RN_FABRIC_ENABLED - -#else @interface UIView (RNSScreen) - (UIViewController *)parentViewController; @end @@ -111,4 +108,3 @@ @interface RNSScreenManager : RCTViewManager @end -#endif diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 754a800d2b..f5e3944ec2 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -40,41 +40,39 @@ @interface RNSScreenView () @implementation RNSScreenView { RNSScreen *_controller; + __weak RCTBridge *_bridge; #ifdef RN_FABRIC_ENABLED RCTSurfaceTouchHandler *_touchHandler; facebook::react::RNSScreenShadowNode::ConcreteState::Shared _state; #else - __weak RCTBridge *_bridge; RCTTouchHandler *_touchHandler; CGRect _reactFrame; #endif } -#ifdef RN_FABRIC_ENABLED - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; - _controller = [[RNSScreen alloc] initWithView:self]; - // TODO: use default props (?) - _stackAnimation = RNSScreenStackAnimationDefault; - _stackPresentation = RNSScreenStackPresentationPush; - _hasStatusBarHiddenSet = NO; - _hasStatusBarStyleSet = NO; - _gestureEnabled = YES; - _hasStatusBarAnimationSet = NO; - _hasOrientationSet = NO; - _hasHomeIndicatorHiddenSet = NO; + [self initCommonProps]; } return self; } -#else + - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super init]) { _bridge = bridge; + [self initCommonProps]; + } + + return self; +} + +- (void)initCommonProps +{ _controller = [[RNSScreen alloc] initWithView:self]; _stackPresentation = RNSScreenStackPresentationPush; _stackAnimation = RNSScreenStackAnimationDefault; @@ -86,11 +84,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge _hasStatusBarHiddenSet = NO; _hasOrientationSet = NO; _hasHomeIndicatorHiddenSet = NO; - } - - return self; } -#endif - (UIViewController *)reactViewController { @@ -259,6 +253,7 @@ - (void)addSubview:(UIView *)view - (void)notifyDismissedWithCount:(int)dismissCount { + _dismissed = YES; #ifdef RN_FABRIC_ENABLED // If screen is already unmounted then there will be no event emitter // it will be cleaned in prepareForRecycle @@ -267,7 +262,6 @@ - (void)notifyDismissedWithCount:(int)dismissCount ->onDismissed(facebook::react::RNSScreenEventEmitter::OnDismissed{dismissCount : dismissCount}); } #else - _dismissed = YES; if (self.onDismissed) { dispatch_async(dispatch_get_main_queue(), ^{ if (self.onDismissed) { @@ -1196,9 +1190,6 @@ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingFor #endif // RN_FABRIC_ENABLED -#ifdef RN_FABRIC_ENABLED - -#else @implementation RNSScreenManager RCT_EXPORT_MODULE() @@ -1239,8 +1230,6 @@ - (UIView *)view @end -#endif // RN_FABRIC_ENABLED - @implementation RCTConvert (RNSScreen) RCT_ENUM_CONVERTER( From 57554c9bb8c99d3791c7a457a2d6077fbb8923f7 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 15:42:04 +0200 Subject: [PATCH 057/105] refact: apply linter suggestion --- ios/RNSScreen.mm | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 7bd60c121c..94cecdc93b 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -73,17 +73,17 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge - (void)initCommonProps { - _controller = [[RNSScreen alloc] initWithView:self]; - _stackPresentation = RNSScreenStackPresentationPush; - _stackAnimation = RNSScreenStackAnimationDefault; - _gestureEnabled = YES; - _replaceAnimation = RNSScreenReplaceAnimationPop; - _dismissed = NO; - _hasStatusBarStyleSet = NO; - _hasStatusBarAnimationSet = NO; - _hasStatusBarHiddenSet = NO; - _hasOrientationSet = NO; - _hasHomeIndicatorHiddenSet = NO; + _controller = [[RNSScreen alloc] initWithView:self]; + _stackPresentation = RNSScreenStackPresentationPush; + _stackAnimation = RNSScreenStackAnimationDefault; + _gestureEnabled = YES; + _replaceAnimation = RNSScreenReplaceAnimationPop; + _dismissed = NO; + _hasStatusBarStyleSet = NO; + _hasStatusBarAnimationSet = NO; + _hasStatusBarHiddenSet = NO; + _hasOrientationSet = NO; + _hasHomeIndicatorHiddenSet = NO; } - (UIViewController *)reactViewController From 0e73f8f08d37aad3ca0f7192ba2f10061e143981 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 16:05:23 +0200 Subject: [PATCH 058/105] fix: remove merge artifact --- ios/RNSScreen.h | 2 -- ios/RNSScreen.mm | 2 -- 2 files changed, 4 deletions(-) diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index f50f01632b..265854039f 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -103,11 +103,9 @@ NS_ASSUME_NONNULL_BEGIN @end -#ifndef RN_FABRIC_ENABLED @interface UIView (RNSScreen) - (UIViewController *)parentViewController; @end -#endif @interface RNSScreenManager : RCTViewManager diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 94cecdc93b..e64e3a8587 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -1194,7 +1194,6 @@ @implementation RNSScreenManager RCT_EXPORT_MODULE() -#ifndef RN_FABRIC_ENABLED // we want to handle the case when activityState is nil RCT_REMAP_VIEW_PROPERTY(activityState, activityStateOrNil, NSNumber) RCT_EXPORT_VIEW_PROPERTY(customAnimationOnSwipe, BOOL); @@ -1228,7 +1227,6 @@ - (UIView *)view { return [[RNSScreenView alloc] initWithBridge:self.bridge]; } -#endif // RN_FABRIC_ENABLED @end From f47cf9a7938cc827e7ce8eb9d2926bc8c62dd45c Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Wed, 20 Apr 2022 16:12:56 +0200 Subject: [PATCH 059/105] refact: apply linter suggestions --- ios/RNSScreenStack.mm | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 32721a8a37..e86e414bf0 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -24,30 +24,27 @@ #import #endif // RN_FABRIC_ENABLED -#import "RNSScreenStack.h" #import "RNSScreen.h" +#import "RNSScreenStack.h" #import "RNSScreenStackAnimator.h" #import "RNSScreenWindowTraits.h" @interface RNSScreenStackView () #ifdef RN_FABRIC_ENABLED -< - UINavigationControllerDelegate, - UIAdaptivePresentationControllerDelegate, - UIGestureRecognizerDelegate, - UIViewControllerTransitioningDelegate, - RCTMountingTransactionObserving> { + { BOOL _updateScheduled; } #else -< - UINavigationControllerDelegate, - UIAdaptivePresentationControllerDelegate, - UIGestureRecognizerDelegate, - UIViewControllerTransitioningDelegate> + #endif - @property (nonatomic) NSMutableArray *presentedModals; @property (nonatomic) BOOL updatingModals; @property (nonatomic) BOOL scheduleModalsUpdate; @@ -354,7 +351,7 @@ - (void)setModalViewControllers:(NSArray *)controllers __weak RNSScreenStackView *weakSelf = self; void (^afterTransitions)(void) = ^{ - // TODO: Implement onFinishTransitioning on Fabric + // TODO: Implement onFinishTransitioning on Fabric #ifndef RN_FABRIC_ENABLED if (weakSelf.onFinishTransitioning) { weakSelf.onFinishTransitioning(nil); @@ -742,7 +739,6 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer #endif } - #if !TARGET_OS_TV // done - (void)setupGestureHandlers From f1e9b9d773a2ec993fcb8fe00961ac0dd99c5f44 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 08:10:45 +0200 Subject: [PATCH 060/105] fix: add *.mm sources to TestExample project --- RNScreens.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNScreens.podspec b/RNScreens.podspec index fd93a55dcb..c722d9548e 100644 --- a/RNScreens.podspec +++ b/RNScreens.podspec @@ -47,7 +47,7 @@ Pod::Spec.new do |s| ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\"" } end else - s.source_files = "ios/**/*.{h,m}" + s.source_files = "ios/**/*.{h,m,mm}" s.requires_arc = true s.dependency "React-Core" From 5d2b1fb95e3552e994891eeec121395408467d57 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 10:23:44 +0200 Subject: [PATCH 061/105] fix: restore RNScreenStackmanager for Fabric impl --- ios/RNSScreenStack.h | 2 -- ios/RNSScreenStack.mm | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ios/RNSScreenStack.h b/ios/RNSScreenStack.h index 86035ff41a..225d02a82e 100644 --- a/ios/RNSScreenStack.h +++ b/ios/RNSScreenStack.h @@ -30,10 +30,8 @@ NS_ASSUME_NONNULL_BEGIN @end -#ifndef RN_FABRIC_ENABLED @interface RNSScreenStackManager : RCTViewManager @end -#endif NS_ASSUME_NONNULL_END diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index e86e414bf0..f82e11fe6d 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -1053,7 +1053,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer return RNSScreenStackView.class; } -#ifndef RN_FABRIC_ENABLED @implementation RNSScreenStackManager { NSPointerArray *_stacks; } @@ -1062,6 +1061,7 @@ @implementation RNSScreenStackManager { RCT_EXPORT_VIEW_PROPERTY(onFinishTransitioning, RCTDirectEventBlock); +#ifndef RN_FABRIC_ENABLED - (UIView *)view { RNSScreenStackView *view = [[RNSScreenStackView alloc] initWithManager:self]; @@ -1071,6 +1071,7 @@ - (UIView *)view [_stacks addPointer:(__bridge void *)view]; return view; } +#endif // RN_FABRIC_ENABLED - (void)invalidate { @@ -1081,4 +1082,3 @@ - (void)invalidate } @end -#endif From 953299e3365edc9abca57a7b5c35b3323df74658 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 11:26:07 +0200 Subject: [PATCH 062/105] fix: make TestsExample compile Notice change of RNSScreenView#controller type from UIViewController to RNSScreen --- ios/RNSConvert.h | 3 ++ ios/RNSConvert.mm | 3 ++ ios/RNSScreen.h | 3 +- ios/RNSScreen.mm | 30 +++++++++---------- ios/RNSScreenStackComponentView.h | 3 ++ ios/RNSScreenStackComponentView.mm | 3 ++ ios/RNSScreenStackHeaderConfigComponentView.h | 2 ++ ...RNSScreenStackHeaderConfigComponentView.mm | 3 ++ ...RNSScreenStackHeaderSubviewComponentView.h | 3 ++ ...NSScreenStackHeaderSubviewComponentView.mm | 3 ++ 10 files changed, 38 insertions(+), 18 deletions(-) diff --git a/ios/RNSConvert.h b/ios/RNSConvert.h index 2bb24c9503..e6e8774e1f 100644 --- a/ios/RNSConvert.h +++ b/ios/RNSConvert.h @@ -1,6 +1,7 @@ #ifndef RNSConvert_h #define RNSConvert_h +#ifdef RN_FABRIC_ENABLED #import #import "RNSEnums.h" @@ -14,4 +15,6 @@ @end +#endif // RN_FABRIC_ENABLED + #endif /* RNSConvert_h */ diff --git a/ios/RNSConvert.mm b/ios/RNSConvert.mm index 8db9635408..6207db99b9 100644 --- a/ios/RNSConvert.mm +++ b/ios/RNSConvert.mm @@ -1,5 +1,6 @@ #import "RNSConvert.h" +#ifdef RN_FABRIC_ENABLED @implementation RNSConvert + (RNSScreenStackPresentation)RNSScreenStackPresentationFromCppEquivalent: @@ -48,3 +49,5 @@ + (RNSScreenStackAnimation)RNSScreenStackAnimationFromCppEquivalent: } @end + +#endif // RN_FABRIC_ENABLED diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index 265854039f..7d48f5e5ce 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -59,6 +59,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) RNSScreenReplaceAnimation replaceAnimation; @property (nonatomic, retain) NSNumber *transitionDuration; @property (nonatomic, readonly) BOOL dismissed; +@property (nonatomic, retain) RNSScreen *controller; #if !TARGET_OS_TV @property (nonatomic) RNSStatusBarStyle statusBarStyle; @@ -71,7 +72,6 @@ NS_ASSUME_NONNULL_BEGIN #ifdef RN_FABRIC_ENABLED @property (weak, nonatomic) UIView *config; @property (weak, nonatomic) UIView *reactSuperview; -@property (nonatomic, retain) RNSScreen *controller; #else @property (nonatomic, copy) RCTDirectEventBlock onAppear; @property (nonatomic, copy) RCTDirectEventBlock onDisappear; @@ -82,7 +82,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, copy) RCTDirectEventBlock onTransitionProgress; @property (weak, nonatomic) UIView *reactSuperview; -@property (nonatomic, retain) UIViewController *controller; @property (nonatomic) int activityState; @property (nonatomic) BOOL preventNativeDismiss; @property (nonatomic) BOOL customAnimationOnSwipe; diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index e64e3a8587..8a0884fff6 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -2,34 +2,28 @@ #import "RNSScreen.h" #import "RNSScreenContainer.h" -#import "RNSScreenStack.h" -#import "RNSScreenStackHeaderConfig.h" #import "RNSScreenWindowTraits.h" -#import - -// TODO: Organize imports #ifdef RN_FABRIC_ENABLED #import +#import #import #import #import #import +#import +#import "RCTFabricComponentsPlugins.h" #import "RNSConvert.h" #import "RNSScreenStackHeaderConfigComponentView.h" #else #import +#import "RNSScreenStack.h" +#import "RNSScreenStackHeaderConfig.h" #endif #import #import -#import -#import "RCTFabricComponentsPlugins.h" - -#import -#import - @interface RNSScreenView () #ifdef RN_FABRIC_ENABLED @@ -50,6 +44,7 @@ @implementation RNSScreenView { #endif } +#ifdef RN_FABRIC_ENABLED - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { @@ -60,7 +55,7 @@ - (instancetype)initWithFrame:(CGRect)frame return self; } - +#else - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super init]) { @@ -70,6 +65,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge return self; } +#endif // RN_FABRIC_ENABLED - (void)initCommonProps { @@ -397,14 +393,14 @@ - (RCTTouchHandler *)touchHandler return nil; } -// altough it is fabric specific code +#pragma mark - Fabric specific +#ifdef RN_FABRIC_ENABLED + + (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider { return facebook::react::concreteComponentDescriptorProvider(); } -#pragma mark - Fabric specific -#ifdef RN_FABRIC_ENABLED - (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { [super mountChildComponentView:childComponentView index:index]; @@ -516,7 +512,7 @@ - (void)setActivityStateOrNil:(NSNumber *)activityStateOrNil int activityState = [activityStateOrNil intValue]; if (activityStateOrNil != nil && activityState != _activityState) { _activityState = activityState; - [_reactSuperview markChildUpdated] + [_reactSuperview markChildUpdated]; } } @@ -581,10 +577,12 @@ - (void)invalidate @end +#ifdef RN_FABRIC_ENABLED Class RNSScreenCls(void) { return RNSScreenView.class; } +#endif #pragma mark - RNSScreen diff --git a/ios/RNSScreenStackComponentView.h b/ios/RNSScreenStackComponentView.h index 03915852ce..547d3cb492 100644 --- a/ios/RNSScreenStackComponentView.h +++ b/ios/RNSScreenStackComponentView.h @@ -1,3 +1,4 @@ +#ifdef RN_FABRIC_ENABLED #import #import @@ -13,3 +14,5 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END + +#endif // RN_FABRIC_ENABLED diff --git a/ios/RNSScreenStackComponentView.mm b/ios/RNSScreenStackComponentView.mm index f6635bacf3..3865558b93 100644 --- a/ios/RNSScreenStackComponentView.mm +++ b/ios/RNSScreenStackComponentView.mm @@ -1,3 +1,4 @@ +#ifdef RN_FABRIC_ENABLED #import "RNSScreenStackComponentView.h" #import "RNSScreen.h" #import "RNSScreenStackAnimator.h" @@ -691,3 +692,5 @@ + (ComponentDescriptorProvider)componentDescriptorProvider { return RNSScreenStackComponentView.class; } + +#endif // RN_FABRIC_ENABLED diff --git a/ios/RNSScreenStackHeaderConfigComponentView.h b/ios/RNSScreenStackHeaderConfigComponentView.h index 390023adc8..5182b6eafd 100644 --- a/ios/RNSScreenStackHeaderConfigComponentView.h +++ b/ios/RNSScreenStackHeaderConfigComponentView.h @@ -1,3 +1,4 @@ +#ifdef RN_FABRIC_ENABLED #import #import @@ -40,3 +41,4 @@ withConfig:(RNSScreenStackHeaderConfigComponentView *)config; @end +#endif diff --git a/ios/RNSScreenStackHeaderConfigComponentView.mm b/ios/RNSScreenStackHeaderConfigComponentView.mm index a0c06455f2..68b3c6a6a6 100644 --- a/ios/RNSScreenStackHeaderConfigComponentView.mm +++ b/ios/RNSScreenStackHeaderConfigComponentView.mm @@ -3,6 +3,7 @@ #import "./utils/RNSUIBarButtonItem.h" +#ifdef RN_FABRIC_ENABLED #import #import @@ -666,3 +667,5 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & { return RNSScreenStackHeaderConfigComponentView.class; } + +#endif // RN_FABRIC_ENABLED diff --git a/ios/RNSScreenStackHeaderSubviewComponentView.h b/ios/RNSScreenStackHeaderSubviewComponentView.h index eaaa920f91..c2d9eff6bb 100644 --- a/ios/RNSScreenStackHeaderSubviewComponentView.h +++ b/ios/RNSScreenStackHeaderSubviewComponentView.h @@ -1,3 +1,4 @@ +#ifdef RN_FABRIC_ENABLED #import #import @@ -12,3 +13,5 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END + +#endif // RN_FABRIC_ENABLED diff --git a/ios/RNSScreenStackHeaderSubviewComponentView.mm b/ios/RNSScreenStackHeaderSubviewComponentView.mm index bad3ecc3fd..61c54ab587 100644 --- a/ios/RNSScreenStackHeaderSubviewComponentView.mm +++ b/ios/RNSScreenStackHeaderSubviewComponentView.mm @@ -1,3 +1,4 @@ +#ifdef RN_FABRIC_ENABLED #import "RNSScreenStackHeaderSubviewComponentView.h" #import @@ -75,3 +76,5 @@ + (ComponentDescriptorProvider)componentDescriptorProvider { return RNSScreenStackHeaderSubviewComponentView.class; } + +#endif // RN_FABRIC_ENABLED From d46daff9fb85a7bc1b49f92ad3574cacc945e95a Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:00:56 +0200 Subject: [PATCH 063/105] potentially important: remove RNSScreen *_controller field from RNSScreenView implementation --- ios/RNSScreen.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 8a0884fff6..0d3cab052d 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -33,7 +33,6 @@ @interface RNSScreenView () @end @implementation RNSScreenView { - RNSScreen *_controller; __weak RCTBridge *_bridge; #ifdef RN_FABRIC_ENABLED RCTSurfaceTouchHandler *_touchHandler; From 3fa258d8940addec9f5334897fd361221f036da0 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:16:42 +0200 Subject: [PATCH 064/105] chore: move setViewToSnapshot & resetViewToScreen methods to Fabric specific section --- ios/RNSScreen.mm | 63 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 0d3cab052d..bb2ab66b49 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -18,9 +18,9 @@ #else #import #import "RNSScreenStack.h" -#import "RNSScreenStackHeaderConfig.h" #endif +#import "RNSScreenStackHeaderConfig.h" #import #import @@ -585,37 +585,45 @@ - (void)invalidate #pragma mark - RNSScreen -#ifdef RN_FABRIC_ENABLED - @implementation RNSScreen { +#ifdef RN_FABRIC_ENABLED RNSScreenView *_initialView; +#else + __weak id _previousFirstResponder; + CGRect _lastViewFrame; + UIView *_fakeView; + CADisplayLink *_animationTimer; + CGFloat _currentAlpha; + BOOL _closing; + BOOL _goingForward; + int _dismissCount; + BOOL _isSwiping; + BOOL _shouldNotify; +#endif } +#pragma mark - Common + +// done - (instancetype)initWithView:(UIView *)view { if (self = [super init]) { self.view = view; +#ifdef RN_FABRIC_ENABLED if ([view isKindOfClass:[RNSScreenView class]]) { _initialView = (RNSScreenView *)view; } else { + // TODO: fix this message RCTLogError(@"ScreenController can only be initialized with ScreenComponentView"); } +#else + _shouldNotify = YES; + _fakeView = [UIView new]; +#endif } return self; } -- (void)setViewToSnapshot:(UIView *)snapshot -{ - [self.view removeFromSuperview]; - self.view = snapshot; -} - -- (void)resetViewToScreen -{ - [self.view removeFromSuperview]; - self.view = _initialView; -} - // TODO: Find out why this is executed when screen is going out - (void)viewWillAppear:(BOOL)animated { @@ -779,9 +787,27 @@ - (BOOL)prefersHomeIndicatorAutoHidden } #endif -@end +#ifdef RN_FABRIC_ENABLED +#pragma mark - Fabric + +- (void)setViewToSnapshot:(UIView *)snapshot +{ + [self.view removeFromSuperview]; + self.view = snapshot; +} + +- (void)resetViewToScreen +{ + [self.view removeFromSuperview]; + self.view = _initialView; +} + #else +#pragma mark - Paper specific +#endif // RN_FABRIC_ENABLED + +@end @implementation RNSScreen { __weak id _previousFirstResponder; @@ -796,6 +822,7 @@ @implementation RNSScreen { BOOL _shouldNotify; } +// done 2 - (instancetype)initWithView:(UIView *)view { if (self = [super init]) { @@ -1185,8 +1212,6 @@ - (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingFor @end -#endif // RN_FABRIC_ENABLED - @implementation RNSScreenManager RCT_EXPORT_MODULE() @@ -1220,10 +1245,12 @@ @implementation RNSScreenManager RCT_EXPORT_VIEW_PROPERTY(homeIndicatorHidden, BOOL) #endif +#ifndef RN_FABRIC_ENABLED - (UIView *)view { return [[RNSScreenView alloc] initWithBridge:self.bridge]; } +#endif @end From 519687632ce260685aa82d167979309ec0c291ca Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:18:50 +0200 Subject: [PATCH 065/105] chore: merge viewWillAppear: methods --- ios/RNSScreen.mm | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index bb2ab66b49..3917e52202 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -624,12 +624,39 @@ - (instancetype)initWithView:(UIView *)view return self; } +// done // TODO: Find out why this is executed when screen is going out - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; +#ifdef RN_FABRIC_ENABLED [RNSScreenWindowTraits updateWindowTraits]; [_initialView notifyWillAppear]; +#else + if (!_isSwiping) { + [((RNSScreenView *)self.view) notifyWillAppear]; + if (self.transitionCoordinator.isInteractive) { + // we started dismissing with swipe gesture + _isSwiping = YES; + } + } else { + // this event is also triggered if we cancelled the swipe. + // The _isSwiping is still true, but we don't want to notify then + _shouldNotify = NO; + } + + [self hideHeaderIfNecessary]; + + // as per documentation of these methods + _goingForward = [self isBeingPresented] || [self isMovingToParentViewController]; + + [RNSScreenWindowTraits updateWindowTraits]; + if (_shouldNotify) { + _closing = NO; + [self notifyTransitionProgress:0.0 closing:_closing goingForward:_goingForward]; + [self setupProgressNotification]; + } +#endif } - (void)viewWillDisappear:(BOOL)animated From a7e0329e9fc33e037e32992d4889089e3b21d0bf Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:20:26 +0200 Subject: [PATCH 066/105] chore: merge viewWillDisappear methods --- ios/RNSScreen.mm | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 3917e52202..2e7711a4c4 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -659,10 +659,45 @@ - (void)viewWillAppear:(BOOL)animated #endif } +// done - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; +#ifdef RN_FABRIC_ENABLED [_initialView notifyWillDisappear]; +#else + if (!self.transitionCoordinator.isInteractive) { + // user might have long pressed ios 14 back button item, + // so he can go back more than one screen and we need to dismiss more screens in JS stack then. + // We check it by calculating the difference between the index of currently displayed screen + // and the index of the target screen, which is the view of topViewController at this point. + // If the value is lower than 1, it means we are dismissing a modal, or navigating forward, or going back with JS. + int selfIndex = [self getIndexOfView:self.view]; + int targetIndex = [self getIndexOfView:self.navigationController.topViewController.view]; + _dismissCount = selfIndex - targetIndex > 0 ? selfIndex - targetIndex : 1; + } else { + _dismissCount = 1; + } + + // same flow as in viewWillAppear + if (!_isSwiping) { + [((RNSScreenView *)self.view) notifyWillDisappear]; + if (self.transitionCoordinator.isInteractive) { + _isSwiping = YES; + } + } else { + _shouldNotify = NO; + } + + // as per documentation of these methods + _goingForward = !([self isBeingDismissed] || [self isMovingFromParentViewController]); + + if (_shouldNotify) { + _closing = YES; + [self notifyTransitionProgress:0.0 closing:_closing goingForward:_goingForward]; + [self setupProgressNotification]; + } +#endif } - (void)viewDidAppear:(BOOL)animated From 4f0ff72553a6cecad00455d67d56e6767c3f8e18 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:21:32 +0200 Subject: [PATCH 067/105] chore: merge viewDidAppear methods --- ios/RNSScreen.mm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 2e7711a4c4..5e3e4d8bac 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -700,10 +700,23 @@ - (void)viewWillDisappear:(BOOL)animated #endif } +// done - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; +#ifdef RN_FABRIC_ENABLED [_initialView notifyAppear]; +#else + if (!_isSwiping || _shouldNotify) { + // we are going forward or dismissing without swipe + // or successfully swiped back + [((RNSScreenView *)self.view) notifyAppear]; + [self notifyTransitionProgress:1.0 closing:NO goingForward:_goingForward]; + } + + _isSwiping = NO; + _shouldNotify = YES; +#endif } - (void)viewDidDisappear:(BOOL)animated From 2bf93c582a868bc54cd71b09615fb524bf0b6439 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:22:36 +0200 Subject: [PATCH 068/105] chore: merge viewDidDisappear methods --- ios/RNSScreen.mm | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 5e3e4d8bac..b089937fe2 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -719,14 +719,40 @@ - (void)viewDidAppear:(BOOL)animated #endif } +// done - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; +#ifdef RN_FABRIC_ENABLED [_initialView notifyDisappear]; if (self.parentViewController == nil && self.presentingViewController == nil) { // screen dismissed, send event [_initialView notifyDismissedWithCount:1]; } +#else + if (self.parentViewController == nil && self.presentingViewController == nil) { + if (((RNSScreenView *)self.view).preventNativeDismiss) { + // if we want to prevent the native dismiss, we do not send dismissal event, + // but instead call `updateContainer`, which restores the JS navigation stack + [((RNSScreenView *)self.view).reactSuperview updateContainer]; + [((RNSScreenView *)self.view) notifyDismissCancelledWithDismissCount:_dismissCount]; + } else { + // screen dismissed, send event + [((RNSScreenView *)self.view) notifyDismissedWithCount:_dismissCount]; + } + } + + // same flow as in viewDidAppear + if (!_isSwiping || _shouldNotify) { + [((RNSScreenView *)self.view) notifyDisappear]; + [self notifyTransitionProgress:1.0 closing:YES goingForward:_goingForward]; + } + + _isSwiping = NO; + _shouldNotify = YES; + + [self traverseForScrollView:self.view]; +#endif } - (void)viewDidLayoutSubviews From 55e4e19069cba65f6c1e32528c81da6c7d6724a4 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:23:56 +0200 Subject: [PATCH 069/105] chore: merge viewDidLayoutSubviews methods --- ios/RNSScreen.mm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index b089937fe2..adc4d14ae5 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -755,13 +755,30 @@ - (void)viewDidDisappear:(BOOL)animated #endif } +// done - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; +#ifdef RN_FABRIC_ENABLED BOOL isDisplayedWithinUINavController = [self.parentViewController isKindOfClass:[UINavigationController class]]; if (isDisplayedWithinUINavController) { [_initialView updateBounds]; } +#else + // The below code makes the screen view adapt dimensions provided by the system. We take these + // into account only when the view is mounted under RNScreensNavigationController in which case system + // provides additional padding to account for possible header, and in the case when screen is + // shown as a native modal, as the final dimensions of the modal on iOS 12+ are shorter than the + // screen size + BOOL isDisplayedWithinUINavController = + [self.parentViewController isKindOfClass:[RNScreensNavigationController class]]; + BOOL isPresentedAsNativeModal = self.parentViewController == nil && self.presentingViewController != nil; + if ((isDisplayedWithinUINavController || isPresentedAsNativeModal) && + !CGRectEqualToRect(_lastViewFrame, self.view.frame)) { + _lastViewFrame = self.view.frame; + [((RNSScreenView *)self.viewIfLoaded) updateBounds]; + } +#endif } #if !TARGET_OS_TV From 77fe9082564ff88fe349139756bdaca9dac38038 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:25:47 +0200 Subject: [PATCH 070/105] chore: move findFirstResponder method to paper specific section --- ios/RNSScreen.mm | 391 +---------------------------------------------- 1 file changed, 1 insertion(+), 390 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index adc4d14ae5..e030db91e2 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -923,177 +923,6 @@ - (void)resetViewToScreen #else #pragma mark - Paper specific -#endif // RN_FABRIC_ENABLED - -@end - -@implementation RNSScreen { - __weak id _previousFirstResponder; - CGRect _lastViewFrame; - UIView *_fakeView; - CADisplayLink *_animationTimer; - CGFloat _currentAlpha; - BOOL _closing; - BOOL _goingForward; - int _dismissCount; - BOOL _isSwiping; - BOOL _shouldNotify; -} - -// done 2 -- (instancetype)initWithView:(UIView *)view -{ - if (self = [super init]) { - self.view = view; - _shouldNotify = YES; - _fakeView = [UIView new]; - } - return self; -} - -#if !TARGET_OS_TV -- (UIViewController *)childViewControllerForStatusBarStyle -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitStyle includingModals:NO]; - return vc == self ? nil : vc; -} - -- (UIStatusBarStyle)preferredStatusBarStyle -{ - return [RNSScreenWindowTraits statusBarStyleForRNSStatusBarStyle:((RNSScreenView *)self.view).statusBarStyle]; -} - -- (UIViewController *)childViewControllerForStatusBarHidden -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHidden includingModals:NO]; - return vc == self ? nil : vc; -} - -- (BOOL)prefersStatusBarHidden -{ - return ((RNSScreenView *)self.view).statusBarHidden; -} - -- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitAnimation includingModals:NO]; - - if ([vc isKindOfClass:[RNSScreen class]]) { - return ((RNSScreenView *)vc.view).statusBarAnimation; - } - return UIStatusBarAnimationFade; -} - -- (UIInterfaceOrientationMask)supportedInterfaceOrientations -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitOrientation includingModals:YES]; - - if ([vc isKindOfClass:[RNSScreen class]]) { - return ((RNSScreenView *)vc.view).screenOrientation; - } - return UIInterfaceOrientationMaskAllButUpsideDown; -} - -- (UIViewController *)childViewControllerForHomeIndicatorAutoHidden -{ - UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitHomeIndicatorHidden includingModals:YES]; - return vc == self ? nil : vc; -} - -- (BOOL)prefersHomeIndicatorAutoHidden -{ - return ((RNSScreenView *)self.view).homeIndicatorHidden; -} - -// if the returned vc is a child, it means that it can provide config; -// if the returned vc is self, it means that there is no child for config and self has config to provide, -// so we return self which results in asking self for preferredStatusBarStyle/Animation etc.; -// if the returned vc is nil, it means none of children could provide config and self does not have config either, -// so if it was asked by parent, it will fallback to parent's option, or use default option if it is the top Screen -- (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals -{ - UIViewController *lastViewController = [[self childViewControllers] lastObject]; - if ([self.presentedViewController isKindOfClass:[RNSScreen class]]) { - lastViewController = self.presentedViewController; - // we don't want to allow controlling of status bar appearance when we present non-fullScreen modal - // and it is not possible if `modalPresentationCapturesStatusBarAppearance` is not set to YES, so even - // if we went into a modal here and ask it, it wouldn't take any effect. For fullScreen modals, the system - // asks them by itself, so we can stop traversing here. - // for screen orientation, we need to start the search again from that modal - return !includingModals - ? nil - : [(RNSScreen *)lastViewController findChildVCForConfigAndTrait:trait includingModals:includingModals] - ?: lastViewController; - } - - UIViewController *selfOrNil = [self hasTraitSet:trait] ? self : nil; - if (lastViewController == nil) { - return selfOrNil; - } else { - if ([lastViewController conformsToProtocol:@protocol(RNScreensViewControllerDelegate)]) { - // If there is a child (should be VC of ScreenContainer or ScreenStack), that has a child that could provide the - // trait, we recursively go into its findChildVCForConfig, and if one of the children has the trait set, we return - // it, otherwise we return self if this VC has config, and nil if it doesn't we use - // `childViewControllerForStatusBarStyle` for all options since the behavior is the same for all of them - UIViewController *childScreen = [lastViewController childViewControllerForStatusBarStyle]; - if ([childScreen isKindOfClass:[RNSScreen class]]) { - return [(RNSScreen *)childScreen findChildVCForConfigAndTrait:trait includingModals:includingModals] - ?: selfOrNil; - } else { - return selfOrNil; - } - } else { - // child vc is not from this library, so we don't ask it - return selfOrNil; - } - } -} - -- (BOOL)hasTraitSet:(RNSWindowTrait)trait -{ - switch (trait) { - case RNSWindowTraitStyle: { - return ((RNSScreenView *)self.view).hasStatusBarStyleSet; - } - case RNSWindowTraitAnimation: { - return ((RNSScreenView *)self.view).hasStatusBarAnimationSet; - } - case RNSWindowTraitHidden: { - return ((RNSScreenView *)self.view).hasStatusBarHiddenSet; - } - case RNSWindowTraitOrientation: { - return ((RNSScreenView *)self.view).hasOrientationSet; - } - case RNSWindowTraitHomeIndicatorHidden: { - return ((RNSScreenView *)self.view).hasHomeIndicatorHiddenSet; - } - default: { - RCTLogError(@"Unknown trait passed: %d", (int)trait); - } - } - return NO; -} - -#endif - -- (void)viewDidLayoutSubviews -{ - [super viewDidLayoutSubviews]; - - // The below code makes the screen view adapt dimensions provided by the system. We take these - // into account only when the view is mounted under RNScreensNavigationController in which case system - // provides additional padding to account for possible header, and in the case when screen is - // shown as a native modal, as the final dimensions of the modal on iOS 12+ are shorter than the - // screen size - BOOL isDisplayedWithinUINavController = - [self.parentViewController isKindOfClass:[RNScreensNavigationController class]]; - BOOL isPresentedAsNativeModal = self.parentViewController == nil && self.presentingViewController != nil; - if ((isDisplayedWithinUINavController || isPresentedAsNativeModal) && - !CGRectEqualToRect(_lastViewFrame, self.view.frame)) { - _lastViewFrame = self.view.frame; - [((RNSScreenView *)self.viewIfLoaded) updateBounds]; - } -} - (id)findFirstResponder:(UIView *)parent { @@ -1108,225 +937,7 @@ - (id)findFirstResponder:(UIView *)parent } return nil; } - -- (void)willMoveToParentViewController:(UIViewController *)parent -{ - [super willMoveToParentViewController:parent]; - if (parent == nil) { - id responder = [self findFirstResponder:self.view]; - if (responder != nil) { - _previousFirstResponder = responder; - } - } -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - if (!_isSwiping) { - [((RNSScreenView *)self.view) notifyWillAppear]; - if (self.transitionCoordinator.isInteractive) { - // we started dismissing with swipe gesture - _isSwiping = YES; - } - } else { - // this event is also triggered if we cancelled the swipe. - // The _isSwiping is still true, but we don't want to notify then - _shouldNotify = NO; - } - - [self hideHeaderIfNecessary]; - - // as per documentation of these methods - _goingForward = [self isBeingPresented] || [self isMovingToParentViewController]; - - [RNSScreenWindowTraits updateWindowTraits]; - if (_shouldNotify) { - _closing = NO; - [self notifyTransitionProgress:0.0 closing:_closing goingForward:_goingForward]; - [self setupProgressNotification]; - } -} - -- (void)hideHeaderIfNecessary -{ -#if !TARGET_OS_TV - // On iOS >=13, there is a bug when user transitions from screen with active search bar to screen without header - // In that case default iOS header will be shown. To fix this we hide header when the screens that appears has header - // hidden and search bar was active on previous screen. We need to do it asynchronously, because default header is - // added after viewWillAppear. - if (@available(iOS 13.0, *)) { - NSUInteger currentIndex = [self.navigationController.viewControllers indexOfObject:self]; - - if (currentIndex > 0 && [self.view.reactSubviews[0] isKindOfClass:[RNSScreenStackHeaderConfig class]]) { - UINavigationItem *prevNavigationItem = - [self.navigationController.viewControllers objectAtIndex:currentIndex - 1].navigationItem; - RNSScreenStackHeaderConfig *config = ((RNSScreenStackHeaderConfig *)self.view.reactSubviews[0]); - - BOOL wasSearchBarActive = prevNavigationItem.searchController.active; - BOOL shouldHideHeader = config.hide; - - if (wasSearchBarActive && shouldHideHeader) { - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { - [self.navigationController setNavigationBarHidden:YES animated:NO]; - }); - } - } - } -#endif -} - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - if (!self.transitionCoordinator.isInteractive) { - // user might have long pressed ios 14 back button item, - // so he can go back more than one screen and we need to dismiss more screens in JS stack then. - // We check it by calculating the difference between the index of currently displayed screen - // and the index of the target screen, which is the view of topViewController at this point. - // If the value is lower than 1, it means we are dismissing a modal, or navigating forward, or going back with JS. - int selfIndex = [self getIndexOfView:self.view]; - int targetIndex = [self getIndexOfView:self.navigationController.topViewController.view]; - _dismissCount = selfIndex - targetIndex > 0 ? selfIndex - targetIndex : 1; - } else { - _dismissCount = 1; - } - - // same flow as in viewWillAppear - if (!_isSwiping) { - [((RNSScreenView *)self.view) notifyWillDisappear]; - if (self.transitionCoordinator.isInteractive) { - _isSwiping = YES; - } - } else { - _shouldNotify = NO; - } - - // as per documentation of these methods - _goingForward = !([self isBeingDismissed] || [self isMovingFromParentViewController]); - - if (_shouldNotify) { - _closing = YES; - [self notifyTransitionProgress:0.0 closing:_closing goingForward:_goingForward]; - [self setupProgressNotification]; - } -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - if (!_isSwiping || _shouldNotify) { - // we are going forward or dismissing without swipe - // or successfully swiped back - [((RNSScreenView *)self.view) notifyAppear]; - [self notifyTransitionProgress:1.0 closing:NO goingForward:_goingForward]; - } - - _isSwiping = NO; - _shouldNotify = YES; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - - if (self.parentViewController == nil && self.presentingViewController == nil) { - if (((RNSScreenView *)self.view).preventNativeDismiss) { - // if we want to prevent the native dismiss, we do not send dismissal event, - // but instead call `updateContainer`, which restores the JS navigation stack - [((RNSScreenView *)self.view).reactSuperview updateContainer]; - [((RNSScreenView *)self.view) notifyDismissCancelledWithDismissCount:_dismissCount]; - } else { - // screen dismissed, send event - [((RNSScreenView *)self.view) notifyDismissedWithCount:_dismissCount]; - } - } - - // same flow as in viewDidAppear - if (!_isSwiping || _shouldNotify) { - [((RNSScreenView *)self.view) notifyDisappear]; - [self notifyTransitionProgress:1.0 closing:YES goingForward:_goingForward]; - } - - _isSwiping = NO; - _shouldNotify = YES; - - [self traverseForScrollView:self.view]; -} - -- (void)traverseForScrollView:(UIView *)view -{ - if (![[self.view valueForKey:@"_bridge"] valueForKey:@"_jsThread"]) { - // we don't want to send `scrollViewDidEndDecelerating` event to JS before the JS thread is ready - return; - } - if ([view isKindOfClass:[UIScrollView class]] && - ([[(UIScrollView *)view delegate] respondsToSelector:@selector(scrollViewDidEndDecelerating:)])) { - [[(UIScrollView *)view delegate] scrollViewDidEndDecelerating:(id)view]; - } - [view.subviews enumerateObjectsUsingBlock:^(__kindof UIView *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) { - [self traverseForScrollView:obj]; - }]; -} - -- (int)getIndexOfView:(UIView *)view -{ - return (int)[[self.view.reactSuperview reactSubviews] indexOfObject:view]; -} - -- (int)getParentChildrenCount -{ - return (int)[[self.view.reactSuperview reactSubviews] count]; -} - -- (void)notifyFinishTransitioning -{ - [_previousFirstResponder becomeFirstResponder]; - _previousFirstResponder = nil; - // the correct Screen for appearance is set after the transition, same for orientation. - [RNSScreenWindowTraits updateWindowTraits]; -} - -#pragma mark - transition progress related methods - -- (void)setupProgressNotification -{ - if (self.transitionCoordinator != nil) { - _fakeView.alpha = 0.0; - [self.transitionCoordinator - animateAlongsideTransition:^(id _Nonnull context) { - [[context containerView] addSubview:self->_fakeView]; - self->_fakeView.alpha = 1.0; - self->_animationTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleAnimation)]; - [self->_animationTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - } - completion:^(id _Nonnull context) { - [self->_animationTimer setPaused:YES]; - [self->_animationTimer invalidate]; - [self->_fakeView removeFromSuperview]; - }]; - } -} - -- (void)handleAnimation -{ - if ([[_fakeView layer] presentationLayer] != nil) { - CGFloat fakeViewAlpha = _fakeView.layer.presentationLayer.opacity; - if (_currentAlpha != fakeViewAlpha) { - _currentAlpha = fmax(0.0, fmin(1.0, fakeViewAlpha)); - [self notifyTransitionProgress:_currentAlpha closing:_closing goingForward:_goingForward]; - } - } -} - -- (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward -{ - [((RNSScreenView *)self.view) notifyTransitionProgress:progress closing:closing goingForward:goingForward]; -} +#endif // RN_FABRIC_ENABLED @end From 51938213ced0af40fbae413fa8afccd340ac8a1f Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:31:38 +0200 Subject: [PATCH 071/105] chore: move willMoveToParentViewController method to paper specific section --- ios/RNSScreen.mm | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index e030db91e2..7498ff3d69 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -787,6 +787,7 @@ - (void)viewDidLayoutSubviews // so we return self which results in asking self for preferredStatusBarStyle/Animation etc.; // if the returned vc is nil, it means none of children could provide config and self does not have config either, // so if it was asked by parent, it will fallback to parent's option, or use default option if it is the top Screen +// done - (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals { UIViewController *lastViewController = [[self childViewControllers] lastObject]; @@ -826,6 +827,7 @@ - (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includi } } +// done - (BOOL)hasTraitSet:(RNSWindowTrait)trait { switch (trait) { @@ -906,7 +908,7 @@ - (BOOL)prefersHomeIndicatorAutoHidden #endif #ifdef RN_FABRIC_ENABLED -#pragma mark - Fabric +#pragma mark - Fabric specific - (void)setViewToSnapshot:(UIView *)snapshot { @@ -937,6 +939,17 @@ - (id)findFirstResponder:(UIView *)parent } return nil; } + +- (void)willMoveToParentViewController:(UIViewController *)parent +{ + [super willMoveToParentViewController:parent]; + if (parent == nil) { + id responder = [self findFirstResponder:self.view]; + if (responder != nil) { + _previousFirstResponder = responder; + } + } +} #endif // RN_FABRIC_ENABLED @end From 834ade9687e7e74c8cc4d4a459b792932e2c89d4 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:33:46 +0200 Subject: [PATCH 072/105] chore: move hideHeaderIfNecessary method to paper specific section --- ios/RNSScreen.mm | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 7498ff3d69..f2eb220205 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -950,6 +950,35 @@ - (void)willMoveToParentViewController:(UIViewController *)parent } } } + +- (void)hideHeaderIfNecessary +{ +#if !TARGET_OS_TV + // On iOS >=13, there is a bug when user transitions from screen with active search bar to screen without header + // In that case default iOS header will be shown. To fix this we hide header when the screens that appears has header + // hidden and search bar was active on previous screen. We need to do it asynchronously, because default header is + // added after viewWillAppear. + if (@available(iOS 13.0, *)) { + NSUInteger currentIndex = [self.navigationController.viewControllers indexOfObject:self]; + + if (currentIndex > 0 && [self.view.reactSubviews[0] isKindOfClass:[RNSScreenStackHeaderConfig class]]) { + UINavigationItem *prevNavigationItem = + [self.navigationController.viewControllers objectAtIndex:currentIndex - 1].navigationItem; + RNSScreenStackHeaderConfig *config = ((RNSScreenStackHeaderConfig *)self.view.reactSubviews[0]); + + BOOL wasSearchBarActive = prevNavigationItem.searchController.active; + BOOL shouldHideHeader = config.hide; + + if (wasSearchBarActive && shouldHideHeader) { + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { + [self.navigationController setNavigationBarHidden:YES animated:NO]; + }); + } + } + } +#endif +} #endif // RN_FABRIC_ENABLED @end From 53fd0099516c4566a2bbde27001733718ca55d73 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:43:47 +0200 Subject: [PATCH 073/105] chore: move traverseForScrollView: method to paper specific section --- ios/RNSScreen.mm | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index f2eb220205..50e0036e16 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -979,6 +979,22 @@ - (void)hideHeaderIfNecessary } #endif } + +- (void)traverseForScrollView:(UIView *)view +{ + if (![[self.view valueForKey:@"_bridge"] valueForKey:@"_jsThread"]) { + // we don't want to send `scrollViewDidEndDecelerating` event to JS before the JS thread is ready + return; + } + if ([view isKindOfClass:[UIScrollView class]] && + ([[(UIScrollView *)view delegate] respondsToSelector:@selector(scrollViewDidEndDecelerating:)])) { + [[(UIScrollView *)view delegate] scrollViewDidEndDecelerating:(id)view]; + } + [view.subviews enumerateObjectsUsingBlock:^(__kindof UIView *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) { + [self traverseForScrollView:obj]; + }]; +} + #endif // RN_FABRIC_ENABLED @end From b946e61078a0e27b1b0dbd1a2c011f80a23c66be Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:46:48 +0200 Subject: [PATCH 074/105] chore: move methods connected to transitioning to paper specific section temporary solution until it is not migrated --- ios/RNSScreen.mm | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 50e0036e16..65926cff7c 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -995,6 +995,52 @@ - (void)traverseForScrollView:(UIView *)view }]; } +- (int)getIndexOfView:(UIView *)view +{ + return (int)[[self.view.reactSuperview reactSubviews] indexOfObject:view]; +} + +- (int)getParentChildrenCount +{ + return (int)[[self.view.reactSuperview reactSubviews] count]; +} + +#pragma mark - transition progress related methods + +- (void)setupProgressNotification +{ + if (self.transitionCoordinator != nil) { + _fakeView.alpha = 0.0; + [self.transitionCoordinator + animateAlongsideTransition:^(id _Nonnull context) { + [[context containerView] addSubview:self->_fakeView]; + self->_fakeView.alpha = 1.0; + self->_animationTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleAnimation)]; + [self->_animationTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + } + completion:^(id _Nonnull context) { + [self->_animationTimer setPaused:YES]; + [self->_animationTimer invalidate]; + [self->_fakeView removeFromSuperview]; + }]; + } +} + +- (void)handleAnimation +{ + if ([[_fakeView layer] presentationLayer] != nil) { + CGFloat fakeViewAlpha = _fakeView.layer.presentationLayer.opacity; + if (_currentAlpha != fakeViewAlpha) { + _currentAlpha = fmax(0.0, fmin(1.0, fakeViewAlpha)); + [self notifyTransitionProgress:_currentAlpha closing:_closing goingForward:_goingForward]; + } + } +} + +- (void)notifyTransitionProgress:(double)progress closing:(BOOL)closing goingForward:(BOOL)goingForward +{ + [((RNSScreenView *)self.view) notifyTransitionProgress:progress closing:closing goingForward:goingForward]; +} #endif // RN_FABRIC_ENABLED @end From c2925e3ce099d1e1e2aabd7e1ffa8d4cbe9fae33 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 12:57:41 +0200 Subject: [PATCH 075/105] refact: apply linter suggestions --- ios/RNSScreen.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 65926cff7c..a5e926e6fd 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -20,9 +20,9 @@ #import "RNSScreenStack.h" #endif -#import "RNSScreenStackHeaderConfig.h" #import #import +#import "RNSScreenStackHeaderConfig.h" @interface RNSScreenView () #ifdef RN_FABRIC_ENABLED @@ -922,7 +922,6 @@ - (void)resetViewToScreen self.view = _initialView; } - #else #pragma mark - Paper specific From 44368ed4f7431834a24f6ba8766b56fdace62c64 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 13:05:57 +0200 Subject: [PATCH 076/105] chore: remove leftover comments --- ios/RNSScreen.mm | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 65926cff7c..8408ebf2cb 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -604,7 +604,6 @@ @implementation RNSScreen { #pragma mark - Common -// done - (instancetype)initWithView:(UIView *)view { if (self = [super init]) { @@ -624,7 +623,6 @@ - (instancetype)initWithView:(UIView *)view return self; } -// done // TODO: Find out why this is executed when screen is going out - (void)viewWillAppear:(BOOL)animated { @@ -659,7 +657,6 @@ - (void)viewWillAppear:(BOOL)animated #endif } -// done - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; @@ -700,7 +697,6 @@ - (void)viewWillDisappear:(BOOL)animated #endif } -// done - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; @@ -719,7 +715,6 @@ - (void)viewDidAppear:(BOOL)animated #endif } -// done - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; @@ -755,7 +750,6 @@ - (void)viewDidDisappear:(BOOL)animated #endif } -// done - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; @@ -787,7 +781,6 @@ - (void)viewDidLayoutSubviews // so we return self which results in asking self for preferredStatusBarStyle/Animation etc.; // if the returned vc is nil, it means none of children could provide config and self does not have config either, // so if it was asked by parent, it will fallback to parent's option, or use default option if it is the top Screen -// done - (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includingModals:(BOOL)includingModals { UIViewController *lastViewController = [[self childViewControllers] lastObject]; @@ -827,7 +820,6 @@ - (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includi } } -// done - (BOOL)hasTraitSet:(RNSWindowTrait)trait { switch (trait) { From 0ab05f33de5be9870e937244bbe48d06015eb672 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 13:22:04 +0200 Subject: [PATCH 077/105] refact: rename BASE_VIEW -> RNS_BASE_VIEW --- ios/RNSScreen.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/RNSScreen.h b/ios/RNSScreen.h index 7d48f5e5ce..f04b1393b4 100644 --- a/ios/RNSScreen.h +++ b/ios/RNSScreen.h @@ -39,12 +39,12 @@ NS_ASSUME_NONNULL_BEGIN @end #ifdef RN_FABRIC_ENABLED -#define BASE_VIEW RCTViewComponentView +#define RNS_BASE_VIEW RCTViewComponentView #else -#define BASE_VIEW RCTView +#define RNS_BASE_VIEW RCTView #endif -@interface RNSScreenView : BASE_VIEW +@interface RNSScreenView : RNS_BASE_VIEW @property (nonatomic) BOOL fullScreenSwipeEnabled; @property (nonatomic) BOOL gestureEnabled; From 15a30cfca7b234b88f60b61d312457acae190249 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 13:23:16 +0200 Subject: [PATCH 078/105] refact: apply linter suggestions --- ios/RNSScreen.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 8408ebf2cb..4a9e24c529 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -20,9 +20,9 @@ #import "RNSScreenStack.h" #endif -#import "RNSScreenStackHeaderConfig.h" #import #import +#import "RNSScreenStackHeaderConfig.h" @interface RNSScreenView () #ifdef RN_FABRIC_ENABLED @@ -914,7 +914,6 @@ - (void)resetViewToScreen self.view = _initialView; } - #else #pragma mark - Paper specific From 0afaafd97f87793d6b84b5ed280250d047b99eec Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 21 Apr 2022 13:24:11 +0200 Subject: [PATCH 079/105] =?UTF-8?q?refact:=20rename=20EXPECTED=5FVIEW=20->?= =?UTF-8?q?=20RNS=5FEXPECTED=5FVIEW=C2=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/RNSScreen.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index 4a9e24c529..b7d4f2d85e 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -342,17 +342,17 @@ - (void)notifyDisappear - (BOOL)isMountedUnderScreenOrReactRoot { #ifdef RN_FABRIC_ENABLED -#define EXPECTED_VIEW RCTRootComponentView +#define RNS_EXPECTED_VIEW RCTRootComponentView #else -#define EXPECTED_VIEW RCTRootView +#define RNS_EXPECTED_VIEW RCTRootView #endif for (UIView *parent = self.superview; parent != nil; parent = parent.superview) { - if ([parent isKindOfClass:[EXPECTED_VIEW class]] || [parent isKindOfClass:[RNSScreenView class]]) { + if ([parent isKindOfClass:[RNS_EXPECTED_VIEW class]] || [parent isKindOfClass:[RNSScreenView class]]) { return YES; } } return NO; -#undef EXPECTED_VIEW +#undef RNS_EXPECTED_VIEW } - (void)didMoveToWindow From d0f128d3e782421e8151630580dadb873cda2c8a Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 09:22:21 +0200 Subject: [PATCH 080/105] chore: restore back initWithBridge method for Fabric Fabric implementation does not need it, but RNSScreenManager is required --- ios/RNSScreen.mm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index b7d4f2d85e..f2868d39e7 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -54,7 +54,8 @@ - (instancetype)initWithFrame:(CGRect)frame return self; } -#else +#endif + - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super init]) { @@ -64,7 +65,6 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge return self; } -#endif // RN_FABRIC_ENABLED - (void)initCommonProps { @@ -1069,12 +1069,10 @@ @implementation RNSScreenManager RCT_EXPORT_VIEW_PROPERTY(homeIndicatorHidden, BOOL) #endif -#ifndef RN_FABRIC_ENABLED - (UIView *)view { return [[RNSScreenView alloc] initWithBridge:self.bridge]; } -#endif @end From d6ccca123c56d7ddca2ab2709bdce70469da990c Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 09:23:16 +0200 Subject: [PATCH 081/105] fix: restore back notifyFinishTransitioning method for paper --- ios/RNSScreen.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index f2868d39e7..7c68a459eb 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -998,6 +998,14 @@ - (int)getParentChildrenCount #pragma mark - transition progress related methods +- (void)notifyFinishTransitioning +{ + [_previousFirstResponder becomeFirstResponder]; + _previousFirstResponder = nil; + // the correct Screen for appearance is set after the transition, same for orientation. + [RNSScreenWindowTraits updateWindowTraits]; +} + - (void)setupProgressNotification { if (self.transitionCoordinator != nil) { From d465135a5ddce2d65f8c89c0cfbb0a7778723efe Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 11:00:06 +0200 Subject: [PATCH 082/105] fix: tvOS: exclude props not existion on tv platform --- ios/RNSScreen.mm | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index dfa9b410c1..b2e5783057 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -441,6 +441,7 @@ - (void)updateProps:(facebook::react::Props::Shared const &)props [self setTransitionDuration:[NSNumber numberWithInt:newScreenProps.transitionDuration]]; +#if !TARGET_OS_TV if (newScreenProps.statusBarHidden != oldScreenProps.statusBarHidden) { [self setStatusBarHidden:newScreenProps.statusBarHidden]; } @@ -459,6 +460,7 @@ - (void)updateProps:(facebook::react::Props::Shared const &)props [self setScreenOrientation:[RCTConvert UIInterfaceOrientationMask:RCTNSStringFromStringNilIfEmpty( newScreenProps.screenOrientation)]]; } +#endif if (newScreenProps.stackPresentation != oldScreenProps.stackPresentation) { [self @@ -1089,16 +1091,6 @@ - (UIView *)view @implementation RCTConvert (RNSScreen) -RCT_ENUM_CONVERTER( - UIStatusBarAnimation, - (@{ - @"none" : @(UIStatusBarAnimationNone), - @"fade" : @(UIStatusBarAnimationFade), - @"slide" : @(UIStatusBarAnimationSlide) - }), - UIStatusBarAnimationNone, - integerValue) - RCT_ENUM_CONVERTER( RNSScreenStackPresentation, (@{ @@ -1148,6 +1140,16 @@ @implementation RCTConvert (RNSScreen) integerValue) #if !TARGET_OS_TV +RCT_ENUM_CONVERTER( + UIStatusBarAnimation, + (@{ + @"none" : @(UIStatusBarAnimationNone), + @"fade" : @(UIStatusBarAnimationFade), + @"slide" : @(UIStatusBarAnimationSlide) + }), + UIStatusBarAnimationNone, + integerValue) + RCT_ENUM_CONVERTER( RNSStatusBarStyle, (@{ From f0e42f0ca288005230153ed00f0b88ad536f2cb7 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 11:05:55 +0200 Subject: [PATCH 083/105] chore: remove unnecessary header guard directives from RNSConvert.h --- ios/RNSConvert.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ios/RNSConvert.h b/ios/RNSConvert.h index e6e8774e1f..1cf1bea0d0 100644 --- a/ios/RNSConvert.h +++ b/ios/RNSConvert.h @@ -1,6 +1,3 @@ -#ifndef RNSConvert_h -#define RNSConvert_h - #ifdef RN_FABRIC_ENABLED #import #import "RNSEnums.h" @@ -16,5 +13,3 @@ @end #endif // RN_FABRIC_ENABLED - -#endif /* RNSConvert_h */ From d9bb8a64e303c8ddfd468f1577d6c3bcbf025c71 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 11:52:44 +0200 Subject: [PATCH 084/105] chore: remove check if passed view is of class RNSScreenView see: https://github.com/software-mansion/react-native-screens/pull/1415#discussion_r855929914 --- ios/RNSScreen.mm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index b2e5783057..5157abaaf4 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -613,12 +613,7 @@ - (instancetype)initWithView:(UIView *)view if (self = [super init]) { self.view = view; #ifdef RN_FABRIC_ENABLED - if ([view isKindOfClass:[RNSScreenView class]]) { - _initialView = (RNSScreenView *)view; - } else { - // TODO: fix this message - RCTLogError(@"ScreenController can only be initialized with ScreenComponentView"); - } + _initialView = (RNSScreenView *)view; #else _shouldNotify = YES; _fakeView = [UIView new]; From 0c096572fb1731d6346dc0589d46bbbc54224e9b Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 12:04:33 +0200 Subject: [PATCH 085/105] chore: remove leftover comments --- ios/RNSScreenStack.mm | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index f82e11fe6d..63d15c9944 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -156,7 +156,6 @@ - (instancetype)initWithManager:(RNSScreenStackManager *)manager #pragma mark - Common -// done - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated @@ -181,7 +180,6 @@ - (void)navigationController:(UINavigationController *)navigationController #endif } -// done - (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController { // We don't directly set presentation delegate but instead rely on the ScreenView's delegate to @@ -212,13 +210,11 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio } } -// done - (NSArray *)reactSubviews { return _reactSubviews; } -// done - (void)didMoveToWindow { #ifdef RN_FABRIC_ENABLED @@ -236,7 +232,6 @@ - (void)didMoveToWindow #endif } -// done - (void)maybeAddToParentAndUpdateContainer { BOOL wasScreenMounted = _controller.parentViewController != nil; @@ -272,7 +267,6 @@ - (void)maybeAddToParentAndUpdateContainer } } -// done - (void)reactAddControllerToClosestParent:(UIViewController *)controller { if (!controller.parentViewController) { @@ -300,7 +294,6 @@ - (void)reactAddControllerToClosestParent:(UIViewController *)controller } } -// done - (void)setModalViewControllers:(NSArray *)controllers { // prevent re-entry @@ -435,7 +428,6 @@ - (void)setModalViewControllers:(NSArray *)controllers } } -// done - (void)setPushViewControllers:(NSArray *)controllers { // when there is no change we return immediately @@ -571,7 +563,6 @@ - (void)setPushViewControllers:(NSArray *)controllers #endif } -// done - (void)updateContainer { NSMutableArray *pushControllers = [NSMutableArray new]; @@ -600,14 +591,12 @@ - (void)updateContainer [self setModalViewControllers:modalControllers]; } -// done - (void)layoutSubviews { [super layoutSubviews]; _controller.view.frame = self.bounds; } -// done - (void)dismissOnReload { #ifdef RN_FABRIC_ENABLED @@ -622,7 +611,6 @@ - (void)dismissOnReload #pragma mark methods connected to transitioning -// done - (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC @@ -643,7 +631,6 @@ - (void)dismissOnReload return nil; } -// done - (void)cancelTouchesInParent { // cancel touches in parent, this is needed to cancel RN touch events. For example when Touchable @@ -667,7 +654,6 @@ - (void)cancelTouchesInParent } } -// done - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; @@ -740,7 +726,6 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer } #if !TARGET_OS_TV -// done - (void)setupGestureHandlers { // gesture recognizers for custom stack animations @@ -763,7 +748,6 @@ - (void)setupGestureHandlers [self addGestureRecognizer:panRecognizer]; } -// done - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer { RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; From 834482333cad4f524026f2200eb2598ab1173010 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 12:14:07 +0200 Subject: [PATCH 086/105] chore: enable RNSScreenStackView#initWithManager on Fabric This seems to be not required on new arch, however RNSScreenStackManager (with RCT_EXPORT_MODULE() macro call) is required --- ios/RNSScreenStack.mm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 63d15c9944..551793b0e1 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -102,11 +102,11 @@ @implementation RNSScreenStackView { BOOL _invalidated; BOOL _isFullWidthSwiping; UIPercentDrivenInteractiveTransition *_interactionController; + BOOL _hasLayout; + __weak RNSScreenStackManager *_manager; #ifdef RN_FABRIC_ENABLED UIView *_snapshot; #else - __weak RNSScreenStackManager *_manager; - BOOL _hasLayout; BOOL _updateScheduled; #endif } @@ -129,7 +129,8 @@ - (instancetype)initWithFrame:(CGRect)frame return self; } -#else +#endif // RN_FABRIC_ENABLED + - (instancetype)initWithManager:(RNSScreenStackManager *)manager { if (self = [super init]) { @@ -152,7 +153,6 @@ - (instancetype)initWithManager:(RNSScreenStackManager *)manager } return self; } -#endif // RN_FABRIC_ENABLED #pragma mark - Common @@ -1045,7 +1045,6 @@ @implementation RNSScreenStackManager { RCT_EXPORT_VIEW_PROPERTY(onFinishTransitioning, RCTDirectEventBlock); -#ifndef RN_FABRIC_ENABLED - (UIView *)view { RNSScreenStackView *view = [[RNSScreenStackView alloc] initWithManager:self]; @@ -1055,7 +1054,6 @@ - (UIView *)view [_stacks addPointer:(__bridge void *)view]; return view; } -#endif // RN_FABRIC_ENABLED - (void)invalidate { From b0d4b287b8c70d6272d00dc582266d552a598d51 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 12:18:43 +0200 Subject: [PATCH 087/105] refact: add descriptions for #endif --- ios/RNSScreenStack.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 551793b0e1..2d7cdcdf5f 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -720,9 +720,9 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer } [self cancelTouchesInParent]; return _controller.viewControllers.count >= 2; -#endif +#endif // !RN_FABRIC_ENABLED -#endif +#endif // TARGET_OS_TV } #if !TARGET_OS_TV From ddee964252a408fdc2a28432b644b16086023826 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 12:31:23 +0200 Subject: [PATCH 088/105] fix: surround RNSScreenStackCls with RN_FABRIC_ENABLED directive It does not build on paper otherwise, because RCTComponentViewProtocol is not seen --- ios/RNSScreenStack.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 2d7cdcdf5f..1fa5d48b5b 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -1032,10 +1032,12 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer @end +#ifdef RN_FABRIC_ENABLED Class RNSScreenStackCls(void) { return RNSScreenStackView.class; } +#endif @implementation RNSScreenStackManager { NSPointerArray *_stacks; From 141164ede8d9de56549cf47fab7f7e220af7065c Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 14:59:20 +0200 Subject: [PATCH 089/105] refact: change #ifndef directives to #ifdef #else ... --- ios/RNSScreenStack.h | 5 +++-- ios/RNSScreenStack.mm | 38 +++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/ios/RNSScreenStack.h b/ios/RNSScreenStack.h index 225d02a82e..976133e40f 100644 --- a/ios/RNSScreenStack.h +++ b/ios/RNSScreenStack.h @@ -21,12 +21,13 @@ NS_ASSUME_NONNULL_BEGIN UIView #endif -#ifndef RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED +#else @property (nonatomic, copy) RCTDirectEventBlock onFinishTransitioning; - (void)markChildUpdated; - (void)didUpdateChildren; -#endif +#endif // RN_FABRIC_ENABLED @end diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index ef3097c441..c77d38b61f 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -195,7 +195,8 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio _updatingModals = NO; [self updateContainer]; // TODO: implement onFinishTransitioning on Fabric -#ifndef RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED +#else if (self.onFinishTransitioning) { // instead of directly triggering onFinishTransitioning this time we enqueue the event on the // main queue. We do that because onDismiss event is also enqueued and we want for the transition @@ -278,7 +279,8 @@ - (void)reactAddControllerToClosestParent:(UIViewController *)controller #if !TARGET_OS_TV _controller.interactivePopGestureRecognizer.delegate = self; #endif -#ifndef RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED +#else [controller didMoveToParentViewController:parentView.reactViewController]; #endif // On iOS pre 12 we observed that `willShowViewController` delegate method does not always @@ -345,7 +347,8 @@ - (void)setModalViewControllers:(NSArray *)controllers void (^afterTransitions)(void) = ^{ // TODO: Implement onFinishTransitioning on Fabric -#ifndef RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED +#else if (weakSelf.onFinishTransitioning) { weakSelf.onFinishTransitioning(nil); } @@ -565,7 +568,8 @@ - (void)setPushViewControllers:(NSArray *)controllers - (void)updateContainer { -#ifndef RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED +#else NSMutableArray *pushControllers = [NSMutableArray new]; NSMutableArray *modalControllers = [NSMutableArray new]; for (RNSScreenView *screen in _reactSubviews) { @@ -590,7 +594,7 @@ - (void)updateContainer [self setPushViewControllers:pushControllers]; [self setModalViewControllers:modalControllers]; -#endif +#endif // RN_FABRIC_ENABLED } - (void)layoutSubviews @@ -686,7 +690,17 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer return NO; } -#ifndef RN_FABRIC_ENABLED +#ifdef RN_FABRIC_ENABLED + if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { + // it should only recognize with `customAnimationOnSwipe` set + return NO; + } else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { + // it should only recognize with `fullScreenSwipeEnabled` set + return NO; + } + [self cancelTouchesInParent]; + return _controller.viewControllers.count >= 2; +#else if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) { if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { // if we do not set any explicit `semanticContentAttribute`, it is `UISemanticContentAttributeUnspecified` instead @@ -712,17 +726,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer [self cancelTouchesInParent]; return YES; } -#else - if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { - // it should only recognize with `customAnimationOnSwipe` set - return NO; - } else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { - // it should only recognize with `fullScreenSwipeEnabled` set - return NO; - } - [self cancelTouchesInParent]; - return _controller.viewControllers.count >= 2; -#endif // !RN_FABRIC_ENABLED +#endif // RN_FABRIC_ENABLED #endif // TARGET_OS_TV } From d8fec0570f158c53e125ec61d45fc941c43338d1 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:11:36 +0200 Subject: [PATCH 090/105] chore: unify implementation of updateContainer --- ios/RNSScreenStack.mm | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index c77d38b61f..67696222ae 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -568,16 +568,10 @@ - (void)setPushViewControllers:(NSArray *)controllers - (void)updateContainer { -#ifdef RN_FABRIC_ENABLED -#else NSMutableArray *pushControllers = [NSMutableArray new]; NSMutableArray *modalControllers = [NSMutableArray new]; for (RNSScreenView *screen in _reactSubviews) { -#ifdef RN_FABRIC_ENABLED - if (screen.controller != nil) -#else if (!screen.dismissed && screen.controller != nil) -#endif { if (pushControllers.count == 0) { // first screen on the list needs to be places as "push controller" @@ -594,7 +588,6 @@ - (void)updateContainer [self setPushViewControllers:pushControllers]; [self setModalViewControllers:modalControllers]; -#endif // RN_FABRIC_ENABLED } - (void)layoutSubviews From e1eea0e0f41ccf21adb8d0de381b3b134b2cd1c7 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:15:45 +0200 Subject: [PATCH 091/105] chore: move markChildUpdated & didUpdateChildren methods to common section --- ios/RNSScreenStack.h | 6 +++--- ios/RNSScreenStack.mm | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ios/RNSScreenStack.h b/ios/RNSScreenStack.h index 976133e40f..018ed294ef 100644 --- a/ios/RNSScreenStack.h +++ b/ios/RNSScreenStack.h @@ -21,12 +21,12 @@ NS_ASSUME_NONNULL_BEGIN UIView #endif +- (void)markChildUpdated; +- (void)didUpdateChildren; + #ifdef RN_FABRIC_ENABLED #else @property (nonatomic, copy) RCTDirectEventBlock onFinishTransitioning; - -- (void)markChildUpdated; -- (void)didUpdateChildren; #endif // RN_FABRIC_ENABLED @end diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 67696222ae..7c2bc74cb0 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -805,6 +805,16 @@ - (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer } #endif +- (void)markChildUpdated +{ + // do nothing +} + +- (void)didUpdateChildren +{ + // do nothing +} + #ifdef RN_FABRIC_ENABLED #pragma mark - Fabric specific @@ -893,16 +903,6 @@ - (void)prepareForRecycle #else #pragma mark - Paper specific -- (void)markChildUpdated -{ - // do nothing -} - -- (void)didUpdateChildren -{ - // do nothing -} - - (UIViewController *)reactViewController { return _controller; From 72605aa55b518d97955882a30946e7759d023450 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:16:18 +0200 Subject: [PATCH 092/105] refact: apply linter suggestion --- ios/RNSScreenStack.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 7c2bc74cb0..316c6b4ce1 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -571,8 +571,7 @@ - (void)updateContainer NSMutableArray *pushControllers = [NSMutableArray new]; NSMutableArray *modalControllers = [NSMutableArray new]; for (RNSScreenView *screen in _reactSubviews) { - if (!screen.dismissed && screen.controller != nil) - { + if (!screen.dismissed && screen.controller != nil) { if (pushControllers.count == 0) { // first screen on the list needs to be places as "push controller" [pushControllers addObject:screen.controller]; From 0f1def49e2d0aed80e91d5ef10e66bddb27e2710 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:20:50 +0200 Subject: [PATCH 093/105] refact: move updateScheduled prop decl. to implementation & make implemented protocols declaration more compact Although this comma looks terrible! --- ios/RNSScreenStack.mm | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 316c6b4ce1..1ea7838f48 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -30,19 +30,14 @@ #import "RNSScreenWindowTraits.h" @interface RNSScreenStackView () -#ifdef RN_FABRIC_ENABLED { - BOOL _updateScheduled; -} + UIViewControllerTransitioningDelegate +#ifdef RN_FABRIC_ENABLED + , RCTMountingTransactionObserving> #else - + > #endif @property (nonatomic) NSMutableArray *presentedModals; @@ -105,6 +100,7 @@ @implementation RNSScreenStackView { BOOL _hasLayout; __weak RNSScreenStackManager *_manager; #ifdef RN_FABRIC_ENABLED + BOOL _updateScheduled; UIView *_snapshot; #else BOOL _updateScheduled; From be25966482107c0dc94f2debcea20f8bebe970cb Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:26:45 +0200 Subject: [PATCH 094/105] refact: add method for common initialization --- ios/RNSScreenStack.mm | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 1ea7838f48..2cbf353ec6 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -113,14 +113,7 @@ - (instancetype)initWithFrame:(CGRect)frame if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; - _reactSubviews = [NSMutableArray new]; - _presentedModals = [NSMutableArray new]; - _controller = [RNScreensNavigationController new]; - _controller.delegate = self; - [_controller setViewControllers:@[ [UIViewController new] ]]; -#if !TARGET_OS_TV - [self setupGestureHandlers]; -#endif + [self initCommonProps]; } return self; @@ -133,21 +126,25 @@ - (instancetype)initWithManager:(RNSScreenStackManager *)manager _hasLayout = NO; _invalidated = NO; _manager = manager; - _reactSubviews = [NSMutableArray new]; - _presentedModals = [NSMutableArray new]; - _controller = [[RNScreensNavigationController alloc] init]; - _controller.delegate = self; + [self initCommonProps]; + } + return self; +} +- (void)initCommonProps +{ + _reactSubviews = [NSMutableArray new]; + _presentedModals = [NSMutableArray new]; + _controller = [RNScreensNavigationController new]; + _controller.delegate = self; #if !TARGET_OS_TV [self setupGestureHandlers]; #endif - // we have to initialize viewControllers with a non empty array for - // largeTitle header to render in the opened state. If it is empty - // the header will render in collapsed state which is perhaps a bug - // in UIKit but ¯\_(ツ)_/¯ - [_controller setViewControllers:@[ [UIViewController new] ]]; - } - return self; + // we have to initialize viewControllers with a non empty array for + // largeTitle header to render in the opened state. If it is empty + // the header will render in collapsed state which is perhaps a bug + // in UIKit but ¯\_(ツ)_/¯ + [_controller setViewControllers:@[ [UIViewController new] ]]; } #pragma mark - Common From 4ac0183857e18df5749a2110f601d11c71195427 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:29:19 +0200 Subject: [PATCH 095/105] chore: move reactViewController getter to common section --- ios/RNSScreenStack.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 2cbf353ec6..f23a4c73ba 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -807,6 +807,11 @@ - (void)didUpdateChildren // do nothing } +- (UIViewController *)reactViewController +{ + return _controller; +} + #ifdef RN_FABRIC_ENABLED #pragma mark - Fabric specific @@ -895,11 +900,6 @@ - (void)prepareForRecycle #else #pragma mark - Paper specific -- (UIViewController *)reactViewController -{ - return _controller; -} - - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated From 0384afe4e6983e313c25847fd71760e9f164f8ba Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:31:50 +0200 Subject: [PATCH 096/105] chore: extract call common to both impls in didMoveToWindow --- ios/RNSScreenStack.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index f23a4c73ba..2f5ef7e6da 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -211,12 +211,11 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio - (void)didMoveToWindow { -#ifdef RN_FABRIC_ENABLED [super didMoveToWindow]; +#ifdef RN_FABRIC_ENABLED // for handling nested stacks [self maybeAddToParentAndUpdateContainer]; #else - [super didMoveToWindow]; if (!_invalidated) { // We check whether the view has been invalidated before running side-effects in didMoveToWindow // This is needed because when LayoutAnimations are used it is possible for view to be re-attached From 8399772ff7eaccfdc4d5735e56f3b7d059499b3a Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:52:43 +0200 Subject: [PATCH 097/105] refact: improve merge of setPushViewControllers method --- ios/RNSScreenStack.mm | 63 +++++++++---------------------------------- 1 file changed, 13 insertions(+), 50 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 2f5ef7e6da..c8637723cc 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -460,6 +460,9 @@ - (void)setPushViewControllers:(NSArray *)controllers UIViewController *top = controllers.lastObject; #ifdef RN_FABRIC_ENABLED UIViewController *previousTop = _controller.topViewController; +#else + UIViewController *previousTop = _controller.viewControllers.lastObject; +#endif // At the start we set viewControllers to contain a single UIViewController // instance. This is a workaround for header height adjustment bug (see comment @@ -474,10 +477,17 @@ - (void)setPushViewControllers:(NSArray *)controllers if (![controllers containsObject:previousTop]) { // if the previous top screen does not exist anymore and the new top was not on the stack before, probably replace // was called, so we check the animation - if (![_controller.viewControllers containsObject:top]) { +#ifdef RN_FABRIC_ENABLED + if (![_controller.viewControllers containsObject:top]) +#else + if (![_controller.viewControllers containsObject:top] && ((RNSScreenView *)top.view).replaceAnimation == RNSScreenReplaceAnimationPush) +#endif // RN_FABRIC_ENABLED + { // setting new controllers with animation does `push` animation by default +#ifdef RN_FABRIC_ENABLED auto screenController = (RNSScreen *)top; [screenController resetViewToScreen]; +#endif [_controller setViewControllers:controllers animated:YES]; } else { // last top controller is no longer on stack @@ -495,8 +505,10 @@ - (void)setPushViewControllers:(NSArray *)controllers NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; [newControllers removeLastObject]; [_controller setViewControllers:newControllers animated:NO]; +#ifdef RN_FABRIC_ENABLED auto screenController = (RNSScreen *)top; [screenController resetViewToScreen]; +#endif [_controller pushViewController:top animated:YES]; } else { // don't really know what this case could be, but may need to handle it @@ -507,55 +519,6 @@ - (void)setPushViewControllers:(NSArray *)controllers // change wasn't on the top of the stack. We don't need animation. [_controller setViewControllers:controllers animated:NO]; } -#else - UIViewController *lastTop = _controller.viewControllers.lastObject; - - // at the start we set viewControllers to contain a single UIVIewController - // instance. This is a workaround for header height adjustment bug (see comment - // in the init function). Here, we need to detect if the initial empty - // controller is still there - BOOL firstTimePush = ![lastTop isKindOfClass:[RNSScreen class]]; - - if (firstTimePush) { - // nothing pushed yet - [_controller setViewControllers:controllers animated:NO]; - } else if (top != lastTop) { - // we always provide `animated:YES` since, if the user does not want the animation, he will provide - // `stackAnimation: 'none'`, which will resolve in no animation anyways. - if (![controllers containsObject:lastTop]) { - // if the previous top screen does not exist anymore and the new top was not on the stack before, probably replace - // was called, so we check the animation - if (![_controller.viewControllers containsObject:top] && - ((RNSScreenView *)top.view).replaceAnimation == RNSScreenReplaceAnimationPush) { - // setting new controllers with animation does `push` animation by default - [_controller setViewControllers:controllers animated:YES]; - } else { - // last top controller is no longer on stack - // in this case we set the controllers stack to the new list with - // added the last top element to it and perform (animated) pop - NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; - [newControllers addObject:lastTop]; - [_controller setViewControllers:newControllers animated:NO]; - [_controller popViewControllerAnimated:YES]; - } - } else if (![_controller.viewControllers containsObject:top]) { - // new top controller is not on the stack - // in such case we update the stack except from the last element with - // no animation and do animated push of the last item - NSMutableArray *newControllers = [NSMutableArray arrayWithArray:controllers]; - [newControllers removeLastObject]; - [_controller setViewControllers:newControllers animated:NO]; - [_controller pushViewController:top animated:YES]; - } else { - // don't really know what this case could be, but may need to handle it - // somehow - [_controller setViewControllers:controllers animated:NO]; - } - } else { - // change wasn't on the top of the stack. We don't need animation. - [_controller setViewControllers:controllers animated:NO]; - } -#endif } - (void)updateContainer From fbcdde26bf66d595aebb05dec92b3bc84f1badec Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 15:58:12 +0200 Subject: [PATCH 098/105] fix: introduce shouldAnimate variable --- ios/RNSScreenStack.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index c8637723cc..aa4fe30d6a 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -513,7 +513,12 @@ - (void)setPushViewControllers:(NSArray *)controllers } else { // don't really know what this case could be, but may need to handle it // somehow - [_controller setViewControllers:controllers animated:YES]; +#ifdef RN_FABRIC_ENABLED + BOOL shouldAnimate = YES; +#else + BOOL shouldAnimate = NO; +#endif + [_controller setViewControllers:controllers animated:shouldAnimate]; } } else { // change wasn't on the top of the stack. We don't need animation. From afe0cda0a11635d70bed55fc1825251b8f6ca7ec Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 16:25:25 +0200 Subject: [PATCH 099/105] chore: remove unused imports --- ios/RNSScreenStack.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/RNSScreenStack.h b/ios/RNSScreenStack.h index 018ed294ef..f3fa068ec1 100644 --- a/ios/RNSScreenStack.h +++ b/ios/RNSScreenStack.h @@ -1,6 +1,5 @@ #ifdef RN_FABRIC_ENABLED #import -#import #else #import #import From 4af10c5d0a48b758788f4949ea9c600104e39754 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 16:28:02 +0200 Subject: [PATCH 100/105] refact: apply linter suggestion --- ios/RNSScreenStack.mm | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index aa4fe30d6a..4b4e305645 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -29,15 +29,16 @@ #import "RNSScreenStackAnimator.h" #import "RNSScreenWindowTraits.h" -@interface RNSScreenStackView () - + , + RCTMountingTransactionObserving> #else - > + > #endif @property (nonatomic) NSMutableArray *presentedModals; @@ -138,7 +139,7 @@ - (void)initCommonProps _controller = [RNScreensNavigationController new]; _controller.delegate = self; #if !TARGET_OS_TV - [self setupGestureHandlers]; + [self setupGestureHandlers]; #endif // we have to initialize viewControllers with a non empty array for // largeTitle header to render in the opened state. If it is empty @@ -480,7 +481,8 @@ - (void)setPushViewControllers:(NSArray *)controllers #ifdef RN_FABRIC_ENABLED if (![_controller.viewControllers containsObject:top]) #else - if (![_controller.viewControllers containsObject:top] && ((RNSScreenView *)top.view).replaceAnimation == RNSScreenReplaceAnimationPush) + if (![_controller.viewControllers containsObject:top] && + ((RNSScreenView *)top.view).replaceAnimation == RNSScreenReplaceAnimationPush) #endif // RN_FABRIC_ENABLED { // setting new controllers with animation does `push` animation by default From ca9a6ec6998ee4e9477406e432ebc295bd00f031 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 16:28:46 +0200 Subject: [PATCH 101/105] chore: unify conditions in setPushViewControllers: --- ios/RNSScreenStack.mm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 4b4e305645..490f303183 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -478,12 +478,8 @@ - (void)setPushViewControllers:(NSArray *)controllers if (![controllers containsObject:previousTop]) { // if the previous top screen does not exist anymore and the new top was not on the stack before, probably replace // was called, so we check the animation -#ifdef RN_FABRIC_ENABLED - if (![_controller.viewControllers containsObject:top]) -#else if (![_controller.viewControllers containsObject:top] && ((RNSScreenView *)top.view).replaceAnimation == RNSScreenReplaceAnimationPush) -#endif // RN_FABRIC_ENABLED { // setting new controllers with animation does `push` animation by default #ifdef RN_FABRIC_ENABLED From aad05ee04facd453c70b19181e7c2b60dc0d4e68 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 16:30:53 +0200 Subject: [PATCH 102/105] chore: remove duplicated prop declaration --- ios/RNSScreenStack.mm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 490f303183..2a88372863 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -100,11 +100,9 @@ @implementation RNSScreenStackView { UIPercentDrivenInteractiveTransition *_interactionController; BOOL _hasLayout; __weak RNSScreenStackManager *_manager; -#ifdef RN_FABRIC_ENABLED BOOL _updateScheduled; +#ifdef RN_FABRIC_ENABLED UIView *_snapshot; -#else - BOOL _updateScheduled; #endif } From 25a200813342f7a873868792878e3b73f383ed59 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 16:32:09 +0200 Subject: [PATCH 103/105] refact: minor adjustment --- ios/RNSScreenStack.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 2a88372863..47700422d4 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -36,10 +36,9 @@ @interface RNSScreenStackView () < UIViewControllerTransitioningDelegate #ifdef RN_FABRIC_ENABLED , - RCTMountingTransactionObserving> -#else - > + RCTMountingTransactionObserving #endif + > @property (nonatomic) NSMutableArray *presentedModals; @property (nonatomic) BOOL updatingModals; From e739f8f9f9d1a2ccec4357b49b8d18f510cb3814 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 16:33:08 +0200 Subject: [PATCH 104/105] chore: unify value for shouldAnimate var --- ios/RNSScreenStack.mm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 47700422d4..c9187de036 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -508,12 +508,7 @@ - (void)setPushViewControllers:(NSArray *)controllers } else { // don't really know what this case could be, but may need to handle it // somehow -#ifdef RN_FABRIC_ENABLED - BOOL shouldAnimate = YES; -#else - BOOL shouldAnimate = NO; -#endif - [_controller setViewControllers:controllers animated:shouldAnimate]; + [_controller setViewControllers:controllers animated:NO]; } } else { // change wasn't on the top of the stack. We don't need animation. From e15e0713b75591a9608cb76c580ce467ade75267 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Fri, 22 Apr 2022 16:48:40 +0200 Subject: [PATCH 105/105] chore: add didMoveToParentViewController: call in maybeAddToParentAndUpdateContainer method in Fabric --- ios/RNSScreenStack.mm | 3 --- 1 file changed, 3 deletions(-) diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index c9187de036..a2102efc6f 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -269,10 +269,7 @@ - (void)reactAddControllerToClosestParent:(UIViewController *)controller #if !TARGET_OS_TV _controller.interactivePopGestureRecognizer.delegate = self; #endif -#ifdef RN_FABRIC_ENABLED -#else [controller didMoveToParentViewController:parentView.reactViewController]; -#endif // On iOS pre 12 we observed that `willShowViewController` delegate method does not always // get triggered when the navigation controller is instantiated. As the only thing we do in // that delegate method is ask nav header to update to the current state it does not hurt to