184 lines
7.2 KiB
Objective-C
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
|