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

Merge branch 'development'

This commit is contained in:
Robert 2021-07-24 20:42:45 +02:00
commit 0e07dbd631
20 changed files with 219 additions and 172 deletions

View File

@ -313,13 +313,10 @@
}, },
"Serilog.Sinks.Console": { "Serilog.Sinks.Console": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.1", "resolved": "4.0.0",
"contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==", "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.Console": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
} }
}, },
"Serilog.Sinks.Debug": { "Serilog.Sinks.Debug": {
@ -332,19 +329,16 @@
}, },
"Serilog.Sinks.File": { "Serilog.Sinks.File": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.1.0", "resolved": "5.0.0",
"contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==", "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.IO.FileSystem": "4.0.1",
"System.Text.Encoding.Extensions": "4.0.11",
"System.Threading.Timer": "4.0.1"
} }
}, },
"SkiaSharp": { "SkiaSharp": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "D25rzdCwh+3L+XyXqpNa+H/yiLJbE3/R3K/XexwHyQjGdzZvSufFW3oqf3En7hhqSIsxsJ8f5NEZ0J5W5wlGBg==", "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==",
"dependencies": { "dependencies": {
"System.Memory": "4.5.3" "System.Memory": "4.5.3"
} }
@ -1230,10 +1224,10 @@
"Ninject.Extensions.ChildKernel": "3.3.0", "Ninject.Extensions.ChildKernel": "3.3.0",
"Ninject.Extensions.Conventions": "3.3.0", "Ninject.Extensions.Conventions": "3.3.0",
"Serilog": "2.10.0", "Serilog": "2.10.0",
"Serilog.Sinks.Console": "3.1.1", "Serilog.Sinks.Console": "4.0.0",
"Serilog.Sinks.Debug": "2.0.0", "Serilog.Sinks.Debug": "2.0.0",
"Serilog.Sinks.File": "4.1.0", "Serilog.Sinks.File": "5.0.0",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.3",
"System.Buffers": "4.5.1", "System.Buffers": "4.5.1",
"System.IO.FileSystem.AccessControl": "5.0.0", "System.IO.FileSystem.AccessControl": "5.0.0",
"System.Numerics.Vectors": "4.5.0", "System.Numerics.Vectors": "4.5.0",

View File

@ -48,10 +48,10 @@
<PackageReference Include="Ninject.Extensions.ChildKernel" Version="3.3.0" /> <PackageReference Include="Ninject.Extensions.ChildKernel" Version="3.3.0" />
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" /> <PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" />
<PackageReference Include="Serilog" Version="2.10.0" /> <PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" /> <PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SkiaSharp" Version="2.80.2" /> <PackageReference Include="SkiaSharp" Version="2.80.3" />
<PackageReference Include="System.Buffers" Version="4.5.1" /> <PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" /> <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />

View File

@ -27,7 +27,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// The full path to the Artemis data folder /// The full path to the Artemis data folder
/// </summary> /// </summary>
public static readonly string DataFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Artemis\\"; public static readonly string DataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Artemis");
/// <summary> /// <summary>
/// The plugin info used by core components of Artemis /// The plugin info used by core components of Artemis

View File

@ -169,29 +169,29 @@ namespace Artemis.Core
internal static ArtemisLayout? GetDefaultLayout(ArtemisDevice device) internal static ArtemisLayout? GetDefaultLayout(ArtemisDevice device)
{ {
string layoutFolder = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts\\Artemis"); string layoutFolder = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts", "Artemis");
if (device.DeviceType == RGBDeviceType.Keyboard) if (device.DeviceType == RGBDeviceType.Keyboard)
{ {
// XL layout is defined by its programmable macro keys // XL layout is defined by its programmable macro keys
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_Programmable1 && l.RgbLed.Id <= LedId.Keyboard_Programmable32)) if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_Programmable1 && l.RgbLed.Id <= LedId.Keyboard_Programmable32))
{ {
if (device.PhysicalLayout == KeyboardLayoutType.ANSI) if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis XL keyboard-ANSI.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ANSI.xml"), LayoutSource.Default);
return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis XL keyboard-ISO.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ISO.xml"), LayoutSource.Default);
} }
// L layout is defined by its numpad // L layout is defined by its numpad
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_NumLock && l.RgbLed.Id <= LedId.Keyboard_NumPeriodAndDelete)) if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_NumLock && l.RgbLed.Id <= LedId.Keyboard_NumPeriodAndDelete))
{ {
if (device.PhysicalLayout == KeyboardLayoutType.ANSI) if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis L keyboard-ANSI.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis L keyboard-ANSI.xml"), LayoutSource.Default);
return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis L keyboard-ISO.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis L keyboard-ISO.xml"), LayoutSource.Default);
} }
// No numpad will result in TKL // No numpad will result in TKL
if (device.PhysicalLayout == KeyboardLayoutType.ANSI) if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis TKL keyboard-ANSI.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis TKL keyboard-ANSI.xml"), LayoutSource.Default);
return new ArtemisLayout(layoutFolder + "\\Keyboard\\Artemis TKL keyboard-ISO.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard","Artemis TKL keyboard-ISO.xml"), LayoutSource.Default);
} }
// if (device.DeviceType == RGBDeviceType.Mouse) // if (device.DeviceType == RGBDeviceType.Mouse)
@ -199,21 +199,21 @@ namespace Artemis.Core
// if (device.Leds.Count == 1) // if (device.Leds.Count == 1)
// { // {
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo)) // if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
// return new ArtemisLayout(layoutFolder + "\\Mouse\\1 LED mouse logo.xml", LayoutSource.Default); // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse logo.xml"), LayoutSource.Default);
// return new ArtemisLayout(layoutFolder + "\\Mouse\\1 LED mouse.xml", LayoutSource.Default); // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse.xml"), LayoutSource.Default);
// } // }
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo)) // if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
// return new ArtemisLayout(layoutFolder + "\\Mouse\\4 LED mouse logo.xml", LayoutSource.Default); // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse logo.xml"), LayoutSource.Default);
// return new ArtemisLayout(layoutFolder + "\\Mouse\\4 LED mouse.xml", LayoutSource.Default); // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse.xml"), LayoutSource.Default);
// } // }
if (device.DeviceType == RGBDeviceType.Headset) if (device.DeviceType == RGBDeviceType.Headset)
{ {
if (device.Leds.Count == 1) if (device.Leds.Count == 1)
return new ArtemisLayout(layoutFolder + "\\Headset\\Artemis 1 LED headset.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 1 LED headset.xml"), LayoutSource.Default);
if (device.Leds.Count == 2) if (device.Leds.Count == 2)
return new ArtemisLayout(layoutFolder + "\\Headset\\Artemis 2 LED headset.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 2 LED headset.xml"), LayoutSource.Default);
return new ArtemisLayout(layoutFolder + "\\Headset\\Artemis 4 LED headset.xml", LayoutSource.Default); return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 4 LED headset.xml"), LayoutSource.Default);
} }
return null; return null;

View File

@ -61,7 +61,6 @@ namespace Artemis.Core
if (LayoutCustomLedData.LogicalLayouts == null || !LayoutCustomLedData.LogicalLayouts.Any()) if (LayoutCustomLedData.LogicalLayouts == null || !LayoutCustomLedData.LogicalLayouts.Any())
return; return;
Uri layoutDirectory = new(Path.GetDirectoryName(DeviceLayout.FilePath)! + "\\", UriKind.Absolute);
// Prefer a matching layout or else a default layout (that has no name) // Prefer a matching layout or else a default layout (that has no name)
LayoutCustomLedDataLogicalLayout logicalLayout = LayoutCustomLedData.LogicalLayouts LayoutCustomLedDataLogicalLayout logicalLayout = LayoutCustomLedData.LogicalLayouts
.OrderBy(l => l.Name == artemisDevice.LogicalLayout) .OrderBy(l => l.Name == artemisDevice.LogicalLayout)
@ -69,7 +68,7 @@ namespace Artemis.Core
.First(); .First();
LogicalName = logicalLayout.Name; LogicalName = logicalLayout.Name;
Image = new Uri(layoutDirectory, logicalLayout.Image); Image = new Uri(Path.Combine(Path.GetDirectoryName(DeviceLayout.FilePath)!, logicalLayout.Image!), UriKind.Absolute);
} }
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.IO;
using Ninject.Activation; using Ninject.Activation;
using Serilog; using Serilog;
using Serilog.Core; using Serilog.Core;
@ -12,7 +13,7 @@ namespace Artemis.Core.Ninject
private static readonly ILogger Logger = new LoggerConfiguration() private static readonly ILogger Logger = new LoggerConfiguration()
.Enrich.FromLogContext() .Enrich.FromLogContext()
.WriteTo.File(Constants.DataFolder + "logs/Artemis log-.log", .WriteTo.File(Path.Combine(Constants.DataFolder, "logs", "Artemis log-.log"),
rollingInterval: RollingInterval.Day, rollingInterval: RollingInterval.Day,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}") outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}")
.WriteTo.Console() .WriteTo.Console()

View File

@ -11,7 +11,7 @@ namespace Artemis.Core
public abstract class PluginFeature : CorePropertyChanged, IDisposable public abstract class PluginFeature : CorePropertyChanged, IDisposable
{ {
private bool _isEnabled; private bool _isEnabled;
private Exception? _loadException;
/// <summary> /// <summary>
/// Gets the plugin feature info related to this feature /// Gets the plugin feature info related to this feature
@ -37,14 +37,7 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _isEnabled, value); internal set => SetAndNotify(ref _isEnabled, value);
} }
/// <summary> internal int AutoEnableAttempts { get; set; }
/// Gets the exception thrown while loading
/// </summary>
public Exception? LoadException
{
get => _loadException;
internal set => SetAndNotify(ref _loadException, value);
}
/// <summary> /// <summary>
/// Gets the identifier of this plugin feature /// Gets the identifier of this plugin feature
@ -146,13 +139,16 @@ namespace Artemis.Core
try try
{ {
if (isAutoEnable)
AutoEnableAttempts++;
if (isAutoEnable && GetLockFileCreated()) if (isAutoEnable && GetLockFileCreated())
{ {
// Don't wrap existing lock exceptions, simply rethrow them // Don't wrap existing lock exceptions, simply rethrow them
if (LoadException is ArtemisPluginLockException) if (Info.LoadException is ArtemisPluginLockException)
throw LoadException; throw Info.LoadException;
throw new ArtemisPluginLockException(LoadException); throw new ArtemisPluginLockException(Info.LoadException);
} }
CreateLockFile(); CreateLockFile();
@ -165,21 +161,22 @@ namespace Artemis.Core
if (!enableTask.Wait(TimeSpan.FromSeconds(15))) if (!enableTask.Wait(TimeSpan.FromSeconds(15)))
throw new ArtemisPluginException(Plugin, "Plugin load timeout"); throw new ArtemisPluginException(Plugin, "Plugin load timeout");
LoadException = null; Info.LoadException = null;
AutoEnableAttempts = 0;
OnEnabled(); OnEnabled();
} }
// If enable failed, put it back in a disabled state // If enable failed, put it back in a disabled state
catch (Exception e) catch (Exception e)
{ {
IsEnabled = false; IsEnabled = false;
LoadException = e; Info.LoadException = e;
throw; throw;
} }
finally finally
{ {
// Clean up the lock file unless the failure was due to the lock file // Clean up the lock file unless the failure was due to the lock file
// After all, we failed but not miserably :) // After all, we failed but not miserably :)
if (!(LoadException is ArtemisPluginLockException)) if (Info.LoadException is not ArtemisPluginLockException)
DeleteLockFile(); DeleteLockFile();
} }
} }

View File

@ -17,6 +17,7 @@ namespace Artemis.Core
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
{ {
private Exception? _loadException;
private string? _description; private string? _description;
private string? _icon; private string? _icon;
private PluginFeature? _instance; private PluginFeature? _instance;
@ -80,6 +81,15 @@ namespace Artemis.Core
/// </summary> /// </summary>
public Type FeatureType { get; } public Type FeatureType { get; }
/// <summary>
/// Gets the exception thrown while loading
/// </summary>
public Exception? LoadException
{
get => _loadException;
internal set => SetAndNotify(ref _loadException, value);
}
/// <summary> /// <summary>
/// The name of the plugin /// The name of the plugin
/// </summary> /// </summary>

View File

@ -5,6 +5,7 @@ using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using Artemis.Core.DeviceProviders; using Artemis.Core.DeviceProviders;
using Artemis.Core.Ninject; using Artemis.Core.Ninject;
using Artemis.Storage.Entities.General; using Artemis.Storage.Entities.General;
@ -90,11 +91,6 @@ namespace Artemis.Core.Services
using StreamReader reader = new(metaDataFileEntry.Open()); using StreamReader reader = new(metaDataFileEntry.Open());
PluginInfo builtInPluginInfo = CoreJson.DeserializeObject<PluginInfo>(reader.ReadToEnd())!; PluginInfo builtInPluginInfo = CoreJson.DeserializeObject<PluginInfo>(reader.ReadToEnd())!;
string preferred = builtInPluginInfo.PreferredPluginDirectory; string preferred = builtInPluginInfo.PreferredPluginDirectory;
string oldPreferred = Path.GetFileNameWithoutExtension(zipFile.Name);
// Rename folders to the new format
// TODO: Get rid of this eventually, it's nice to keep around but it's extra IO that's best avoided
if (pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == oldPreferred) != null)
Directory.Move(Path.Combine(pluginDirectory.FullName, oldPreferred), Path.Combine(pluginDirectory.FullName, preferred));
// Find the matching plugin in the plugin folder // Find the matching plugin in the plugin folder
DirectoryInfo? match = pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == preferred); DirectoryInfo? match = pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == preferred);
@ -431,6 +427,7 @@ namespace Artemis.Core.Services
catch (Exception e) catch (Exception e)
{ {
_logger.Warning(new ArtemisPluginException(plugin, "Failed to instantiate feature", e), "Failed to instantiate feature", plugin); _logger.Warning(new ArtemisPluginException(plugin, "Failed to instantiate feature", e), "Failed to instantiate feature", plugin);
featureInfo.LoadException = e;
} }
} }
@ -614,10 +611,38 @@ namespace Artemis.Core.Services
} }
catch (Exception e) catch (Exception e)
{ {
if (isAutoEnable)
{
// Schedule a retry based on the amount of attempts
if (pluginFeature.AutoEnableAttempts < 4)
{
TimeSpan retryDelay = TimeSpan.FromSeconds(pluginFeature.AutoEnableAttempts * 10);
_logger.Warning( _logger.Warning(
new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e), e,
"Failed to enable plugin" "Plugin feature '{feature} - {plugin}' failed to enable during attempt ({attempt}/3), scheduling a retry in {retryDelay}.",
pluginFeature,
pluginFeature.Plugin,
pluginFeature.AutoEnableAttempts,
retryDelay
); );
Task.Run(async () =>
{
await Task.Delay(retryDelay);
if (!pluginFeature.IsEnabled)
EnablePluginFeature(pluginFeature, saveState, true);
});
}
else
{
_logger.Warning(e, "Plugin feature '{feature} - {plugin}' failed to enable after 3 attempts, giving up.", pluginFeature, pluginFeature.Plugin);
}
}
else
{
_logger.Warning(e, "Plugin feature '{feature} - {plugin}' failed to enable.", pluginFeature, pluginFeature.Plugin);
throw;
}
} }
finally finally
{ {

View File

@ -18,8 +18,8 @@ namespace Artemis.Core
public static void PrepareFirstLaunch() public static void PrepareFirstLaunch()
{ {
CreateAccessibleDirectory(Constants.DataFolder); CreateAccessibleDirectory(Constants.DataFolder);
CreateAccessibleDirectory(Constants.DataFolder + "plugins"); CreateAccessibleDirectory(Path.Combine(Constants.DataFolder ,"plugins"));
CreateAccessibleDirectory(Constants.DataFolder + "user layouts"); CreateAccessibleDirectory(Path.Combine(Constants.DataFolder ,"user layouts"));
} }
/// <summary> /// <summary>

View File

@ -81,14 +81,11 @@
}, },
"Serilog.Sinks.Console": { "Serilog.Sinks.Console": {
"type": "Direct", "type": "Direct",
"requested": "[3.1.1, )", "requested": "[4.0.0, )",
"resolved": "3.1.1", "resolved": "4.0.0",
"contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==", "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.Console": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
} }
}, },
"Serilog.Sinks.Debug": { "Serilog.Sinks.Debug": {
@ -102,21 +99,18 @@
}, },
"Serilog.Sinks.File": { "Serilog.Sinks.File": {
"type": "Direct", "type": "Direct",
"requested": "[4.1.0, )", "requested": "[5.0.0, )",
"resolved": "4.1.0", "resolved": "5.0.0",
"contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==", "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.IO.FileSystem": "4.0.1",
"System.Text.Encoding.Extensions": "4.0.11",
"System.Threading.Timer": "4.0.1"
} }
}, },
"SkiaSharp": { "SkiaSharp": {
"type": "Direct", "type": "Direct",
"requested": "[2.80.2, )", "requested": "[2.80.3, )",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "D25rzdCwh+3L+XyXqpNa+H/yiLJbE3/R3K/XexwHyQjGdzZvSufFW3oqf3En7hhqSIsxsJ8f5NEZ0J5W5wlGBg==", "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==",
"dependencies": { "dependencies": {
"System.Memory": "4.5.3" "System.Memory": "4.5.3"
} }

View File

@ -19,11 +19,11 @@ namespace Artemis.Storage
if (_inUse) if (_inUse)
throw new Exception("Storage is already in use, can't backup now."); throw new Exception("Storage is already in use, can't backup now.");
string database = $"{dataFolder}\\database.db"; string database = Path.Combine(dataFolder, "database.db");
if (!File.Exists(database)) if (!File.Exists(database))
return; return;
string backupFolder = $"{dataFolder}\\database backups"; string backupFolder = Path.Combine(dataFolder, "database backups");
Directory.CreateDirectory(backupFolder); Directory.CreateDirectory(backupFolder);
FileSystemInfo[] files = new DirectoryInfo(backupFolder).GetFileSystemInfos(); FileSystemInfo[] files = new DirectoryInfo(backupFolder).GetFileSystemInfos();
if (files.Length >= 5) if (files.Length >= 5)
@ -36,7 +36,7 @@ namespace Artemis.Storage
oldest.Delete(); oldest.Delete();
} }
File.Copy(database, $"{backupFolder}\\database-{DateTime.Now:yyyy-dd-M--HH-mm-ss}.db"); File.Copy(database, Path.Combine(backupFolder, $"database-{DateTime.Now:yyyy-dd-M--HH-mm-ss}.db"));
} }
/// <summary> /// <summary>
@ -51,7 +51,7 @@ namespace Artemis.Storage
try try
{ {
_inUse = true; _inUse = true;
return new LiteRepository($"FileName={dataFolder}\\database.db"); return new LiteRepository($"FileName={Path.Combine(dataFolder, "database.db")}");
} }
catch (LiteException e) catch (LiteException e)
{ {

View File

@ -40,8 +40,8 @@
<PackageReference Include="Ninject" Version="3.3.4" /> <PackageReference Include="Ninject" Version="3.3.4" />
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" /> <PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" />
<PackageReference Include="SharpVectors.Reloaded" Version="1.7.5" /> <PackageReference Include="SharpVectors.Reloaded" Version="1.7.5" />
<PackageReference Include="SkiaSharp" Version="2.80.2" /> <PackageReference Include="SkiaSharp" Version="2.80.3" />
<PackageReference Include="SkiaSharp.Views.WPF" Version="2.80.2" /> <PackageReference Include="SkiaSharp.Views.WPF" Version="2.80.3" />
<PackageReference Include="Stylet" Version="1.3.6" /> <PackageReference Include="Stylet" Version="1.3.6" />
<PackageReference Include="System.Buffers" Version="4.5.1" /> <PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" /> <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />

View File

@ -60,21 +60,21 @@
}, },
"SkiaSharp": { "SkiaSharp": {
"type": "Direct", "type": "Direct",
"requested": "[2.80.2, )", "requested": "[2.80.3, )",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "D25rzdCwh+3L+XyXqpNa+H/yiLJbE3/R3K/XexwHyQjGdzZvSufFW3oqf3En7hhqSIsxsJ8f5NEZ0J5W5wlGBg==", "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==",
"dependencies": { "dependencies": {
"System.Memory": "4.5.3" "System.Memory": "4.5.3"
} }
}, },
"SkiaSharp.Views.WPF": { "SkiaSharp.Views.WPF": {
"type": "Direct", "type": "Direct",
"requested": "[2.80.2, )", "requested": "[2.80.3, )",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "Fzo2+MNwHDh9Cob8sk7OO26kp3bhofjXMwlEK8IncF1ehu9hi3sH9iQDJrue9a88VEJJ+yyLISPUFcmXlGHSyQ==", "contentHash": "oKUMm7WzFeoie6rW5nnwSGKZ94misyRsAc1wU6SEqgd6ssW17nyfohHxHuBHtmpLtIRwvjhfAu3cMLrpX/oNcw==",
"dependencies": { "dependencies": {
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.3",
"SkiaSharp.Views.Desktop.Common": "2.80.2" "SkiaSharp.Views.Desktop.Common": "2.80.3"
} }
}, },
"Stylet": { "Stylet": {
@ -378,13 +378,10 @@
}, },
"Serilog.Sinks.Console": { "Serilog.Sinks.Console": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.1", "resolved": "4.0.0",
"contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==", "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.Console": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
} }
}, },
"Serilog.Sinks.Debug": { "Serilog.Sinks.Debug": {
@ -397,21 +394,19 @@
}, },
"Serilog.Sinks.File": { "Serilog.Sinks.File": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.1.0", "resolved": "5.0.0",
"contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==", "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.IO.FileSystem": "4.0.1",
"System.Text.Encoding.Extensions": "4.0.11",
"System.Threading.Timer": "4.0.1"
} }
}, },
"SkiaSharp.Views.Desktop.Common": { "SkiaSharp.Views.Desktop.Common": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "0vBvweMysgl1wgjuTQUhdJMD5z5nBjtYqmnHPeX+qHfkc336Wj2L3jEqwmGb0YP+RV47gFGz0EzMAW6szZch9w==", "contentHash": "CMQu9fr3BxGRsRryDC6lkYbYaSI2CI+RqisFX0WIdbOdbigUOLhqchmKIMb4EdFAZk13vk862qiE9v97iDZS7g==",
"dependencies": { "dependencies": {
"SkiaSharp": "2.80.2" "SkiaSharp": "2.80.3",
"System.Drawing.Common": "4.5.1"
} }
}, },
"System.AppContext": { "System.AppContext": {
@ -1309,10 +1304,10 @@
"Ninject.Extensions.ChildKernel": "3.3.0", "Ninject.Extensions.ChildKernel": "3.3.0",
"Ninject.Extensions.Conventions": "3.3.0", "Ninject.Extensions.Conventions": "3.3.0",
"Serilog": "2.10.0", "Serilog": "2.10.0",
"Serilog.Sinks.Console": "3.1.1", "Serilog.Sinks.Console": "4.0.0",
"Serilog.Sinks.Debug": "2.0.0", "Serilog.Sinks.Debug": "2.0.0",
"Serilog.Sinks.File": "4.1.0", "Serilog.Sinks.File": "5.0.0",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.3",
"System.Buffers": "4.5.1", "System.Buffers": "4.5.1",
"System.IO.FileSystem.AccessControl": "5.0.0", "System.IO.FileSystem.AccessControl": "5.0.0",
"System.Numerics.Vectors": "4.5.0", "System.Numerics.Vectors": "4.5.0",

View File

@ -137,7 +137,7 @@
<Resource Include="Resources\Images\Sidebar\sidebar-header.png" /> <Resource Include="Resources\Images\Sidebar\sidebar-header.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="10.2.3" /> <PackageReference Include="FluentValidation" Version="10.3.0" />
<PackageReference Include="Flurl.Http" Version="3.2.0" /> <PackageReference Include="Flurl.Http" Version="3.2.0" />
<PackageReference Include="gong-wpf-dragdrop" Version="2.3.2" /> <PackageReference Include="gong-wpf-dragdrop" Version="2.3.2" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf.NetCore" Version="1.0.18" /> <PackageReference Include="Hardcodet.NotifyIcon.Wpf.NetCore" Version="1.0.18" />
@ -152,8 +152,8 @@
<PackageReference Include="Ookii.Dialogs.Wpf" Version="3.1.0" /> <PackageReference Include="Ookii.Dialogs.Wpf" Version="3.1.0" />
<PackageReference Include="RawInput.Sharp" Version="0.0.4" /> <PackageReference Include="RawInput.Sharp" Version="0.0.4" />
<PackageReference Include="Serilog" Version="2.10.0" /> <PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="SkiaSharp.Views.WPF" Version="2.80.2" /> <PackageReference Include="SkiaSharp.Views.WPF" Version="2.80.3" />
<PackageReference Include="SkiaSharp.Vulkan.SharpVk" Version="2.80.2" /> <PackageReference Include="SkiaSharp.Vulkan.SharpVk" Version="2.80.3" />
<PackageReference Include="Stylet" Version="1.3.6" /> <PackageReference Include="Stylet" Version="1.3.6" />
<PackageReference Include="System.Buffers" Version="4.5.1" /> <PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />

View File

@ -261,8 +261,14 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
public void ResetZoomAndPan() public void ResetZoomAndPan()
{ {
if (!Devices.Any())
{
PanZoomViewModel.Reset();
return;
}
// Create a rect surrounding all devices // Create a rect surrounding all devices
SKRect rect = new SKRect( SKRect rect = new(
Devices.Min(d => d.Rectangle.Left), Devices.Min(d => d.Rectangle.Left),
Devices.Min(d => d.Rectangle.Top), Devices.Min(d => d.Rectangle.Top),
Devices.Max(d => d.Rectangle.Right), Devices.Max(d => d.Rectangle.Right),

View File

@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings" xmlns:local="clr-namespace:Artemis.UI.Screens.Settings"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:SettingsTabsViewModel}"> d:DataContext="{d:DesignInstance local:SettingsTabsViewModel}">
@ -16,6 +17,7 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<Grid>
<TabControl Style="{StaticResource MaterialDesignAppBarTabControl}" <TabControl Style="{StaticResource MaterialDesignAppBarTabControl}"
ItemsSource="{Binding Items}" ItemsSource="{Binding Items}"
SelectedItem="{Binding ActiveItem}" SelectedItem="{Binding ActiveItem}"
@ -30,4 +32,16 @@
</DataTemplate> </DataTemplate>
</TabControl.ContentTemplate> </TabControl.ContentTemplate>
</TabControl> </TabControl>
<!-- Bug: materialDesign:RippleAssist.RippleOnTop doesn't look as nice but otherwise it doesn't work at all, not sure why -->
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
VerticalAlignment="Top"
HorizontalAlignment="Right"
ToolTip="Open debugger"
Command="{s:Action ShowDebugger}"
materialDesign:RippleAssist.RippleOnTop="True">
<materialDesign:PackIcon Kind="Matrix" />
</Button>
</Grid>
</UserControl> </UserControl>

View File

@ -2,18 +2,23 @@
using Artemis.UI.Screens.Settings.Tabs.Devices; using Artemis.UI.Screens.Settings.Tabs.Devices;
using Artemis.UI.Screens.Settings.Tabs.General; using Artemis.UI.Screens.Settings.Tabs.General;
using Artemis.UI.Screens.Settings.Tabs.Plugins; using Artemis.UI.Screens.Settings.Tabs.Plugins;
using Artemis.UI.Services;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.Settings namespace Artemis.UI.Screens.Settings
{ {
public class SettingsTabsViewModel : Conductor<Screen>.Collection.OneActive public class SettingsTabsViewModel : Conductor<Screen>.Collection.OneActive
{ {
private readonly IDebugService _debugService;
public SettingsTabsViewModel( public SettingsTabsViewModel(
GeneralSettingsTabViewModel generalSettingsTabViewModel, GeneralSettingsTabViewModel generalSettingsTabViewModel,
PluginSettingsTabViewModel pluginSettingsTabViewModel, PluginSettingsTabViewModel pluginSettingsTabViewModel,
DeviceSettingsTabViewModel deviceSettingsTabViewModel, DeviceSettingsTabViewModel deviceSettingsTabViewModel,
AboutTabViewModel aboutTabViewModel) AboutTabViewModel aboutTabViewModel,
IDebugService debugService)
{ {
_debugService = debugService;
DisplayName = "Settings"; DisplayName = "Settings";
Items.Add(generalSettingsTabViewModel); Items.Add(generalSettingsTabViewModel);
@ -23,5 +28,10 @@ namespace Artemis.UI.Screens.Settings
ActiveItem = generalSettingsTabViewModel; ActiveItem = generalSettingsTabViewModel;
} }
public void ShowDebugger()
{
_debugService.ShowDebugger();
}
} }
} }

View File

@ -37,7 +37,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
} }
public PluginFeatureInfo FeatureInfo { get; } public PluginFeatureInfo FeatureInfo { get; }
public Exception LoadException => FeatureInfo.Instance?.LoadException; public Exception LoadException => FeatureInfo.LoadException;
public bool ShowShield { get; } public bool ShowShield { get; }
@ -81,7 +81,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
public async Task InstallPrerequisites() public async Task InstallPrerequisites()
{ {
if (FeatureInfo.Prerequisites.Any()) if (FeatureInfo.Prerequisites.Any())
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> { FeatureInfo }); await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
} }
public async Task RemovePrerequisites() public async Task RemovePrerequisites()
@ -119,12 +119,19 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
private async Task UpdateEnabled(bool enable) private async Task UpdateEnabled(bool enable)
{ {
if (IsEnabled == enable || FeatureInfo.Instance == null) if (IsEnabled == enable)
{ {
NotifyOfPropertyChange(nameof(IsEnabled)); NotifyOfPropertyChange(nameof(IsEnabled));
return; return;
} }
if (FeatureInfo.Instance == null)
{
NotifyOfPropertyChange(nameof(IsEnabled));
_messageService.ShowMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.", "VIEW LOGS", ShowLogsFolder);
return;
}
if (enable) if (enable)
{ {
Enabling = true; Enabling = true;
@ -144,7 +151,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
// Check if all prerequisites are met async // Check if all prerequisites are met async
if (!FeatureInfo.ArePrerequisitesMet()) if (!FeatureInfo.ArePrerequisitesMet())
{ {
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> { FeatureInfo }); await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
if (!FeatureInfo.ArePrerequisitesMet()) if (!FeatureInfo.ArePrerequisitesMet())
{ {
NotifyOfPropertyChange(nameof(IsEnabled)); NotifyOfPropertyChange(nameof(IsEnabled));
@ -156,7 +163,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
} }
catch (Exception e) catch (Exception e)
{ {
_messageService.ShowMessage($"Failed to enable {FeatureInfo.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder); _messageService.ShowMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
} }
finally finally
{ {

View File

@ -4,9 +4,9 @@
".NETCoreApp,Version=v5.0": { ".NETCoreApp,Version=v5.0": {
"FluentValidation": { "FluentValidation": {
"type": "Direct", "type": "Direct",
"requested": "[10.2.3, )", "requested": "[10.3.0, )",
"resolved": "10.2.3", "resolved": "10.3.0",
"contentHash": "R2w/E6jgg9RPSlg7JQSTHg6AWDwlOXARaV4ZUKrPJ1gi1e+oaBEcomxmo29j9BLZivkyQhOpAboJ9nKZS4/xYA==" "contentHash": "ujEB9UMBPDLib6dyhSRhl93IE6ko4ZU6Nz9MFqohaKcvyf06Hk0yDQUFJGF6RgAOsm27O7ZZHVDpXx7oU5vBcg=="
}, },
"Flurl.Http": { "Flurl.Http": {
"type": "Direct", "type": "Direct",
@ -130,22 +130,22 @@
}, },
"SkiaSharp.Views.WPF": { "SkiaSharp.Views.WPF": {
"type": "Direct", "type": "Direct",
"requested": "[2.80.2, )", "requested": "[2.80.3, )",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "Fzo2+MNwHDh9Cob8sk7OO26kp3bhofjXMwlEK8IncF1ehu9hi3sH9iQDJrue9a88VEJJ+yyLISPUFcmXlGHSyQ==", "contentHash": "oKUMm7WzFeoie6rW5nnwSGKZ94misyRsAc1wU6SEqgd6ssW17nyfohHxHuBHtmpLtIRwvjhfAu3cMLrpX/oNcw==",
"dependencies": { "dependencies": {
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.3",
"SkiaSharp.Views.Desktop.Common": "2.80.2" "SkiaSharp.Views.Desktop.Common": "2.80.3"
} }
}, },
"SkiaSharp.Vulkan.SharpVk": { "SkiaSharp.Vulkan.SharpVk": {
"type": "Direct", "type": "Direct",
"requested": "[2.80.2, )", "requested": "[2.80.3, )",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "qiqlbgMsSdxTsaPErtE1lXoMXolVVF9E6irmSTzlW++6BbW8tzA89n7GNsgMYJgyo2ljHZhX5ydhFn0Rkj7VHw==", "contentHash": "IeR9oOHBsJUqpuVs23XgZXnrFV6WuOTaLpFhLVlXt2XILWIRrlrqx1PILgJm5bLqesceJLYZyMxVb/Ow7/uReA==",
"dependencies": { "dependencies": {
"SharpVk": "0.4.2", "SharpVk": "0.4.2",
"SkiaSharp": "2.80.2" "SkiaSharp": "2.80.3"
} }
}, },
"Stylet": { "Stylet": {
@ -486,13 +486,10 @@
}, },
"Serilog.Sinks.Console": { "Serilog.Sinks.Console": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.1.1", "resolved": "4.0.0",
"contentHash": "56mI5AqvyF/i/c2451nvV71kq370XOCE4Uu5qiaJ295sOhMb9q3BWwG7mWLOVSnmpWiq0SBT3SXfgRXGNP6vzA==", "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.Console": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
} }
}, },
"Serilog.Sinks.Debug": { "Serilog.Sinks.Debug": {
@ -505,13 +502,10 @@
}, },
"Serilog.Sinks.File": { "Serilog.Sinks.File": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.1.0", "resolved": "5.0.0",
"contentHash": "U0b34w+ZikbqWEZ3ui7BdzxY/19zwrdhLtI3o6tfmLdD3oXxg7n2TZJjwCCTlKPgRuYic9CBWfrZevbb70mTaw==", "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
"dependencies": { "dependencies": {
"Serilog": "2.5.0", "Serilog": "2.10.0"
"System.IO.FileSystem": "4.0.1",
"System.Text.Encoding.Extensions": "4.0.11",
"System.Threading.Timer": "4.0.1"
} }
}, },
"SharpVectors.Reloaded": { "SharpVectors.Reloaded": {
@ -530,18 +524,19 @@
}, },
"SkiaSharp": { "SkiaSharp": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "D25rzdCwh+3L+XyXqpNa+H/yiLJbE3/R3K/XexwHyQjGdzZvSufFW3oqf3En7hhqSIsxsJ8f5NEZ0J5W5wlGBg==", "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==",
"dependencies": { "dependencies": {
"System.Memory": "4.5.3" "System.Memory": "4.5.3"
} }
}, },
"SkiaSharp.Views.Desktop.Common": { "SkiaSharp.Views.Desktop.Common": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.80.2", "resolved": "2.80.3",
"contentHash": "0vBvweMysgl1wgjuTQUhdJMD5z5nBjtYqmnHPeX+qHfkc336Wj2L3jEqwmGb0YP+RV47gFGz0EzMAW6szZch9w==", "contentHash": "CMQu9fr3BxGRsRryDC6lkYbYaSI2CI+RqisFX0WIdbOdbigUOLhqchmKIMb4EdFAZk13vk862qiE9v97iDZS7g==",
"dependencies": { "dependencies": {
"SkiaSharp": "2.80.2" "SkiaSharp": "2.80.3",
"System.Drawing.Common": "4.5.1"
} }
}, },
"System.AppContext": { "System.AppContext": {
@ -1437,10 +1432,10 @@
"Ninject.Extensions.ChildKernel": "3.3.0", "Ninject.Extensions.ChildKernel": "3.3.0",
"Ninject.Extensions.Conventions": "3.3.0", "Ninject.Extensions.Conventions": "3.3.0",
"Serilog": "2.10.0", "Serilog": "2.10.0",
"Serilog.Sinks.Console": "3.1.1", "Serilog.Sinks.Console": "4.0.0",
"Serilog.Sinks.Debug": "2.0.0", "Serilog.Sinks.Debug": "2.0.0",
"Serilog.Sinks.File": "4.1.0", "Serilog.Sinks.File": "5.0.0",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.3",
"System.Buffers": "4.5.1", "System.Buffers": "4.5.1",
"System.IO.FileSystem.AccessControl": "5.0.0", "System.IO.FileSystem.AccessControl": "5.0.0",
"System.Numerics.Vectors": "4.5.0", "System.Numerics.Vectors": "4.5.0",
@ -1466,8 +1461,8 @@
"Ninject": "3.3.4", "Ninject": "3.3.4",
"Ninject.Extensions.Conventions": "3.3.0", "Ninject.Extensions.Conventions": "3.3.0",
"SharpVectors.Reloaded": "1.7.5", "SharpVectors.Reloaded": "1.7.5",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.3",
"SkiaSharp.Views.WPF": "2.80.2", "SkiaSharp.Views.WPF": "2.80.3",
"Stylet": "1.3.6", "Stylet": "1.3.6",
"System.Buffers": "4.5.1", "System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.5.0" "System.Numerics.Vectors": "4.5.0"