Browse Source

Make iOS backend compilable with TVOS and MacCatalyst

pull/14196/head
Max Katz 2 years ago
parent
commit
da16fecbc0
  1. 2
      src/Avalonia.Base/Compatibility/OperatingSystem.cs
  2. 34
      src/iOS/Avalonia.iOS/AvaloniaView.cs
  3. 2
      src/iOS/Avalonia.iOS/ClipboardImpl.cs
  4. 7
      src/iOS/Avalonia.iOS/InsetsManager.cs
  5. 4
      src/iOS/Avalonia.iOS/Storage/IOSSecurityScopedStream.cs
  6. 4
      src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs
  7. 4
      src/iOS/Avalonia.iOS/Storage/IOSStorageProvider.cs
  8. 5
      src/iOS/Avalonia.iOS/TextInputResponder.cs
  9. 13
      src/iOS/Avalonia.iOS/UIKitInputPane.cs
  10. 8
      src/iOS/Avalonia.iOS/ViewController.cs

2
src/Avalonia.Base/Compatibility/OperatingSystem.cs

@ -11,6 +11,7 @@ namespace Avalonia.Compatibility
public static bool IsLinux() => OperatingSystem.IsLinux();
public static bool IsAndroid() => OperatingSystem.IsAndroid();
public static bool IsIOS() => OperatingSystem.IsIOS();
public static bool IsTvOS() => OperatingSystem.IsTvOS();
public static bool IsBrowser() => OperatingSystem.IsBrowser();
public static bool IsOSPlatform(string platform) => OperatingSystem.IsOSPlatform(platform);
#else
@ -19,6 +20,7 @@ namespace Avalonia.Compatibility
public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
public static bool IsAndroid() => IsOSPlatform("ANDROID");
public static bool IsIOS() => IsOSPlatform("IOS");
public static bool IsTvOS() => IsOSPlatform("TVOS"); // untested
public static bool IsBrowser() => IsOSPlatform("BROWSER");
public static bool IsOSPlatform(string platform) => RuntimeInformation.IsOSPlatform(OSPlatform.Create(platform));
#endif

34
src/iOS/Avalonia.iOS/AvaloniaView.cs

@ -48,7 +48,9 @@ namespace Avalonia.iOS
_topLevel.StartRendering();
InitLayerSurface();
#if !TVOS
MultipleTouchEnabled = true;
#endif
}
[ObsoletedOSPlatform("ios12.0", "Use 'Metal' instead.")]
@ -111,9 +113,10 @@ namespace Avalonia.iOS
{
private readonly AvaloniaView _view;
private readonly INativeControlHostImpl _nativeControlHost;
private readonly IStorageProvider _storageProvider;
internal readonly InsetsManager _insetsManager;
private readonly ClipboardImpl _clipboard;
private readonly IStorageProvider? _storageProvider;
private readonly IClipboard? _clipboard;
private readonly IInputPane? _inputPane;
private IDisposable? _paddingInsets;
public AvaloniaView View => _view;
@ -122,8 +125,12 @@ namespace Avalonia.iOS
{
_view = view;
_nativeControlHost = new NativeControlHostImpl(view);
#if !TVOS
_storageProvider = new IOSStorageProvider(view);
_insetsManager = new InsetsManager(view);
_clipboard = new ClipboardImpl();
_inputPane = UIKitInputPane.Instance;
#endif
_insetsManager = new InsetsManager();
_insetsManager.DisplayEdgeToEdgeChanged += (_, edgeToEdge) =>
{
// iOS doesn't add any paddings/margins to the application by itself.
@ -138,7 +145,6 @@ namespace Avalonia.iOS
BindingPriority.Style); // lower priority, so it can be redefined by user
}
};
_clipboard = new ClipboardImpl();
}
public void Dispose()
@ -195,8 +201,11 @@ namespace Avalonia.iOS
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
#if !TVOS
// TODO adjust status bar depending on full screen mode.
if (OperatingSystem.IsIOSVersionAtLeast(13) && _view._controller is not null)
if ((OperatingSystem.IsIOSVersionAtLeast(13)
|| OperatingSystem.IsMacCatalyst())
&& _view._controller is not null)
{
_view._controller.PreferredStatusBarStyle = themeVariant switch
{
@ -205,6 +214,7 @@ namespace Avalonia.iOS
_ => UIStatusBarStyle.Default
};
}
#endif
}
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } =
@ -212,11 +222,6 @@ namespace Avalonia.iOS
public object? TryGetFeature(Type featureType)
{
if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
if (featureType == typeof(ITextInputMethodImpl))
{
return _view;
@ -232,15 +237,22 @@ namespace Avalonia.iOS
return _insetsManager;
}
#if !TVOS
if (featureType == typeof(IClipboard))
{
return _clipboard;
}
if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
if (featureType == typeof(IInputPane))
{
return UIKitInputPane.Instance;
return _inputPane;
}
#endif
return null;
}

2
src/iOS/Avalonia.iOS/ClipboardImpl.cs

@ -1,3 +1,4 @@
#if !TVOS
using System;
using System.Threading.Tasks;
using Avalonia.Input;
@ -32,3 +33,4 @@ namespace Avalonia.iOS
public Task<object> GetDataAsync(string format) => Task.FromResult<object>(null);
}
}
#endif

7
src/iOS/Avalonia.iOS/InsetsManager.cs

@ -1,22 +1,15 @@
using System;
using Avalonia.Controls.Platform;
using Avalonia.Media;
using UIKit;
namespace Avalonia.iOS;
#nullable enable
internal class InsetsManager : IInsetsManager
{
private readonly AvaloniaView _view;
private IAvaloniaViewController? _controller;
private bool _displayEdgeToEdge = true;
public InsetsManager(AvaloniaView view)
{
_view = view;
}
internal void InitWithController(IAvaloniaViewController controller)
{
_controller = controller;

4
src/iOS/Avalonia.iOS/Storage/IOSSecurityScopedStream.cs

@ -1,4 +1,5 @@
using System.IO;
#if !TVOS
using System.IO;
using Foundation;
@ -66,3 +67,4 @@ internal sealed class IOSSecurityScopedStream : Stream
}
}
}
#endif

4
src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs

@ -1,4 +1,5 @@
using System;
#if !TVOS
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -275,3 +276,4 @@ internal sealed class IOSStorageFolder : IOSStorageItem, IStorageBookmarkFolder
}
}
}
#endif

4
src/iOS/Avalonia.iOS/Storage/IOSStorageProvider.cs

@ -1,4 +1,5 @@
using System;
#if !TVOS
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
@ -244,3 +245,4 @@ internal class IOSStorageProvider : IStorageProvider
}
}
}
#endif

5
src/iOS/Avalonia.iOS/TextInputResponder.cs

@ -108,7 +108,10 @@ partial class AvaloniaView
{
get
{
var mode = UITextInputMode.CurrentInputMode;
UITextInputMode? mode = null;
#if !TVOS
mode = UITextInputMode.CurrentInputMode;
#endif
// Can be empty see https://developer.apple.com/documentation/uikit/uitextinputmode/1614522-activeinputmodes
if (mode is null && UITextInputMode.ActiveInputModes.Length > 0)
{

13
src/iOS/Avalonia.iOS/UIKitInputPane.cs

@ -1,5 +1,7 @@
#if !TVOS
using System;
using System.Diagnostics;
using System.Runtime.Versioning;
using Avalonia.Animation.Easings;
using Avalonia.Controls.Platform;
using Foundation;
@ -8,6 +10,9 @@ using UIKit;
#nullable enable
namespace Avalonia.iOS;
[UnsupportedOSPlatform("tvos")]
[SupportedOSPlatform("maccatalyst")]
[SupportedOSPlatform("ios")]
internal sealed class UIKitInputPane : IInputPane
{
public static UIKitInputPane Instance { get; } = new();
@ -33,7 +38,11 @@ internal sealed class UIKitInputPane : IInputPane
private void RaiseEventFromNotification(bool isUp, NSNotification notification)
{
State = isUp ? InputPaneState.Open : InputPaneState.Closed;
#if MACCATALYST
OccludedRect = default;
StateChanged?.Invoke(this, new InputPaneStateEventArgs(
State, null, OccludedRect));
#else
var startFrame = UIKeyboard.FrameBeginFromNotification(notification);
var endFrame = UIKeyboard.FrameEndFromNotification(notification);
var duration = UIKeyboard.AnimationDurationFromNotification(notification);
@ -50,5 +59,7 @@ internal sealed class UIKitInputPane : IInputPane
StateChanged?.Invoke(this, new InputPaneStateEventArgs(
State, startRect, OccludedRect, TimeSpan.FromSeconds(duration), easing));
#endif
}
}
#endif

8
src/iOS/Avalonia.iOS/ViewController.cs

@ -7,7 +7,9 @@ namespace Avalonia.iOS;
[Unstable]
public interface IAvaloniaViewController
{
#if !TVOS
UIStatusBarStyle PreferredStatusBarStyle { get; set; }
#endif
bool PrefersStatusBarHidden { get; set; }
Thickness SafeAreaPadding { get; }
event EventHandler SafeAreaPaddingChanged;
@ -16,7 +18,9 @@ public interface IAvaloniaViewController
/// <inheritdoc cref="IAvaloniaViewController" />
public class DefaultAvaloniaViewController : UIViewController, IAvaloniaViewController
{
#if !TVOS
private UIStatusBarStyle? _preferredStatusBarStyle;
#endif
private bool? _prefersStatusBarHidden;
/// <inheritdoc/>
@ -33,6 +37,7 @@ public class DefaultAvaloniaViewController : UIViewController, IAvaloniaViewCont
}
}
#if !TVOS
/// <inheritdoc/>
public override bool PrefersStatusBarHidden()
{
@ -55,6 +60,7 @@ public class DefaultAvaloniaViewController : UIViewController, IAvaloniaViewCont
SetNeedsStatusBarAppearanceUpdate();
}
}
#endif
bool IAvaloniaViewController.PrefersStatusBarHidden
{
@ -62,7 +68,9 @@ public class DefaultAvaloniaViewController : UIViewController, IAvaloniaViewCont
set
{
_prefersStatusBarHidden = value;
#if !TVOS
SetNeedsStatusBarAppearanceUpdate();
#endif
}
}

Loading…
Cancel
Save