1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

UI - Added splash screen

UI - Added tray icon
This commit is contained in:
Robert 2021-11-26 23:57:16 +01:00
parent 90d028fd58
commit f531c9d0d9
31 changed files with 687 additions and 136 deletions

View File

@ -68,6 +68,9 @@
Gets or sets a list of LEDs to highlight Gets or sets a list of LEDs to highlight
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.Controls.DeviceVisualizer.OnDetachedFromVisualTree(Avalonia.VisualTreeAttachmentEventArgs)">
<inheritdoc />
</member>
<member name="M:Artemis.UI.Shared.Controls.DeviceVisualizer.OnAttachedToLogicalTree(Avalonia.LogicalTree.LogicalTreeAttachmentEventArgs)"> <member name="M:Artemis.UI.Shared.Controls.DeviceVisualizer.OnAttachedToLogicalTree(Avalonia.LogicalTree.LogicalTreeAttachmentEventArgs)">
<inheritdoc /> <inheritdoc />
</member> </member>
@ -295,8 +298,8 @@
<member name="T:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration"> <member name="T:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration">
<summary> <summary>
Represents a layer brush registered through Represents a layer brush registered through
<see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})" /> or <see cref="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})" /> or
<see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)" /> <see cref="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)" />
</summary> </summary>
</member> </member>
<member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration.RegistrationType"> <member name="P:Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration.RegistrationType">
@ -349,7 +352,7 @@
Gets the type of event arguments this event triggers and that must be displayed as children Gets the type of event arguments this event triggers and that must be displayed as children
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.Update(Artemis.UI.Shared.Services.Interfaces.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.GetCurrentValue"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelEventViewModel.GetCurrentValue">
@ -389,7 +392,7 @@
<member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.DisplayPath"> <member name="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.DisplayPath">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.Update(Artemis.UI.Shared.Services.Interfaces.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.GetCurrentValue"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertiesViewModel.GetCurrentValue">
@ -417,7 +420,7 @@
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.GetCurrentValue"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.GetCurrentValue">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.Update(Artemis.UI.Shared.Services.Interfaces.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.ToString"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListPropertyViewModel.ToString">
@ -453,7 +456,7 @@
Gets a list of child view models that visualize the elements in the list Gets a list of child view models that visualize the elements in the list
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.Update(Artemis.UI.Shared.Services.Interfaces.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.ToString"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelListViewModel.ToString">
@ -474,7 +477,7 @@
Gets the value of the property that is being visualized Gets the value of the property that is being visualized
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.Update(Artemis.UI.Shared.Services.Interfaces.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.GetCurrentValue"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel.GetCurrentValue">
@ -504,7 +507,7 @@
Gets the view model used to display the display value Gets the view model used to display the display value
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.Update(Artemis.UI.Shared.Services.Interfaces.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
<inheritdoc /> <inheritdoc />
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.ToString"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertyViewModel.ToString">
@ -587,7 +590,7 @@
Gets a user-friendly representation of the <see cref="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.DataModelPath" /> Gets a user-friendly representation of the <see cref="P:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.DataModelPath" />
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Update(Artemis.UI.Shared.Services.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)"> <member name="M:Artemis.UI.Shared.DataModelVisualization.Shared.DataModelVisualizationViewModel.Update(Artemis.UI.Shared.Services.Interfaces.IDataModelUIService,Artemis.UI.Shared.DataModelVisualization.Shared.DataModelUpdateConfiguration)">
<summary> <summary>
Updates the datamodel and if in an parent, any children Updates the datamodel and if in an parent, any children
</summary> </summary>
@ -837,6 +840,104 @@
Represents a service provided by the Artemis Shared UI library Represents a service provided by the Artemis Shared UI library
</summary> </summary>
</member> </member>
<member name="T:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService">
<summary>
A service for UI related data model tasks
</summary>
</member>
<member name="P:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisteredDataModelEditors">
<summary>
Gets a read-only list of all registered data model editors
</summary>
</member>
<member name="P:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisteredDataModelDisplays">
<summary>
Gets a read-only list of all registered data model displays
</summary>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.GetMainDataModelVisualization">
<summary>
Creates a data model visualization view model for the main data model
</summary>
<returns>
A data model visualization view model containing all data model expansions and modules that expand the main
data model
</returns>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.GetPluginDataModelVisualization(System.Collections.Generic.List{Artemis.Core.Modules.Module},System.Boolean)">
<summary>
Creates a data model visualization view model for the data model of the provided plugin feature
</summary>
<param name="modules">The modules to create the data model visualization view model for</param>
<param name="includeMainDataModel">
Whether or not also to include the main data model (and therefore any modules marked
as <see cref="P:Artemis.Core.Modules.Module.IsAlwaysAvailable" />)
</param>
<returns>A data model visualization view model containing the data model of the provided feature</returns>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.UpdateModules(Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel)">
<summary>
Updates the children of the provided main data model visualization, removing disabled children and adding newly
enabled children
</summary>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})">
<summary>
Registers a new data model editor
</summary>
<typeparam name="T">The type of the editor</typeparam>
<param name="plugin">The plugin this editor belongs to</param>
<param name="compatibleConversionTypes">A collection of extra types this editor supports</param>
<returns>A registration that can be used to remove the editor</returns>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)">
<summary>
Registers a new data model display
</summary>
<typeparam name="T">The type of the display</typeparam>
<param name="plugin">The plugin this display belongs to</param>
<returns>A registration that can be used to remove the display</returns>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RemoveDataModelInput(Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration)">
<summary>
Removes a data model editor
</summary>
<param name="registration">
The registration of the editor as returned by <see cref="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})" />
</param>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RemoveDataModelDisplay(Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration)">
<summary>
Removes a data model display
</summary>
<param name="registration">
The registration of the display as returned by <see cref="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)" />
</param>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.GetDataModelDisplayViewModel(System.Type,Artemis.Core.Modules.DataModelPropertyAttribute,System.Boolean)">
<summary>
Creates the most appropriate display view model for the provided <paramref name="propertyType" /> that can display
a value
</summary>
<param name="propertyType">The type of data model property to find a display view model for</param>
<param name="description">The description of the data model property</param>
<param name="fallBackToDefault">
If <see langword="true"></see>, a simple .ToString() display view model will be
returned if nothing else is found
</param>
<returns>The most appropriate display view model for the provided <paramref name="propertyType"></paramref></returns>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IDataModelUIService.GetDataModelInputViewModel(System.Type,Artemis.Core.Modules.DataModelPropertyAttribute,System.Object,System.Action{System.Object,System.Boolean})">
<summary>
Creates the most appropriate input view model for the provided <paramref name="propertyType" /> that allows
inputting a value
</summary>
<param name="propertyType">The type of data model property to find a display view model for</param>
<param name="description">The description of the data model property</param>
<param name="initialValue">The initial value to show in the input</param>
<param name="updateCallback">A function to call whenever the input was updated (submitted or not)</param>
<returns>The most appropriate input view model for the provided <paramref name="propertyType" /></returns>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IWindowService.ShowWindow``1(System.ValueTuple{System.String,System.Object}[])"> <member name="M:Artemis.UI.Shared.Services.Interfaces.IWindowService.ShowWindow``1(System.ValueTuple{System.String,System.Object}[])">
<summary> <summary>
Creates a view model instance of type <typeparamref name="TViewModel" /> and shows its corresponding View as a window Creates a view model instance of type <typeparamref name="TViewModel" /> and shows its corresponding View as a window
@ -895,103 +996,79 @@
</summary> </summary>
<returns>The builder that can be used to configure the dialog</returns> <returns>The builder that can be used to configure the dialog</returns>
</member> </member>
<member name="T:Artemis.UI.Shared.Services.IDataModelUIService"> <member name="M:Artemis.UI.Shared.Services.Interfaces.IWindowService.CreateContentDialog">
<summary> <summary>
A service for UI related data model tasks Creates a content dialog, use the fluent API to configure it
</summary>
<returns>The builder that can be used to configure the dialog</returns>
</member>
<member name="M:Artemis.UI.Shared.Services.Interfaces.IWindowService.GetCurrentWindow">
<summary>
Gets the current window of the application
</summary>
<returns>The current window of the application</returns>
</member>
<member name="T:Artemis.UI.Shared.Services.MainWindowService.IMainWindowProvider">
<summary>
Represents a class that provides the main window, so that <see cref="T:Artemis.UI.Shared.Services.MainWindowService.IMainWindowService" /> can control the state of
the main window.
</summary> </summary>
</member> </member>
<member name="P:Artemis.UI.Shared.Services.IDataModelUIService.RegisteredDataModelEditors"> <member name="P:Artemis.UI.Shared.Services.MainWindowService.IMainWindowProvider.IsMainWindowOpen">
<summary> <summary>
Gets a read-only list of all registered data model editors Gets a boolean indicating whether the main window is currently open
</summary> </summary>
</member> </member>
<member name="P:Artemis.UI.Shared.Services.IDataModelUIService.RegisteredDataModelDisplays"> <member name="M:Artemis.UI.Shared.Services.MainWindowService.IMainWindowProvider.OpenMainWindow">
<summary> <summary>
Gets a read-only list of all registered data model displays Opens the main window
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetMainDataModelVisualization"> <member name="M:Artemis.UI.Shared.Services.MainWindowService.IMainWindowProvider.CloseMainWindow">
<summary> <summary>
Creates a data model visualization view model for the main data model Closes the main window
</summary>
<returns>
A data model visualization view model containing all data model expansions and modules that expand the main
data model
</returns>
</member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetPluginDataModelVisualization(System.Collections.Generic.List{Artemis.Core.Modules.Module},System.Boolean)">
<summary>
Creates a data model visualization view model for the data model of the provided plugin feature
</summary>
<param name="modules">The modules to create the data model visualization view model for</param>
<param name="includeMainDataModel">
Whether or not also to include the main data model (and therefore any modules marked
as <see cref="P:Artemis.Core.Modules.Module.IsAlwaysAvailable" />)
</param>
<returns>A data model visualization view model containing the data model of the provided feature</returns>
</member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.UpdateModules(Artemis.UI.Shared.DataModelVisualization.Shared.DataModelPropertiesViewModel)">
<summary>
Updates the children of the provided main data model visualization, removing disabled children and adding newly
enabled children
</summary> </summary>
</member> </member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})"> <member name="E:Artemis.UI.Shared.Services.MainWindowService.IMainWindowProvider.MainWindowOpened">
<summary> <summary>
Registers a new data model editor Occurs when the main window has been opened
</summary> </summary>
<typeparam name="T">The type of the editor</typeparam>
<param name="plugin">The plugin this editor belongs to</param>
<param name="compatibleConversionTypes">A collection of extra types this editor supports</param>
<returns>A registration that can be used to remove the editor</returns>
</member> </member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)"> <member name="E:Artemis.UI.Shared.Services.MainWindowService.IMainWindowProvider.MainWindowClosed">
<summary> <summary>
Registers a new data model display Occurs when the main window has been closed
</summary> </summary>
<typeparam name="T">The type of the display</typeparam>
<param name="plugin">The plugin this display belongs to</param>
<returns>A registration that can be used to remove the display</returns>
</member> </member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RemoveDataModelInput(Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration)"> <member name="P:Artemis.UI.Shared.Services.MainWindowService.IMainWindowService.IsMainWindowOpen">
<summary> <summary>
Removes a data model editor Gets a boolean indicating whether the main window is currently open
</summary> </summary>
<param name="registration">
The registration of the editor as returned by <see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelInput``1(Artemis.Core.Plugin,System.Collections.Generic.IReadOnlyCollection{System.Type})" />
</param>
</member> </member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.RemoveDataModelDisplay(Artemis.UI.Shared.DataModelVisualization.DataModelVisualizationRegistration)"> <member name="M:Artemis.UI.Shared.Services.MainWindowService.IMainWindowService.ConfigureMainWindowProvider(Artemis.UI.Shared.Services.MainWindowService.IMainWindowProvider)">
<summary> <summary>
Removes a data model display Sets up the main window provider that controls the state of the main window
</summary> </summary>
<param name="registration"> <param name="mainWindowProvider">The main window provider to use to control the state of the main window</param>
The registration of the display as returned by <see cref="M:Artemis.UI.Shared.Services.IDataModelUIService.RegisterDataModelDisplay``1(Artemis.Core.Plugin)" />
</param>
</member> </member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetDataModelDisplayViewModel(System.Type,Artemis.Core.Modules.DataModelPropertyAttribute,System.Boolean)"> <member name="M:Artemis.UI.Shared.Services.MainWindowService.IMainWindowService.OpenMainWindow">
<summary> <summary>
Creates the most appropriate display view model for the provided <paramref name="propertyType" /> that can display Opens the main window if it is not already open
a value
</summary> </summary>
<param name="propertyType">The type of data model property to find a display view model for</param>
<param name="description">The description of the data model property</param>
<param name="fallBackToDefault">
If <see langword="true"></see>, a simple .ToString() display view model will be
returned if nothing else is found
</param>
<returns>The most appropriate display view model for the provided <paramref name="propertyType"></paramref></returns>
</member> </member>
<member name="M:Artemis.UI.Shared.Services.IDataModelUIService.GetDataModelInputViewModel(System.Type,Artemis.Core.Modules.DataModelPropertyAttribute,System.Object,System.Action{System.Object,System.Boolean})"> <member name="M:Artemis.UI.Shared.Services.MainWindowService.IMainWindowService.CloseMainWindow">
<summary> <summary>
Creates the most appropriate input view model for the provided <paramref name="propertyType" /> that allows Closes the main window if it is not already closed
inputting a value </summary>
</member>
<member name="E:Artemis.UI.Shared.Services.MainWindowService.IMainWindowService.MainWindowOpened">
<summary>
Occurs when the main window has been opened
</summary>
</member>
<member name="E:Artemis.UI.Shared.Services.MainWindowService.IMainWindowService.MainWindowClosed">
<summary>
Occurs when the main window has been closed
</summary> </summary>
<param name="propertyType">The type of data model property to find a display view model for</param>
<param name="description">The description of the data model property</param>
<param name="initialValue">The initial value to show in the input</param>
<param name="updateCallback">A function to call whenever the input was updated (submitted or not)</param>
<returns>The most appropriate input view model for the provided <paramref name="propertyType" /></returns>
</member> </member>
<member name="T:Artemis.UI.Shared.ViewModelBase"> <member name="T:Artemis.UI.Shared.ViewModelBase">
<summary> <summary>

View File

@ -19,7 +19,7 @@ namespace Artemis.UI.Screens.Splash
{ {
_coreService = coreService; _coreService = coreService;
_pluginManagementService = pluginManagementService; _pluginManagementService = pluginManagementService;
Status = "Initializing Core"; Status = "Initializing Core";
} }
public string Status public string Status

View File

@ -1,5 +1,4 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Threading; using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
@ -10,17 +9,14 @@ namespace Artemis.UI.Linux
{ {
public override void Initialize() public override void Initialize()
{ {
ArtemisBootstrapper.Bootstrap(); ArtemisBootstrapper.Bootstrap(this);
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
public override void OnFrameworkInitializationCompleted() public override void OnFrameworkInitializationCompleted()
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ArtemisBootstrapper.Initialized();
ArtemisBootstrapper.ConfigureApplicationLifetime(desktop);
base.OnFrameworkInitializationCompleted();
} }
} }
} }

View File

@ -1,5 +1,4 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Threading; using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
@ -10,17 +9,14 @@ namespace Artemis.UI.MacOS
{ {
public override void Initialize() public override void Initialize()
{ {
ArtemisBootstrapper.Bootstrap(); ArtemisBootstrapper.Bootstrap(this);
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
public override void OnFrameworkInitializationCompleted() public override void OnFrameworkInitializationCompleted()
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) ArtemisBootstrapper.Initialized();
ArtemisBootstrapper.ConfigureApplicationLifetime(desktop);
base.OnFrameworkInitializationCompleted();
} }
} }
} }

View File

@ -88,20 +88,6 @@ namespace Artemis.UI.Shared.Controls
/// </summary> /// </summary>
public event EventHandler<LedClickedEventArgs>? LedClicked; public event EventHandler<LedClickedEventArgs>? LedClicked;
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_deviceImage?.Dispose();
_deviceImage = null;
if (Device != null)
{
Device.RgbDevice.PropertyChanged -= DevicePropertyChanged;
Device.DeviceUpdated -= DeviceUpdated;
}
base.OnDetachedFromVisualTree(e);
}
/// <summary> /// <summary>
/// Invokes the <see cref="LedClicked" /> event /// Invokes the <see cref="LedClicked" /> event
/// </summary> /// </summary>
@ -216,6 +202,21 @@ namespace Artemis.UI.Shared.Controls
#region Lifetime management #region Lifetime management
/// <inheritdoc />
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_deviceImage?.Dispose();
_deviceImage = null;
if (Device != null)
{
Device.RgbDevice.PropertyChanged -= DevicePropertyChanged;
Device.DeviceUpdated -= DeviceUpdated;
}
base.OnDetachedFromVisualTree(e);
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{ {

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.DataModelVisualization namespace Artemis.UI.Shared.DataModelVisualization
{ {

View File

@ -3,6 +3,7 @@ using System.Linq;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared namespace Artemis.UI.Shared.DataModelVisualization.Shared

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared namespace Artemis.UI.Shared.DataModelVisualization.Shared

View File

@ -1,5 +1,6 @@
using System; using System;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared namespace Artemis.UI.Shared.DataModelVisualization.Shared

View File

@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared namespace Artemis.UI.Shared.DataModelVisualization.Shared

View File

@ -2,6 +2,7 @@
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared namespace Artemis.UI.Shared.DataModelVisualization.Shared

View File

@ -2,6 +2,7 @@
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared namespace Artemis.UI.Shared.DataModelVisualization.Shared

View File

@ -7,6 +7,7 @@ using System.Text;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Shared.DataModelVisualization.Shared namespace Artemis.UI.Shared.DataModelVisualization.Shared

View File

@ -8,6 +8,7 @@ using Artemis.Core.Services;
using Artemis.UI.Shared.DataModelVisualization; using Artemis.UI.Shared.DataModelVisualization;
using Artemis.UI.Shared.DataModelVisualization.Shared; using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.DefaultTypes.DataModel.Display; using Artemis.UI.Shared.DefaultTypes.DataModel.Display;
using Artemis.UI.Shared.Services.Interfaces;
using Ninject; using Ninject;
using Ninject.Parameters; using Ninject.Parameters;

View File

@ -4,9 +4,8 @@ using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.UI.Shared.DataModelVisualization; using Artemis.UI.Shared.DataModelVisualization;
using Artemis.UI.Shared.DataModelVisualization.Shared; using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.Services namespace Artemis.UI.Shared.Services.Interfaces
{ {
/// <summary> /// <summary>
/// A service for UI related data model tasks /// A service for UI related data model tasks

View File

@ -65,8 +65,16 @@ namespace Artemis.UI.Shared.Services.Interfaces
/// <returns>The builder that can be used to configure the dialog</returns> /// <returns>The builder that can be used to configure the dialog</returns>
SaveFileDialogBuilder CreateSaveFileDialog(); SaveFileDialogBuilder CreateSaveFileDialog();
/// <summary>
/// Creates a content dialog, use the fluent API to configure it
/// </summary>
/// <returns>The builder that can be used to configure the dialog</returns>
ContentDialogBuilder CreateContentDialog(); ContentDialogBuilder CreateContentDialog();
/// <summary>
/// Gets the current window of the application
/// </summary>
/// <returns>The current window of the application</returns>
Window GetCurrentWindow(); Window GetCurrentWindow();
} }
} }

View File

@ -0,0 +1,36 @@
using System;
namespace Artemis.UI.Shared.Services.MainWindowService
{
/// <summary>
/// Represents a class that provides the main window, so that <see cref="IMainWindowService" /> can control the state of
/// the main window.
/// </summary>
public interface IMainWindowProvider
{
/// <summary>
/// Gets a boolean indicating whether the main window is currently open
/// </summary>
bool IsMainWindowOpen { get; }
/// <summary>
/// Opens the main window
/// </summary>
void OpenMainWindow();
/// <summary>
/// Closes the main window
/// </summary>
void CloseMainWindow();
/// <summary>
/// Occurs when the main window has been opened
/// </summary>
public event EventHandler? MainWindowOpened;
/// <summary>
/// Occurs when the main window has been closed
/// </summary>
public event EventHandler? MainWindowClosed;
}
}

View File

@ -0,0 +1,39 @@
using System;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.Services.MainWindowService
{
public interface IMainWindowService : IArtemisSharedUIService
{
/// <summary>
/// Gets a boolean indicating whether the main window is currently open
/// </summary>
bool IsMainWindowOpen { get; }
/// <summary>
/// Sets up the main window provider that controls the state of the main window
/// </summary>
/// <param name="mainWindowProvider">The main window provider to use to control the state of the main window</param>
void ConfigureMainWindowProvider(IMainWindowProvider mainWindowProvider);
/// <summary>
/// Opens the main window if it is not already open
/// </summary>
void OpenMainWindow();
/// <summary>
/// Closes the main window if it is not already closed
/// </summary>
void CloseMainWindow();
/// <summary>
/// Occurs when the main window has been opened
/// </summary>
public event EventHandler? MainWindowOpened;
/// <summary>
/// Occurs when the main window has been closed
/// </summary>
public event EventHandler? MainWindowClosed;
}
}

View File

@ -0,0 +1,80 @@
using System;
namespace Artemis.UI.Shared.Services.MainWindowService
{
internal class MainWindowService : IMainWindowService
{
private IMainWindowProvider? _mainWindowManager;
protected virtual void OnMainWindowOpened()
{
MainWindowOpened?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnMainWindowClosed()
{
MainWindowClosed?.Invoke(this, EventArgs.Empty);
}
private void SyncWithManager()
{
if (_mainWindowManager == null)
return;
if (IsMainWindowOpen && !_mainWindowManager.IsMainWindowOpen)
{
IsMainWindowOpen = false;
OnMainWindowClosed();
}
if (!IsMainWindowOpen && _mainWindowManager.IsMainWindowOpen)
{
IsMainWindowOpen = true;
OnMainWindowOpened();
}
}
private void HandleMainWindowOpened(object? sender, EventArgs e)
{
SyncWithManager();
}
private void HandleMainWindowClosed(object? sender, EventArgs e)
{
SyncWithManager();
}
public bool IsMainWindowOpen { get; private set; }
public void ConfigureMainWindowProvider(IMainWindowProvider mainWindowProvider)
{
if (mainWindowProvider == null) throw new ArgumentNullException(nameof(mainWindowProvider));
if (_mainWindowManager != null)
{
_mainWindowManager.MainWindowOpened -= HandleMainWindowOpened;
_mainWindowManager.MainWindowClosed -= HandleMainWindowClosed;
}
_mainWindowManager = mainWindowProvider;
_mainWindowManager.MainWindowOpened += HandleMainWindowOpened;
_mainWindowManager.MainWindowClosed += HandleMainWindowClosed;
// Sync up with the new manager's state
SyncWithManager();
}
public void OpenMainWindow()
{
_mainWindowManager?.OpenMainWindow();
}
public void CloseMainWindow()
{
_mainWindowManager?.CloseMainWindow();
}
public event EventHandler? MainWindowOpened;
public event EventHandler? MainWindowClosed;
}
}

View File

@ -33,7 +33,7 @@ namespace Artemis.UI.Shared.Services
public void ShowWindow(object viewModel) public void ShowWindow(object viewModel)
{ {
Window parent = GetCurrentWindow(); Window? parent = GetCurrentWindow();
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View"); string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
Type? type = viewModel.GetType().Assembly.GetType(name); Type? type = viewModel.GetType().Assembly.GetType(name);
@ -50,7 +50,10 @@ namespace Artemis.UI.Shared.Services
Window window = (Window) Activator.CreateInstance(type)!; Window window = (Window) Activator.CreateInstance(type)!;
window.DataContext = viewModel; window.DataContext = viewModel;
window.Show(parent); if (parent != null)
window.Show(parent);
else
window.Show();
} }
public async Task<TResult> ShowDialogAsync<TViewModel, TResult>(params (string name, object value)[] parameters) where TViewModel : DialogViewModelBase<TResult> public async Task<TResult> ShowDialogAsync<TViewModel, TResult>(params (string name, object value)[] parameters) where TViewModel : DialogViewModelBase<TResult>
@ -132,14 +135,14 @@ namespace Artemis.UI.Shared.Services
return new SaveFileDialogBuilder(GetCurrentWindow()); return new SaveFileDialogBuilder(GetCurrentWindow());
} }
public Window GetCurrentWindow() public Window? GetCurrentWindow()
{ {
if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic) if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic)
{ {
throw new ArtemisSharedUIException("Can't show a dialog when application lifetime is not IClassicDesktopStyleApplicationLifetime."); throw new ArtemisSharedUIException("Can't show a dialog when application lifetime is not IClassicDesktopStyleApplicationLifetime.");
} }
Window parent = classic.Windows.FirstOrDefault(w => w.IsActive) ?? classic.MainWindow; Window? parent = classic.Windows.FirstOrDefault(w => w.IsActive) ?? classic.MainWindow;
return parent; return parent;
} }
} }

View File

@ -2,7 +2,6 @@ using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Threading; using Avalonia.Threading;
using FluentAvalonia.Styling;
using Ninject; using Ninject;
using ReactiveUI; using ReactiveUI;
@ -10,27 +9,23 @@ namespace Artemis.UI.Windows
{ {
public class App : Application public class App : Application
{ {
private StandardKernel _kernel; // ReSharper disable NotAccessedField.Local
private ApplicationStateManager _stateManager; private StandardKernel? _kernel;
private ApplicationStateManager? _applicationStateManager;
// ReSharper restore NotAccessedField.Local
public override void Initialize() public override void Initialize()
{ {
_kernel = ArtemisBootstrapper.Bootstrap(); _kernel = ArtemisBootstrapper.Bootstrap(this);
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
public override void OnFrameworkInitializationCompleted() public override void OnFrameworkInitializationCompleted()
{ {
ArtemisBootstrapper.Initialized();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ _applicationStateManager = new ApplicationStateManager(_kernel!, desktop.Args);
ArtemisBootstrapper.ConfigureApplicationLifetime(desktop);
AvaloniaLocator.Current.GetService<FluentAvaloniaTheme>().ForceNativeTitleBarToTheme(desktop.MainWindow, "Dark");
_stateManager = new ApplicationStateManager(_kernel, desktop.Args);
}
base.OnFrameworkInitializationCompleted();
} }
} }
} }

View File

@ -3,6 +3,8 @@ using Artemis.UI.Exceptions;
using Artemis.UI.Ninject; using Artemis.UI.Ninject;
using Artemis.UI.Screens.Root; using Artemis.UI.Screens.Root;
using Artemis.UI.Shared.Ninject; using Artemis.UI.Shared.Ninject;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Ninject; using Ninject;
using Splat.Ninject; using Splat.Ninject;
@ -12,12 +14,14 @@ namespace Artemis.UI
public static class ArtemisBootstrapper public static class ArtemisBootstrapper
{ {
private static StandardKernel? _kernel; private static StandardKernel? _kernel;
private static Application? _application;
public static StandardKernel Bootstrap() public static StandardKernel Bootstrap(Application application)
{ {
if (_kernel != null) if (_application != null || _kernel != null)
throw new ArtemisUIException("UI already bootstrapped"); throw new ArtemisUIException("UI already bootstrapped");
_application = application;
_kernel = new StandardKernel(); _kernel = new StandardKernel();
_kernel.Settings.InjectNonPublic = true; _kernel.Settings.InjectNonPublic = true;
@ -30,12 +34,19 @@ namespace Artemis.UI
return _kernel; return _kernel;
} }
public static void ConfigureApplicationLifetime(IClassicDesktopStyleApplicationLifetime applicationLifetime) public static void Initialized()
{ {
if (_kernel == null) if (_application == null || _kernel == null)
throw new ArtemisUIException("UI not yet bootstrapped"); throw new ArtemisUIException("UI not yet bootstrapped");
if (_application.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
return;
applicationLifetime.MainWindow = new MainWindow {DataContext = _kernel.Get<RootViewModel>()}; // Don't shut down when the last window closes, we might still be active in the tray
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
// Create the root view model that drives the UI
RootViewModel rootViewModel = _kernel.Get<RootViewModel>();
// Apply the root view model to the data context of the application so that tray icon commands work
_application.DataContext = rootViewModel;
} }
} }
} }

View File

@ -0,0 +1,12 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<NativeMenu x:Key="TrayIconMenu">
<NativeMenuItem Header="Home" Command="{Binding OpenScreen}" CommandParameter="Home" />
<NativeMenuItem Header="Workshop" Command="{Binding OpenScreen}" CommandParameter="Workshop" />
<NativeMenuItem Header="Surface Editor" Command="{Binding OpenScreen}" CommandParameter="SurfaceEditor" />
<NativeMenuItem Header="Settings" Command="{Binding OpenScreen}" CommandParameter="Settings" />
<NativeMenuItemSeparator />
<NativeMenuItem Header="Debugger" Command="{Binding OpenDebugger}" />
<NativeMenuItem Header="Exit" Command="{Binding Exit}" />
</NativeMenu>
</ResourceDictionary>

View File

@ -34,7 +34,7 @@ namespace Artemis.UI.Ninject.Factories
public interface ISidebarVmFactory : IVmFactory public interface ISidebarVmFactory : IVmFactory
{ {
SidebarViewModel SidebarViewModel(IScreen hostScreen); SidebarViewModel? SidebarViewModel(IScreen hostScreen);
SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory); SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory);
SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration); SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration);
} }

View File

@ -3,6 +3,8 @@ using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens; using Artemis.UI.Screens;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Ninject.Extensions.Conventions; using Ninject.Extensions.Conventions;
using Ninject.Modules; using Ninject.Modules;
using Ninject.Planning.Bindings.Resolvers; using Ninject.Planning.Bindings.Resolvers;
@ -17,6 +19,7 @@ namespace Artemis.UI.Ninject
throw new ArgumentNullException("Kernel shouldn't be null here."); throw new ArgumentNullException("Kernel shouldn't be null here.");
Kernel.Components.Add<IMissingBindingResolver, SelfBindingResolver>(); Kernel.Components.Add<IMissingBindingResolver, SelfBindingResolver>();
Kernel.Bind<IAssetLoader>().ToConstant(new AssetLoader());
Kernel.Bind(x => Kernel.Bind(x =>
{ {

View File

@ -11,6 +11,7 @@ using Artemis.Core.Services;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.DataModelVisualization.Shared; using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Interfaces;
using DynamicData; using DynamicData;
using ReactiveUI; using ReactiveUI;

View File

@ -1,30 +1,172 @@
using Artemis.Core.Services; using System;
using System.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.Root.Sidebar; using Artemis.UI.Screens.Root.Sidebar;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Services.MainWindowService;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Screens.Root namespace Artemis.UI.Screens.Root
{ {
public class RootViewModel : ActivatableViewModelBase, IScreen public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvider
{ {
private readonly IClassicDesktopStyleApplicationLifetime _lifeTime;
private readonly ICoreService _coreService; private readonly ICoreService _coreService;
private readonly ISettingsService _settingsService;
private readonly IWindowService _windowService;
private readonly IAssetLoader _assetLoader;
private readonly ISidebarVmFactory _sidebarVmFactory;
private SidebarViewModel? _sidebarViewModel;
private TrayIcon? _trayIcon;
private TrayIcons? _trayIcons;
public RootViewModel(ICoreService coreService, IRegistrationService registrationService, ISidebarVmFactory sidebarVmFactory) public RootViewModel(ICoreService coreService,
ISettingsService settingsService,
IRegistrationService registrationService,
IWindowService windowService,
IMainWindowService mainWindowService,
IAssetLoader assetLoader,
ISidebarVmFactory sidebarVmFactory)
{ {
Router = new RoutingState(); Router = new RoutingState();
SidebarViewModel = sidebarVmFactory.SidebarViewModel(this);
_coreService = coreService; _coreService = coreService;
_coreService.Initialize(); _settingsService = settingsService;
_windowService = windowService;
_assetLoader = assetLoader;
_sidebarVmFactory = sidebarVmFactory;
_lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current.ApplicationLifetime;
coreService.StartupArguments = _lifeTime.Args.ToList();
mainWindowService.ConfigureMainWindowProvider(this);
registrationService.RegisterProviders(); registrationService.RegisterProviders();
DisplayAccordingToSettings();
Task.Run(coreService.Initialize);
} }
public SidebarViewModel SidebarViewModel { get; } public SidebarViewModel? SidebarViewModel
{
get => _sidebarViewModel;
set => this.RaiseAndSetIfChanged(ref _sidebarViewModel, value);
}
/// <inheritdoc /> /// <inheritdoc />
public RoutingState Router { get; } public RoutingState Router { get; }
public async Task Exit()
{
// Don't freeze the UI right after clicking
await Task.Delay(200);
Utilities.Shutdown();
}
private void CurrentMainWindowOnClosed(object? sender, EventArgs e)
{
_lifeTime.MainWindow = null;
SidebarViewModel = null;
OnMainWindowClosed();
}
private void DisplayAccordingToSettings()
{
bool autoRunning = _coreService.StartupArguments.Contains("--autorun");
bool minimized = _coreService.StartupArguments.Contains("--minimized");
bool showOnAutoRun = _settingsService.GetSetting("UI.ShowOnStartup", true).Value;
// Always show the tray icon if ShowOnStartup is false or the user has no way to open the main window
bool showTrayIcon = !showOnAutoRun || _settingsService.GetSetting("UI.ShowTrayIcon", true).Value;
if (showTrayIcon)
ShowTrayIcon();
if (autoRunning && !showOnAutoRun || minimized)
{
// TODO: Auto-update
}
else
{
ShowSplashScreen();
_coreService.Initialized += (_, _) => Dispatcher.UIThread.InvokeAsync(OpenMainWindow);
}
}
private void ShowSplashScreen()
{
_windowService.ShowWindow<SplashViewModel>();
}
private void ShowTrayIcon()
{
_trayIcon = new TrayIcon {Icon = new WindowIcon(_assetLoader.Open(new Uri("avares://Artemis.UI/Assets/Images/Logo/bow.ico")))};
_trayIcon.Menu = (NativeMenu?) Application.Current.FindResource("TrayIconMenu");
_trayIcons = new TrayIcons {_trayIcon};
TrayIcon.SetIcons(Application.Current, _trayIcons);
}
private void HideTrayIcon()
{
_trayIcon?.Dispose();
TrayIcon.SetIcons(Application.Current, null!);
_trayIcon = null;
_trayIcons = null;
}
#region Implementation of IMainWindowProvider
/// <inheritdoc />
public bool IsMainWindowOpen => _lifeTime.MainWindow != null;
/// <inheritdoc />
public void OpenMainWindow()
{
if (_lifeTime.MainWindow == null)
{
SidebarViewModel = _sidebarVmFactory.SidebarViewModel(this);
_lifeTime.MainWindow = new MainWindow {DataContext = this};
_lifeTime.MainWindow.Show();
_lifeTime.MainWindow.Closed += CurrentMainWindowOnClosed;
}
_lifeTime.MainWindow.Activate();
OnMainWindowOpened();
}
/// <inheritdoc />
public void CloseMainWindow()
{
_lifeTime.MainWindow?.Close();
}
/// <inheritdoc />
public event EventHandler? MainWindowOpened;
/// <inheritdoc />
public event EventHandler? MainWindowClosed;
protected virtual void OnMainWindowOpened()
{
MainWindowOpened?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnMainWindowClosed()
{
MainWindowClosed?.Invoke(this, EventArgs.Empty);
}
#endregion
} }
} }

View File

@ -0,0 +1,32 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Root.SplashView"
Icon="/Assets/Images/Logo/bow.ico"
Title="Artemis 2.0"
Height="450"
Width="400"
CanResize="False"
WindowStartupLocation="CenterScreen"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaTitleBarHeightHint="450">
<Grid RowDefinitions="250,50,Auto,*" IsHitTestVisible="False">
<Image Grid.Column="0" Stretch="Uniform">
<Image.Source>
<svg:SvgImage Source="/Assets/Images/Logo/bow.svg" />
</Image.Source>
</Image>
<TextBlock Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
FontSize="16"
TextWrapping="Wrap">
Artemis is initializing...
</TextBlock>
<TextBlock Grid.Row="2" HorizontalAlignment="Center" Text="{Binding Status}" />
<ProgressBar Grid.Row="3" IsIndeterminate="True" Margin="16 0" />
</Grid>
</Window>

View File

@ -0,0 +1,33 @@
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using ReactiveUI;
namespace Artemis.UI.Screens.Root
{
public class SplashView : ReactiveWindow<SplashViewModel>
{
public SplashView()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
this.WhenActivated(disposables =>
{
Observable.FromEventPattern(x => ViewModel!.CoreService.Initialized += x, x => ViewModel!.CoreService.Initialized -= x)
.Subscribe(_ => Dispatcher.UIThread.Post(Close))
.DisposeWith(disposables);
});
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared;
using Humanizer;
using ReactiveUI;
namespace Artemis.UI.Screens.Root
{
public class SplashViewModel : ViewModelBase
{
private string _status;
public SplashViewModel(ICoreService coreService, IPluginManagementService pluginManagementService)
{
CoreService = coreService;
_status = "Initializing Core";
pluginManagementService.CopyingBuildInPlugins += OnPluginManagementServiceOnCopyingBuildInPluginsManagement;
pluginManagementService.PluginLoading += OnPluginManagementServiceOnPluginManagementLoading;
pluginManagementService.PluginLoaded += OnPluginManagementServiceOnPluginManagementLoaded;
pluginManagementService.PluginEnabling += PluginManagementServiceOnPluginManagementEnabling;
pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled;
pluginManagementService.PluginFeatureEnabling += PluginManagementServiceOnPluginFeatureEnabling;
pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureEnabled;
}
public ICoreService CoreService { get; }
public string Status
{
get => _status;
set => this.RaiseAndSetIfChanged(ref _status, value);
}
private void OnPluginManagementServiceOnPluginManagementLoaded(object? sender, PluginEventArgs args)
{
Status = "Initializing UI";
}
private void OnPluginManagementServiceOnPluginManagementLoading(object? sender, PluginEventArgs args)
{
Status = "Loading plugin: " + args.Plugin.Info.Name;
}
private void PluginManagementServiceOnPluginManagementEnabled(object? sender, PluginEventArgs args)
{
Status = "Initializing UI";
}
private void PluginManagementServiceOnPluginManagementEnabling(object? sender, PluginEventArgs args)
{
Status = "Enabling plugin: " + args.Plugin.Info.Name;
}
private void PluginManagementServiceOnPluginFeatureEnabling(object? sender, PluginFeatureEventArgs e)
{
Status = "Enabling: " + e.PluginFeature.GetType().Name.Humanize();
}
private void PluginManagementServiceOnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e)
{
Status = "Initializing UI";
}
private void OnPluginManagementServiceOnCopyingBuildInPluginsManagement(object? sender, EventArgs args)
{
Status = "Updating built-in plugins";
}
}
}

View File

@ -1,7 +1,14 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styling="clr-namespace:FluentAvalonia.Styling;assembly=FluentAvalonia"> xmlns:styling="clr-namespace:FluentAvalonia.Styling;assembly=FluentAvalonia">
<Styles.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="/ArtemisTrayIcon.axaml"/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="Warning">Yellow</SolidColorBrush>
</ResourceDictionary>
</Styles.Resources>
<!-- Third party styles --> <!-- Third party styles -->
<styling:FluentAvaloniaTheme RequestedTheme="Dark" /> <styling:FluentAvaloniaTheme RequestedTheme="Dark" />
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" /> <StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />