1 | #import "RNSScreenWindowTraits.h"
|
2 | #import "RNSScreenContainer.h"
|
3 | #import "RNSScreenStack.h"
|
4 |
|
5 | @implementation RNSScreenWindowTraits
|
6 |
|
7 | #if !TARGET_OS_TV && !TARGET_OS_VISION
|
8 | + (void)assertViewControllerBasedStatusBarAppearenceSet
|
9 | {
|
10 | static dispatch_once_t once;
|
11 | static bool viewControllerBasedAppearence;
|
12 | dispatch_once(&once, ^{
|
13 | viewControllerBasedAppearence =
|
14 | [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"] boolValue];
|
15 | });
|
16 | if (!viewControllerBasedAppearence) {
|
17 | RCTLogError(@"If you want to change the appearance of status bar, you have to change \
|
18 | UIViewControllerBasedStatusBarAppearance key in the Info.plist to YES");
|
19 | }
|
20 | }
|
21 | #endif
|
22 |
|
23 | + (void)updateStatusBarAppearance
|
24 | {
|
25 | #if !TARGET_OS_TV && !TARGET_OS_VISION
|
26 | [UIView animateWithDuration:0.4
|
27 | animations:^{
|
28 | [RCTKeyWindow().rootViewController setNeedsStatusBarAppearanceUpdate];
|
29 | }];
|
30 | #endif
|
31 | }
|
32 |
|
33 | + (void)updateHomeIndicatorAutoHidden
|
34 | {
|
35 | #if !TARGET_OS_TV
|
36 | [RCTKeyWindow().rootViewController setNeedsUpdateOfHomeIndicatorAutoHidden];
|
37 | #endif
|
38 | }
|
39 |
|
40 | #if !TARGET_OS_TV
|
41 | + (UIStatusBarStyle)statusBarStyleForRNSStatusBarStyle:(RNSStatusBarStyle)statusBarStyle
|
42 | {
|
43 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
|
44 | __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
45 | if (@available(iOS 13.0, *)) {
|
46 | switch (statusBarStyle) {
|
47 | case RNSStatusBarStyleAuto:
|
48 | return [UITraitCollection.currentTraitCollection userInterfaceStyle] == UIUserInterfaceStyleDark
|
49 | ? UIStatusBarStyleLightContent
|
50 | : UIStatusBarStyleDarkContent;
|
51 | case RNSStatusBarStyleInverted:
|
52 | return [UITraitCollection.currentTraitCollection userInterfaceStyle] == UIUserInterfaceStyleDark
|
53 | ? UIStatusBarStyleDarkContent
|
54 | : UIStatusBarStyleLightContent;
|
55 | case RNSStatusBarStyleLight:
|
56 | return UIStatusBarStyleLightContent;
|
57 | case RNSStatusBarStyleDark:
|
58 | return UIStatusBarStyleDarkContent;
|
59 | default:
|
60 | return UIStatusBarStyleLightContent;
|
61 | }
|
62 | }
|
63 | #endif
|
64 |
|
65 | if (statusBarStyle == RNSStatusBarStyleLight) {
|
66 | return UIStatusBarStyleLightContent;
|
67 | }
|
68 | return UIStatusBarStyleDefault;
|
69 | }
|
70 | #endif
|
71 |
|
72 | #if !TARGET_OS_TV
|
73 | + (UIInterfaceOrientation)defaultOrientationForOrientationMask:(UIInterfaceOrientationMask)orientationMask
|
74 | {
|
75 | if (UIInterfaceOrientationMaskPortrait & orientationMask) {
|
76 | return UIInterfaceOrientationPortrait;
|
77 | } else if (UIInterfaceOrientationMaskLandscapeLeft & orientationMask) {
|
78 | return UIInterfaceOrientationLandscapeLeft;
|
79 | } else if (UIInterfaceOrientationMaskLandscapeRight & orientationMask) {
|
80 | return UIInterfaceOrientationLandscapeRight;
|
81 | } else if (UIInterfaceOrientationMaskPortraitUpsideDown & orientationMask) {
|
82 | return UIInterfaceOrientationPortraitUpsideDown;
|
83 | }
|
84 | return UIInterfaceOrientationUnknown;
|
85 | }
|
86 |
|
87 | + (UIInterfaceOrientation)interfaceOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
|
88 | {
|
89 | switch (deviceOrientation) {
|
90 | case UIDeviceOrientationPortrait:
|
91 | return UIInterfaceOrientationPortrait;
|
92 | case UIDeviceOrientationPortraitUpsideDown:
|
93 | return UIInterfaceOrientationPortraitUpsideDown;
|
94 |
|
95 | case UIDeviceOrientationLandscapeLeft:
|
96 | return UIInterfaceOrientationLandscapeRight;
|
97 | case UIDeviceOrientationLandscapeRight:
|
98 | return UIInterfaceOrientationLandscapeLeft;
|
99 | default:
|
100 | return UIInterfaceOrientationUnknown;
|
101 | }
|
102 | }
|
103 |
|
104 | + (UIInterfaceOrientationMask)maskFromOrientation:(UIInterfaceOrientation)orientation
|
105 | {
|
106 | return 1 << orientation;
|
107 | }
|
108 | #endif
|
109 |
|
110 | + (void)enforceDesiredDeviceOrientation
|
111 | {
|
112 | #if !TARGET_OS_TV && !TARGET_OS_VISION
|
113 | dispatch_async(dispatch_get_main_queue(), ^{
|
114 | UIInterfaceOrientationMask orientationMask = [RCTKeyWindow().rootViewController supportedInterfaceOrientations];
|
115 |
|
116 | UIInterfaceOrientation currentDeviceOrientation =
|
117 | [RNSScreenWindowTraits interfaceOrientationFromDeviceOrientation:[[UIDevice currentDevice] orientation]];
|
118 | UIInterfaceOrientation currentInterfaceOrientation = [RNSScreenWindowTraits interfaceOrientation];
|
119 | UIInterfaceOrientation newOrientation = UIInterfaceOrientationUnknown;
|
120 | if ([RNSScreenWindowTraits maskFromOrientation:currentDeviceOrientation] & orientationMask) {
|
121 | if (!([RNSScreenWindowTraits maskFromOrientation:currentInterfaceOrientation] & orientationMask)) {
|
122 |
|
123 | newOrientation = currentDeviceOrientation;
|
124 | } else {
|
125 | if (currentDeviceOrientation != currentInterfaceOrientation) {
|
126 |
|
127 |
|
128 | newOrientation = currentDeviceOrientation;
|
129 | }
|
130 | }
|
131 | } else {
|
132 | if (!([RNSScreenWindowTraits maskFromOrientation:currentInterfaceOrientation] & orientationMask)) {
|
133 |
|
134 |
|
135 | newOrientation = [RNSScreenWindowTraits defaultOrientationForOrientationMask:orientationMask];
|
136 | } else {
|
137 |
|
138 | }
|
139 | }
|
140 | if (newOrientation != UIInterfaceOrientationUnknown) {
|
141 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_16_0) && \
|
142 | __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_0
|
143 | if (@available(iOS 16.0, *)) {
|
144 | NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
|
145 |
|
146 |
|
147 |
|
148 | UIWindowScene *scene = nil;
|
149 | for (id connectedScene in array) {
|
150 | if ([connectedScene isKindOfClass:[UIWindowScene class]]) {
|
151 | scene = connectedScene;
|
152 | break;
|
153 | }
|
154 | }
|
155 |
|
156 | if (scene == nil) {
|
157 | return;
|
158 | }
|
159 |
|
160 | UIWindowSceneGeometryPreferencesIOS *geometryPreferences =
|
161 | [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:orientationMask];
|
162 | [scene requestGeometryUpdateWithPreferences:geometryPreferences
|
163 | errorHandler:^(NSError *_Nonnull error){
|
164 | }];
|
165 |
|
166 |
|
167 |
|
168 | UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
|
169 | while (topController.presentedViewController) {
|
170 | topController = topController.presentedViewController;
|
171 | }
|
172 |
|
173 | [topController setNeedsUpdateOfSupportedInterfaceOrientations];
|
174 | } else
|
175 | #endif // Check for iOS 16
|
176 | {
|
177 | [[UIDevice currentDevice] setValue:@(newOrientation) forKey:@"orientation"];
|
178 | [UIViewController attemptRotationToDeviceOrientation];
|
179 | }
|
180 | }
|
181 | });
|
182 | #endif // !TARGET_TV_OS
|
183 | }
|
184 |
|
185 | + (void)updateWindowTraits
|
186 | {
|
187 | [RNSScreenWindowTraits updateStatusBarAppearance];
|
188 | [RNSScreenWindowTraits enforceDesiredDeviceOrientation];
|
189 | [RNSScreenWindowTraits updateHomeIndicatorAutoHidden];
|
190 | }
|
191 |
|
192 | #if !TARGET_OS_TV && !TARGET_OS_VISION
|
193 |
|
194 |
|
195 | + (UIInterfaceOrientation)interfaceOrientation
|
196 | {
|
197 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
|
198 | __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
199 | if (@available(iOS 13.0, *)) {
|
200 | UIWindowScene *windowScene = RCTKeyWindow().windowScene;
|
201 | if (windowScene == nil) {
|
202 | return UIInterfaceOrientationUnknown;
|
203 | }
|
204 | return windowScene.interfaceOrientation;
|
205 | } else
|
206 | #endif
|
207 | {
|
208 | return UIApplication.sharedApplication.statusBarOrientation;
|
209 | }
|
210 | }
|
211 | #endif
|
212 |
|
213 |
|
214 | + (BOOL)shouldAskScreensForTrait:(RNSWindowTrait)trait
|
215 | includingModals:(BOOL)includingModals
|
216 | inViewController:(UIViewController *)vc
|
217 | {
|
218 | UIViewController *lastViewController = [[vc childViewControllers] lastObject];
|
219 | if ([lastViewController conformsToProtocol:@protocol(RNSViewControllerDelegate)]) {
|
220 | UIViewController *vc = nil;
|
221 | if ([lastViewController isKindOfClass:[RNSViewController class]]) {
|
222 | vc = [(RNSViewController *)lastViewController findActiveChildVC];
|
223 | } else if ([lastViewController isKindOfClass:[RNSNavigationController class]]) {
|
224 | vc = [(RNSNavigationController *)lastViewController topViewController];
|
225 | }
|
226 | return [vc isKindOfClass:[RNSScreen class]] &&
|
227 | [(RNSScreen *)vc findChildVCForConfigAndTrait:trait includingModals:includingModals] != nil;
|
228 | }
|
229 | return NO;
|
230 | }
|
231 |
|
232 |
|
233 | + (BOOL)shouldAskScreensForScreenOrientationInViewController:(UIViewController *)vc
|
234 | {
|
235 | return [RNSScreenWindowTraits shouldAskScreensForTrait:RNSWindowTraitOrientation
|
236 | includingModals:YES
|
237 | inViewController:vc];
|
238 | }
|
239 |
|
240 | @end
|