Browse Source

Add Application.TryGetFeature, re-add new feature - IActivatableLifetime (#14556)

* Implement IOptionalFeatureProvider on Application class

* Use IActivatableLifetime from the TryGetFeature instead of a lifetime

* Reimplement macOS IActivatableLifetime

* Reimplement iOS IActivatableLifetime

* Reimplement Browser IActivatableLifetime

* Reimplement Android IActivatableLifetime

* Make AndroidActivatableLifetime aware of activity re-creation

* Don't crash control catalog dialogs page

* Browser TryEnterBackground shouldn't return true
pull/14826/head
Max Katz 2 years ago
committed by GitHub
parent
commit
b9ec339cfa
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      Avalonia.sln.DotSettings
  2. 3
      samples/ControlCatalog/App.xaml.cs
  3. 12
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  4. 4
      src/Android/Avalonia.Android/AndroidPlatform.cs
  5. 12
      src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs
  6. 47
      src/Android/Avalonia.Android/Platform/AndroidActivatableLifetime.cs
  7. 23
      src/Android/Avalonia.Android/SingleViewLifetime.cs
  8. 7
      src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs
  9. 10
      src/Avalonia.Controls/AppBuilder.cs
  10. 35
      src/Avalonia.Controls/Application.cs
  11. 3
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  12. 9
      src/Avalonia.Controls/ApplicationLifetimes/IActivatableApplicationLifetime.cs
  13. 16
      src/Avalonia.Native/AvaloniaNativeApplicationPlatform.cs
  14. 4
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  15. 4
      src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
  16. 3
      src/Avalonia.Native/MacOSActivatableLifetime.cs
  17. 36
      src/Browser/Avalonia.Browser/BrowserActivatableLifetime.cs
  18. 20
      src/Browser/Avalonia.Browser/BrowserSingleViewLifetime.cs
  19. 4
      src/Browser/Avalonia.Browser/WindowingPlatform.cs
  20. 18
      src/iOS/Avalonia.iOS/ActivatableLifetime.cs
  21. 4
      src/iOS/Avalonia.iOS/AvaloniaAppDelegate.cs
  22. 16
      src/iOS/Avalonia.iOS/Platform.cs
  23. 15
      src/iOS/Avalonia.iOS/SingleViewLifetime.cs

1
Avalonia.sln.DotSettings

@ -37,5 +37,6 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EDaemon_002ESettings_002EMigration_002ESwaWarningsModeSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Activatable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Avalonia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fcitx/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

3
samples/ControlCatalog/App.xaml.cs

@ -3,6 +3,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.Themes.Simple;
using Avalonia.Themes.Fluent;
@ -51,7 +52,7 @@ namespace ControlCatalog
singleViewLifetime.MainView = new MainView { DataContext = new MainWindowViewModel() };
}
if (ApplicationLifetime is IActivatableApplicationLifetime activatableApplicationLifetime)
if (this.TryGetFeature<IActivatableLifetime>() is {} activatableApplicationLifetime)
{
activatableApplicationLifetime.Activated += (sender, args) =>
Console.WriteLine($"App activated: {args.Kind}");

12
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -3,6 +3,7 @@ using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
@ -43,7 +44,7 @@ namespace ControlCatalog.Pages
{
lastSelectedDirectory = await GetStorageProvider().TryGetWellKnownFolderAsync(folderEnum);
}
else
else if (!string.IsNullOrWhiteSpace(currentFolderBox.Text))
{
if (!Uri.TryCreate(currentFolderBox.Text, UriKind.Absolute, out var folderLink))
{
@ -52,7 +53,14 @@ namespace ControlCatalog.Pages
if (folderLink is not null)
{
lastSelectedDirectory = await GetStorageProvider().TryGetFolderFromPathAsync(folderLink);
try
{
lastSelectedDirectory = await GetStorageProvider().TryGetFolderFromPathAsync(folderLink);
}
catch (SecurityException)
{
}
}
}
};

4
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -5,6 +5,7 @@ using Avalonia.Controls;
using Avalonia.Android;
using Avalonia.Android.Platform;
using Avalonia.Android.Platform.Input;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.OpenGL.Egl;
@ -81,7 +82,8 @@ namespace Avalonia.Android
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IActivatableLifetime>().ToConstant(new AndroidActivatableLifetime());
var graphics = InitializeGraphics(Options);
if (graphics is not null)

12
src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs

@ -1,5 +1,9 @@
#nullable enable
using Avalonia.Android.Platform;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
namespace Avalonia.Android
{
partial class AvaloniaMainActivity<TApp> where TApp : Application, new()
@ -36,11 +40,17 @@ namespace Avalonia.Android
{
var builder = CreateAppBuilder();
builder.SetupWithLifetime(new SingleViewLifetime(this));
builder.SetupWithLifetime(new SingleViewLifetime());
s_appBuilder = builder;
}
if (Avalonia.Application.Current?.TryGetFeature<IActivatableLifetime>()
is AndroidActivatableLifetime activatableLifetime)
{
activatableLifetime.Activity = this;
}
View = new AvaloniaView(this);
if (ViewContent != null)
{

47
src/Android/Avalonia.Android/Platform/AndroidActivatableLifetime.cs

@ -0,0 +1,47 @@
using System;
using Android.App;
using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.Android.Platform;
internal class AndroidActivatableLifetime : IActivatableLifetime
{
private IAvaloniaActivity _activity;
public IAvaloniaActivity Activity
{
get => _activity;
set
{
if (_activity is not null)
{
_activity.Activated -= ActivityOnActivated;
_activity.Deactivated -= ActivityOnDeactivated;
}
_activity = value;
if (_activity is not null)
{
_activity.Activated += ActivityOnActivated;
_activity.Deactivated += ActivityOnDeactivated;
}
}
}
public event EventHandler<ActivatedEventArgs> Activated;
public event EventHandler<ActivatedEventArgs> Deactivated;
public bool TryLeaveBackground() => (_activity as Activity)?.MoveTaskToBack(true) == true;
public bool TryEnterBackground() => false;
private void ActivityOnDeactivated(object sender, ActivatedEventArgs e)
{
Deactivated?.Invoke(this, e);
}
private void ActivityOnActivated(object sender, ActivatedEventArgs e)
{
Activated?.Invoke(this, e);
}
}

23
src/Android/Avalonia.Android/SingleViewLifetime.cs

@ -1,25 +1,11 @@
using System;
using Android.App;
using Avalonia.Controls;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.Android
{
internal class SingleViewLifetime : ISingleViewApplicationLifetime, IActivatableApplicationLifetime
internal class SingleViewLifetime : ISingleViewApplicationLifetime
{
private readonly Activity _activity;
private AvaloniaView _view;
public SingleViewLifetime(Activity activity)
{
_activity = activity;
if (activity is IAvaloniaActivity activableActivity)
{
activableActivity.Activated += (_, args) => Activated?.Invoke(this, args);
activableActivity.Deactivated += (_, args) => Deactivated?.Invoke(this, args);
}
}
public AvaloniaView View
{
@ -36,10 +22,5 @@ namespace Avalonia.Android
}
public Control MainView { get; set; }
public event EventHandler<ActivatedEventArgs> Activated;
public event EventHandler<ActivatedEventArgs> Deactivated;
public bool TryLeaveBackground() => _activity.MoveTaskToBack(true);
public bool TryEnterBackground() => false;
}
}

7
src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs

@ -1,22 +1,25 @@
using System;
using System.Diagnostics.CodeAnalysis;
// TODO12: move to Avalonia namespace.
namespace Avalonia.Platform;
public interface IOptionalFeatureProvider
{
/// <summary>
/// Queries for an optional feature
/// Queries for an optional feature.
/// </summary>
/// <param name="featureType">Feature type</param>
/// <param name="featureType">Feature type.</param>
public object? TryGetFeature(Type featureType);
}
public static class OptionalFeatureProviderExtensions
{
/// <inheritdoc cref="IOptionalFeatureProvider.TryGetFeature"/>
public static T? TryGetFeature<T>(this IOptionalFeatureProvider provider) where T : class =>
(T?)provider.TryGetFeature(typeof(T));
/// <inheritdoc cref="IOptionalFeatureProvider.TryGetFeature"/>
public static bool TryGetFeature<T>(this IOptionalFeatureProvider provider, [MaybeNullWhen(false)] out T rv)
where T : class
{

10
src/Avalonia.Controls/AppBuilder.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Linq;
@ -58,6 +59,8 @@ namespace Avalonia
/// <summary>
/// Gets a method to override a lifetime factory.
/// </summary>
[Obsolete("This property has no effect", true)]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Func<Type, IApplicationLifetime?>? LifetimeOverride { get; private set; }
/// <summary>
@ -244,13 +247,6 @@ namespace Avalonia
return Self;
}
[PrivateApi]
public AppBuilder UseLifetimeOverride(Func<Type, IApplicationLifetime?> func)
{
LifetimeOverride = func;
return Self;
}
/// <summary>
/// Configures platform-specific options
/// </summary>

35
src/Avalonia.Controls/Application.cs

@ -30,7 +30,7 @@ namespace Avalonia
/// method.
/// - Tracks the lifetime of the application.
/// </remarks>
public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IThemeVariantHost, IApplicationPlatformEvents
public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemplates, IGlobalStyles, IThemeVariantHost, IApplicationPlatformEvents, IOptionalFeatureProvider
{
/// <summary>
/// The application-global data templates.
@ -62,7 +62,7 @@ namespace Avalonia
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged;
[Obsolete("Cast ApplicationLifetime to IActivatableApplicationLifetime instead.")]
[Obsolete("Use Application.Current.TryGetFeature<IActivatableLifetime>() instead.")]
public event EventHandler<UrlOpenedEventArgs>? UrlsOpened;
/// <inheritdoc/>
@ -204,7 +204,7 @@ namespace Avalonia
/// which should always be preferred over a global one,
/// as specific top levels might have different settings set-up.
/// </remarks>
public IPlatformSettings? PlatformSettings => AvaloniaLocator.Current.GetService<IPlatformSettings>();
public IPlatformSettings? PlatformSettings => this.TryGetFeature<IPlatformSettings>();
event Action<IReadOnlyList<IStyle>>? IGlobalStyles.GlobalStylesAdded
{
@ -329,7 +329,34 @@ namespace Avalonia
get => _name;
set => SetAndRaise(NameProperty, ref _name, value);
}
/// <summary>
/// Queries for an optional feature.
/// </summary>
/// <param name="featureType">Feature type.</param>
/// <remarks>
/// Features currently supported by <see cref="Application.TryGetFeature"/>:
/// <list type="bullet">
/// <item>IPlatformSettings</item>
/// <item>IActivatableApplicationLifetime</item>
/// </list>
/// </remarks>
public object? TryGetFeature(Type featureType)
{
if (featureType == typeof(IPlatformSettings))
{
return AvaloniaLocator.Current.GetService<IPlatformSettings>();
}
if (featureType == typeof(IActivatableLifetime))
{
return AvaloniaLocator.Current.GetService<IActivatableLifetime>();
}
// Do not return just any service from AvaloniaLocator.
return null;
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

3
src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs

@ -217,8 +217,7 @@ namespace Avalonia
private static ClassicDesktopStyleApplicationLifetime PrepareLifetime(AppBuilder builder, string[] args,
Action<IClassicDesktopStyleApplicationLifetime>? lifetimeBuilder)
{
var lifetime = builder.LifetimeOverride?.Invoke(typeof(ClassicDesktopStyleApplicationLifetime)) as ClassicDesktopStyleApplicationLifetime
?? new ClassicDesktopStyleApplicationLifetime();
var lifetime = new ClassicDesktopStyleApplicationLifetime();
lifetime.SubscribeGlobalEvents();
lifetime.Args = args;

9
src/Avalonia.Controls/ApplicationLifetimes/IActivatableApplicationLifetime.cs

@ -1,13 +1,20 @@
using System;
using System.Diagnostics;
using Avalonia.Metadata;
namespace Avalonia.Controls.ApplicationLifetimes;
[NotClientImplementable]
[Obsolete("This interface has no effect. Instead use Application.Current.TryGetFeature<IActivatableLifetime>().", true)]
public interface IActivatableApplicationLifetime : IActivatableLifetime {
}
/// <summary>
/// An interface for ApplicationLifetimes where the application can be Activated and Deactivated.
/// </summary>
[NotClientImplementable]
public interface IActivatableApplicationLifetime
public interface IActivatableLifetime
{
/// <summary>
/// An event that is raised when the application is Activated for various reasons

16
src/Avalonia.Native/AvaloniaNativeApplicationPlatform.cs

@ -9,18 +9,18 @@ namespace Avalonia.Native
internal class AvaloniaNativeApplicationPlatform : NativeCallbackBase, IAvnApplicationEvents, IPlatformLifetimeEventsImpl
{
public event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
void IAvnApplicationEvents.FilesOpened(IAvnStringArray urls)
{
((IApplicationPlatformEvents)Application.Current).RaiseUrlsOpened(urls.ToStringArray());
((IApplicationPlatformEvents)Application.Current)?.RaiseUrlsOpened(urls.ToStringArray());
}
void IAvnApplicationEvents.UrlsOpened(IAvnStringArray urls)
{
// Raise the urls opened event to be compatible with legacy behavior.
((IApplicationPlatformEvents)Application.Current).RaiseUrlsOpened(urls.ToStringArray());
((IApplicationPlatformEvents)Application.Current)?.RaiseUrlsOpened(urls.ToStringArray());
if (Application.Current?.ApplicationLifetime is MacOSClassicDesktopStyleApplicationLifetime lifetime)
if (AvaloniaLocator.Current.GetService<IActivatableLifetime>() is MacOSActivatableLifetime lifetime)
{
foreach (var url in urls.ToStringArray())
{
@ -34,7 +34,7 @@ namespace Avalonia.Native
void IAvnApplicationEvents.OnReopen()
{
if (Application.Current?.ApplicationLifetime is MacOSClassicDesktopStyleApplicationLifetime lifetime)
if (AvaloniaLocator.Current.GetService<IActivatableLifetime>() is MacOSActivatableLifetime lifetime)
{
lifetime.RaiseActivated(ActivationKind.Reopen);
}
@ -42,7 +42,7 @@ namespace Avalonia.Native
void IAvnApplicationEvents.OnHide()
{
if (Application.Current?.ApplicationLifetime is MacOSClassicDesktopStyleApplicationLifetime lifetime)
if (AvaloniaLocator.Current.GetService<IActivatableLifetime>() is MacOSActivatableLifetime lifetime)
{
lifetime.RaiseDeactivated(ActivationKind.Background);
}
@ -50,7 +50,7 @@ namespace Avalonia.Native
void IAvnApplicationEvents.OnUnhide()
{
if (Application.Current?.ApplicationLifetime is MacOSClassicDesktopStyleApplicationLifetime lifetime)
if (AvaloniaLocator.Current.GetService<IActivatableLifetime>() is MacOSActivatableLifetime lifetime)
{
lifetime.RaiseActivated(ActivationKind.Background);
}

4
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Compatibility;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
@ -112,7 +113,8 @@ namespace Avalonia.Native
.Bind<IMountedVolumeInfoProvider>().ToConstant(new MacOSMountedVolumeInfoProvider())
.Bind<IPlatformDragSource>().ToConstant(new AvaloniaNativeDragSource(_factory))
.Bind<IPlatformLifetimeEventsImpl>().ToConstant(applicationPlatform)
.Bind<INativeApplicationCommands>().ToConstant(new MacOSNativeMenuCommands(_factory.CreateApplicationCommands()));
.Bind<INativeApplicationCommands>().ToConstant(new MacOSNativeMenuCommands(_factory.CreateApplicationCommands()))
.Bind<IActivatableLifetime>().ToSingleton<MacOSActivatableLifetime>();
var hotkeys = new PlatformHotkeyConfiguration(KeyModifiers.Meta, wholeWordTextActionModifiers: KeyModifiers.Alt);
hotkeys.MoveCursorToTheStartOfLine.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers));

4
src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs

@ -23,9 +23,7 @@ namespace Avalonia
platform.SetupApplicationName();
platform.SetupApplicationMenuExporter();
});
})
.UseLifetimeOverride(type => type == typeof(ClassicDesktopStyleApplicationLifetime)
? new MacOSClassicDesktopStyleApplicationLifetime() : null);
});
return builder;
}

3
src/Avalonia.Native/MacOSClassicDesktopStyleApplicationLifetime.cs → src/Avalonia.Native/MacOSActivatableLifetime.cs

@ -6,8 +6,7 @@ namespace Avalonia.Native;
#nullable enable
internal class MacOSClassicDesktopStyleApplicationLifetime : ClassicDesktopStyleApplicationLifetime,
IActivatableApplicationLifetime
internal class MacOSActivatableLifetime : IActivatableLifetime
{
/// <inheritdoc />
public event EventHandler<ActivatedEventArgs>? Activated;

36
src/Browser/Avalonia.Browser/BrowserActivatableLifetime.cs

@ -0,0 +1,36 @@
using System;
using Avalonia.Browser.Interop;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
namespace Avalonia.Browser;
internal class BrowserActivatableLifetime : IActivatableLifetime
{
public BrowserActivatableLifetime()
{
bool? initiallyVisible = InputHelper.SubscribeVisibilityChange(visible =>
{
initiallyVisible = null;
(visible ? Activated : Deactivated)?.Invoke(this, new ActivatedEventArgs(ActivationKind.Background));
});
// Trigger Activated as an initial state, if web page is visible, and wasn't hidden during initialization.
if (initiallyVisible == true)
{
_ = Dispatcher.UIThread.InvokeAsync(() =>
{
if (initiallyVisible == true)
{
Activated?.Invoke(this, new ActivatedEventArgs(ActivationKind.Background));
}
}, DispatcherPriority.Background);
}
}
public event EventHandler<ActivatedEventArgs>? Activated;
public event EventHandler<ActivatedEventArgs>? Deactivated;
public bool TryLeaveBackground() => false;
public bool TryEnterBackground() => false;
}

20
src/Browser/Avalonia.Browser/BrowserSingleViewLifetime.cs

@ -2,24 +2,12 @@
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using System.Runtime.Versioning;
using Avalonia.Browser;
using Avalonia.Browser.Interop;
using Avalonia.Threading;
namespace Avalonia;
internal class BrowserSingleViewLifetime : ISingleViewApplicationLifetime, IActivatableApplicationLifetime
internal class BrowserSingleViewLifetime : ISingleViewApplicationLifetime
{
public BrowserSingleViewLifetime()
{
bool? initiallyVisible = InputHelper.SubscribeVisibilityChange(visible =>
{
initiallyVisible = null;
(visible ? Activated : Deactivated)?.Invoke(this, new ActivatedEventArgs(ActivationKind.Background));
});
}
public AvaloniaView? View;
public Control? MainView
@ -44,10 +32,4 @@ internal class BrowserSingleViewLifetime : ISingleViewApplicationLifetime, IActi
throw new InvalidOperationException("Browser lifetime was not initialized. Make sure AppBuilder.StartBrowserApp was called.");
}
}
public event EventHandler<ActivatedEventArgs>? Activated;
public event EventHandler<ActivatedEventArgs>? Deactivated;
public bool TryLeaveBackground() => false;
public bool TryEnterBackground() => false;
}

4
src/Browser/Avalonia.Browser/WindowingPlatform.cs

@ -1,6 +1,7 @@
using System;
using Avalonia.Browser.Interop;
using Avalonia.Browser.Skia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Platform;
@ -43,7 +44,8 @@ internal class BrowserWindowingPlatform : IWindowingPlatform
.Bind<IWindowingPlatform>().ToConstant(instance)
.Bind<IPlatformGraphics>().ToConstant(new BrowserSkiaGraphics())
.Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IActivatableLifetime>().ToSingleton<BrowserActivatableLifetime>();
if (AvaloniaLocator.Current.GetService<BrowserPlatformOptions>() is { } options
&& options.RegisterAvaloniaServiceWorker)

18
src/iOS/Avalonia.iOS/ActivatableLifetime.cs

@ -0,0 +1,18 @@
using System;
using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.iOS;
internal class ActivatableLifetime : IActivatableLifetime
{
public ActivatableLifetime(IAvaloniaAppDelegate avaloniaAppDelegate)
{
avaloniaAppDelegate.Activated += (_, args) => Activated?.Invoke(this, args);
avaloniaAppDelegate.Deactivated += (_, args) => Deactivated?.Invoke(this, args);
}
public event EventHandler<ActivatedEventArgs>? Activated;
public event EventHandler<ActivatedEventArgs>? Deactivated;
public bool TryLeaveBackground() => false;
public bool TryEnterBackground() => false;
}

4
src/iOS/Avalonia.iOS/AvaloniaAppDelegate.cs

@ -42,9 +42,9 @@ namespace Avalonia.iOS
[Export("application:didFinishLaunchingWithOptions:")]
public bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
var builder = AppBuilder.Configure<TApp>().UseiOS();
var builder = AppBuilder.Configure<TApp>().UseiOS(this);
var lifetime = new SingleViewLifetime(this);
var lifetime = new SingleViewLifetime();
builder.AfterSetup(_ =>
{

16
src/iOS/Avalonia.iOS/Platform.cs

@ -1,8 +1,10 @@
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;
@ -39,13 +41,15 @@ namespace Avalonia
public static class IOSApplicationExtensions
{
public static AppBuilder UseiOS(this AppBuilder builder)
public static AppBuilder UseiOS(this AppBuilder builder, IAvaloniaAppDelegate appDelegate)
{
return builder
.UseStandardRuntimePlatformSubsystem()
.UseWindowingSubsystem(iOS.Platform.Register, "iOS")
.UseWindowingSubsystem(() => iOS.Platform.Register(appDelegate), "iOS")
.UseSkia();
}
public static AppBuilder UseiOS(this AppBuilder builder) => UseiOS(builder, null!);
}
}
@ -58,7 +62,7 @@ namespace Avalonia.iOS
public static DisplayLinkTimer? Timer;
internal static Compositor? Compositor { get; private set; }
public static void Register()
public static void Register(IAvaloniaAppDelegate? appDelegate)
{
Options = AvaloniaLocator.Current.GetService<iOSPlatformOptions>() ?? new iOSPlatformOptions();
@ -77,6 +81,12 @@ namespace Avalonia.iOS
.Bind<IDispatcherImpl>().ToConstant(DispatcherImpl.Instance)
.Bind<IKeyboardDevice>().ToConstant(keyboard);
if (appDelegate is not null)
{
AvaloniaLocator.CurrentMutable
.Bind<IActivatableLifetime>().ToConstant(new ActivatableLifetime(appDelegate));
}
Compositor = new Compositor(AvaloniaLocator.Current.GetService<IPlatformGraphics>());
AvaloniaLocator.CurrentMutable.Bind<Compositor>().ToConstant(Compositor);
}

15
src/iOS/Avalonia.iOS/SingleViewLifetime.cs

@ -4,14 +4,8 @@ using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.iOS;
internal class SingleViewLifetime : ISingleViewApplicationLifetime, IActivatableApplicationLifetime
{
public SingleViewLifetime(IAvaloniaAppDelegate avaloniaAppDelegate)
{
avaloniaAppDelegate.Activated += (_, args) => Activated?.Invoke(this, args);
avaloniaAppDelegate.Deactivated += (_, args) => Deactivated?.Invoke(this, args);
}
internal class SingleViewLifetime : ISingleViewApplicationLifetime
{
public AvaloniaView? View;
public Control? MainView
@ -19,9 +13,4 @@ internal class SingleViewLifetime : ISingleViewApplicationLifetime, IActivatable
get => View!.Content;
set => View!.Content = value;
}
public event EventHandler<ActivatedEventArgs>? Activated;
public event EventHandler<ActivatedEventArgs>? Deactivated;
public bool TryLeaveBackground() => false;
public bool TryEnterBackground() => false;
}

Loading…
Cancel
Save