mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Profile adaption - Added support for device hint to 'all' devices
Layouts - Round LED sizes to integers Auto-update - Use modern Windows 10 toasts UI - On shutdown wait 6 seconds longer before force-shutdown UI - Use black icons in notifications on white Windows theme Message service - Added optional toast callbacks
This commit is contained in:
parent
5c337e9c5e
commit
96c55e5c03
@ -48,7 +48,7 @@ namespace Artemis.Core
|
|||||||
public void Apply(Layer layer, List<ArtemisDevice> devices)
|
public void Apply(Layer layer, List<ArtemisDevice> devices)
|
||||||
{
|
{
|
||||||
IEnumerable<ArtemisDevice> matches = devices
|
IEnumerable<ArtemisDevice> matches = devices
|
||||||
.Where(d => d.RgbDevice.DeviceInfo.DeviceType == DeviceType)
|
.Where(d => DeviceType == RGBDeviceType.All || d.RgbDevice.DeviceInfo.DeviceType == DeviceType)
|
||||||
.OrderBy(d => d.Rectangle.Top)
|
.OrderBy(d => d.Rectangle.Top)
|
||||||
.ThenBy(d => d.Rectangle.Left)
|
.ThenBy(d => d.Rectangle.Left)
|
||||||
.Skip(Skip);
|
.Skip(Skip);
|
||||||
|
|||||||
@ -66,8 +66,8 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
_leds = new List<ArtemisLed>();
|
_leds = new List<ArtemisLed>();
|
||||||
|
|
||||||
Load();
|
|
||||||
Adapter = new LayerAdapter(this);
|
Adapter = new LayerAdapter(this);
|
||||||
|
Load();
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +242,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
ExpandedPropertyGroups.AddRange(LayerEntity.ExpandedPropertyGroups);
|
ExpandedPropertyGroups.AddRange(LayerEntity.ExpandedPropertyGroups);
|
||||||
LoadRenderElement();
|
LoadRenderElement();
|
||||||
|
Adapter.Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Save()
|
internal override void Save()
|
||||||
@ -276,6 +277,9 @@ namespace Artemis.Core
|
|||||||
LayerEntity.Leds.Add(ledEntity);
|
LayerEntity.Leds.Add(ledEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adaption hints
|
||||||
|
Adapter.Save();
|
||||||
|
|
||||||
SaveRenderElement();
|
SaveRenderElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,6 +70,14 @@ namespace Artemis.Core
|
|||||||
public List<IAdaptionHint> DetermineHints(IEnumerable<ArtemisDevice> devices)
|
public List<IAdaptionHint> DetermineHints(IEnumerable<ArtemisDevice> devices)
|
||||||
{
|
{
|
||||||
List<IAdaptionHint> newHints = new();
|
List<IAdaptionHint> newHints = new();
|
||||||
|
if (devices.All(DoesLayerCoverDevice))
|
||||||
|
{
|
||||||
|
DeviceAdaptionHint hint = new() {DeviceType = RGBDeviceType.All};
|
||||||
|
AdaptionHints.Add(hint);
|
||||||
|
newHints.Add(hint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Any fully covered device will add a device adaption hint for that type
|
// Any fully covered device will add a device adaption hint for that type
|
||||||
foreach (IGrouping<ArtemisDevice, ArtemisLed> deviceLeds in Layer.Leds.GroupBy(l => l.Device))
|
foreach (IGrouping<ArtemisDevice, ArtemisLed> deviceLeds in Layer.Leds.GroupBy(l => l.Device))
|
||||||
{
|
{
|
||||||
@ -99,6 +107,7 @@ namespace Artemis.Core
|
|||||||
newHints.Add(hint);
|
newHints.Add(hint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return newHints;
|
return newHints;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,5 +38,9 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsLastActiveProfile { get; }
|
public bool IsLastActiveProfile { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a boolean indicating whether the profile will be adapted the next time it is activated
|
||||||
|
/// </summary>
|
||||||
|
public bool NeedsAdaption { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,7 +381,8 @@ namespace Artemis.Core
|
|||||||
"set to true because the device provider does not support it");
|
"set to true because the device provider does not support it");
|
||||||
|
|
||||||
if (layout.IsValid)
|
if (layout.IsValid)
|
||||||
layout.RgbLayout!.ApplyTo(RgbDevice, createMissingLeds, removeExcessiveLeds);
|
layout.ApplyTo(RgbDevice, createMissingLeds, removeExcessiveLeds);
|
||||||
|
|
||||||
|
|
||||||
UpdateLeds();
|
UpdateLeds();
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using RGB.NET.Core;
|
||||||
using RGB.NET.Layout;
|
using RGB.NET.Layout;
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
@ -107,6 +108,44 @@ namespace Artemis.Core
|
|||||||
else
|
else
|
||||||
Image = null;
|
Image = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the layout to the provided device
|
||||||
|
/// </summary>
|
||||||
|
public void ApplyTo(IRGBDevice device, bool createMissingLeds = false, bool removeExcessiveLeds = false)
|
||||||
|
{
|
||||||
|
device.Size = new Size(MathF.Round(RgbLayout.Width), MathF.Round(RgbLayout.Height));
|
||||||
|
device.DeviceInfo.LayoutMetadata = RgbLayout.CustomData;
|
||||||
|
|
||||||
|
HashSet<LedId> ledIds = new();
|
||||||
|
foreach (ILedLayout layoutLed in RgbLayout.Leds)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(layoutLed.Id, true, out LedId ledId))
|
||||||
|
{
|
||||||
|
ledIds.Add(ledId);
|
||||||
|
|
||||||
|
Led? led = device[ledId];
|
||||||
|
if ((led == null) && createMissingLeds)
|
||||||
|
led = device.AddLed(ledId, new Point(), new Size());
|
||||||
|
|
||||||
|
if (led != null)
|
||||||
|
{
|
||||||
|
led.Location = new Point(MathF.Round(layoutLed.X), MathF.Round(layoutLed.Y));
|
||||||
|
led.Size = new Size(MathF.Round(layoutLed.Width), MathF.Round(layoutLed.Height));
|
||||||
|
led.Shape = layoutLed.Shape;
|
||||||
|
led.ShapeData = layoutLed.ShapeData;
|
||||||
|
led.LayoutMetadata = layoutLed.CustomData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeExcessiveLeds)
|
||||||
|
{
|
||||||
|
List<LedId> ledsToRemove = device.Select(led => led.Id).Where(id => !ledIds.Contains(id)).ToList();
|
||||||
|
foreach (LedId led in ledsToRemove)
|
||||||
|
device.RemoveLed(led);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.DataModelExpansions;
|
using Artemis.Core.DataModelExpansions;
|
||||||
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core.Modules
|
namespace Artemis.Core.Modules
|
||||||
@ -91,11 +94,13 @@ namespace Artemis.Core.Modules
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ProfileModule : Module
|
public abstract class ProfileModule : Module
|
||||||
{
|
{
|
||||||
|
private readonly List<ProfileDescriptor> _defaultProfiles;
|
||||||
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
|
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal readonly List<PropertyInfo> HiddenPropertiesList = new();
|
protected internal readonly List<PropertyInfo> HiddenPropertiesList = new();
|
||||||
private readonly object _lock = new();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="ProfileModule" /> class
|
/// Creates a new instance of the <see cref="ProfileModule" /> class
|
||||||
@ -103,6 +108,7 @@ namespace Artemis.Core.Modules
|
|||||||
protected ProfileModule()
|
protected ProfileModule()
|
||||||
{
|
{
|
||||||
OpacityOverride = 1;
|
OpacityOverride = 1;
|
||||||
|
_defaultProfiles = new List<ProfileDescriptor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -130,6 +136,11 @@ namespace Artemis.Core.Modules
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AnimatingProfileChange { get; private set; }
|
public bool AnimatingProfileChange { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of default profiles, to add a new default profile use <see cref="AddDefaultProfile" />
|
||||||
|
/// </summary>
|
||||||
|
public ReadOnlyCollection<ProfileDescriptor> DefaultProfiles => _defaultProfiles.AsReadOnly();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called after the profile has updated
|
/// Called after the profile has updated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -148,6 +159,40 @@ namespace Artemis.Core.Modules
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the <see cref="ActiveProfile" /> has changed
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler? ActiveProfileChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a default profile by reading it from the file found at the provided path
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file"></param>
|
||||||
|
protected void AddDefaultProfile(string file)
|
||||||
|
{
|
||||||
|
// Ensure the file exists
|
||||||
|
if (!File.Exists(file))
|
||||||
|
throw new ArtemisPluginFeatureException(this, $"Could not find default profile at {file}.");
|
||||||
|
// Deserialize and make sure that succeeded
|
||||||
|
ProfileEntity? profileEntity = JsonConvert.DeserializeObject<ProfileEntity>(File.ReadAllText(file));
|
||||||
|
if (profileEntity == null)
|
||||||
|
throw new ArtemisPluginFeatureException(this, $"Failed to deserialize default profile at {file}.");
|
||||||
|
// Ensure the profile ID is unique
|
||||||
|
ProfileDescriptor descriptor = new(this, profileEntity) {NeedsAdaption = true};
|
||||||
|
if (_defaultProfiles.Any(d => d.Id == descriptor.Id))
|
||||||
|
throw new ArtemisPluginFeatureException(this, $"Cannot add default profile from {file}, profile ID {descriptor.Id} already in use.");
|
||||||
|
|
||||||
|
_defaultProfiles.Add(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the <see cref="ActiveProfileChanged" /> event
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnActiveProfileChanged()
|
||||||
|
{
|
||||||
|
ActiveProfileChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
internal override void InternalUpdate(double deltaTime)
|
internal override void InternalUpdate(double deltaTime)
|
||||||
{
|
{
|
||||||
StartUpdateMeasure();
|
StartUpdateMeasure();
|
||||||
@ -245,22 +290,5 @@ namespace Artemis.Core.Modules
|
|||||||
base.Deactivate(isDeactivateOverride);
|
base.Deactivate(isDeactivateOverride);
|
||||||
Activate(isActivateOverride);
|
Activate(isActivateOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Events
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when the <see cref="ActiveProfile" /> has changed
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler? ActiveProfileChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invokes the <see cref="ActiveProfileChanged" /> event
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void OnActiveProfileChanged()
|
|
||||||
{
|
|
||||||
ActiveProfileChanged?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,7 +23,7 @@ namespace Artemis.Core
|
|||||||
public abstract string Description { get; }
|
public abstract string Description { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a boolean indicating whether installing or uninstalling this prerequisite requires admin privileges
|
/// [NYI] Gets a boolean indicating whether installing or uninstalling this prerequisite requires admin privileges
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract bool RequiresElevation { get; }
|
public abstract bool RequiresElevation { get; }
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -17,11 +18,13 @@ namespace Artemis.Core
|
|||||||
/// <param name="fileName">The target file to execute</param>
|
/// <param name="fileName">The target file to execute</param>
|
||||||
/// <param name="arguments">A set of command-line arguments to use when starting the application</param>
|
/// <param name="arguments">A set of command-line arguments to use when starting the application</param>
|
||||||
/// <param name="waitForExit">A boolean indicating whether the action should wait for the process to exit</param>
|
/// <param name="waitForExit">A boolean indicating whether the action should wait for the process to exit</param>
|
||||||
public ExecuteFileAction(string name, string fileName, string? arguments = null, bool waitForExit = true) : base(name)
|
/// <param name="elevate">A boolean indicating whether the file should run with administrator privileges (does not require <see cref="PluginPrerequisite.RequiresElevation"/>)</param>
|
||||||
|
public ExecuteFileAction(string name, string fileName, string? arguments = null, bool waitForExit = true, bool elevate = false) : base(name)
|
||||||
{
|
{
|
||||||
FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
|
FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
|
||||||
Arguments = arguments;
|
Arguments = arguments;
|
||||||
WaitForExit = waitForExit;
|
WaitForExit = waitForExit;
|
||||||
|
Elevate = elevate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -39,6 +42,11 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool WaitForExit { get; }
|
public bool WaitForExit { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean indicating whether the file should run with administrator privileges
|
||||||
|
/// </summary>
|
||||||
|
public bool Elevate { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task Execute(CancellationToken cancellationToken)
|
public override async Task Execute(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@ -48,7 +56,7 @@ namespace Artemis.Core
|
|||||||
ShowProgressBar = true;
|
ShowProgressBar = true;
|
||||||
ProgressIndeterminate = true;
|
ProgressIndeterminate = true;
|
||||||
|
|
||||||
int result = await RunProcessAsync(FileName, Arguments);
|
int result = await RunProcessAsync(FileName, Arguments, Elevate);
|
||||||
|
|
||||||
Status = $"{FileName} exited with code {result}";
|
Status = $"{FileName} exited with code {result}";
|
||||||
}
|
}
|
||||||
@ -64,13 +72,19 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task<int> RunProcessAsync(string fileName, string? arguments)
|
private static Task<int> RunProcessAsync(string fileName, string? arguments, bool elevate)
|
||||||
{
|
{
|
||||||
TaskCompletionSource<int> tcs = new();
|
TaskCompletionSource<int> tcs = new();
|
||||||
|
|
||||||
Process process = new()
|
Process process = new()
|
||||||
{
|
{
|
||||||
StartInfo = {FileName = fileName, Arguments = arguments!},
|
StartInfo =
|
||||||
|
{
|
||||||
|
FileName = fileName,
|
||||||
|
Arguments = arguments!,
|
||||||
|
Verb = elevate ? "RunAs" : "",
|
||||||
|
UseShellExecute = elevate
|
||||||
|
},
|
||||||
EnableRaisingEvents = true
|
EnableRaisingEvents = true
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,7 +94,17 @@ namespace Artemis.Core
|
|||||||
process.Dispose();
|
process.Dispose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
process.Start();
|
process.Start();
|
||||||
|
}
|
||||||
|
catch (Win32Exception e)
|
||||||
|
{
|
||||||
|
if (!elevate || e.NativeErrorCode != 0x4c7)
|
||||||
|
throw;
|
||||||
|
tcs.SetResult(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -107,6 +107,11 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
Profile profile = new(profileDescriptor.ProfileModule, profileEntity);
|
Profile profile = new(profileDescriptor.ProfileModule, profileEntity);
|
||||||
InstantiateProfile(profile);
|
InstantiateProfile(profile);
|
||||||
|
if (profileDescriptor.NeedsAdaption)
|
||||||
|
{
|
||||||
|
AdaptProfile(profile);
|
||||||
|
profileDescriptor.NeedsAdaption = false;
|
||||||
|
}
|
||||||
|
|
||||||
profileDescriptor.ProfileModule.ChangeActiveProfile(profile, _rgbService.EnabledDevices);
|
profileDescriptor.ProfileModule.ChangeActiveProfile(profile, _rgbService.EnabledDevices);
|
||||||
SaveActiveProfile(profileDescriptor.ProfileModule);
|
SaveActiveProfile(profileDescriptor.ProfileModule);
|
||||||
@ -290,7 +295,7 @@ namespace Artemis.Core.Services
|
|||||||
profileEntity.Name = $"{profileEntity.Name} - {nameAffix}";
|
profileEntity.Name = $"{profileEntity.Name} - {nameAffix}";
|
||||||
|
|
||||||
_profileRepository.Add(profileEntity);
|
_profileRepository.Add(profileEntity);
|
||||||
return new ProfileDescriptor(profileModule, profileEntity);
|
return new ProfileDescriptor(profileModule, profileEntity) {NeedsAdaption = true};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
/// Sets up the notification provider that shows desktop notifications
|
/// Sets up the notification provider that shows desktop notifications
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="notificationProvider">The notification provider that shows desktop notifications</param>
|
/// <param name="notificationProvider">The notification provider that shows desktop notifications</param>
|
||||||
void ConfigureNotificationProvider(INotificationProvider notificationProvider);
|
void SetNotificationProvider(INotificationProvider notificationProvider);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queues a notification message for display in a snackbar.
|
/// Queues a notification message for display in a snackbar.
|
||||||
@ -123,7 +123,9 @@ namespace Artemis.UI.Shared.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title of the notification</param>
|
/// <param name="title">The title of the notification</param>
|
||||||
/// <param name="message">The message of the notification</param>
|
/// <param name="message">The message of the notification</param>
|
||||||
void ShowNotification(string title, string message);
|
/// <param name="activatedCallback">An optional callback that is invoked when the notification is clicked</param>
|
||||||
|
/// <param name="dismissedCallback">An optional callback that is invoked when the notification is dismissed</param>
|
||||||
|
void ShowNotification(string title, string message, Action? activatedCallback = null, Action? dismissedCallback = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows a desktop notification with a Material Design icon
|
/// Shows a desktop notification with a Material Design icon
|
||||||
@ -131,7 +133,9 @@ namespace Artemis.UI.Shared.Services
|
|||||||
/// <param name="title">The title of the notification</param>
|
/// <param name="title">The title of the notification</param>
|
||||||
/// <param name="message">The message of the notification</param>
|
/// <param name="message">The message of the notification</param>
|
||||||
/// <param name="icon">The name of the icon</param>
|
/// <param name="icon">The name of the icon</param>
|
||||||
void ShowNotification(string title, string message, PackIconKind icon);
|
/// <param name="activatedCallback">An optional callback that is invoked when the notification is clicked</param>
|
||||||
|
/// <param name="dismissedCallback">An optional callback that is invoked when the notification is dismissed</param>
|
||||||
|
void ShowNotification(string title, string message, PackIconKind icon, Action? activatedCallback = null, Action? dismissedCallback = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows a desktop notification with a Material Design icon
|
/// Shows a desktop notification with a Material Design icon
|
||||||
@ -139,6 +143,8 @@ namespace Artemis.UI.Shared.Services
|
|||||||
/// <param name="title">The title of the notification</param>
|
/// <param name="title">The title of the notification</param>
|
||||||
/// <param name="message">The message of the notification</param>
|
/// <param name="message">The message of the notification</param>
|
||||||
/// <param name="icon">The name of the icon as a string</param>
|
/// <param name="icon">The name of the icon as a string</param>
|
||||||
void ShowNotification(string title, string message, string icon);
|
/// <param name="activatedCallback">An optional callback that is invoked when the notification is clicked</param>
|
||||||
|
/// <param name="dismissedCallback">An optional callback that is invoked when the notification is dismissed</param>
|
||||||
|
void ShowNotification(string title, string message, string icon, Action? activatedCallback = null, Action? dismissedCallback = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using MaterialDesignThemes.Wpf;
|
using System;
|
||||||
|
using MaterialDesignThemes.Wpf;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Services
|
namespace Artemis.UI.Shared.Services
|
||||||
{
|
{
|
||||||
@ -6,7 +7,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
/// Represents a class provides desktop notifications so that <see cref="IMessageService" /> can us it to show desktop
|
/// Represents a class provides desktop notifications so that <see cref="IMessageService" /> can us it to show desktop
|
||||||
/// notifications
|
/// notifications
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface INotificationProvider
|
public interface INotificationProvider : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows a notification
|
/// Shows a notification
|
||||||
@ -14,6 +15,8 @@ namespace Artemis.UI.Shared.Services
|
|||||||
/// <param name="title">The title of the notification</param>
|
/// <param name="title">The title of the notification</param>
|
||||||
/// <param name="message">The message of the notification</param>
|
/// <param name="message">The message of the notification</param>
|
||||||
/// <param name="icon">The Material Design icon to show in the notification</param>
|
/// <param name="icon">The Material Design icon to show in the notification</param>
|
||||||
void ShowNotification(string title, string message, PackIconKind icon);
|
/// <param name="activatedCallback">A callback that is invoked when the notification is clicked</param>
|
||||||
|
/// <param name="dismissedCallback">A callback that is invoked when the notification is dismissed</param>
|
||||||
|
void ShowNotification(string title, string message, PackIconKind icon, Action? activatedCallback, Action? dismissedCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@ using MaterialDesignThemes.Wpf;
|
|||||||
|
|
||||||
namespace Artemis.UI.Shared.Services
|
namespace Artemis.UI.Shared.Services
|
||||||
{
|
{
|
||||||
internal class MessageService : IMessageService
|
internal class MessageService : IMessageService, IDisposable
|
||||||
{
|
{
|
||||||
private INotificationProvider? _notificationProvider;
|
private INotificationProvider? _notificationProvider;
|
||||||
public ISnackbarMessageQueue MainMessageQueue { get; }
|
public ISnackbarMessageQueue MainMessageQueue { get; }
|
||||||
@ -14,8 +14,12 @@ namespace Artemis.UI.Shared.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ConfigureNotificationProvider(INotificationProvider notificationProvider)
|
public void SetNotificationProvider(INotificationProvider notificationProvider)
|
||||||
{
|
{
|
||||||
|
if (ReferenceEquals(_notificationProvider, notificationProvider))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_notificationProvider?.Dispose();
|
||||||
_notificationProvider = notificationProvider;
|
_notificationProvider = notificationProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,22 +76,32 @@ namespace Artemis.UI.Shared.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ShowNotification(string title, string message)
|
public void ShowNotification(string title, string message, Action? activatedCallback = null, Action? dismissedCallback = null)
|
||||||
{
|
{
|
||||||
_notificationProvider?.ShowNotification(title, message, PackIconKind.None);
|
_notificationProvider?.ShowNotification(title, message, PackIconKind.None, activatedCallback, dismissedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ShowNotification(string title, string message, PackIconKind icon)
|
public void ShowNotification(string title, string message, PackIconKind icon, Action? activatedCallback = null, Action? dismissedCallback = null)
|
||||||
{
|
{
|
||||||
_notificationProvider?.ShowNotification(title, message, icon);
|
_notificationProvider?.ShowNotification(title, message, icon, activatedCallback, dismissedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ShowNotification(string title, string message, string icon)
|
public void ShowNotification(string title, string message, string icon, Action? activatedCallback = null, Action? dismissedCallback = null)
|
||||||
{
|
{
|
||||||
Enum.TryParse(typeof(PackIconKind), icon, true, out object? iconKind);
|
Enum.TryParse(typeof(PackIconKind), icon, true, out object? iconKind);
|
||||||
_notificationProvider?.ShowNotification(title, message, (PackIconKind) (iconKind ?? PackIconKind.None));
|
_notificationProvider?.ShowNotification(title, message, (PackIconKind) (iconKind ?? PackIconKind.None), activatedCallback, dismissedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_notificationProvider?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,10 +118,10 @@ namespace Artemis.UI
|
|||||||
|
|
||||||
private void UtilitiesOnShutdownRequested(object sender, EventArgs e)
|
private void UtilitiesOnShutdownRequested(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// Use PowerShell to kill the process after 2 sec just in case
|
// Use PowerShell to kill the process after 8 sec just in case
|
||||||
ProcessStartInfo info = new()
|
ProcessStartInfo info = new()
|
||||||
{
|
{
|
||||||
Arguments = "-Command \"& {Start-Sleep -s 2; (Get-Process 'Artemis.UI').kill()}",
|
Arguments = "-Command \"& {Start-Sleep -s 8; (Get-Process 'Artemis.UI').kill()}",
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
FileName = "PowerShell.exe"
|
FileName = "PowerShell.exe"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net5.0-windows</TargetFramework>
|
<TargetFramework>net5.0-windows10.0.17763.0</TargetFramework>
|
||||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<AssemblyTitle>Artemis</AssemblyTitle>
|
<AssemblyTitle>Artemis</AssemblyTitle>
|
||||||
@ -10,7 +10,8 @@
|
|||||||
<Description>Provides advanced unified lighting across many different brands RGB peripherals</Description>
|
<Description>Provides advanced unified lighting across many different brands RGB peripherals</Description>
|
||||||
<Copyright>Copyright © Robert Beekman - 2021</Copyright>
|
<Copyright>Copyright © Robert Beekman - 2021</Copyright>
|
||||||
<FileVersion>2.0.0.0</FileVersion>
|
<FileVersion>2.0.0.0</FileVersion>
|
||||||
<OutputPath>bin\</OutputPath>
|
<OutputPath>bin\net5.0-windows\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>False</AppendTargetFrameworkToOutputPath>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<SupportedPlatform>windows</SupportedPlatform>
|
<SupportedPlatform>windows</SupportedPlatform>
|
||||||
@ -135,13 +136,14 @@
|
|||||||
<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.0.0" />
|
<PackageReference Include="FluentValidation" Version="10.1.0" />
|
||||||
<PackageReference Include="Flurl.Http" Version="3.0.1" />
|
<PackageReference Include="Flurl.Http" Version="3.0.1" />
|
||||||
<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" />
|
||||||
<PackageReference Include="Humanizer.Core" Version="2.8.26" />
|
<PackageReference Include="Humanizer.Core" Version="2.8.26" />
|
||||||
<PackageReference Include="MaterialDesignExtensions" Version="3.3.0" />
|
<PackageReference Include="MaterialDesignExtensions" Version="3.3.0" />
|
||||||
<PackageReference Include="MaterialDesignThemes" Version="4.0.0" />
|
<PackageReference Include="MaterialDesignThemes" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.0.2" />
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.31" />
|
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.31" />
|
||||||
<PackageReference Include="Ninject" Version="3.3.4" />
|
<PackageReference Include="Ninject" Version="3.3.4" />
|
||||||
|
|||||||
@ -98,7 +98,7 @@ namespace Artemis.UI
|
|||||||
});
|
});
|
||||||
|
|
||||||
IRegistrationService registrationService = Kernel.Get<IRegistrationService>();
|
IRegistrationService registrationService = Kernel.Get<IRegistrationService>();
|
||||||
registrationService.RegisterInputProvider();
|
registrationService.RegisterProviders();
|
||||||
registrationService.RegisterControllers();
|
registrationService.RegisterControllers();
|
||||||
|
|
||||||
Execute.OnUIThreadSync(() => { registrationService.ApplyPreferredGraphicsContext(); });
|
Execute.OnUIThreadSync(() => { registrationService.ApplyPreferredGraphicsContext(); });
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Utilities;
|
using Artemis.UI.Utilities;
|
||||||
@ -14,7 +12,7 @@ using Linearstar.Windows.RawInput.Native;
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using MouseButton = Artemis.Core.Services.MouseButton;
|
using MouseButton = Artemis.Core.Services.MouseButton;
|
||||||
|
|
||||||
namespace Artemis.UI.InputProviders
|
namespace Artemis.UI.Providers
|
||||||
{
|
{
|
||||||
public class NativeWindowInputProvider : InputProvider
|
public class NativeWindowInputProvider : InputProvider
|
||||||
{
|
{
|
||||||
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace Artemis.UI.InputProviders
|
namespace Artemis.UI.Providers
|
||||||
{
|
{
|
||||||
public sealed class SpongeWindow : NativeWindow
|
public sealed class SpongeWindow : NativeWindow
|
||||||
{
|
{
|
||||||
101
src/Artemis.UI/Providers/ToastNotificationProvider.cs
Normal file
101
src/Artemis.UI/Providers/ToastNotificationProvider.cs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Windows.UI.Notifications;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.UI.Utilities;
|
||||||
|
using MaterialDesignThemes.Wpf;
|
||||||
|
using Microsoft.Toolkit.Uwp.Notifications;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Providers
|
||||||
|
{
|
||||||
|
public class ToastNotificationProvider : INotificationProvider
|
||||||
|
{
|
||||||
|
private ThemeWatcher _themeWatcher;
|
||||||
|
|
||||||
|
public ToastNotificationProvider()
|
||||||
|
{
|
||||||
|
_themeWatcher = new ThemeWatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PngBitmapEncoder GetEncoderForIcon(PackIconKind icon, Color color)
|
||||||
|
{
|
||||||
|
// Convert the PackIcon to an icon by drawing it on a visual
|
||||||
|
DrawingVisual drawingVisual = new();
|
||||||
|
DrawingContext drawingContext = drawingVisual.RenderOpen();
|
||||||
|
|
||||||
|
PackIcon packIcon = new() {Kind = icon};
|
||||||
|
Geometry geometry = Geometry.Parse(packIcon.Data);
|
||||||
|
|
||||||
|
// Scale the icon up to fit a 256x256 image and draw it
|
||||||
|
geometry = Geometry.Combine(geometry, Geometry.Empty, GeometryCombineMode.Union, new ScaleTransform(256 / geometry.Bounds.Right, 256 / geometry.Bounds.Bottom));
|
||||||
|
|
||||||
|
drawingContext.DrawGeometry(new SolidColorBrush(color), null, geometry);
|
||||||
|
drawingContext.Close();
|
||||||
|
|
||||||
|
// Render the visual and add it to a PNG encoder (we want opacity in our icon)
|
||||||
|
RenderTargetBitmap renderTargetBitmap = new(256, 256, 96, 96, PixelFormats.Pbgra32);
|
||||||
|
renderTargetBitmap.Render(drawingVisual);
|
||||||
|
PngBitmapEncoder encoder = new();
|
||||||
|
encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
|
||||||
|
|
||||||
|
return encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToastDismissed(string imagePath, Action dismissedCallback)
|
||||||
|
{
|
||||||
|
if (File.Exists(imagePath))
|
||||||
|
File.Delete(imagePath);
|
||||||
|
|
||||||
|
dismissedCallback?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToastActivated(string imagePath, Action activatedCallback)
|
||||||
|
{
|
||||||
|
if (File.Exists(imagePath))
|
||||||
|
File.Delete(imagePath);
|
||||||
|
|
||||||
|
activatedCallback?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Implementation of INotificationProvider
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ShowNotification(string title, string message, PackIconKind icon, Action activatedCallback, Action dismissedCallback)
|
||||||
|
{
|
||||||
|
string imagePath = Path.GetTempFileName().Replace(".tmp", "png");
|
||||||
|
|
||||||
|
Execute.OnUIThreadSync(() =>
|
||||||
|
{
|
||||||
|
using FileStream stream = File.OpenWrite(imagePath);
|
||||||
|
GetEncoderForIcon(icon, _themeWatcher.GetWindowsTheme() == ThemeWatcher.WindowsTheme.Dark ? Colors.White : Colors.Black).Save(stream);
|
||||||
|
});
|
||||||
|
|
||||||
|
new ToastContentBuilder()
|
||||||
|
.AddAppLogoOverride(new Uri(imagePath))
|
||||||
|
.AddText(title, AdaptiveTextStyle.Header)
|
||||||
|
.AddText(message)
|
||||||
|
.Show(t =>
|
||||||
|
{
|
||||||
|
t.Dismissed += (_, _) => ToastDismissed(imagePath, dismissedCallback);
|
||||||
|
t.Activated += (_, _) => ToastActivated(imagePath, activatedCallback);
|
||||||
|
t.Data = new NotificationData(new List<KeyValuePair<string, string>> {new("image", imagePath)});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ToastNotificationManagerCompat.Uninstall();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="574.026"
|
d:DesignHeight="574.026"
|
||||||
d:DesignWidth="1029.87"
|
d:DesignWidth="1029.87"
|
||||||
d:DataContext="{d:DesignInstance home:HomeViewModel, IsDesignTimeCreatable=True}">
|
d:DataContext="{d:DesignInstance home:HomeViewModel}">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
@ -38,22 +38,23 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Image Source="{svgc:SvgImage Source=/Resources/Images/Logo/bow.svg}" Height="100" Width="100"/>
|
<Image Source="{svgc:SvgImage Source=/Resources/Images/Logo/bow.svg}" Height="100" Width="100" />
|
||||||
<StackPanel Grid.Column="1" Margin="24 0 0 0" VerticalAlignment="Center">
|
<StackPanel Grid.Column="1" Margin="24 0 0 0" VerticalAlignment="Center">
|
||||||
<TextBlock Style="{StaticResource MaterialDesignHeadline4TextBlock}" TextWrapping="Wrap">
|
<TextBlock Style="{StaticResource MaterialDesignHeadline4TextBlock}" TextWrapping="Wrap">
|
||||||
<Run Text="Welcome to Artemis, the unified"></Run>
|
<Run Text="Welcome to Artemis, the unified" />
|
||||||
<Run Text="RGB">
|
<Run Text="RGB">
|
||||||
<Run.Foreground>
|
<Run.Foreground>
|
||||||
<LinearGradientBrush EndPoint="0,0" StartPoint="1,1">
|
<LinearGradientBrush EndPoint="0,0" StartPoint="1,1">
|
||||||
<GradientStop Color="#f19d25"/>
|
<GradientStop Color="#f19d25" />
|
||||||
<GradientStop Color="#f63d3d" Offset="0.2"/>
|
<GradientStop Color="#f63d3d" Offset="0.2" />
|
||||||
<GradientStop Color="#c93cec" Offset="0.4"/>
|
<GradientStop Color="#c93cec" Offset="0.4" />
|
||||||
<GradientStop Color="#2667f4" Offset="0.6"/>
|
<GradientStop Color="#2667f4" Offset="0.6" />
|
||||||
<GradientStop Color="#1cb6e7" Offset="0.8"/>
|
<GradientStop Color="#1cb6e7" Offset="0.8" />
|
||||||
<GradientStop Color="#2df4b5" Offset="1"/>
|
<GradientStop Color="#2df4b5" Offset="1" />
|
||||||
</LinearGradientBrush>
|
</LinearGradientBrush>
|
||||||
</Run.Foreground></Run>
|
</Run.Foreground>
|
||||||
<Run Text="platform."></Run>
|
</Run>
|
||||||
|
<Run Text="platform." />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
Foreground="{StaticResource SecondaryHueMidBrush}"
|
Foreground="{StaticResource SecondaryHueMidBrush}"
|
||||||
@ -70,7 +71,7 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Bottom"
|
VerticalAlignment="Bottom"
|
||||||
Margin="0 0 0 32">
|
Margin="0 0 0 32">
|
||||||
<Grid>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:Card Width="420" Margin="8 2 4 16" Height="Auto">
|
<materialDesign:Card Width="420" Margin="8 2 4 16" Height="Auto">
|
||||||
<Grid VerticalAlignment="Stretch">
|
<Grid VerticalAlignment="Stretch">
|
||||||
@ -187,7 +188,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:Card>
|
</materialDesign:Card>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<!-- PopupBox could be nice in the future when we actually have some stuff to send ppl to -->
|
<!-- PopupBox could be nice in the future when we actually have some stuff to send ppl to -->
|
||||||
<!--<materialDesign:PopupBox Style="{StaticResource MaterialDesignMultiFloatingActionPopupBox}"
|
<!--<materialDesign:PopupBox Style="{StaticResource MaterialDesignMultiFloatingActionPopupBox}"
|
||||||
|
|||||||
@ -35,13 +35,13 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
|
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
|
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||||
Width="26"
|
Width="26"
|
||||||
Height="26"
|
Height="26"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Command="{s:Action DeleteProfile}"
|
Command="{s:Action DeleteProfile}"
|
||||||
CommandParameter="{Binding}">
|
CommandParameter="{Binding}">
|
||||||
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" HorizontalAlignment="Right" />
|
<materialDesign:PackIcon Kind="Delete" Height="16" Width="16" HorizontalAlignment="Right" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|||||||
@ -59,6 +59,7 @@ namespace Artemis.UI.Screens.ProfileEditor
|
|||||||
Module = module;
|
Module = module;
|
||||||
DialogService = dialogService;
|
DialogService = dialogService;
|
||||||
|
|
||||||
|
DefaultProfiles = new BindableCollection<ProfileDescriptor>(module.DefaultProfiles);
|
||||||
Profiles = new BindableCollection<ProfileDescriptor>();
|
Profiles = new BindableCollection<ProfileDescriptor>();
|
||||||
|
|
||||||
// Populate the panels
|
// Populate the panels
|
||||||
@ -99,6 +100,9 @@ namespace Artemis.UI.Screens.ProfileEditor
|
|||||||
set => SetAndNotify(ref _profileViewModel, value);
|
set => SetAndNotify(ref _profileViewModel, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BindableCollection<ProfileDescriptor> DefaultProfiles { get; }
|
||||||
|
public bool HasDefaultProfiles => DefaultProfiles.Any();
|
||||||
|
|
||||||
public BindableCollection<ProfileDescriptor> Profiles
|
public BindableCollection<ProfileDescriptor> Profiles
|
||||||
{
|
{
|
||||||
get => _profiles;
|
get => _profiles;
|
||||||
@ -388,7 +392,9 @@ namespace Artemis.UI.Screens.ProfileEditor
|
|||||||
{
|
{
|
||||||
// Get all profiles from the database
|
// Get all profiles from the database
|
||||||
Profiles.Clear();
|
Profiles.Clear();
|
||||||
Profiles.AddRange(_profileService.GetProfileDescriptors(Module).OrderBy(d => d.Name));
|
Profiles.AddRange(_profileService.GetProfileDescriptors(Module));
|
||||||
|
Profiles.AddRange(Module.DefaultProfiles.Where(d => Profiles.All(p => p.Id != d.Id)));
|
||||||
|
Profiles.Sort(p => p.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Events;
|
using Artemis.UI.Events;
|
||||||
@ -17,18 +13,17 @@ using Hardcodet.Wpf.TaskbarNotification;
|
|||||||
using MaterialDesignThemes.Wpf;
|
using MaterialDesignThemes.Wpf;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
using Icon = System.Drawing.Icon;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens
|
namespace Artemis.UI.Screens
|
||||||
{
|
{
|
||||||
public class TrayViewModel : Screen, IMainWindowProvider, INotificationProvider
|
public class TrayViewModel : Screen, IMainWindowProvider
|
||||||
{
|
{
|
||||||
|
private readonly PluginSetting<ApplicationColorScheme> _colorScheme;
|
||||||
private readonly IDebugService _debugService;
|
private readonly IDebugService _debugService;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly IKernel _kernel;
|
private readonly IKernel _kernel;
|
||||||
private readonly IWindowManager _windowManager;
|
|
||||||
private readonly ThemeWatcher _themeWatcher;
|
private readonly ThemeWatcher _themeWatcher;
|
||||||
private readonly PluginSetting<ApplicationColorScheme> _colorScheme;
|
private readonly IWindowManager _windowManager;
|
||||||
private RootViewModel _rootViewModel;
|
private RootViewModel _rootViewModel;
|
||||||
private SplashViewModel _splashViewModel;
|
private SplashViewModel _splashViewModel;
|
||||||
private TaskbarIcon _taskBarIcon;
|
private TaskbarIcon _taskBarIcon;
|
||||||
@ -36,7 +31,6 @@ namespace Artemis.UI.Screens
|
|||||||
public TrayViewModel(IKernel kernel,
|
public TrayViewModel(IKernel kernel,
|
||||||
IWindowManager windowManager,
|
IWindowManager windowManager,
|
||||||
IWindowService windowService,
|
IWindowService windowService,
|
||||||
IMessageService messageService,
|
|
||||||
IUpdateService updateService,
|
IUpdateService updateService,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
ICoreService coreService,
|
ICoreService coreService,
|
||||||
@ -59,7 +53,6 @@ namespace Artemis.UI.Screens
|
|||||||
ApplyColorSchemeSetting();
|
ApplyColorSchemeSetting();
|
||||||
|
|
||||||
windowService.ConfigureMainWindowProvider(this);
|
windowService.ConfigureMainWindowProvider(this);
|
||||||
messageService.ConfigureNotificationProvider(this);
|
|
||||||
bool autoRunning = Bootstrapper.StartupArguments.Contains("--autorun");
|
bool autoRunning = Bootstrapper.StartupArguments.Contains("--autorun");
|
||||||
bool minimized = Bootstrapper.StartupArguments.Contains("--minimized");
|
bool minimized = Bootstrapper.StartupArguments.Contains("--minimized");
|
||||||
bool showOnAutoRun = settingsService.GetSetting("UI.ShowOnStartup", true).Value;
|
bool showOnAutoRun = settingsService.GetSetting("UI.ShowOnStartup", true).Value;
|
||||||
@ -207,43 +200,6 @@ namespace Artemis.UI.Screens
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Implementation of INotificationProvider
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void ShowNotification(string title, string message, PackIconKind icon)
|
|
||||||
{
|
|
||||||
Execute.OnUIThread(() =>
|
|
||||||
{
|
|
||||||
// Convert the PackIcon to an icon by drawing it on a visual
|
|
||||||
DrawingVisual drawingVisual = new();
|
|
||||||
DrawingContext drawingContext = drawingVisual.RenderOpen();
|
|
||||||
|
|
||||||
PackIcon packIcon = new() {Kind = icon};
|
|
||||||
Geometry geometry = Geometry.Parse(packIcon.Data);
|
|
||||||
|
|
||||||
// Scale the icon up to fit a 256x256 image and draw it
|
|
||||||
geometry = Geometry.Combine(geometry, Geometry.Empty, GeometryCombineMode.Union, new ScaleTransform(256 / geometry.Bounds.Right, 256 / geometry.Bounds.Bottom));
|
|
||||||
drawingContext.DrawGeometry(new SolidColorBrush(Colors.White), null, geometry);
|
|
||||||
drawingContext.Close();
|
|
||||||
|
|
||||||
// Render the visual and add it to a PNG encoder (we want opacity in our icon)
|
|
||||||
RenderTargetBitmap renderTargetBitmap = new(256, 256, 96, 96, PixelFormats.Pbgra32);
|
|
||||||
renderTargetBitmap.Render(drawingVisual);
|
|
||||||
PngBitmapEncoder encoder = new();
|
|
||||||
encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
|
|
||||||
|
|
||||||
// Save the PNG and get an icon handle
|
|
||||||
using MemoryStream stream = new();
|
|
||||||
encoder.Save(stream);
|
|
||||||
Icon convertedIcon = Icon.FromHandle(new Bitmap(stream).GetHicon());
|
|
||||||
|
|
||||||
// Show the 'balloon'
|
|
||||||
_taskBarIcon.ShowBalloonTip(title, message, convertedIcon, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Implementation of IMainWindowProvider
|
#region Implementation of IMainWindowProvider
|
||||||
|
|
||||||
public bool IsMainWindowOpen { get; private set; }
|
public bool IsMainWindowOpen { get; private set; }
|
||||||
|
|||||||
@ -6,8 +6,8 @@ using Artemis.UI.Controllers;
|
|||||||
using Artemis.UI.DefaultTypes.DataModel.Display;
|
using Artemis.UI.DefaultTypes.DataModel.Display;
|
||||||
using Artemis.UI.DefaultTypes.DataModel.Input;
|
using Artemis.UI.DefaultTypes.DataModel.Input;
|
||||||
using Artemis.UI.DefaultTypes.PropertyInput;
|
using Artemis.UI.DefaultTypes.PropertyInput;
|
||||||
using Artemis.UI.InputProviders;
|
|
||||||
using Artemis.UI.Ninject;
|
using Artemis.UI.Ninject;
|
||||||
|
using Artemis.UI.Providers;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.UI.SkiaSharp;
|
using Artemis.UI.SkiaSharp;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
@ -22,6 +22,7 @@ namespace Artemis.UI.Services
|
|||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly IInputService _inputService;
|
private readonly IInputService _inputService;
|
||||||
|
private readonly IMessageService _messageService;
|
||||||
private readonly IWebServerService _webServerService;
|
private readonly IWebServerService _webServerService;
|
||||||
private readonly IRgbService _rgbService;
|
private readonly IRgbService _rgbService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
@ -36,6 +37,7 @@ namespace Artemis.UI.Services
|
|||||||
IProfileEditorService profileEditorService,
|
IProfileEditorService profileEditorService,
|
||||||
IPluginManagementService pluginManagementService,
|
IPluginManagementService pluginManagementService,
|
||||||
IInputService inputService,
|
IInputService inputService,
|
||||||
|
IMessageService messageService,
|
||||||
IWebServerService webServerService,
|
IWebServerService webServerService,
|
||||||
IRgbService rgbService,
|
IRgbService rgbService,
|
||||||
ISettingsService settingsService)
|
ISettingsService settingsService)
|
||||||
@ -46,6 +48,7 @@ namespace Artemis.UI.Services
|
|||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
_pluginManagementService = pluginManagementService;
|
_pluginManagementService = pluginManagementService;
|
||||||
_inputService = inputService;
|
_inputService = inputService;
|
||||||
|
_messageService = messageService;
|
||||||
_webServerService = webServerService;
|
_webServerService = webServerService;
|
||||||
_rgbService = rgbService;
|
_rgbService = rgbService;
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
@ -99,9 +102,10 @@ namespace Artemis.UI.Services
|
|||||||
_registeredBuiltInPropertyEditors = true;
|
_registeredBuiltInPropertyEditors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterInputProvider()
|
public void RegisterProviders()
|
||||||
{
|
{
|
||||||
_inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService));
|
_inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService));
|
||||||
|
_messageService.SetNotificationProvider(new ToastNotificationProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterControllers()
|
public void RegisterControllers()
|
||||||
@ -160,7 +164,7 @@ namespace Artemis.UI.Services
|
|||||||
void RegisterBuiltInDataModelDisplays();
|
void RegisterBuiltInDataModelDisplays();
|
||||||
void RegisterBuiltInDataModelInputs();
|
void RegisterBuiltInDataModelInputs();
|
||||||
void RegisterBuiltInPropertyEditors();
|
void RegisterBuiltInPropertyEditors();
|
||||||
void RegisterInputProvider();
|
void RegisterProviders();
|
||||||
void RegisterControllers();
|
void RegisterControllers();
|
||||||
void ApplyPreferredGraphicsContext();
|
void ApplyPreferredGraphicsContext();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
using Windows.UI.Notifications;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Exceptions;
|
using Artemis.UI.Exceptions;
|
||||||
@ -16,9 +17,8 @@ using Artemis.UI.Services.Models.UpdateService;
|
|||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Flurl;
|
using Flurl;
|
||||||
using Flurl.Http;
|
using Flurl.Http;
|
||||||
using MaterialDesignThemes.Wpf;
|
using Microsoft.Toolkit.Uwp.Notifications;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Constants = Artemis.Core.Constants;
|
|
||||||
using File = System.IO.File;
|
using File = System.IO.File;
|
||||||
|
|
||||||
namespace Artemis.UI.Services
|
namespace Artemis.UI.Services
|
||||||
@ -32,14 +32,12 @@ namespace Artemis.UI.Services
|
|||||||
private readonly PluginSetting<bool> _checkForUpdates;
|
private readonly PluginSetting<bool> _checkForUpdates;
|
||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IMessageService _messageService;
|
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
|
|
||||||
public UpdateService(ILogger logger, ISettingsService settingsService, IDialogService dialogService, IMessageService messageService, IWindowService windowService)
|
public UpdateService(ILogger logger, ISettingsService settingsService, IDialogService dialogService, IWindowService windowService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
_messageService = messageService;
|
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
_windowService.MainWindowOpened += WindowServiceOnMainWindowOpened;
|
_windowService.MainWindowOpened += WindowServiceOnMainWindowOpened;
|
||||||
|
|
||||||
@ -52,8 +50,6 @@ namespace Artemis.UI.Services
|
|||||||
timer.Start();
|
timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SuspendAutoUpdate { get; set; }
|
|
||||||
|
|
||||||
private async Task OfferUpdate(DevOpsBuild buildInfo)
|
private async Task OfferUpdate(DevOpsBuild buildInfo)
|
||||||
{
|
{
|
||||||
object result = await _dialogService.ShowDialog<UpdateDialogViewModel>(new Dictionary<string, object> {{"buildInfo", buildInfo}});
|
object result = await _dialogService.ShowDialog<UpdateDialogViewModel>(new Dictionary<string, object> {{"buildInfo", buildInfo}});
|
||||||
@ -82,6 +78,31 @@ namespace Artemis.UI.Services
|
|||||||
await httpResponseMessage.Content.CopyToAsync(fs);
|
await httpResponseMessage.Content.CopyToAsync(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void TOnActivated(ToastNotification sender, object args)
|
||||||
|
{
|
||||||
|
if (args is not ToastActivatedEventArgs toastEventArgs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (toastEventArgs.Arguments == "update")
|
||||||
|
await ApplyUpdate();
|
||||||
|
else if (toastEventArgs.Arguments == "later")
|
||||||
|
SuspendAutoUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void CheckForUpdatesOnSettingChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// Run an auto-update as soon as the setting gets changed to enabled
|
||||||
|
if (_checkForUpdates.Value)
|
||||||
|
await AutoUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void WindowServiceOnMainWindowOpened(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
await AutoUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SuspendAutoUpdate { get; set; }
|
||||||
|
|
||||||
public async Task<bool> AutoUpdate()
|
public async Task<bool> AutoUpdate()
|
||||||
{
|
{
|
||||||
if (Constants.BuildInfo.IsLocalBuild)
|
if (Constants.BuildInfo.IsLocalBuild)
|
||||||
@ -114,27 +135,26 @@ namespace Artemis.UI.Services
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_windowService.IsMainWindowOpen)
|
if (_windowService.IsMainWindowOpen)
|
||||||
{
|
|
||||||
await OfferUpdate(buildInfo);
|
await OfferUpdate(buildInfo);
|
||||||
}
|
|
||||||
else if (_autoInstallUpdates.Value)
|
else if (_autoInstallUpdates.Value)
|
||||||
{
|
{
|
||||||
// Lets go
|
new ToastContentBuilder()
|
||||||
_messageService.ShowNotification(
|
.AddText("Installing new version", AdaptiveTextStyle.Header)
|
||||||
"Installing new version",
|
.AddText($"Build {buildNumberDisplay} is available, currently on {Constants.BuildInfo.BuildNumberDisplay}.")
|
||||||
$"Build {buildNumberDisplay} is available, currently on {Constants.BuildInfo.BuildNumberDisplay}.",
|
.AddProgressBar(null, null, true)
|
||||||
PackIconKind.Update
|
.Show();
|
||||||
);
|
|
||||||
await ApplyUpdate();
|
await ApplyUpdate();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If auto-install is disabled and the window is closed, best we can do is notify the user and stop.
|
// If auto-install is disabled and the window is closed, best we can do is notify the user and stop.
|
||||||
_messageService.ShowNotification(
|
new ToastContentBuilder()
|
||||||
"New version available",
|
.AddText("New version available", AdaptiveTextStyle.Header)
|
||||||
$"Build {buildNumberDisplay} is available, currently on {Constants.BuildInfo.BuildNumberDisplay}.",
|
.AddText($"Build {buildNumberDisplay} is available, currently on {Constants.BuildInfo.BuildNumberDisplay}.")
|
||||||
PackIconKind.Update
|
.AddButton("Update", ToastActivationType.Background, "update")
|
||||||
);
|
.AddButton("Later", ToastActivationType.Background, "later")
|
||||||
|
.Show(t => t.Activated += TOnActivated);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -157,9 +177,7 @@ namespace Artemis.UI.Services
|
|||||||
|
|
||||||
// Always update installer if it is missing ^^
|
// Always update installer if it is missing ^^
|
||||||
if (!File.Exists(installerPath))
|
if (!File.Exists(installerPath))
|
||||||
{
|
|
||||||
await UpdateInstaller();
|
await UpdateInstaller();
|
||||||
}
|
|
||||||
// Compare the creation date of the installer with the build date and update if needed
|
// Compare the creation date of the installer with the build date and update if needed
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -226,22 +244,6 @@ namespace Artemis.UI.Services
|
|||||||
.WithHeader("Accept", "application/vnd.github.v3+json")
|
.WithHeader("Accept", "application/vnd.github.v3+json")
|
||||||
.GetJsonAsync<GitHubDifference>();
|
.GetJsonAsync<GitHubDifference>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event handlers
|
|
||||||
|
|
||||||
private async void CheckForUpdatesOnSettingChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
// Run an auto-update as soon as the setting gets changed to enabled
|
|
||||||
if (_checkForUpdates.Value)
|
|
||||||
await AutoUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void WindowServiceOnMainWindowOpened(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
await AutoUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IUpdateService : IArtemisUIService
|
public interface IUpdateService : IArtemisUIService
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
".NETCoreApp,Version=v5.0": {
|
".NETCoreApp,Version=v5.0": {
|
||||||
"FluentValidation": {
|
"FluentValidation": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[10.0.0, )",
|
"requested": "[10.1.0, )",
|
||||||
"resolved": "10.0.0",
|
"resolved": "10.1.0",
|
||||||
"contentHash": "jNFPbLjBy/bfIWx4BV/WVEsS+1OxBVf22mmSdvVa9RCHJDkNhAjbKZkxgA0s1rYNFxVn+a1fQbos95t4j/z3Zg=="
|
"contentHash": "RxhhfY9IcEY2qUMYjoUxegInbuE5Bwll7dVLsXpiJf25g0ztmzUK+HHqtPcub1caPemhMJsC+NwjHei+NgAkvA=="
|
||||||
},
|
},
|
||||||
"Flurl.Http": {
|
"Flurl.Http": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
@ -60,6 +60,18 @@
|
|||||||
"MaterialDesignColors": "2.0.0"
|
"MaterialDesignColors": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Toolkit.Uwp.Notifications": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[7.0.2, )",
|
||||||
|
"resolved": "7.0.2",
|
||||||
|
"contentHash": "UWwo9Jdkk52E3zmUMoO+JC2Aix1gizCPIHtVBUON/uyzjKlnjgqoBd7zeS8HJ94Vsm2mW4OjVtPVhz3sEwEDQA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Win32.Registry": "4.7.0",
|
||||||
|
"System.Drawing.Common": "4.7.0",
|
||||||
|
"System.Reflection.Emit": "4.7.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Win32.Registry": {
|
"Microsoft.Win32.Registry": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[5.0.0, )",
|
"requested": "[5.0.0, )",
|
||||||
@ -990,15 +1002,8 @@
|
|||||||
},
|
},
|
||||||
"System.Reflection.Emit": {
|
"System.Reflection.Emit": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.7.0",
|
||||||
"contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==",
|
"contentHash": "VR4kk8XLKebQ4MZuKuIni/7oh+QGFmZW3qORd1GvBq/8026OpW501SzT/oypwiQl4TvT8ErnReh/NzY9u+C6wQ=="
|
||||||
"dependencies": {
|
|
||||||
"System.IO": "4.3.0",
|
|
||||||
"System.Reflection": "4.3.0",
|
|
||||||
"System.Reflection.Emit.ILGeneration": "4.3.0",
|
|
||||||
"System.Reflection.Primitives": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"System.Reflection.Emit.ILGeneration": {
|
"System.Reflection.Emit.ILGeneration": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user