diff --git a/src/Artemis.Core/Extensions/IEnumerableExtensions.cs b/src/Artemis.Core/Extensions/IEnumerableExtensions.cs new file mode 100644 index 000000000..c4c0363a4 --- /dev/null +++ b/src/Artemis.Core/Extensions/IEnumerableExtensions.cs @@ -0,0 +1,92 @@ +// I don't want all of MoreLINQ (https://github.com/morelinq/MoreLINQ) so we'll borrow just this + +#region License and Terms + +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2008 Jonathan Skeet. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System; +using System.Collections.Generic; + +namespace Artemis.Core.Extensions +{ + public static class IEnumerableExtensions + { + /// + /// Returns all distinct elements of the given source, where "distinctness" + /// is determined via a projection and the default equality comparer for the projected type. + /// + /// + /// This operator uses deferred execution and streams the results, although + /// a set of already-seen keys is retained. If a key is seen multiple times, + /// only the first element with that key is returned. + /// + /// Type of the source sequence + /// Type of the projected element + /// Source sequence + /// Projection for determining "distinctness" + /// + /// A sequence consisting of distinct elements from the source sequence, + /// comparing them by the specified key projection. + /// + public static IEnumerable DistinctBy(this IEnumerable source, + Func keySelector) + { + return source.DistinctBy(keySelector, null); + } + + /// + /// Returns all distinct elements of the given source, where "distinctness" + /// is determined via a projection and the specified comparer for the projected type. + /// + /// + /// This operator uses deferred execution and streams the results, although + /// a set of already-seen keys is retained. If a key is seen multiple times, + /// only the first element with that key is returned. + /// + /// Type of the source sequence + /// Type of the projected element + /// Source sequence + /// Projection for determining "distinctness" + /// + /// The equality comparer to use to determine whether or not keys are equal. + /// If null, the default equality comparer for TSource is used. + /// + /// + /// A sequence consisting of distinct elements from the source sequence, + /// comparing them by the specified key projection. + /// + public static IEnumerable DistinctBy(this IEnumerable source, + Func keySelector, IEqualityComparer comparer) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); + + return _(); + + IEnumerable _() + { + var knownKeys = new HashSet(comparer); + foreach (var element in source) + { + if (knownKeys.Add(keySelector(element))) + yield return element; + } + } + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Abstract/DeviceProvider.cs b/src/Artemis.Core/Plugins/Abstract/DeviceProvider.cs index 2c1becd98..6c0db6ef4 100644 --- a/src/Artemis.Core/Plugins/Abstract/DeviceProvider.cs +++ b/src/Artemis.Core/Plugins/Abstract/DeviceProvider.cs @@ -3,7 +3,9 @@ using System.Diagnostics; using System.IO; using Artemis.Core.Extensions; using Artemis.Core.Plugins.Models; +using Ninject; using RGB.NET.Core; +using Serilog; namespace Artemis.Core.Plugins.Abstract { @@ -20,6 +22,8 @@ namespace Artemis.Core.Plugins.Abstract public IRGBDeviceProvider RgbDeviceProvider { get; } + [Inject] + public ILogger Logger { get; set; } protected void ResolveAbsolutePath(Type type, object sender, ResolvePathEventArgs e) { @@ -30,7 +34,24 @@ namespace Artemis.Core.Plugins.Abstract e.FinalPath = Path.Combine(PluginInfo.Directory.FullName, e.RelativePart, e.FileName); else if (e.RelativePath != null) e.FinalPath = Path.Combine(PluginInfo.Directory.FullName, e.RelativePath); + + var deviceInfo = ((IRGBDevice) sender).DeviceInfo; + if (e.FileName != null && !File.Exists(e.FinalPath)) + { + Logger?.Information("Couldn't find a layout for device {deviceName}, model {deviceModel} at {filePath}", + deviceInfo.DeviceName, deviceInfo.Model, e.FinalPath); + } } } + + public override void Dispose() + { + // Does not happen with device providers, they require Artemis to restart + } + + public override void DisablePlugin() + { + // Does not happen with device providers, they require Artemis to restart + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Models/PluginInfo.cs b/src/Artemis.Core/Plugins/Models/PluginInfo.cs index 413085ae9..d129d93ab 100644 --- a/src/Artemis.Core/Plugins/Models/PluginInfo.cs +++ b/src/Artemis.Core/Plugins/Models/PluginInfo.cs @@ -31,6 +31,12 @@ namespace Artemis.Core.Plugins.Models /// public string Description { get; set; } + /// + /// The plugins display icon that's shown in the settings see for available + /// icons + /// + public string Icon { get; set; } + /// /// The version of the plugin /// @@ -78,7 +84,7 @@ namespace Artemis.Core.Plugins.Models /// [JsonIgnore] internal PluginEntity PluginEntity { get; set; } - + public override string ToString() { return $"{nameof(Guid)}: {Guid}, {nameof(Name)}: {Name}, {nameof(Version)}: {Version}"; diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginService.cs index 8d26c122a..d8ce410a7 100644 --- a/src/Artemis.Core/Services/PluginService.cs +++ b/src/Artemis.Core/Services/PluginService.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Windows; using Artemis.Core.Events; using Artemis.Core.Exceptions; using Artemis.Core.Extensions; @@ -10,6 +12,7 @@ using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Exceptions; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; +using Artemis.Core.Utilities; using Artemis.Storage.Entities.Plugins; using Artemis.Storage.Repositories.Interfaces; using McMaster.NETCore.Plugins; @@ -219,7 +222,7 @@ namespace Artemis.Core.Services var pluginEntity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid); if (pluginEntity == null) pluginEntity = new PluginEntity {PluginGuid = pluginInfo.Guid, IsEnabled = true, LastEnableSuccessful = true}; - + pluginInfo.PluginEntity = pluginEntity; pluginInfo.Enabled = pluginEntity.IsEnabled; @@ -332,7 +335,7 @@ namespace Artemis.Core.Services plugin.PluginInfo.PluginEntity.LastEnableSuccessful = true; _pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity); } - + OnPluginEnabled(new PluginEventArgs(plugin.PluginInfo)); } @@ -342,11 +345,15 @@ namespace Artemis.Core.Services plugin.PluginInfo.PluginEntity.IsEnabled = false; _pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity); + // Device providers cannot be disabled at runtime, restart the application + if (plugin is DeviceProvider) + { + CurrentProcessUtilities.RestartSelf(); + return; + } + plugin.DisablePlugin(); - - // We got this far so the plugin enabled and we didn't crash horribly, yay - _pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity); - + OnPluginDisabled(new PluginEventArgs(plugin.PluginInfo)); } diff --git a/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs b/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs new file mode 100644 index 000000000..a549c4b4f --- /dev/null +++ b/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs @@ -0,0 +1,27 @@ +using System.Diagnostics; +using System.Windows; +using Stylet; + +namespace Artemis.Core.Utilities +{ + public static class CurrentProcessUtilities + { + public static string GetCurrentLocation() + { + return Process.GetCurrentProcess().MainModule.FileName; + } + + public static void RestartSelf() + { + var info = new ProcessStartInfo + { + Arguments = "/C choice /C Y /N /D Y /T 5 & START /wait taskkill /f /im \"Artemis.UI.exe\" & START \"\" \"" + GetCurrentLocation() + "\"", + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true, + FileName = "cmd.exe" + }; + Process.Start(info); + Execute.OnUIThread(() => Application.Current.Shutdown()); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs index 145502cf9..3d6a3def7 100644 --- a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs +++ b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs @@ -100,12 +100,19 @@ namespace Artemis.UI.Shared.Services.Dialog private async Task ShowDialog(string identifier, DialogViewModelBase viewModel) { - var view = _viewManager.CreateViewForModel(viewModel); - _viewManager.BindViewToModel(view, viewModel); + Task result = null; + await Execute.OnUIThreadAsync(() => + { + var view = _viewManager.CreateViewForModel(viewModel); + _viewManager.BindViewToModel(view, viewModel); + + if (identifier == null) + result = DialogHost.Show(view, viewModel.OnDialogOpened, viewModel.OnDialogClosed); + else + result = DialogHost.Show(view, identifier, viewModel.OnDialogOpened, viewModel.OnDialogClosed); + }); - if (identifier == null) - return await DialogHost.Show(view, viewModel.OnDialogOpened, viewModel.OnDialogClosed); - return await DialogHost.Show(view, identifier, viewModel.OnDialogOpened, viewModel.OnDialogClosed); + return await result; } } } \ No newline at end of file diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs index 404236c5f..840588978 100644 --- a/src/Artemis.UI/Bootstrapper.cs +++ b/src/Artemis.UI/Bootstrapper.cs @@ -93,7 +93,14 @@ namespace Artemis.UI logger.Fatal(e.Exception, "Unhandled exception"); var dialogService = Kernel.Get(); - dialogService.ShowExceptionDialog("Artemis encountered an error", e.Exception); + try + { + dialogService.ShowExceptionDialog("Artemis encountered an error", e.Exception); + } + catch (Exception) + { + // We did our best eh.. trap exceptions during exception display here to avoid an infinite loop + } // Don't shut down, is that a good idea? Depends on the exception of course.. e.Handled = true; diff --git a/src/Artemis.UI/Screens/Settings/SettingsView.xaml b/src/Artemis.UI/Screens/Settings/SettingsView.xaml index 51470170b..2eb391a49 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsView.xaml +++ b/src/Artemis.UI/Screens/Settings/SettingsView.xaml @@ -225,56 +225,28 @@ - - The list below shows all loaded plugins. If you're missing something, view your logs folder. - - - - - - - - - - - - - - - - - - - - - - - + + + The list below shows all loaded plugins. If you're missing something, view your logs folder. + + + + + + + + + + + + + + - - Below you view and manage the devices that were detected by Artemis - + + + Below you view and manage the devices that were detected by Artemis @@ -287,8 +259,8 @@ - - + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs index 38cdec0ec..0ff156fba 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs @@ -10,6 +10,7 @@ using Artemis.Core.Plugins.Abstract; using Artemis.Core.Services; using Artemis.Core.Services.Interfaces; using Artemis.Core.Services.Storage.Interfaces; +using Artemis.Core.Utilities; using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.Settings.Debug; using Artemis.UI.Screens.Settings.Tabs.Devices; @@ -205,7 +206,7 @@ namespace Artemis.UI.Screens.Settings try { var autoRunFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "Artemis.lnk"); - var executableFile = Process.GetCurrentProcess().MainModule.FileName; + var executableFile = CurrentProcessUtilities.GetCurrentLocation(); if (File.Exists(autoRunFile)) File.Delete(autoRunFile); diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsView.xaml index f46687665..45f33c9f0 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsView.xaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsView.xaml @@ -41,8 +41,8 @@ - - + + - diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml new file mode 100644 index 000000000..46988ad48 --- /dev/null +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Plugin enabled + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml.cs new file mode 100644 index 000000000..432ca670c --- /dev/null +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Artemis.UI.Screens.Settings.Tabs.Plugins +{ + /// + /// Interaction logic for PluginSettingsView.xaml + /// + public partial class PluginSettingsView : UserControl + { + public PluginSettingsView() + { + InitializeComponent(); + } + } +} diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs index 550f06689..ee9e09929 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs @@ -1,8 +1,11 @@ using System; using System.Threading.Tasks; using Artemis.Core.Plugins.Abstract; +using Artemis.Core.Plugins.LayerBrush; +using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; using Artemis.UI.Shared.Services.Interfaces; +using MaterialDesignThemes.Wpf; using Stylet; namespace Artemis.UI.Screens.Settings.Tabs.Plugins @@ -10,36 +13,65 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins public class PluginSettingsViewModel : PropertyChangedBase { private readonly IDialogService _dialogService; - private readonly Plugin _plugin; private readonly IPluginService _pluginService; private readonly IWindowManager _windowManager; public PluginSettingsViewModel(Plugin plugin, IWindowManager windowManager, IDialogService dialogService, IPluginService pluginService) { - _plugin = plugin; + Plugin = plugin; + PluginInfo = plugin.PluginInfo; + _windowManager = windowManager; _dialogService = dialogService; _pluginService = pluginService; } - public string Type => _plugin.GetType().BaseType?.Name ?? _plugin.GetType().Name; - public string Name => _plugin.PluginInfo.Name; - public string Description => _plugin.PluginInfo.Description; - public Version Version => _plugin.PluginInfo.Version; + public Plugin Plugin { get; set; } + public PluginInfo PluginInfo { get; set; } + + public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name; + + public PackIconKind Icon => GetIconKind(); + + private PackIconKind GetIconKind() + { + if (PluginInfo.Icon != null) + { + var parsedIcon = Enum.TryParse(PluginInfo.Icon, true, out var iconEnum); + if (parsedIcon == false) + return PackIconKind.QuestionMarkCircle; + } + + switch (Plugin) + { + case DataModelExpansion _: + return PackIconKind.TableAdd; + case DeviceProvider _: + return PackIconKind.Devices; + case ProfileModule _: + return PackIconKind.VectorRectangle; + case Core.Plugins.Abstract.Module _: + return PackIconKind.GearBox; + case LayerBrushProvider _: + return PackIconKind.Brush; + } + + return PackIconKind.Plugin; + } public bool IsEnabled { - get => _plugin.PluginInfo.Enabled; + get => PluginInfo.Enabled; set => Task.Run(() => UpdateEnabled(value)); } - public bool CanOpenSettings => IsEnabled && _plugin.HasConfigurationViewModel; + public bool CanOpenSettings => IsEnabled && Plugin.HasConfigurationViewModel; public async Task OpenSettings() { try { - var configurationViewModel = _plugin.GetConfigurationViewModel(); + var configurationViewModel = Plugin.GetConfigurationViewModel(); if (configurationViewModel != null) _windowManager.ShowDialog(new PluginSettingsWindowViewModel(configurationViewModel)); } @@ -50,15 +82,33 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins } } - private void UpdateEnabled(in bool enable) + private async Task UpdateEnabled(bool enable) { - if (_plugin.PluginInfo.Enabled == enable) + if (PluginInfo.Enabled == enable) + { + NotifyOfPropertyChange(() => IsEnabled); return; + } + + if (!enable && Plugin is DeviceProvider) + { + var confirm = await _dialogService.ShowConfirmDialog( + "Disable device provider", + "You are disabling a device provider, this requires that Artemis restarts, please confirm." + ); + if (!confirm) + { + NotifyOfPropertyChange(() => IsEnabled); + return; + } + } if (enable) - _pluginService.EnablePlugin(_plugin); + _pluginService.EnablePlugin(Plugin); else - _pluginService.DisablePlugin(_plugin); + _pluginService.DisablePlugin(Plugin); + + NotifyOfPropertyChange(() => IsEnabled); } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Asus/AsusDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Asus/AsusDeviceProvider.cs index 30db6dfad..f2bd5d9d9 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Asus/AsusDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Asus/AsusDeviceProvider.cs @@ -21,17 +21,5 @@ namespace Artemis.Plugins.Devices.Asus PathHelper.ResolvingAbsolutePath += (sender, args) => ResolveAbsolutePath(typeof(AsusRGBDevice<>), sender, args); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // AsusDeviceProvider.Instance.ResetDevices(); - // AsusDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Asus/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Asus/plugin.json index d66dbe00d..a6dcf96e2 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Asus/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Asus/plugin.json @@ -1,6 +1,7 @@ { "Guid": "c20e876f-7cb0-4fa1-b0cc-ae1afb5865d1", "Name": "Asus Devices", + "Description": "Allows Artemis to control lighting on different ASUS devices such as motherboards, GPUs, headsets, RAM, keyboards and PC cases.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Asus.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs index d3ae2747e..4b4c30871 100644 --- a/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; @@ -24,17 +25,5 @@ namespace Artemis.Plugins.Devices.CoolerMaster RGB.NET.Devices.CoolerMaster.CoolerMasterDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "CMSDK.dll")); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // CoolerMasterDeviceProvider.Instance.ResetDevices(); - // CoolerMasterDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/plugin.json b/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/plugin.json index 1d8cf427f..9461d368b 100644 --- a/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.CoolerMaster/plugin.json @@ -1,6 +1,7 @@ { "Guid": "b78f644b-827f-4bb4-bf03-2adaa365b58b", "Name": "CoolerMaster Devices", + "Description": "Allows Artemis to control the lighting on CoolerMaster mice and keyboards.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.CoolerMaster.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs index fe5d257c6..d51c8f0ca 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs @@ -24,16 +24,5 @@ namespace Artemis.Plugins.Devices.Corsair RGB.NET.Devices.Corsair.CorsairDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "CUESDK_2017.dll")); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // CorsairDeviceProvider.Instance.ResetDevices(); - // CorsairDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Corsair/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Corsair/plugin.json index 4e455fd0c..cc05b35ed 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Corsair/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Corsair/plugin.json @@ -1,6 +1,7 @@ { "Guid": "926629ab-8170-42f3-be18-22c694aa91cd", "Name": "Corsair Devices", + "Description": "Allows Artemis to control lighting on all iCUE enabled Corsair products", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Corsair.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.DMX/DMXDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.DMX/DMXDeviceProvider.cs index 61f3047bd..b4c1a4c2c 100644 --- a/src/Plugins/Artemis.Plugins.Devices.DMX/DMXDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.DMX/DMXDeviceProvider.cs @@ -24,18 +24,6 @@ namespace Artemis.Plugins.Devices.DMX _rgbService.AddDeviceProvider(RgbDeviceProvider); } - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // DMXDeviceProvider.Instance.ResetDevices(); - // DMXDeviceProvider.Instance.Dispose(); - } - public override PluginConfigurationViewModel GetConfigurationViewModel() { return new DMXConfigurationViewModel(this); diff --git a/src/Plugins/Artemis.Plugins.Devices.DMX/plugin.json b/src/Plugins/Artemis.Plugins.Devices.DMX/plugin.json index d4270e256..9a90d4ce6 100644 --- a/src/Plugins/Artemis.Plugins.Devices.DMX/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.DMX/plugin.json @@ -1,6 +1,7 @@ { "Guid": "6f073d4d-d97d-4040-9750-841fdbe06915", "Name": "DMX Devices", + "Description": "Allows Artemis to control lighting on DMX controllers via a COM port.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.DMX.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Logitech/LogitechDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Logitech/LogitechDeviceProvider.cs index 1073c4c9a..d0924afdd 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Logitech/LogitechDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Logitech/LogitechDeviceProvider.cs @@ -1,5 +1,6 @@ using System.IO; using System.Linq; +using Artemis.Core.Extensions; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; @@ -33,18 +34,10 @@ namespace Artemis.Plugins.Devices.Logitech if (_logger.IsEnabled(LogEventLevel.Debug)) LogDeviceIds(); } - - public override void DisablePlugin() - { - } - - public override void Dispose() - { - } - + private void LogDeviceIds() { - var devices = DeviceList.Local.GetHidDevices(VENDOR_ID).ToList(); + var devices = DeviceList.Local.GetHidDevices(VENDOR_ID).DistinctBy(d => d.ProductID).ToList(); _logger.Debug("Found {count} Logitech device(s)", devices.Count); foreach (var hidDevice in devices) _logger.Debug("Found Logitech device {name} with PID {pid}", hidDevice.GetFriendlyName(), hidDevice.ProductID); diff --git a/src/Plugins/Artemis.Plugins.Devices.Logitech/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Logitech/plugin.json index 4680d7fed..008a23377 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Logitech/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Logitech/plugin.json @@ -1,6 +1,7 @@ { "Guid": "62a45c0c-884c-4868-9fd7-3c5987fe07ca", "Name": "Logitech Devices", + "Description": "Allows Artemis to control the lighting on Logitech mice and keyboards.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Logitech.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Msi/MsiDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Msi/MsiDeviceProvider.cs index f04102a0a..aa51d1e9e 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Msi/MsiDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Msi/MsiDeviceProvider.cs @@ -24,17 +24,5 @@ namespace Artemis.Plugins.Devices.Msi RGB.NET.Devices.Msi.MsiDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "MysticLight_SDK.dll")); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // MsiDeviceProvider.Instance.ResetDevices(); - // MsiDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Msi/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Msi/plugin.json index a3d2ea984..40663b7a7 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Msi/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Msi/plugin.json @@ -1,6 +1,7 @@ { "Guid": "9177c320-1206-48a3-af52-b1749c758786", - "Name": "Msi Devices", + "Name": "MSI Devices", + "Description": "Allows Artemis to control the lighting on MSI GPUs and motherboards.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Msi.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Novation/Artemis.Plugins.Devices.Novation.csproj b/src/Plugins/Artemis.Plugins.Devices.Novation/Artemis.Plugins.Devices.Novation.csproj index 90e20d376..4d5f02ce7 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Novation/Artemis.Plugins.Devices.Novation.csproj +++ b/src/Plugins/Artemis.Plugins.Devices.Novation/Artemis.Plugins.Devices.Novation.csproj @@ -28,6 +28,11 @@ PreserveNewest + + + NU1701 + + false diff --git a/src/Plugins/Artemis.Plugins.Devices.Novation/Images/Novation/Launchpads/LaunchpadMini.png b/src/Plugins/Artemis.Plugins.Devices.Novation/Images/Novation/Launchpads/LaunchpadMini.png new file mode 100644 index 000000000..871523c11 Binary files /dev/null and b/src/Plugins/Artemis.Plugins.Devices.Novation/Images/Novation/Launchpads/LaunchpadMini.png differ diff --git a/src/Plugins/Artemis.Plugins.Devices.Novation/Layouts/Novation/Launchpads/LaunchpadMini.xml b/src/Plugins/Artemis.Plugins.Devices.Novation/Layouts/Novation/Launchpads/LaunchpadMini.xml new file mode 100644 index 000000000..6f135df16 --- /dev/null +++ b/src/Plugins/Artemis.Plugins.Devices.Novation/Layouts/Novation/Launchpads/LaunchpadMini.xml @@ -0,0 +1,412 @@ + + + Launchpad Mini + Launchpad Mini (8x8-Pad Grid) + LedMatrix + Key + Novation + Launchpad S + 185 + 185 + 14 + 14 + Images\Novation\Launchpads + LaunchpadMini.png + + + Circle + 16 + 18 + 10mm + 10mm + + + Circle + +8 + 10mm + 10mm + + + Circle + +8 + 10mm + 10mm + + + Circle + +8 + 10mm + 10mm + + + Circle + +8 + 10mm + 10mm + + + Circle + +8 + 10mm + 10mm + + + Circle + +8 + 10mm + 10mm + + + Circle + +8 + 10mm + 10mm + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + 14 + +4 + + + +4 + + + +4 + + + M0,0 L0,1 L0.75,1 L1,0.75 L1,0 Z + +4 + + + M0,0 L0,0.75 L0.25,1 L1,1 L1,0 Z + +4 + + + +4 + + + +4 + + + +4 + + + 14 + +4 + + + +4 + + + +4 + + + M0,0 L0,1 L1,1 L1,0.25 L0.75,0 Z + +4 + + + M0,0.25 L0,1 L1,1 L1,0 L0.25,0 Z + +4 + + + +4 + + + +4 + + + +4 + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + Circle + +4 + 34 + 10mm + 10mm + + + Circle + ~ + +8 + 10mm + 10mm + + + Circle + ~ + +8 + 10mm + 10mm + + + Circle + ~ + +8 + 10mm + 10mm + + + Circle + ~ + +8 + 10mm + 10mm + + + Circle + ~ + +8 + 10mm + 10mm + + + Circle + ~ + +8 + 10mm + 10mm + + + Circle + ~ + +8 + 10mm + 10mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Novation/NovationDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Novation/NovationDeviceProvider.cs index c1b0879c5..d5c794cfd 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Novation/NovationDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Novation/NovationDeviceProvider.cs @@ -21,17 +21,5 @@ namespace Artemis.Plugins.Devices.Novation PathHelper.ResolvingAbsolutePath += (sender, args) => ResolveAbsolutePath(typeof(NovationRGBDevice<>), sender, args); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // NovationDeviceProvider.Instance.ResetDevices(); - // NovationDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Novation/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Novation/plugin.json index 3b52164dc..b79a3b965 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Novation/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Novation/plugin.json @@ -1,6 +1,7 @@ { "Guid": "a487332f-c4b3-43e7-b80f-f33adc6fff87", "Name": "Novation Devices", + "Description": "Allows Artemis to control the lighting on Novation launchpads.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Novation.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Razer/RazerDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Razer/RazerDeviceProvider.cs index bdb8fe98d..2ce9c157a 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Razer/RazerDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Razer/RazerDeviceProvider.cs @@ -24,17 +24,5 @@ namespace Artemis.Plugins.Devices.Razer RGB.NET.Devices.Razer.RazerDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "RzChromaSDK.dll")); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // RazerDeviceProvider.Instance.ResetDevices(); - // RazerDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Razer/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Razer/plugin.json index 5fc2496a0..d606ddf3e 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Razer/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Razer/plugin.json @@ -1,6 +1,7 @@ { "Guid": "58a3d80e-d5cb-4a40-9465-c0a5d54825d6", "Name": "Razer Devices", + "Description": "Allows Artemis to control lighting on all Synapse enabled Razer products", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Razer.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Roccat/RoccatDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Roccat/RoccatDeviceProvider.cs index 27775661d..68449dad9 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Roccat/RoccatDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Roccat/RoccatDeviceProvider.cs @@ -25,17 +25,5 @@ namespace Artemis.Plugins.Devices.Roccat RGB.NET.Devices.Roccat.RoccatDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "RoccatTalkSDKWrapper.dll")); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // RoccatDeviceProvider.Instance.ResetDevices(); - // RoccatDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Roccat/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Roccat/plugin.json index b10a350b7..f75f381fc 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Roccat/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Roccat/plugin.json @@ -1,6 +1,7 @@ { "Guid": "10049953-94c1-4102-988b-9e4f0b64c232", "Name": "Roccat Devices", + "Description": "Not yet implemented, sorry!", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Roccat.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj index 30a16321d..b2913659d 100644 --- a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj +++ b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj @@ -20,6 +20,9 @@ PreserveNewest + + + false diff --git a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/SteelSeriesDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/SteelSeriesDeviceProvider.cs index 7f6cec433..f406829a7 100644 --- a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/SteelSeriesDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/SteelSeriesDeviceProvider.cs @@ -23,17 +23,5 @@ namespace Artemis.Plugins.Devices.SteelSeries PathHelper.ResolvingAbsolutePath += (sender, args) => ResolveAbsolutePath(typeof(SteelSeriesRGBDevice), sender, args); _rgbService.AddDeviceProvider(RgbDeviceProvider); } - - public override void DisablePlugin() - { - // TODO: Remove the device provider from the surface - } - - public override void Dispose() - { - // TODO: This will probably not go well without first removing the device provider - // SteelSeriesDeviceProvider.Instance.ResetDevices(); - // SteelSeriesDeviceProvider.Instance.Dispose(); - } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/plugin.json b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/plugin.json index 688b38aa4..76c9b657c 100644 --- a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/plugin.json @@ -1,6 +1,7 @@ { "Guid": "27945704-6edd-48b4-bc0e-319cce9693fc", "Name": "SteelSeries Devices", + "Description": "Allows Artemis to control lighting on select SteelSeries mice and keyboards", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.SteelSeries.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.WS281X/WS281XDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.WS281X/WS281XDeviceProvider.cs index 82a2e763e..02a69750f 100644 --- a/src/Plugins/Artemis.Plugins.Devices.WS281X/WS281XDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.WS281X/WS281XDeviceProvider.cs @@ -27,6 +27,9 @@ namespace Artemis.Plugins.Devices.WS281X public override void EnablePlugin() { var definitions = Settings.GetSetting>("DeviceDefinitions"); + if (definitions.Value == null) + definitions.Value = new List(); + foreach (var deviceDefinition in definitions.Value) { switch (deviceDefinition.Type) diff --git a/src/Plugins/Artemis.Plugins.Devices.WS281X/plugin.json b/src/Plugins/Artemis.Plugins.Devices.WS281X/plugin.json index d2cd12745..c393728d0 100644 --- a/src/Plugins/Artemis.Plugins.Devices.WS281X/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.WS281X/plugin.json @@ -1,6 +1,7 @@ { "Guid": "ec86de32-1010-4bf7-97d7-1dcc46659ab6", "Name": "WS281X Devices", + "Description": "Allows Artemis to control WS281X lighting strips via an Arduino or BitWizard.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.WS281X.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Devices.Wooting/plugin.json b/src/Plugins/Artemis.Plugins.Devices.Wooting/plugin.json index 62721a268..1de81bc61 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Wooting/plugin.json +++ b/src/Plugins/Artemis.Plugins.Devices.Wooting/plugin.json @@ -1,6 +1,7 @@ { "Guid": "e70fd5ba-9881-480a-8ff6-078ed5f747fa", "Name": "Wooting Devices", + "Description": "Allows Artemis to control lighting on Wooting keyboards. Will eventually also expose analog key data.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Devices.Wooting.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs index 22d22c91e..6200a1c35 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs @@ -37,7 +37,7 @@ namespace Artemis.Plugins.LayerBrushes.Color GradientTypeProperty.ValueChanged += (sender, args) => CreateShader(_shaderBounds); } - private void GradientTypePropertyOnValueChanged(object? sender, EventArgs e) + private void GradientTypePropertyOnValueChanged(object sender, EventArgs e) { throw new NotImplementedException(); } diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/plugin.json b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/plugin.json index 09791069e..6bd751b4b 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/plugin.json +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/plugin.json @@ -1,6 +1,7 @@ { "Guid": "92a9d6ba-6f7a-4937-94d5-c1d715b4141a", "Name": "Color layer brush", + "Description": "A basic color layer-brush providing solid colors and several types of gradients.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.LayerBrushes.Color.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/plugin.json b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/plugin.json index d148030d1..1221fabc0 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/plugin.json +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/plugin.json @@ -1,6 +1,7 @@ { "Guid": "61cbbf01-8d69-4ede-a972-f3f269da66d9", "Name": "Noise layer brush", + "Description": "An OpenSimplex noise layer-brush providing configurable randomized and animated noise.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.LayerBrushes.Noise.dll" } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Modules.General/plugin.json b/src/Plugins/Artemis.Plugins.Modules.General/plugin.json index 256e5b80e..1196d534f 100644 --- a/src/Plugins/Artemis.Plugins.Modules.General/plugin.json +++ b/src/Plugins/Artemis.Plugins.Modules.General/plugin.json @@ -1,6 +1,7 @@ { "Guid": "0de2991a-d7b8-4f61-ae4e-6623849215b5", "Name": "General module", + "Description": "A general profile-enabled module for every-day use.", "Version": "1.0.0.0", "Main": "Artemis.Plugins.Modules.General.dll" } \ No newline at end of file