Badminton-Scoreboard/Classes/UI/SplashScreen.mm
2023-10-08 10:24:48 +08:00

244 lines
7.8 KiB
Plaintext

#include "SplashScreen.h"
#include "UnityViewControllerBase.h"
#include "OrientationSupport.h"
#include "Unity/ObjCRuntime.h"
#include "UI/UnityView.h"
#include <cstring>
#include "Unity/UnitySharedDecls.h"
#include <utility>
static SplashScreen* _splash = nil;
static SplashScreenController* _controller = nil;
@implementation SplashScreen
{
UIImageView* m_ImageView;
UIView* m_XibView;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame: frame];
return self;
}
- (void)createUI
{
NSString* launchScreen = [[NSBundle mainBundle].infoDictionary[@"UILaunchStoryboardName"] stringByDeletingPathExtension];
const bool hasXIB = [[NSBundle mainBundle] pathForResource: launchScreen ofType: @"nib"] != nil;
if (hasXIB)
{
self->m_XibView = [[[NSBundle mainBundle] loadNibNamed: launchScreen owner: nil options: nil] objectAtIndex: 0];
[self addSubview: self->m_XibView];
}
else
{
#if !PLATFORM_TVOS
NSAssert(NO, @"no storyboard/xib was provided.");
#endif
// we still support launch images on tvos, but unlike iOS there are only two options and no orientations
UIImage* launchImage = nil;
if ([UIScreen mainScreen].scale > 1.0)
launchImage = [UIImage imageNamed: @"LaunchImage@2x"];
if (!launchImage)
launchImage = [UIImage imageNamed: @"LaunchImage@"];
self->m_ImageView = [[UIImageView alloc] initWithImage: launchImage];
[self addSubview: self->m_ImageView];
}
}
- (void)updateOrientation:(ScreenOrientation)orient withSupportedOrientations:(const OrientationMask&)supportedOrientations
{
CGFloat scale = UnityScreenScaleFactor([UIScreen mainScreen]);
UnityReportResizeView((unsigned)(self.bounds.size.width * scale), (unsigned)(self.bounds.size.height * scale), orient);
ReportSafeAreaChangeForView(self);
// for iOS only xib/storyboard are supported, for tvOS (launch images are supported) no orientation takes place at all
}
- (void)layoutSubviews
{
if (self->m_XibView)
self->m_XibView.frame = self.bounds;
else if (self->m_ImageView)
self->m_ImageView.frame = self.bounds;
}
+ (SplashScreen*)Instance
{
return _splash;
}
- (void)freeSubviews
{
m_ImageView = nil;
m_XibView = nil;
}
@end
@implementation SplashScreenController
{
OrientationMask _supportedOrientations;
}
- (id)init
{
self = [super init];
if (self)
{
self->_supportedOrientations = { false, false, false, false };
}
return self;
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
ScreenOrientation curOrient = UIViewControllerOrientation(self);
ScreenOrientation newOrient = OrientationAfterTransform(curOrient, [coordinator targetTransform]);
[_splash updateOrientation: newOrient withSupportedOrientations: self->_supportedOrientations];
[super viewWillTransitionToSize: size withTransitionCoordinator: coordinator];
}
- (void)initImpl
{
NSArray* supportedOrientation = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"UISupportedInterfaceOrientations"];
// splash will be shown way before unity is inited so we need to override autorotation handling with values read from info.plist
self->_supportedOrientations.portrait = [supportedOrientation containsObject: @"UIInterfaceOrientationPortrait"];
self->_supportedOrientations.portraitUpsideDown = [supportedOrientation containsObject: @"UIInterfaceOrientationPortraitUpsideDown"];
self->_supportedOrientations.landscapeLeft = [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeRight"];
self->_supportedOrientations.landscapeRight = [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeLeft"];
// special handling of devices/ios that do not support upside down orientation
if (!UnityDeviceSupportsUpsideDown())
{
self->_supportedOrientations.portraitUpsideDown = false;
OrientationMask om = self->_supportedOrientations;
const bool anySupported = om.portrait || om.landscapeLeft || om.landscapeRight;
if (!anySupported)
{
self->_supportedOrientations.portrait = true;
printf_console("This device does not support UpsideDown orientation, so we switched to Portrait.\n");
}
}
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
if ((self = [super initWithCoder: coder]))
[self initImpl];
return self;
}
- (void)create:(UIWindow*)window
{
[self initImpl];
_splash = [[SplashScreen alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
_splash.contentScaleFactor = UnityScreenScaleFactor([UIScreen mainScreen]);
_splash.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_splash.autoresizesSubviews = YES;
[_splash createUI];
window.rootViewController = self;
self.view = _splash;
[window addSubview: _splash];
[window bringSubviewToFront: _splash];
ScreenOrientation orient = UIViewControllerOrientation(self);
[_splash updateOrientation: orient withSupportedOrientations: self->_supportedOrientations];
OrientView([SplashScreenController Instance], _splash, orient);
}
#if PLATFORM_IOS
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
NSUInteger ret = 0;
if (self->_supportedOrientations.portrait)
ret |= (1 << UIInterfaceOrientationPortrait);
if (self->_supportedOrientations.portraitUpsideDown)
ret |= (1 << UIInterfaceOrientationPortraitUpsideDown);
if (self->_supportedOrientations.landscapeLeft)
ret |= (1 << UIInterfaceOrientationLandscapeRight);
if (self->_supportedOrientations.landscapeRight)
ret |= (1 << UIInterfaceOrientationLandscapeLeft);
return ret;
}
#endif
+ (SplashScreenController*)Instance
{
return _controller;
}
@end
void ShowSplashScreen(UIWindow* window)
{
NSString* launchScreen = [[NSBundle mainBundle].infoDictionary[@"UILaunchStoryboardName"] stringByDeletingPathExtension];
#if PLATFORM_IOS
// since launch images are no longer supported on ios we MUST have UILaunchStoryboardName filled
assert(launchScreen != nil && "UILaunchStoryboardName key is missing from info.plist");
#endif
const bool hasStoryboard = launchScreen != nil && [[NSBundle mainBundle] pathForResource: launchScreen ofType: @"storyboardc"] != nil;
if (hasStoryboard)
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName: launchScreen bundle: [NSBundle mainBundle]];
// on ios13 we can finally tweak initial storyboard view controller: use unity base view controller
// this way we can handle orientations/status-bar/whatever-we-want-to-tweak uniformly
// as we still support xcode pre-11 we must do this weird dance of checking for both sdk and runtime version
// otherwise it fails to compile (due to unknown selector)
#if (PLATFORM_IOS && defined(__IPHONE_13_0)) || (PLATFORM_TVOS && defined(__TVOS_13_0))
if (@available(iOS 13.0, tvOS 13.0, *))
{
_controller = [storyboard instantiateInitialViewControllerWithCreator:^(NSCoder *coder) {
return [[SplashScreenController alloc] initWithCoder: coder];
}];
}
else
#endif
{
_controller = [storyboard instantiateInitialViewController];
}
window.rootViewController = _controller;
}
else
{
_controller = [[SplashScreenController alloc] init];
[_controller create: window];
}
[window makeKeyAndVisible];
}
void HideSplashScreen()
{
if (_splash)
{
[_splash removeFromSuperview];
[_splash freeSubviews];
}
_splash = nil;
_controller = nil;
}