diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
index 61728d988..b1ea041c1 100644
--- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings
+++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
@@ -68,6 +68,7 @@
True
True
True
+ True
True
True
True
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
index 27418f2d1..e207c18eb 100644
--- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
+++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Reflection;
using Artemis.Core.Modules;
using Humanizer;
+using Newtonsoft.Json;
namespace Artemis.Core.DataModelExpansions
{
@@ -28,12 +29,14 @@ namespace Artemis.Core.DataModelExpansions
///
/// Gets the plugin feature this data model belongs to
///
+ [JsonIgnore]
[DataModelIgnore]
public DataModelPluginFeature Feature { get; internal set; }
///
/// Gets the describing this data model
///
+ [JsonIgnore]
[DataModelIgnore]
public DataModelPropertyAttribute DataModelDescription { get; internal set; }
diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs
index 853649b0b..0575a80ac 100644
--- a/src/Artemis.Core/Plugins/Plugin.cs
+++ b/src/Artemis.Core/Plugins/Plugin.cs
@@ -44,7 +44,6 @@ namespace Artemis.Core
///
public DirectoryInfo Directory { get; }
-
///
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
///
diff --git a/src/Artemis.Core/Plugins/PluginFeature.cs b/src/Artemis.Core/Plugins/PluginFeature.cs
index 733c3ee9b..b0e08554f 100644
--- a/src/Artemis.Core/Plugins/PluginFeature.cs
+++ b/src/Artemis.Core/Plugins/PluginFeature.cs
@@ -13,6 +13,11 @@ namespace Artemis.Core
private bool _isEnabled;
private Exception? _loadException;
+ ///
+ /// Gets the plugin feature info related to this feature
+ ///
+ public PluginFeatureInfo Info { get; internal set; } = null!; // Will be set right after construction
+
///
/// Gets the plugin that provides this feature
///
diff --git a/src/Artemis.Core/Plugins/PluginFeatureAttribute.cs b/src/Artemis.Core/Plugins/PluginFeatureAttribute.cs
new file mode 100644
index 000000000..0bb78fb75
--- /dev/null
+++ b/src/Artemis.Core/Plugins/PluginFeatureAttribute.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Artemis.Core
+{
+ ///
+ /// Represents an attribute that describes a plugin feature
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class PluginFeatureAttribute : Attribute
+ {
+ ///
+ /// Gets or sets the user-friendly name for this property, shown in the UI.
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// Gets or sets the user-friendly description for this property, shown in the UI.
+ ///
+ public string? Description { get; set; }
+
+ ///
+ /// The plugins display icon that's shown in the settings see for
+ /// available icons
+ ///
+ public string? Icon { get; set; }
+ }
+}
diff --git a/src/Artemis.Core/Plugins/PluginFeatureInfo.cs b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
new file mode 100644
index 000000000..7fe5a20de
--- /dev/null
+++ b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
@@ -0,0 +1,92 @@
+using Artemis.Core.DataModelExpansions;
+using Artemis.Core.DeviceProviders;
+using Artemis.Core.LayerBrushes;
+using Artemis.Core.LayerEffects;
+using Artemis.Core.Modules;
+using Humanizer;
+using Newtonsoft.Json;
+
+namespace Artemis.Core
+{
+ ///
+ /// Represents basic info about a plugin feature and contains a reference to the instance of said feature
+ ///
+ [JsonObject(MemberSerialization.OptIn)]
+ public class PluginFeatureInfo : CorePropertyChanged
+ {
+ private string? _description;
+ private string? _icon;
+ private string _name = null!;
+ private PluginFeature _pluginFeature = null!;
+
+ internal PluginFeatureInfo()
+ {
+ }
+
+ internal PluginFeatureInfo(PluginFeature instance, PluginFeatureAttribute? attribute)
+ {
+ Name = attribute?.Name ?? instance.GetType().Name.Humanize(LetterCasing.Title);
+ Description = attribute?.Description;
+ Icon = attribute?.Icon;
+ PluginFeature = instance;
+
+ if (Icon != null) return;
+ Icon = PluginFeature switch
+ {
+ BaseDataModelExpansion => "TableAdd",
+ DeviceProvider => "Devices",
+ ProfileModule => "VectorRectangle",
+ Module => "GearBox",
+ LayerBrushProvider => "Brush",
+ LayerEffectProvider => "AutoAwesome",
+ _ => "Plugin"
+ };
+ }
+
+ ///
+ /// The name of the plugin
+ ///
+ [JsonProperty(Required = Required.Always)]
+ public string Name
+ {
+ get => _name;
+ internal set => SetAndNotify(ref _name, value);
+ }
+
+ ///
+ /// A short description of the plugin
+ ///
+ [JsonProperty]
+ public string? Description
+ {
+ get => _description;
+ set => SetAndNotify(ref _description, value);
+ }
+
+ ///
+ /// The plugins display icon that's shown in the settings see for
+ /// available icons
+ ///
+ [JsonProperty]
+ public string? Icon
+ {
+ get => _icon;
+ set => SetAndNotify(ref _icon, value);
+ }
+
+ ///
+ /// Gets the plugin this info is associated with
+ ///
+ public PluginFeature PluginFeature
+ {
+ get => _pluginFeature;
+ internal set => SetAndNotify(ref _pluginFeature, value);
+ }
+
+ ///
+ public override string ToString()
+ {
+ return PluginFeature.Id;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index 39ef62b89..c15122d1d 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -9,6 +9,7 @@ using Artemis.Core.DeviceProviders;
using Artemis.Core.Ninject;
using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Repositories.Interfaces;
+using Humanizer;
using McMaster.NETCore.Plugins;
using Ninject;
using Ninject.Extensions.ChildKernel;
@@ -342,6 +343,10 @@ namespace Artemis.Core.Services
// Include Plugin as a parameter for the PluginSettingsProvider
IParameter[] parameters = {new Parameter("Plugin", plugin, false)};
PluginFeature instance = (PluginFeature) plugin.Kernel.Get(featureType, parameters);
+
+ // Get the PluginFeature attribute which contains extra info on the feature
+ PluginFeatureAttribute? pluginFeatureAttribute = (PluginFeatureAttribute?) Attribute.GetCustomAttribute(featureType, typeof(PluginFeatureAttribute));
+ instance.Info = new PluginFeatureInfo(instance, pluginFeatureAttribute);
plugin.AddFeature(instance);
// Load the enabled state and if not found, default to true
diff --git a/src/Artemis.Core/Services/WebServer/Controllers/PluginsController.cs b/src/Artemis.Core/Services/WebServer/Controllers/PluginsController.cs
deleted file mode 100644
index 7c4e8c29e..000000000
--- a/src/Artemis.Core/Services/WebServer/Controllers/PluginsController.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using EmbedIO;
-using EmbedIO.Routing;
-using EmbedIO.WebApi;
-
-namespace Artemis.Core.Services
-{
- internal class PluginsController : WebApiController
- {
- private readonly IWebServerService _webServerService;
-
- public PluginsController(IWebServerService webServerService)
- {
- _webServerService = webServerService;
- }
-
- [Route(HttpVerbs.Get, "/plugins/endpoints")]
- public IReadOnlyCollection GetPluginEndPoints()
- {
- return _webServerService.PluginsModule.PluginEndPoints;
- }
-
- [Route(HttpVerbs.Get, "/plugins/endpoints/{plugin}/{endPoint}")]
- public PluginEndPoint GetPluginEndPoint(Guid plugin, string endPoint)
- {
- PluginEndPoint? pluginEndPoint = _webServerService.PluginsModule.PluginEndPoints.FirstOrDefault(e => e.PluginFeature.Plugin.Guid == plugin && e.Name == endPoint);
- if (pluginEndPoint == null)
- throw HttpException.NotFound();
-
- return pluginEndPoint;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs
index 79f7959d7..41b3911de 100644
--- a/src/Artemis.Core/Services/WebServer/WebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs
@@ -52,8 +52,6 @@ namespace Artemis.Core.Services
.HandleHttpException((context, exception) => HandleHttpExceptionJson(context, exception))
.HandleUnhandledException(JsonExceptionHandlerCallback);
- // Add built-in core controllers to the API module
- apiModule.RegisterController(() => _kernel.Get());
// Add registered controllers to the API module
foreach (WebApiControllerRegistration registration in _controllers)
apiModule.RegisterController(registration.ControllerType, (Func) registration.UntypedFactory);
@@ -177,7 +175,8 @@ namespace Artemis.Core.Services
{
context.Response.ContentType = MimeType.Json;
await using TextWriter writer = context.OpenResponseText();
- await writer.WriteAsync(JsonConvert.SerializeObject(data));
+ string json = JsonConvert.SerializeObject(data, new JsonSerializerSettings {PreserveReferencesHandling = PreserveReferencesHandling.Objects});
+ await writer.WriteAsync(json);
}
private async Task HandleHttpExceptionJson(IHttpContext context, IHttpException httpException)
diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs
index 446cba8cb..5544c2307 100644
--- a/src/Artemis.UI/Bootstrapper.cs
+++ b/src/Artemis.UI/Bootstrapper.cs
@@ -87,8 +87,9 @@ namespace Artemis.UI
}
});
- Kernel.Get().RegisterInputProvider();
- Kernel.Get();
+ IRegistrationService registrationService = Kernel.Get();
+ registrationService.RegisterInputProvider();
+ registrationService.RegisterControllers();
}
protected override void ConfigureIoC(IKernel kernel)
diff --git a/src/Artemis.UI/Services/RemoteManagement/RemoteController.cs b/src/Artemis.UI/Controllers/RemoteController.cs
similarity index 96%
rename from src/Artemis.UI/Services/RemoteManagement/RemoteController.cs
rename to src/Artemis.UI/Controllers/RemoteController.cs
index a39468924..2c8c793d5 100644
--- a/src/Artemis.UI/Services/RemoteManagement/RemoteController.cs
+++ b/src/Artemis.UI/Controllers/RemoteController.cs
@@ -5,7 +5,7 @@ using EmbedIO;
using EmbedIO.Routing;
using EmbedIO.WebApi;
-namespace Artemis.UI.Services
+namespace Artemis.UI.Controllers
{
public class RemoteController : WebApiController
{
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabView.xaml
index f7c14eebf..9f0564084 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabView.xaml
@@ -59,6 +59,28 @@
+
+
+
+
+
+
+
+
+
+
+ Startup delay
+
+ Set the amount of seconds to wait before running Artemis with Windows.
+ If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value.
+
+
+
+
+
+
+
+
@@ -89,62 +111,14 @@
-
- Setup wizard
-
- Opens the startup wizard usually shown when Artemis first starts.
+
+ Log level
+
+ Sets the logging level, a higher logging level will result in more log files.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Debugger
-
- Use the debugger to see the raw image Artemis is rendering on the surface.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Application files
-
- Opens the directory where application files like plugins and settings are stored.
-
-
-
-
+
@@ -170,28 +144,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Log level
-
- Sets the logging level, a higher logging level will result in more log files.
-
-
-
-
-
-
-
@@ -418,6 +370,82 @@
+
+
+
+ Tools
+
+
+
+
+
+
+
+
+
+
+
+
+ Setup wizard
+
+ Opens the startup wizard usually shown when Artemis first starts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Debugger
+
+ Use the debugger to see the raw image Artemis is rendering on the surface.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Application files
+
+ Opens the directory where application files like plugins and settings are stored.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs
index 9318f27f8..21a54084c 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs
@@ -125,7 +125,19 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
_settingsService.GetSetting("UI.AutoRun", false).Value = value;
_settingsService.GetSetting("UI.AutoRun", false).Save();
NotifyOfPropertyChange(nameof(StartWithWindows));
- Task.Run(ApplyAutorun);
+ Task.Run(() => ApplyAutorun(false));
+ }
+ }
+
+ public int AutoRunDelay
+ {
+ get => _settingsService.GetSetting("UI.AutoRunDelay", 15).Value;
+ set
+ {
+ _settingsService.GetSetting("UI.AutoRunDelay", 15).Value = value;
+ _settingsService.GetSetting("UI.AutoRunDelay", 15).Save();
+ NotifyOfPropertyChange(nameof(AutoRunDelay));
+ Task.Run(() => ApplyAutorun(true));
}
}
@@ -293,11 +305,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
protected override void OnInitialActivate()
{
- Task.Run(ApplyAutorun);
+ Task.Run(() => ApplyAutorun(false));
base.OnInitialActivate();
}
- private void ApplyAutorun()
+ private void ApplyAutorun(bool recreate)
{
if (!StartWithWindows)
StartMinimized = false;
@@ -307,23 +319,29 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
if (File.Exists(autoRunFile))
File.Delete(autoRunFile);
+ // TODO: Don't do anything if running a development build, only auto-run release builds
+
// Create or remove the task if necessary
try
{
- Process schtasks = new()
+ bool taskCreated = false;
+ if (!recreate)
{
- StartInfo =
+ Process schtasks = new()
{
- WindowStyle = ProcessWindowStyle.Hidden,
- UseShellExecute = true,
- FileName = Path.Combine(Environment.SystemDirectory, "schtasks.exe"),
- Arguments = "/TN \"Artemis 2 autorun\""
- }
- };
+ StartInfo =
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ UseShellExecute = true,
+ FileName = Path.Combine(Environment.SystemDirectory, "schtasks.exe"),
+ Arguments = "/TN \"Artemis 2 autorun\""
+ }
+ };
- schtasks.Start();
- schtasks.WaitForExit();
- bool taskCreated = schtasks.ExitCode == 0;
+ schtasks.Start();
+ schtasks.WaitForExit();
+ taskCreated = schtasks.ExitCode == 0;
+ }
if (StartWithWindows && !taskCreated)
CreateAutoRunTask();
@@ -347,6 +365,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
task.Descendants().First(d => d.Name.LocalName == "RegistrationInfo").Descendants().First(d => d.Name.LocalName == "Author")
.SetValue(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
+ task.Descendants().First(d => d.Name.LocalName == "Triggers").Descendants().First(d => d.Name.LocalName == "LogonTrigger").Descendants().First(d => d.Name.LocalName == "Delay")
+ .SetValue(TimeSpan.FromSeconds(AutoRunDelay));
+
task.Descendants().First(d => d.Name.LocalName == "Principals").Descendants().First(d => d.Name.LocalName == "Principal").Descendants().First(d => d.Name.LocalName == "UserId")
.SetValue(System.Security.Principal.WindowsIdentity.GetCurrent().User.Value);
@@ -369,7 +390,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
UseShellExecute = true,
Verb = "runas",
FileName = Path.Combine(Environment.SystemDirectory, "schtasks.exe"),
- Arguments = $"/Create /XML \"{xmlPath}\" /tn \"Artemis 2 autorun\""
+ Arguments = $"/Create /XML \"{xmlPath}\" /tn \"Artemis 2 autorun\" /F"
}
};
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml
index 9e88a2346..eb8f06d5f 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml
@@ -7,6 +7,7 @@
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
+ xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:PluginFeatureViewModel}">
@@ -21,8 +22,9 @@
-
@@ -40,7 +42,7 @@
-
+
Feature.GetType().Name.Humanize();
-
public Exception LoadException => Feature.LoadException;
public bool Enabling
@@ -109,7 +97,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
catch (Exception e)
{
- _messageService.ShowMessage($"Failed to enable {Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
+ _messageService.ShowMessage($"Failed to enable {Feature.Info.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
}
finally
{
@@ -123,20 +111,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
}
- private PackIconKind GetIconKind()
- {
- return Feature switch
- {
- BaseDataModelExpansion => PackIconKind.TableAdd,
- DeviceProvider => PackIconKind.Devices,
- ProfileModule => PackIconKind.VectorRectangle,
- Module => PackIconKind.GearBox,
- LayerBrushProvider => PackIconKind.Brush,
- LayerEffectProvider => PackIconKind.AutoAwesome,
- _ => PackIconKind.Plugin
- };
- }
-
#region Event handlers
private void OnFeatureEnabling(object sender, PluginFeatureEventArgs e)
diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs
index 6ae335bf4..c6c80e900 100644
--- a/src/Artemis.UI/Services/RegistrationService.cs
+++ b/src/Artemis.UI/Services/RegistrationService.cs
@@ -1,6 +1,7 @@
using System.Linq;
using Artemis.Core;
using Artemis.Core.Services;
+using Artemis.UI.Controllers;
using Artemis.UI.DefaultTypes.DataModel.Display;
using Artemis.UI.DefaultTypes.DataModel.Input;
using Artemis.UI.InputProviders;
@@ -19,6 +20,7 @@ namespace Artemis.UI.Services
private readonly IPluginManagementService _pluginManagementService;
private readonly ISurfaceService _surfaceService;
private readonly IInputService _inputService;
+ private readonly IWebServerService _webServerService;
private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs;
private bool _registeredBuiltInPropertyEditors;
@@ -28,7 +30,8 @@ namespace Artemis.UI.Services
IProfileEditorService profileEditorService,
IPluginManagementService pluginManagementService,
ISurfaceService surfaceService,
- IInputService inputService)
+ IInputService inputService,
+ IWebServerService webServerService)
{
_logger = logger;
_dataModelUIService = dataModelUIService;
@@ -36,6 +39,7 @@ namespace Artemis.UI.Services
_pluginManagementService = pluginManagementService;
_surfaceService = surfaceService;
_inputService = inputService;
+ _webServerService = webServerService;
LoadPluginModules();
pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling;
@@ -91,6 +95,11 @@ namespace Artemis.UI.Services
_inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService));
}
+ public void RegisterControllers()
+ {
+ _webServerService.AddController();
+ }
+
private void PluginServiceOnPluginEnabling(object sender, PluginEventArgs e)
{
e.Plugin.Kernel.Load(new[] {new PluginUIModule(e.Plugin)});
@@ -109,5 +118,6 @@ namespace Artemis.UI.Services
void RegisterBuiltInDataModelInputs();
void RegisterBuiltInPropertyEditors();
void RegisterInputProvider();
+ void RegisterControllers();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Services/RemoteManagement/Interfaces/IRemoteManagementService.cs b/src/Artemis.UI/Services/RemoteManagement/Interfaces/IRemoteManagementService.cs
deleted file mode 100644
index 25cafb0d3..000000000
--- a/src/Artemis.UI/Services/RemoteManagement/Interfaces/IRemoteManagementService.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Artemis.UI.Services
-{
- public interface IRemoteManagementService : IArtemisUIService
- {
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.UI/Services/RemoteManagement/RemoteManagementService.cs b/src/Artemis.UI/Services/RemoteManagement/RemoteManagementService.cs
deleted file mode 100644
index 956e8a474..000000000
--- a/src/Artemis.UI/Services/RemoteManagement/RemoteManagementService.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using Artemis.Core.Services;
-
-namespace Artemis.UI.Services
-{
- public class RemoteManagementService : IRemoteManagementService
- {
- public RemoteManagementService(IWebServerService webServerService)
- {
- webServerService.AddController();
- }
- }
-}
\ No newline at end of file