Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix(iOS): invalid initial orientation of screen underneath full screen modal #1848

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions FabricTestExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import Test1649 from './src/Test1649';
import Test1671 from './src/Test1671';
import Test1683 from './src/Test1683';
import Test1726 from './src/Test1726';
import Test1775 from './src/Test1775';
import Test1802 from './src/Test1802';
import Test1844 from './src/Test1844';
import Test1864 from './src/Test1864';
Expand Down
58 changes: 58 additions & 0 deletions FabricTestExample/src/Test1775.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';

import { View, Button } from 'react-native';

import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { NavigationContainer, ParamListBase } from '@react-navigation/native';
import { NativeStackNavigationProp } from 'react-native-screens/native-stack';

type NavProp = {
navigation: NativeStackNavigationProp<ParamListBase>;
};

const Stack = createNativeStackNavigator();

function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="HomeScreen"
component={HomeScreen}
options={{ orientation: 'portrait' }}
/>

<Stack.Screen
name="Landscape"
component={LandscapeScreen}
options={{
orientation: 'landscape_right',
animation: 'flip',
presentation: 'fullScreenModal',
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

function HomeScreen({ navigation }: NavProp) {
return (
<View style={{ flex: 1, backgroundColor: 'gold' }}>
<Button
title="Navigate to Landscape screen"
onPress={() => navigation.navigate('Landscape')}
/>
</View>
);
}

function LandscapeScreen({ navigation }: NavProp) {
return (
<View style={{ flex: 1, backgroundColor: 'purple' }}>
<Button title="Back" onPress={navigation.goBack} />
</View>
);
}

export default App;
1 change: 1 addition & 0 deletions TestsExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import Test1649 from './src/Test1649';
import Test1671 from './src/Test1671';
import Test1683 from './src/Test1683';
import Test1726 from './src/Test1726';
import Test1775 from './src/Test1775';
import Test1791 from './src/Test1791';
import Test1802 from './src/Test1802';
import Test1844 from './src/Test1844';
Expand Down
59 changes: 59 additions & 0 deletions TestsExample/src/Test1775.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as React from 'react';

import { View, Button } from 'react-native';

// import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createNativeStackNavigator } from 'react-native-screens/native-stack';
import { NavigationContainer, ParamListBase } from '@react-navigation/native';
import { NativeStackNavigationProp } from 'react-native-screens/native-stack';

type NavProp = {
navigation: NativeStackNavigationProp<ParamListBase>;
};

const Stack = createNativeStackNavigator();

function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="HomeScreen"
component={HomeScreen}
options={{ screenOrientation: 'portrait' }}
/>

<Stack.Screen
name="Landscape"
component={LandscapeScreen}
options={{
screenOrientation: 'landscape_right',
stackAnimation: 'slide_from_bottom',
stackPresentation: 'fullScreenModal',
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

function HomeScreen({ navigation }: NavProp) {
return (
<View style={{ flex: 1, backgroundColor: 'gold' }}>
<Button
title="Navigate to Landscape screen"
onPress={() => navigation.navigate('Landscape')}
/>
</View>
);
}

function LandscapeScreen({ navigation }: NavProp) {
return (
<View style={{ flex: 1, backgroundColor: 'purple' }}>
<Button title="Back" onPress={navigation.goBack} />
</View>
);
}

export default App;
32 changes: 32 additions & 0 deletions ios/RNSScreen.mm
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,9 @@ - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
- (void)didSetProps:(NSArray<NSString *> *)changedProps
{
[super didSetProps:changedProps];
if ([changedProps containsObject:@"stackPresentation"]) {
NSLog(@"RNSScreen %p has set stackPresentation to: %ld", self.controller, self.stackPresentation);
}
#if !TARGET_OS_TV
[self updatePresentationStyle];
#endif // !TARGET_OS_TV
Expand Down Expand Up @@ -894,6 +897,7 @@ - (instancetype)initWithView:(UIView *)view
#ifdef RCT_NEW_ARCH_ENABLED
_initialView = (RNSScreenView *)view;
#endif
NSLog(@"RNSScreen %p created with RNSScreenView %p", self, self.view);
}
return self;
}
Expand Down Expand Up @@ -1219,7 +1223,21 @@ - (UIViewController *)findChildVCForConfigAndTrait:(RNSWindowTrait)trait includi
{
UIViewController *lastViewController = [[self childViewControllers] lastObject];
if ([self.presentedViewController isKindOfClass:[RNSScreen class]]) {
NSLog(
@"RNSScreen %p found that presentedViewController is of class RNSScreen %p",
self,
self.presentedViewController);
lastViewController = self.presentedViewController;
RNSScreen *modalScreen = (RNSScreen *)lastViewController;
if (modalScreen.screenView.stackPresentation == RNSScreenStackPresentationFullScreenModal) {
NSLog(@"RNSScreen %p presented another screen with full screen stack presentation", self);
return self;
} else {
NSLog(
@"RNSScreen %p presented another screen with stack presentation OTHER than full screen: %ld",
self,
modalScreen.screenView.stackPresentation);
}
// 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
Expand Down Expand Up @@ -1313,11 +1331,25 @@ - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
NSLog(@"RNSScreen %p supportedInterfaceOrientations", self);
UIViewController *vc = [self findChildVCForConfigAndTrait:RNSWindowTraitOrientation includingModals:YES];

if ([vc isKindOfClass:[RNSScreen class]]) {
UIInterfaceOrientationMask mask = ((RNSScreen *)vc).screenView.screenOrientation;
NSLog(
@"RNSScreen %p supportedInterfaceOrientations found vc %p with orientation %ld; self?: %d",
self,
vc,
mask,
self == vc);
return ((RNSScreen *)vc).screenView.screenOrientation;
}
NSLog(
@"RNSScreen %p supportedInterfaceOrientations found vc %p with orientation %ld; self?: %d",
self,
vc,
UIInterfaceOrientationMaskAllButUpsideDown,
self == vc);
return UIInterfaceOrientationMaskAllButUpsideDown;
}

Expand Down
13 changes: 12 additions & 1 deletion ios/RNSScreenStack.mm
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,17 @@ - (void)viewDidLayoutSubviews

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return [self topViewController].supportedInterfaceOrientations;
NSLog(@"RNSScreenStack %p supportedInterfaceOrientations", self);
UIViewController *topViewController = [self topViewController];
UIInterfaceOrientationMask mask = topViewController.supportedInterfaceOrientations;
NSLog(
@"RNSScreenStack %p supportedInterfaceOrientations topVC: %@ with orientation mask: %ld",
self,
topViewController,
mask);
return mask;

// return [self topViewController].supportedInterfaceOrientations;
}

- (UIViewController *)childViewControllerForHomeIndicatorAutoHidden
Expand Down Expand Up @@ -801,6 +811,7 @@ - (void)navigationController:(UINavigationController *)navigationController
{
[self emitOnFinishTransitioningEvent];
[RNSScreenWindowTraits updateWindowTraits];
[self setNeedsLayout];
}
#endif

Expand Down
16 changes: 15 additions & 1 deletion ios/UIViewController+RNScreens.mm
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,22 @@ - (UIStatusBarAnimation)reactNativeScreensPreferredStatusBarUpdateAnimation

- (UIInterfaceOrientationMask)reactNativeScreensSupportedInterfaceOrientations
{
NSLog(@"UIVC + RNS: Looking for child RNSViewController");
UIViewController *childVC = [self findChildRNSScreensViewController];
return childVC ? childVC.supportedInterfaceOrientations : [self reactNativeScreensSupportedInterfaceOrientations];
if (childVC != nil) {
UIInterfaceOrientationMask mask = childVC.supportedInterfaceOrientations;
NSLog(
@"UIVC + RNS %p found child VC for supported interface orientations: %@, with orientation mask %ld",
self,
childVC,
mask);
return mask;
} else {
NSLog(@"UIVC + RNS %p did NOT found child VC for supported interface orientations", self);
return [self reactNativeScreensSupportedInterfaceOrientations];
}

// return childVC ? childVC.supportedInterfaceOrientations : [self reactNativeScreensSupportedInterfaceOrientations];
}

- (UIViewController *)reactNativeScreensChildViewControllerForHomeIndicatorAutoHidden
Expand Down