using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.iOS;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;
namespace Avalonia
{
///
/// Represents the rendering mode for platform graphics.
///
public enum iOSRenderingMode
{
///
/// Enables EaGL rendering for iOS and tvOS. Not supported on macCatalyst.
///
OpenGl = 1,
///
/// Enables Metal rendering for all apple targets. Not stable and currently only works on iOS.
///
Metal
}
///
/// iOS backend options.
///
public class iOSPlatformOptions
{
///
/// Gets or sets Avalonia rendering modes with fallbacks.
/// The first element in the array has the highest priority.
/// The default value is: .
///
/// Thrown if no values were matched.
public IReadOnlyList RenderingMode { get; set; } = new[]
{
iOSRenderingMode.Metal, iOSRenderingMode.OpenGl
};
}
public static class IOSApplicationExtensions
{
public static AppBuilder UseiOS(this AppBuilder builder, IAvaloniaAppDelegate appDelegate)
{
return builder
.UseStandardRuntimePlatformSubsystem()
.UseWindowingSubsystem(() => iOS.Platform.Register(appDelegate), "iOS")
.UseHarfBuzz()
.UseSkia();
}
public static AppBuilder UseiOS(this AppBuilder builder) => UseiOS(builder, null!);
}
}
namespace Avalonia.iOS
{
static class Platform
{
public static iOSPlatformOptions? Options;
public static IPlatformGraphics? Graphics;
public static DisplayLinkTimer? Timer;
internal static Compositor? Compositor { get; private set; }
public static void Register(IAvaloniaAppDelegate? appDelegate)
{
Options = AvaloniaLocator.Current.GetService() ?? new iOSPlatformOptions();
Graphics = InitializeGraphics(Options);
Timer ??= new DisplayLinkTimer();
var keyboard = new KeyboardDevice();
Dispatcher.InitializeUIThreadDispatcher(DispatcherImpl.Instance);
AvaloniaLocator.CurrentMutable
.Bind().ToConstant(Graphics)
.Bind().ToConstant(new CursorFactoryStub())
.Bind().ToConstant(new WindowingPlatformStub())
.Bind().ToSingleton()
.Bind().ToConstant(new PlatformIconLoaderStub())
.Bind().ToSingleton()
.Bind().ToSingleton()
.Bind().ToConstant(new KeyGestureFormatInfo(new Dictionary()
{
{ Key.Back , "⌫" }, { Key.Down , "↓" }, { Key.End , "↘" }, { Key.Escape , "⎋" },
{ Key.Home , "↖" }, { Key.Left , "←" }, { Key.Return , "↩" }, { Key.PageDown , "⇟" },
{ Key.PageUp , "⇞" }, { Key.Right , "→" }, { Key.Space , "␣" }, { Key.Tab , "⇥" },
{ Key.Up , "↑" }
}, ctrl: "⌃", meta: "⌘", shift: "⇧", alt: "⌥"))
.Bind().ToConstant(RenderLoop.FromTimer(Timer))
.Bind().ToConstant(keyboard);
if (appDelegate is not null)
{
AvaloniaLocator.CurrentMutable
.Bind().ToConstant(new ActivatableLifetime(appDelegate));
}
Compositor = new Compositor(AvaloniaLocator.Current.GetService());
AvaloniaLocator.CurrentMutable.Bind().ToConstant(Compositor);
}
private static IPlatformGraphics InitializeGraphics(iOSPlatformOptions opts)
{
if (opts.RenderingMode is null || !opts.RenderingMode.Any())
{
throw new InvalidOperationException($"{nameof(iOSPlatformOptions)}.{nameof(iOSPlatformOptions.RenderingMode)} must not be empty or null");
}
foreach (var renderingMode in opts.RenderingMode)
{
#if !MACCATALYST
if (renderingMode == iOSRenderingMode.OpenGl
&& !OperatingSystem.IsMacCatalyst()
#pragma warning disable CA1422
&& Eagl.EaglPlatformGraphics.TryCreate() is { } eaglGraphics)
#pragma warning restore CA1422
{
return eaglGraphics;
}
#endif
if (renderingMode == iOSRenderingMode.Metal
&& Metal.MetalPlatformGraphics.TryCreate() is { } metalGraphics)
{
return metalGraphics;
}
}
throw new InvalidOperationException($"{nameof(iOSPlatformOptions)}.{nameof(iOSPlatformOptions.RenderingMode)} has a value of \"{string.Join(", ", opts.RenderingMode)}\", but no options were applied.");
}
}
}