From 3994b49f089226559d6b7b098e1d0f6863bfb48a Mon Sep 17 00:00:00 2001 From: Robert Date: Sat, 3 Sep 2022 10:34:53 +0200 Subject: [PATCH] Windows - Fix crash when clicking on update notification Meta - Code cleanup --- src/Artemis.Core/Constants.cs | 10 ++--- .../LayerPropertyKeyframeEventArgs.cs | 29 ++++++------ src/Artemis.Core/Models/BreakableModel.cs | 6 +-- .../Services/Interfaces/ICoreService.cs | 3 +- .../ProcessMonitor/ProcessComparer.cs | 20 +++++++++ .../ProcessMonitor/ProcessMonitorService.cs | 17 ------- .../Services/WebServer/WebServerService.cs | 44 +++++++++---------- src/Artemis.Core/Utilities/Numeric.cs | 25 ++++++++--- src/Artemis.Core/VisualScripting/InputPin.cs | 8 ++-- .../VisualScripting/Interfaces/INode.cs | 4 +- .../VisualScripting/Interfaces/IPin.cs | 5 ++- .../Internal/DataBindingExitNode.cs | 22 +++++----- src/Artemis.Core/VisualScripting/Node.cs | 4 +- .../VisualScripting/NodeScript.cs | 26 +++++------ src/Artemis.Core/VisualScripting/OutputPin.cs | 2 - src/Artemis.Core/VisualScripting/Pin.cs | 1 - .../Providers/Input/LinuxInputProvider.cs | 6 +-- .../LostFocusNumericUpDownBindingBehavior.cs | 1 - .../Services/MainWindow/IMainWindowService.cs | 6 +-- .../Services/MainWindow/MainWindowService.cs | 6 +-- .../NodeEditor/Commands/ConnectPins.cs | 5 +-- .../NodeEditor/NodeConnectionStore.cs | 2 +- src/Artemis.UI.Windows/App.axaml.cs | 11 ++--- .../Providers/Input/WindowsInputProvider.cs | 2 +- .../Providers/UpdateProvider.cs | 10 ++--- src/Artemis.UI/ArtemisBootstrapper.cs | 1 - .../Controllers/RemoteController.cs | 3 +- src/Artemis.UI/MainWindow.axaml.cs | 2 +- .../Device/DevicePropertiesViewModel.cs | 20 ++++----- .../ProfileTree/ProfileTreeView.axaml.cs | 2 +- .../Panels/ProfileTree/TreeItemViewModel.cs | 1 + .../DataBinding/DataBindingViewModel.cs | 2 +- .../ProfileEditor/ProfileEditorViewModel.cs | 8 ++-- src/Artemis.UI/Screens/Root/RootViewModel.cs | 29 ++++++------ .../SurfaceEditor/SurfaceEditorViewModel.cs | 44 +++++++++---------- .../NodeScriptWindowViewModel.cs | 7 ++- 36 files changed, 201 insertions(+), 193 deletions(-) create mode 100644 src/Artemis.Core/Services/ProcessMonitor/ProcessComparer.cs diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs index e37f18ffb..f2abc9aa3 100644 --- a/src/Artemis.Core/Constants.cs +++ b/src/Artemis.Core/Constants.cs @@ -91,11 +91,6 @@ public static class Constants /// public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null); - /// - /// Gets the startup arguments provided to the application - /// - public static ReadOnlyCollection StartupArguments { get; set; } = null!; - internal static readonly CorePluginFeature CorePluginFeature = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Core")}; internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Effect Placeholder")}; @@ -153,6 +148,11 @@ public static class Constants typeof(decimal) }; + /// + /// Gets the startup arguments provided to the application + /// + public static ReadOnlyCollection StartupArguments { get; set; } = null!; + /// /// Gets the graphics context to be used for rendering by SkiaSharp. Can be set via /// . diff --git a/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs b/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs index 962240239..5a46b7c7f 100644 --- a/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs +++ b/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs @@ -1,20 +1,19 @@ using System; -namespace Artemis.Core -{ - /// - /// Provides data for layer property events. - /// - public class LayerPropertyKeyframeEventArgs : EventArgs - { - internal LayerPropertyKeyframeEventArgs(ILayerPropertyKeyframe keyframe) - { - Keyframe = keyframe; - } +namespace Artemis.Core; - /// - /// Gets the keyframe this event is related to - /// - public ILayerPropertyKeyframe Keyframe { get; } +/// +/// Provides data for layer property events. +/// +public class LayerPropertyKeyframeEventArgs : EventArgs +{ + internal LayerPropertyKeyframeEventArgs(ILayerPropertyKeyframe keyframe) + { + Keyframe = keyframe; } + + /// + /// Gets the keyframe this event is related to + /// + public ILayerPropertyKeyframe Keyframe { get; } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/BreakableModel.cs b/src/Artemis.Core/Models/BreakableModel.cs index a752bf38b..1910cc2cc 100644 --- a/src/Artemis.Core/Models/BreakableModel.cs +++ b/src/Artemis.Core/Models/BreakableModel.cs @@ -69,16 +69,16 @@ public abstract class BreakableModel : CorePropertyChanged, IBreakableModel /// public void ClearBrokenState(string state) { - if (state == null) + if (state == null) throw new ArgumentNullException(nameof(state)); - + // If there was no broken state to begin with, done! if (BrokenState == null) return; // Only clear similar broken states if (BrokenState != state) return; - + BrokenState = null; BrokenStateException = null; OnBrokenStateChanged(); diff --git a/src/Artemis.Core/Services/Interfaces/ICoreService.cs b/src/Artemis.Core/Services/Interfaces/ICoreService.cs index 8dd297038..66de54365 100644 --- a/src/Artemis.Core/Services/Interfaces/ICoreService.cs +++ b/src/Artemis.Core/Services/Interfaces/ICoreService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace Artemis.Core.Services; @@ -27,7 +26,7 @@ public interface ICoreService : IArtemisService, IDisposable /// Gets or sets whether profiles are rendered each frame by calling their Render method /// bool ProfileRenderingDisabled { get; set; } - + /// /// Gets a boolean indicating whether Artemis is running in an elevated environment (admin permissions) /// diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessComparer.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessComparer.cs new file mode 100644 index 000000000..14ac5e765 --- /dev/null +++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessComparer.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Artemis.Core.Services; + +internal class ProcessComparer : IEqualityComparer +{ + public bool Equals(Process? x, Process? y) + { + if (x == null && y == null) return true; + if (x == null || y == null) return false; + return x.Id == y.Id && x.ProcessName == y.ProcessName && x.SessionId == y.SessionId; + } + + public int GetHashCode(Process? obj) + { + if (obj == null) return 0; + return obj.Id; + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs index e5da142a7..fffcc100d 100644 --- a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs +++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Linq; using System.Timers; using Artemis.Core.Modules; -using Serilog; namespace Artemis.Core.Services; @@ -42,20 +41,4 @@ internal class ProcessMonitorService : IProcessMonitorService { return _lastScannedProcesses; } -} - -internal class ProcessComparer : IEqualityComparer -{ - public bool Equals(Process? x, Process? y) - { - if (x == null && y == null) return true; - if (x == null || y == null) return false; - return x.Id == y.Id && x.ProcessName == y.ProcessName && x.SessionId == y.SessionId; - } - - public int GetHashCode(Process? obj) - { - if (obj == null) return 0; - return obj.Id; - } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs index f082ed6df..83d269fc4 100644 --- a/src/Artemis.Core/Services/WebServer/WebServerService.cs +++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs @@ -38,6 +38,24 @@ internal class WebServerService : IWebServerService, IDisposable StartWebServer(); } + public event EventHandler? WebServerStopped; + public event EventHandler? WebServerStarted; + + protected virtual void OnWebServerStopped() + { + WebServerStopped?.Invoke(this, EventArgs.Empty); + } + + protected virtual void OnWebServerStarting() + { + WebServerStarting?.Invoke(this, EventArgs.Empty); + } + + protected virtual void OnWebServerStarted() + { + WebServerStarted?.Invoke(this, EventArgs.Empty); + } + private void WebServerEnabledSettingOnSettingChanged(object? sender, EventArgs e) { StartWebServer(); @@ -76,6 +94,7 @@ internal class WebServerService : IWebServerService, IDisposable public WebServer? Server { get; private set; } public PluginsModule PluginsModule { get; } + public event EventHandler? WebServerStarting; #region Web server managament @@ -129,7 +148,7 @@ internal class WebServerService : IWebServerService, IDisposable if (!_webServerEnabledSetting.Value) return; - + if (Constants.StartupArguments.Contains("--disable-webserver")) { _logger.Warning("Artemis launched with --disable-webserver, not enabling the webserver"); @@ -302,27 +321,4 @@ internal class WebServerService : IWebServerService, IDisposable } #endregion - - #region Events - - protected virtual void OnWebServerStopped() - { - WebServerStopped?.Invoke(this, EventArgs.Empty); - } - - protected virtual void OnWebServerStarting() - { - WebServerStarting?.Invoke(this, EventArgs.Empty); - } - - protected virtual void OnWebServerStarted() - { - WebServerStarted?.Invoke(this, EventArgs.Empty); - } - - public event EventHandler? WebServerStopped; - public event EventHandler? WebServerStarting; - public event EventHandler? WebServerStarted; - - #endregion } \ No newline at end of file diff --git a/src/Artemis.Core/Utilities/Numeric.cs b/src/Artemis.Core/Utilities/Numeric.cs index 36f04e14f..a6d776575 100644 --- a/src/Artemis.Core/Utilities/Numeric.cs +++ b/src/Artemis.Core/Utilities/Numeric.cs @@ -48,7 +48,7 @@ public readonly struct Numeric : IComparable, IConvertible { _value = value; } - + /// /// Creates a new instance of from a /// @@ -160,10 +160,25 @@ public readonly struct Numeric : IComparable, IConvertible return (byte) Math.Clamp(p._value, 0, 255); } - public static implicit operator Numeric(double d) => new(d); - public static implicit operator Numeric(float f) => new(f); - public static implicit operator Numeric(int i) => new(i); - public static implicit operator Numeric(byte b) => new(b); + public static implicit operator Numeric(double d) + { + return new(d); + } + + public static implicit operator Numeric(float f) + { + return new(f); + } + + public static implicit operator Numeric(int i) + { + return new(i); + } + + public static implicit operator Numeric(byte b) + { + return new(b); + } public static implicit operator long(Numeric p) { diff --git a/src/Artemis.Core/VisualScripting/InputPin.cs b/src/Artemis.Core/VisualScripting/InputPin.cs index 9db82c693..90933f31b 100644 --- a/src/Artemis.Core/VisualScripting/InputPin.cs +++ b/src/Artemis.Core/VisualScripting/InputPin.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using Newtonsoft.Json; namespace Artemis.Core; @@ -96,7 +94,7 @@ public sealed class InputPin : Pin { if (type == _type) return; - + base.ChangeType(type, ref _type); Value = type.GetDefault(); } @@ -111,9 +109,13 @@ public sealed class InputPin : Pin Value = Type.GetDefault()!; } else if (ConnectedTo.Count > 0) + { Value = ConnectedTo[0].PinValue; + } else + { Value = null; + } } #endregion diff --git a/src/Artemis.Core/VisualScripting/Interfaces/INode.cs b/src/Artemis.Core/VisualScripting/Interfaces/INode.cs index eb3fc4177..022cddfaa 100644 --- a/src/Artemis.Core/VisualScripting/Interfaces/INode.cs +++ b/src/Artemis.Core/VisualScripting/Interfaces/INode.cs @@ -59,7 +59,7 @@ public interface INode : INotifyPropertyChanged, IBreakableModel /// Called when the node resets /// event EventHandler Resetting; - + /// /// Occurs when a pin was added to the node /// @@ -69,7 +69,7 @@ public interface INode : INotifyPropertyChanged, IBreakableModel /// Occurs when a pin was removed from the node /// event EventHandler> PinRemoved; - + /// /// Occurs when a pin collection was added to the node /// diff --git a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs index 67a0619c3..be3f1868e 100644 --- a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs +++ b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs @@ -85,7 +85,10 @@ public interface IPin /// Determines whether this pin is compatible with the given type /// /// The type to check for compatibility - /// A boolean indicating whether or not enums should be exactly equal or just both be enums + /// + /// A boolean indicating whether or not enums should be exactly equal or just both be + /// enums + /// /// if the type is compatible, otherwise . public bool IsTypeCompatible(Type type, bool forgivingEnumMatching = true); } \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs b/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs index cd7818b41..6b4d367f5 100644 --- a/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs +++ b/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs @@ -26,6 +26,17 @@ internal class DataBindingExitNode : Node, IExitNode property.SetValue(pendingValue); } + public override void Evaluate() + { + foreach ((IDataBindingProperty? property, InputPin? inputPin) in _propertyPins) + { + if (inputPin.ConnectedTo.Any()) + _propertyValues[property] = inputPin.Value!; + else + _propertyValues.Remove(property); + } + } + private void ClearInputPins() { while (Pins.Any()) @@ -59,15 +70,4 @@ internal class DataBindingExitNode : Node, IExitNode } public override bool IsExitNode => true; - - public override void Evaluate() - { - foreach ((IDataBindingProperty? property, InputPin? inputPin) in _propertyPins) - { - if (inputPin.ConnectedTo.Any()) - _propertyValues[property] = inputPin.Value!; - else - _propertyValues.Remove(property); - } - } } \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/Node.cs b/src/Artemis.Core/VisualScripting/Node.cs index 70b313fd3..7e2161580 100644 --- a/src/Artemis.Core/VisualScripting/Node.cs +++ b/src/Artemis.Core/VisualScripting/Node.cs @@ -97,7 +97,7 @@ public abstract class Node : BreakableModel, INode /// public override string BrokenDisplayName => Name; - + #endregion #region Construtors @@ -373,7 +373,7 @@ public abstract class Node : BreakableModel, INode { TryOrBreak(Evaluate, "Failed to evaluate"); } - + /// /// Called whenever the node must show it's custom view model, if , no custom view model is used /// diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs index 3034187f0..1c77626f8 100644 --- a/src/Artemis.Core/VisualScripting/NodeScript.cs +++ b/src/Artemis.Core/VisualScripting/NodeScript.cs @@ -14,6 +14,19 @@ namespace Artemis.Core; /// public abstract class NodeScript : CorePropertyChanged, INodeScript { + private void NodeTypeStoreOnNodeTypeAdded(object? sender, NodeTypeStoreEvent e) + { + if (Entity.Nodes.Any(n => e.TypeRegistration.MatchesEntity(n))) + Load(); + } + + private void NodeTypeStoreOnNodeTypeRemoved(object? sender, NodeTypeStoreEvent e) + { + List nodes = Nodes.Where(n => n.GetType() == e.TypeRegistration.NodeData.Type).ToList(); + foreach (INode node in nodes) + RemoveNode(node); + } + /// public event EventHandler>? NodeAdded; @@ -374,19 +387,6 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript } #endregion - - private void NodeTypeStoreOnNodeTypeAdded(object? sender, NodeTypeStoreEvent e) - { - if (Entity.Nodes.Any(n => e.TypeRegistration.MatchesEntity(n))) - Load(); - } - - private void NodeTypeStoreOnNodeTypeRemoved(object? sender, NodeTypeStoreEvent e) - { - List nodes = Nodes.Where(n => n.GetType() == e.TypeRegistration.NodeData.Type).ToList(); - foreach (INode node in nodes) - RemoveNode(node); - } } /// diff --git a/src/Artemis.Core/VisualScripting/OutputPin.cs b/src/Artemis.Core/VisualScripting/OutputPin.cs index b9fa3332d..52bd0993a 100644 --- a/src/Artemis.Core/VisualScripting/OutputPin.cs +++ b/src/Artemis.Core/VisualScripting/OutputPin.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using Newtonsoft.Json; namespace Artemis.Core; diff --git a/src/Artemis.Core/VisualScripting/Pin.cs b/src/Artemis.Core/VisualScripting/Pin.cs index 8258ed4bc..742e0e4b7 100644 --- a/src/Artemis.Core/VisualScripting/Pin.cs +++ b/src/Artemis.Core/VisualScripting/Pin.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Threading.Tasks; using Artemis.Core.Events; namespace Artemis.Core; diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs index 26c5c36ed..e735a8ed9 100644 --- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs +++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs @@ -33,14 +33,12 @@ public class LinuxInputProvider : InputProvider protected override void Dispose(bool disposing) { if (disposing) - { for (int i = _readers.Count - 1; i >= 0; i--) { _readers[i].InputEvent -= OnInputEvent; _readers[i].Dispose(); _readers.RemoveAt(i); } - } base.Dispose(disposing); } @@ -51,7 +49,7 @@ public class LinuxInputProvider : InputProvider { if (sender is not LinuxInputDeviceReader reader) return; - + switch (reader.InputDevice.DeviceType) { case LinuxDeviceType.Keyboard: @@ -69,7 +67,7 @@ public class LinuxInputProvider : InputProvider { if (args.Type != LinuxInputEventType.KEY) return; - + KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes) args.Code); bool isDown = args.Value != 0; diff --git a/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs b/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs index 3c73456a7..23e2bdbdb 100644 --- a/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs +++ b/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs @@ -4,7 +4,6 @@ using Avalonia.Controls; using Avalonia.Data; using Avalonia.Interactivity; using Avalonia.Xaml.Interactivity; -using FluentAvalonia.UI.Controls; namespace Artemis.UI.Shared.Behaviors; diff --git a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs index c19b06c78..bf7716f0b 100644 --- a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs +++ b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs @@ -19,12 +19,12 @@ public interface IMainWindowService : IArtemisSharedUIService void ConfigureMainWindowProvider(IMainWindowProvider mainWindowProvider); /// - /// Opens the main window if it is not already open + /// Opens the main window if it is not already open, must be called on the UI thread /// void OpenMainWindow(); /// - /// Closes the main window if it is not already closed + /// Closes the main window if it is not already closed, must be called on the UI thread /// void CloseMainWindow(); @@ -37,7 +37,7 @@ public interface IMainWindowService : IArtemisSharedUIService /// Occurs when the main window has been closed /// public event EventHandler? MainWindowClosed; - + /// /// Occurs when the main window has been focused /// diff --git a/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs b/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs index 407bec98b..fbdda52e1 100644 --- a/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs +++ b/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs @@ -15,7 +15,7 @@ internal class MainWindowService : IMainWindowService { MainWindowClosed?.Invoke(this, EventArgs.Empty); } - + protected virtual void OnMainWindowFocused() { MainWindowFocused?.Invoke(this, EventArgs.Empty); @@ -53,7 +53,7 @@ internal class MainWindowService : IMainWindowService { SyncWithManager(); } - + private void HandleMainWindowFocused(object? sender, EventArgs e) { OnMainWindowFocused(); @@ -83,7 +83,7 @@ internal class MainWindowService : IMainWindowService _mainWindowManager.MainWindowClosed += HandleMainWindowClosed; _mainWindowManager.MainWindowFocused += HandleMainWindowFocused; _mainWindowManager.MainWindowUnfocused += HandleMainWindowUnfocused; - + // Sync up with the new manager's state SyncWithManager(); } diff --git a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs index 0b65a56e1..1898745b1 100644 --- a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs +++ b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Linq; +using System.Linq; using Artemis.Core; namespace Artemis.UI.Shared.Services.NodeEditor.Commands; @@ -9,9 +8,9 @@ namespace Artemis.UI.Shared.Services.NodeEditor.Commands; /// public class ConnectPins : INodeEditorCommand { - private readonly IPin _output; private readonly IPin _input; private readonly IPin? _originalConnection; + private readonly IPin _output; /// /// Creates a new instance of the class. diff --git a/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs b/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs index 596e66304..8182aec2b 100644 --- a/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs +++ b/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs @@ -31,7 +31,7 @@ public class NodeConnectionStore public void Store() { _pinConnections.Clear(); - + // Iterate to save foreach (IPin nodePin in Node.Pins.ToList()) _pinConnections.Add(nodePin, new List(nodePin.ConnectedTo)); diff --git a/src/Artemis.UI.Windows/App.axaml.cs b/src/Artemis.UI.Windows/App.axaml.cs index f82d58f29..c41c00aa1 100644 --- a/src/Artemis.UI.Windows/App.axaml.cs +++ b/src/Artemis.UI.Windows/App.axaml.cs @@ -24,11 +24,6 @@ public class App : Application private StandardKernel? _kernel; private bool _shutDown; - // ReSharper disable NotAccessedField.Local - private ApplicationStateManager? _applicationStateManager; - private Mutex? _artemisMutex; - // ReSharper restore NotAccessedField.Local - public override void Initialize() { // If Artemis is already running, bring it to foreground and stop this process @@ -110,4 +105,10 @@ public class App : Application } } } + + // ReSharper disable NotAccessedField.Local + private ApplicationStateManager? _applicationStateManager; + + private Mutex? _artemisMutex; + // ReSharper restore NotAccessedField.Local } \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs index 605e23892..d834c3002 100644 --- a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs +++ b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs @@ -17,10 +17,10 @@ public class WindowsInputProvider : InputProvider private readonly IInputService _inputService; private readonly ILogger _logger; + private readonly SpongeWindow _sponge; private readonly Timer _taskManagerTimer; private DateTime _lastMouseUpdate; private int _lastProcessId; - private readonly SpongeWindow _sponge; public WindowsInputProvider(ILogger logger, IInputService inputService) { diff --git a/src/Artemis.UI.Windows/Providers/UpdateProvider.cs b/src/Artemis.UI.Windows/Providers/UpdateProvider.cs index 788c02231..40ffbc776 100644 --- a/src/Artemis.UI.Windows/Providers/UpdateProvider.cs +++ b/src/Artemis.UI.Windows/Providers/UpdateProvider.cs @@ -24,8 +24,8 @@ namespace Artemis.UI.Windows.Providers; public class UpdateProvider : IUpdateProvider, IDisposable { - private const string ApiUrl = "https://dev.azure.com/artemis-rgb/Artemis/_apis/"; - private const string InstallerUrl = "https://builds.artemis-rgb.com/binaries/Artemis.Installer.exe"; + private const string API_URL = "https://dev.azure.com/artemis-rgb/Artemis/_apis/"; + private const string INSTALLER_URL = "https://builds.artemis-rgb.com/binaries/Artemis.Installer.exe"; private readonly ILogger _logger; private readonly IMainWindowService _mainWindowService; @@ -42,7 +42,7 @@ public class UpdateProvider : IUpdateProvider, IDisposable public async Task GetBuildInfo(int buildDefinition, string? buildNumber = null) { - Url request = ApiUrl.AppendPathSegments("build", "builds") + Url request = API_URL.AppendPathSegments("build", "builds") .SetQueryParam("definitions", buildDefinition) .SetQueryParam("resultFilter", "succeeded") .SetQueryParam("$top", 1) @@ -143,9 +143,9 @@ public class UpdateProvider : IUpdateProvider, IDisposable string installerDirectory = Path.Combine(Constants.DataFolder, "installer"); string installerPath = Path.Combine(installerDirectory, "Artemis.Installer.exe"); - _logger.Information("UpdateInstaller: Downloading installer from {DownloadUrl}", InstallerUrl); + _logger.Information("UpdateInstaller: Downloading installer from {DownloadUrl}", INSTALLER_URL); using HttpClient client = new(); - HttpResponseMessage httpResponseMessage = await client.GetAsync(InstallerUrl); + HttpResponseMessage httpResponseMessage = await client.GetAsync(INSTALLER_URL); if (!httpResponseMessage.IsSuccessStatusCode) throw new ArtemisUIException($"Failed to download installer, status code {httpResponseMessage.StatusCode}"); diff --git a/src/Artemis.UI/ArtemisBootstrapper.cs b/src/Artemis.UI/ArtemisBootstrapper.cs index 7bade4f67..901388bf8 100644 --- a/src/Artemis.UI/ArtemisBootstrapper.cs +++ b/src/Artemis.UI/ArtemisBootstrapper.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; using System.Reactive; using Artemis.Core; using Artemis.Core.Ninject; diff --git a/src/Artemis.UI/Controllers/RemoteController.cs b/src/Artemis.UI/Controllers/RemoteController.cs index 15db2f0ef..56b88ef6a 100644 --- a/src/Artemis.UI/Controllers/RemoteController.cs +++ b/src/Artemis.UI/Controllers/RemoteController.cs @@ -2,6 +2,7 @@ using System; using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.Shared.Services.MainWindow; +using Avalonia.Threading; using EmbedIO; using EmbedIO.Routing; using EmbedIO.WebApi; @@ -22,7 +23,7 @@ public class RemoteController : WebApiController [Route(HttpVerbs.Post, "/remote/bring-to-foreground")] public void PostBringToForeground() { - _mainWindowService.OpenMainWindow(); + Dispatcher.UIThread.Post(() => _mainWindowService.OpenMainWindow()); } [Route(HttpVerbs.Post, "/remote/restart")] diff --git a/src/Artemis.UI/MainWindow.axaml.cs b/src/Artemis.UI/MainWindow.axaml.cs index a22f46831..14732e730 100644 --- a/src/Artemis.UI/MainWindow.axaml.cs +++ b/src/Artemis.UI/MainWindow.axaml.cs @@ -44,7 +44,7 @@ public class MainWindow : ReactiveCoreWindow SetTitleBar(this.Get("DragHandle")); } } - + private void OnActivated(object? sender, EventArgs e) { ViewModel?.Focused(); diff --git a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs index 98ea28983..d0200cb70 100644 --- a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs @@ -37,6 +37,16 @@ public class DevicePropertiesViewModel : DialogViewModelBase ClearSelectedLeds = ReactiveCommand.Create(ExecuteClearSelectedLeds); } + public ArtemisDevice Device + { + get => _device; + set => RaiseAndSetIfChanged(ref _device, value); + } + + public ObservableCollection SelectedLeds { get; } + public ObservableCollection Tabs { get; } + public ReactiveCommand ClearSelectedLeds { get; } + private void RgbServiceOnDeviceAdded(object? sender, DeviceEventArgs e) { if (e.Device.Identifier != Device.Identifier || Device == e.Device) @@ -52,16 +62,6 @@ public class DevicePropertiesViewModel : DialogViewModelBase SelectedLeds.Clear(); } - public ArtemisDevice Device - { - get => _device; - set => RaiseAndSetIfChanged(ref _device, value); - } - - public ObservableCollection SelectedLeds { get; } - public ObservableCollection Tabs { get; } - public ReactiveCommand ClearSelectedLeds { get; } - private void AddTabs() { Tabs.Add(_deviceVmFactory.DevicePropertiesTabViewModel(Device)); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml.cs index 960db3e86..d519466b3 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml.cs @@ -15,10 +15,10 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree; public class ProfileTreeView : ReactiveUserControl { + private readonly TreeView _treeView; private Image? _dragAdorner; private Point _dragStartPosition; private Point _elementDragOffset; - private readonly TreeView _treeView; public ProfileTreeView() { diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs index 6ccaea894..95e9b7f01 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs @@ -293,6 +293,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase CanPaste = false; return; } + CanPaste = formats.Contains(ProfileElementExtensions.ClipboardDataFormat); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs index eb1dd81e5..cb155b447 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs @@ -22,10 +22,10 @@ public class DataBindingViewModel : ActivatableViewModelBase private readonly IProfileEditorService _profileEditorService; private readonly IWindowService _windowService; private ObservableAsPropertyHelper? _dataBindingEnabled; + private bool _editorOpen; private ObservableAsPropertyHelper? _layerProperty; private ObservableAsPropertyHelper? _nodeScriptViewModel; private bool _playing; - private bool _editorOpen; public DataBindingViewModel(IProfileEditorService profileEditorService, INodeVmFactory nodeVmFactory, IWindowService windowService, ISettingsService settingsService) { diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs index 24a29ad59..435ab4655 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs @@ -22,9 +22,9 @@ namespace Artemis.UI.Screens.ProfileEditor; public class ProfileEditorViewModel : MainScreenViewModel { + private readonly IMainWindowService _mainWindowService; private readonly IProfileEditorService _profileEditorService; private readonly ISettingsService _settingsService; - private readonly IMainWindowService _mainWindowService; private readonly SourceList _tools; private DisplayConditionScriptViewModel? _displayConditionScriptViewModel; private ObservableAsPropertyHelper? _history; @@ -69,7 +69,7 @@ public class ProfileEditorViewModel : MainScreenViewModel _profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d); _history = profileEditorService.History.ToProperty(this, vm => vm.History).DisposeWith(d); _suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d); - + mainWindowService.MainWindowFocused += MainWindowServiceOnMainWindowFocused; mainWindowService.MainWindowUnfocused += MainWindowServiceOnMainWindowUnfocused; @@ -78,7 +78,7 @@ public class ProfileEditorViewModel : MainScreenViewModel mainWindowService.MainWindowFocused -= MainWindowServiceOnMainWindowFocused; mainWindowService.MainWindowUnfocused -= MainWindowServiceOnMainWindowUnfocused; }).DisposeWith(d); - + // Slow and steady wins the race (and doesn't lock up the entire UI) Dispatcher.UIThread.Post(() => StatusBarViewModel = statusBarViewModel, DispatcherPriority.Loaded); Dispatcher.UIThread.Post(() => VisualEditorViewModel = visualEditorViewModel, DispatcherPriority.Loaded); @@ -165,7 +165,7 @@ public class ProfileEditorViewModel : MainScreenViewModel toolViewModel.IsSelected = false; }); } - + private void MainWindowServiceOnMainWindowFocused(object? sender, EventArgs e) { if (_settingsService.GetSetting("ProfileEditor.AutoSuspend", true).Value) diff --git a/src/Artemis.UI/Screens/Root/RootViewModel.cs b/src/Artemis.UI/Screens/Root/RootViewModel.cs index 61fbe58c2..f34d77f50 100644 --- a/src/Artemis.UI/Screens/Root/RootViewModel.cs +++ b/src/Artemis.UI/Screens/Root/RootViewModel.cs @@ -54,7 +54,7 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi _defaultTitleBarViewModel = defaultTitleBarViewModel; _sidebarVmFactory = sidebarVmFactory; _lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current!.ApplicationLifetime!; - + mainWindowService.ConfigureMainWindowProvider(this); DisplayAccordingToSettings(); @@ -162,20 +162,17 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi /// public void OpenMainWindow() { - Dispatcher.UIThread.Post(() => + if (_lifeTime.MainWindow == null) { - if (_lifeTime.MainWindow == null) - { - SidebarViewModel = _sidebarVmFactory.SidebarViewModel(this); - _lifeTime.MainWindow = new MainWindow {DataContext = this}; - _lifeTime.MainWindow.Show(); - _lifeTime.MainWindow.Closing += CurrentMainWindowOnClosing; - } + SidebarViewModel = _sidebarVmFactory.SidebarViewModel(this); + _lifeTime.MainWindow = new MainWindow {DataContext = this}; + _lifeTime.MainWindow.Show(); + _lifeTime.MainWindow.Closing += CurrentMainWindowOnClosing; + } - _lifeTime.MainWindow.WindowState = WindowState.Normal; - _lifeTime.MainWindow.Activate(); - OnMainWindowOpened(); - }); + _lifeTime.MainWindow.WindowState = WindowState.Normal; + _lifeTime.MainWindow.Activate(); + OnMainWindowOpened(); } /// @@ -183,7 +180,7 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi { Dispatcher.UIThread.Post(() => { _lifeTime.MainWindow?.Close(); }); } - + public void Focused() { IsMainWindowFocused = true; @@ -201,7 +198,7 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi /// public event EventHandler? MainWindowClosed; - + /// public event EventHandler? MainWindowFocused; @@ -217,7 +214,7 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi { MainWindowClosed?.Invoke(this, EventArgs.Empty); } - + protected virtual void OnMainWindowFocused() { MainWindowFocused?.Invoke(this, EventArgs.Empty); diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs index c642578a5..dd0f738dd 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs @@ -21,8 +21,8 @@ public class SurfaceEditorViewModel : MainScreenViewModel private readonly IDeviceService _deviceService; private readonly IDeviceVmFactory _deviceVmFactory; private readonly IRgbService _rgbService; - private readonly ISurfaceVmFactory _surfaceVmFactory; private readonly ISettingsService _settingsService; + private readonly ISurfaceVmFactory _surfaceVmFactory; private readonly IWindowService _windowService; private bool _colorDevices; private bool _colorFirstLedOnly; @@ -72,27 +72,6 @@ public class SurfaceEditorViewModel : MainScreenViewModel }); } - private void RgbServiceOnDeviceAdded(object? sender, DeviceEventArgs e) - { - if (!e.Device.IsEnabled) - return; - - SurfaceDeviceViewModels.Add(_surfaceVmFactory.SurfaceDeviceViewModel(e.Device, this)); - ListDeviceViewModels.Add(_surfaceVmFactory.ListDeviceViewModel(e.Device, this)); - SurfaceDeviceViewModels.Sort(l => l.Device.ZIndex * -1); - ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1); - } - - private void RgbServiceOnDeviceRemoved(object? sender, DeviceEventArgs e) - { - SurfaceDeviceViewModel? surfaceVm = SurfaceDeviceViewModels.FirstOrDefault(vm => vm.Device == e.Device); - ListDeviceViewModel? listVm = ListDeviceViewModels.FirstOrDefault(vm => vm.Device == e.Device); - if (surfaceVm != null) - SurfaceDeviceViewModels.Remove(surfaceVm); - if (listVm != null) - ListDeviceViewModels.Remove(listVm); - } - public bool ColorDevices { get => _colorDevices; @@ -180,6 +159,27 @@ public class SurfaceEditorViewModel : MainScreenViewModel surfaceDeviceViewModel.UpdateMouseDrag(mousePosition, round, ignoreOverlap); } + private void RgbServiceOnDeviceAdded(object? sender, DeviceEventArgs e) + { + if (!e.Device.IsEnabled) + return; + + SurfaceDeviceViewModels.Add(_surfaceVmFactory.SurfaceDeviceViewModel(e.Device, this)); + ListDeviceViewModels.Add(_surfaceVmFactory.ListDeviceViewModel(e.Device, this)); + SurfaceDeviceViewModels.Sort(l => l.Device.ZIndex * -1); + ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1); + } + + private void RgbServiceOnDeviceRemoved(object? sender, DeviceEventArgs e) + { + SurfaceDeviceViewModel? surfaceVm = SurfaceDeviceViewModels.FirstOrDefault(vm => vm.Device == e.Device); + ListDeviceViewModel? listVm = ListDeviceViewModels.FirstOrDefault(vm => vm.Device == e.Device); + if (surfaceVm != null) + SurfaceDeviceViewModels.Remove(surfaceVm); + if (listVm != null) + ListDeviceViewModels.Remove(listVm); + } + private async Task ExecuteAutoArrange() { bool confirmed = await _windowService.ShowConfirmContentDialog("Auto-arrange layout", "Are you sure you want to auto-arrange your layout? Your current settings will be overwritten."); diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs index 09dc7d049..19eefefb8 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs +++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs @@ -12,7 +12,6 @@ using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.NodeEditor; using Artemis.UI.Shared.Services.NodeEditor.Commands; -using Artemis.UI.Shared.Services.ProfileEditor; using Avalonia; using Avalonia.Threading; using DynamicData; @@ -25,8 +24,8 @@ public class NodeScriptWindowViewModel : DialogViewModelBase { private readonly INodeEditorService _nodeEditorService; private readonly INodeService _nodeService; - private readonly ISettingsService _settingsService; private readonly IProfileService _profileService; + private readonly ISettingsService _settingsService; private readonly IWindowService _windowService; public NodeScriptWindowViewModel(NodeScript nodeScript, @@ -66,10 +65,10 @@ public class NodeScriptWindowViewModel : DialogViewModelBase DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000), DispatcherPriority.Normal, Update); // TODO: Remove in favor of saving each time a node editor command is executed DispatcherTimer saveTimer = new(TimeSpan.FromMinutes(2), DispatcherPriority.Normal, Save); - + updateTimer.Start(); saveTimer.Start(); - + Disposable.Create(() => { updateTimer.Stop();