diff --git a/osu.Android.props b/osu.Android.props index 7ae16b8b70..d2682fc024 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 7b0a027d39..309a9dcc87 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs index e88b39f710..5d309f2fc1 100644 --- a/osu.iOS/AppDelegate.cs +++ b/osu.iOS/AppDelegate.cs @@ -1,14 +1,61 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using Foundation; using osu.Framework.iOS; +using UIKit; namespace osu.iOS { [Register("AppDelegate")] public class AppDelegate : GameApplicationDelegate { - protected override Framework.Game CreateGame() => new OsuGameIOS(); + private UIInterfaceOrientationMask? defaultOrientationsMask; + private UIInterfaceOrientationMask? orientations; + + /// + /// The current orientation the game is displayed in. + /// + public UIInterfaceOrientation CurrentOrientation => Host.Window.UIWindow.WindowScene!.InterfaceOrientation; + + /// + /// Controls the orientations allowed for the device to rotate to, overriding the default allowed orientations. + /// + public UIInterfaceOrientationMask? Orientations + { + get => orientations; + set + { + if (orientations == value) + return; + + orientations = value; + + if (OperatingSystem.IsIOSVersionAtLeast(16)) + Host.Window.ViewController.SetNeedsUpdateOfSupportedInterfaceOrientations(); + else + UIViewController.AttemptRotationToDeviceOrientation(); + } + } + + protected override Framework.Game CreateGame() => new OsuGameIOS(this); + + public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow) + { + if (orientations != null) + return orientations.Value; + + if (defaultOrientationsMask == null) + { + defaultOrientationsMask = 0; + var defaultOrientations = (NSArray)NSBundle.MainBundle.ObjectForInfoDictionary("UISupportedInterfaceOrientations"); + + foreach (var value in defaultOrientations.ToArray()) + defaultOrientationsMask |= Enum.Parse(value.ToString().Replace("UIInterfaceOrientation", string.Empty)); + } + + return defaultOrientationsMask.Value; + } } } diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist index 70747fc9c8..120e8caecc 100644 --- a/osu.iOS/Info.plist +++ b/osu.iOS/Info.plist @@ -153,6 +153,8 @@ Editor + ITSAppUsesNonExemptEncryption + LSApplicationCategoryType public.app-category.music-games LSSupportsOpeningDocumentsInPlace diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs index a9ca1778a0..a5a42c1e66 100644 --- a/osu.iOS/OsuGameIOS.cs +++ b/osu.iOS/OsuGameIOS.cs @@ -8,17 +8,60 @@ using osu.Framework.Graphics; using osu.Framework.iOS; using osu.Framework.Platform; using osu.Game; +using osu.Game.Screens; using osu.Game.Updater; using osu.Game.Utils; +using UIKit; namespace osu.iOS { public partial class OsuGameIOS : OsuGame { + private readonly AppDelegate appDelegate; public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString()); public override bool HideUnlicensedContent => true; + public OsuGameIOS(AppDelegate appDelegate) + { + this.appDelegate = appDelegate; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + UserPlayingState.BindValueChanged(_ => updateOrientation()); + } + + protected override void ScreenChanged(IOsuScreen? current, IOsuScreen? newScreen) + { + base.ScreenChanged(current, newScreen); + + if (newScreen != null) + updateOrientation(); + } + + private void updateOrientation() + { + bool iPad = UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad; + var orientation = MobileUtils.GetOrientation(this, (IOsuScreen)ScreenStack.CurrentScreen, iPad); + + switch (orientation) + { + case MobileUtils.Orientation.Locked: + appDelegate.Orientations = (UIInterfaceOrientationMask)(1 << (int)appDelegate.CurrentOrientation); + break; + + case MobileUtils.Orientation.Portrait: + appDelegate.Orientations = UIInterfaceOrientationMask.Portrait; + break; + + case MobileUtils.Orientation.Default: + appDelegate.Orientations = null; + break; + } + } + protected override UpdateManager CreateUpdateManager() => new MobileUpdateNotifier(); protected override BatteryInfo CreateBatteryInfo() => new IOSBatteryInfo();