GT2/Ejectable/node_modules/react-native-screens/ios/RNSScreenWindowTraits.m

184 lines
7.2 KiB
Objective-C

#import "RNSScreenWindowTraits.h"
#import "RNSScreen.h"
@implementation RNSScreenWindowTraits
#if !TARGET_OS_TV
+ (void)assertViewControllerBasedStatusBarAppearenceSet
{
static dispatch_once_t once;
static bool viewControllerBasedAppearence;
dispatch_once(&once, ^{
viewControllerBasedAppearence = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"] boolValue];
});
if (!viewControllerBasedAppearence) {
RCTLogError(@"If you want to change the appearance of status bar, you have to change \
UIViewControllerBasedStatusBarAppearance key in the Info.plist to YES");
}
}
#endif
+ (void)updateStatusBarAppearance
{
#if !TARGET_OS_TV
[UIView animateWithDuration:0.4 animations:^{ // duration based on "Programming iOS 13" p. 311 implementation
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13, *)) {
UIWindow *firstWindow = [[[UIApplication sharedApplication] windows] firstObject];
if (firstWindow != nil) {
[[firstWindow rootViewController] setNeedsStatusBarAppearanceUpdate];
}
} else
#endif
{
[UIApplication.sharedApplication.keyWindow.rootViewController setNeedsStatusBarAppearanceUpdate];
}
}];
#endif
}
#if !TARGET_OS_TV
+ (UIStatusBarStyle)statusBarStyleForRNSStatusBarStyle:(RNSStatusBarStyle)statusBarStyle
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13.0, *)) {
switch (statusBarStyle) {
case RNSStatusBarStyleAuto:
return [UITraitCollection.currentTraitCollection userInterfaceStyle] == UIUserInterfaceStyleDark ? UIStatusBarStyleLightContent : UIStatusBarStyleDarkContent;
case RNSStatusBarStyleInverted:
return [UITraitCollection.currentTraitCollection userInterfaceStyle] == UIUserInterfaceStyleDark ? UIStatusBarStyleDarkContent : UIStatusBarStyleLightContent;
case RNSStatusBarStyleLight:
return UIStatusBarStyleLightContent;
case RNSStatusBarStyleDark:
return UIStatusBarStyleDarkContent;
default:
return UIStatusBarStyleLightContent;
}
}
#endif
// it is the only non-default style available for iOS < 13
if (statusBarStyle == RNSStatusBarStyleLight) {
return UIStatusBarStyleLightContent;
}
return UIStatusBarStyleDefault;
}
#endif
#if !TARGET_OS_TV
+ (UIInterfaceOrientation)defaultOrientationForOrientationMask:(UIInterfaceOrientationMask)orientationMask
{
if (UIInterfaceOrientationMaskPortrait & orientationMask) {
return UIInterfaceOrientationPortrait;
} else if (UIInterfaceOrientationMaskLandscapeLeft & orientationMask) {
return UIInterfaceOrientationLandscapeLeft;
} else if (UIInterfaceOrientationMaskLandscapeRight & orientationMask) {
return UIInterfaceOrientationLandscapeRight;
} else if (UIInterfaceOrientationMaskPortraitUpsideDown & orientationMask) {
return UIInterfaceOrientationPortraitUpsideDown;
}
return UIInterfaceOrientationUnknown;
}
+ (UIInterfaceOrientation)interfaceOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
{
switch (deviceOrientation) {
case UIDeviceOrientationPortrait:
return UIInterfaceOrientationPortrait;
case UIDeviceOrientationPortraitUpsideDown:
return UIInterfaceOrientationPortraitUpsideDown;
// UIDevice and UIInterface landscape orientations are switched
case UIDeviceOrientationLandscapeLeft:
return UIInterfaceOrientationLandscapeRight;
case UIDeviceOrientationLandscapeRight:
return UIInterfaceOrientationLandscapeLeft;
default:
return UIInterfaceOrientationUnknown;
}
}
+ (UIInterfaceOrientationMask)maskFromOrientation:(UIInterfaceOrientation)orientation
{
return 1 << orientation;
}
#endif
+ (void)enforceDesiredDeviceOrientation
{
#if !TARGET_OS_TV
dispatch_async(dispatch_get_main_queue(), ^{
UIInterfaceOrientationMask orientationMask = UIInterfaceOrientationMaskAllButUpsideDown;
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13, *)) {
UIWindow *firstWindow = [[[UIApplication sharedApplication] windows] firstObject];
if (firstWindow != nil) {
orientationMask = [firstWindow rootViewController].supportedInterfaceOrientations;
}
} else
#endif
{
orientationMask = UIApplication.sharedApplication.keyWindow.rootViewController.supportedInterfaceOrientations;
}
UIInterfaceOrientation currentDeviceOrientation = [RNSScreenWindowTraits interfaceOrientationFromDeviceOrientation:[[UIDevice currentDevice] orientation]];
UIInterfaceOrientation currentInterfaceOrientation = [RNSScreenWindowTraits interfaceOrientation];
UIInterfaceOrientation newOrientation = UIInterfaceOrientationUnknown;
if ([RNSScreenWindowTraits maskFromOrientation:currentDeviceOrientation] & orientationMask) {
if (!([RNSScreenWindowTraits maskFromOrientation:currentInterfaceOrientation] & orientationMask)) {
// if the device orientation is in the mask, but interface orientation is not, we rotate to device's orientation
newOrientation = currentDeviceOrientation;
} else {
if (currentDeviceOrientation != currentInterfaceOrientation) {
// if both device orientation and interface orientation are in the mask, but in different orientations, we rotate to device's orientation
newOrientation = currentDeviceOrientation;
}
}
} else {
if (!([RNSScreenWindowTraits maskFromOrientation:currentInterfaceOrientation] & orientationMask)) {
// if both device orientation and interface orientation are not in the mask, we rotate to closest available rotation from mask
newOrientation = [RNSScreenWindowTraits defaultOrientationForOrientationMask:orientationMask];
} else {
// if the device orientation is not in the mask, but interface orientation is in the mask, do nothing
}
}
if (newOrientation != UIInterfaceOrientationUnknown) {
[[UIDevice currentDevice] setValue:@(newOrientation) forKey:@"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
}
});
#endif
}
+ (void)updateWindowTraits
{
[RNSScreenWindowTraits updateStatusBarAppearance];
[RNSScreenWindowTraits enforceDesiredDeviceOrientation];
}
#if !TARGET_OS_TV
// based on https://stackoverflow.com/questions/57965701/statusbarorientation-was-deprecated-in-ios-13-0-when-attempting-to-get-app-ori/61249908#61249908
+ (UIInterfaceOrientation)interfaceOrientation
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13.0, *)) {
UIWindow *firstWindow = [[[UIApplication sharedApplication] windows] firstObject];
if (firstWindow == nil) {
return UIInterfaceOrientationUnknown;
}
UIWindowScene *windowScene = firstWindow.windowScene;
if (windowScene == nil) {
return UIInterfaceOrientationUnknown;
}
return windowScene.interfaceOrientation;
} else
#endif
{
return UIApplication.sharedApplication.statusBarOrientation;
}
}
#endif
@end