From 64decaf0c2e085c481f2032f572aa143839c0e11 Mon Sep 17 00:00:00 2001 From: Robert Date: Sat, 4 Feb 2023 23:32:14 +0100 Subject: [PATCH 01/11] Core - Refactor service registration pt 2 --- src/Artemis.Core/DryIoc/ContainerExtensions.cs | 2 +- src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs | 2 +- src/Artemis.UI/ArtemisBootstrapper.cs | 3 --- src/Artemis.UI/DryIoc/ContainerExtensions.cs | 4 ++-- src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Artemis.Core/DryIoc/ContainerExtensions.cs b/src/Artemis.Core/DryIoc/ContainerExtensions.cs index 4f418d453..927f606a9 100644 --- a/src/Artemis.Core/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.Core/DryIoc/ContainerExtensions.cs @@ -13,7 +13,7 @@ namespace Artemis.Core.DryIoc; /// /// Provides an extension method to register services onto a DryIoc . /// -public static class CoreContainerExtensions +public static class ContainerExtensions { /// /// Registers core services into the container. diff --git a/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs b/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs index cb7baef36..4c4711b02 100644 --- a/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs @@ -7,7 +7,7 @@ namespace Artemis.UI.Shared.DryIoc; /// /// Provides an extension method to register services onto a DryIoc . /// -public static class UIContainerExtensions +public static class ContainerExtensions { /// /// Registers shared UI services into the container. diff --git a/src/Artemis.UI/ArtemisBootstrapper.cs b/src/Artemis.UI/ArtemisBootstrapper.cs index 1056070e1..1b47e8748 100644 --- a/src/Artemis.UI/ArtemisBootstrapper.cs +++ b/src/Artemis.UI/ArtemisBootstrapper.cs @@ -12,8 +12,6 @@ using Artemis.UI.Shared.DataModelPicker; using Artemis.UI.Shared.DryIoc; using Artemis.UI.Shared.Services; using Artemis.VisualScripting.DryIoc; -using Artemis.WebClient.Updating; -using Artemis.WebClient.Updating.DryIoc; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -44,7 +42,6 @@ public static class ArtemisBootstrapper _container.RegisterCore(); _container.RegisterUI(); _container.RegisterSharedUI(); - _container.RegisterUpdatingClient(); _container.RegisterNoStringEvaluating(); configureServices?.Invoke(_container); diff --git a/src/Artemis.UI/DryIoc/ContainerExtensions.cs b/src/Artemis.UI/DryIoc/ContainerExtensions.cs index f4c484bec..3e4caf226 100644 --- a/src/Artemis.UI/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.UI/DryIoc/ContainerExtensions.cs @@ -16,7 +16,7 @@ namespace Artemis.UI.DryIoc; /// /// Provides an extension method to register services onto a DryIoc . /// -public static class UIContainerExtensions +public static class ContainerExtensions { /// /// Registers UI services into the container. @@ -24,7 +24,7 @@ public static class UIContainerExtensions /// The builder building the current container public static void RegisterUI(this IContainer container) { - Assembly[] thisAssembly = {typeof(UIContainerExtensions).Assembly}; + Assembly[] thisAssembly = {typeof(ContainerExtensions).Assembly}; container.RegisterInstance(new AssetLoader(), IfAlreadyRegistered.Throw); container.Register(Reuse.Singleton); diff --git a/src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs b/src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs index 6e388f30d..0377f56ec 100644 --- a/src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs @@ -13,7 +13,7 @@ namespace Artemis.VisualScripting.DryIoc; /// /// Provides an extension method to register services onto a DryIoc . /// -public static class UIContainerExtensions +public static class ContainerExtensions { /// /// Registers NoStringEvaluating services into the container. From 0200839a26300e4757005172bb1eaad8917da8a0 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Fri, 10 Feb 2023 11:06:52 +0000 Subject: [PATCH 02/11] Nodes - Added more HSV and HSL nodes --- .../Nodes/Color/HslSKColorNode.cs | 2 +- .../Nodes/Color/HsvSKColorNode.cs | 31 ++++++++++++++++ .../Nodes/Color/SkColorHsl.cs | 36 +++++++++++++++++++ .../Nodes/Color/SkColorHsv.cs | 36 +++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/Artemis.VisualScripting/Nodes/Color/HsvSKColorNode.cs create mode 100644 src/Artemis.VisualScripting/Nodes/Color/SkColorHsl.cs create mode 100644 src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs diff --git a/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs b/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs index cba686c38..15ce66d84 100644 --- a/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs +++ b/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs @@ -3,7 +3,7 @@ using SkiaSharp; namespace Artemis.VisualScripting.Nodes.Color; -[Node("HSL Color", "Creates a color from hue, saturation and lightness values", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))] +[Node("HSL Color", "Creates a color from hue, saturation and lightness numbers", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))] public class HslSKColorNode : Node { public HslSKColorNode() diff --git a/src/Artemis.VisualScripting/Nodes/Color/HsvSKColorNode.cs b/src/Artemis.VisualScripting/Nodes/Color/HsvSKColorNode.cs new file mode 100644 index 000000000..2544ccec2 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Color/HsvSKColorNode.cs @@ -0,0 +1,31 @@ +using Artemis.Core; +using SkiaSharp; + +namespace Artemis.VisualScripting.Nodes.Color; + +[Node("HSV Color", "Creates a color from hue, saturation and value numbers", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))] +public class HsvSKColorNode : Node +{ + public HsvSKColorNode() + { + H = CreateInputPin("H"); + S = CreateInputPin("S"); + V = CreateInputPin("V"); + Output = CreateOutputPin(); + } + + public InputPin H { get; set; } + public InputPin S { get; set; } + public InputPin V { get; set; } + public OutputPin Output { get; } + + #region Overrides of Node + + /// + public override void Evaluate() + { + Output.Value = SKColor.FromHsv(H.Value, S.Value, V.Value); + } + + #endregion +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Color/SkColorHsl.cs b/src/Artemis.VisualScripting/Nodes/Color/SkColorHsl.cs new file mode 100644 index 000000000..aaa1c6e26 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Color/SkColorHsl.cs @@ -0,0 +1,36 @@ +using Artemis.Core; +using SkiaSharp; + +namespace Artemis.VisualScripting.Nodes.Color; + +[Node("Color to HSL", "Outputs H, S and L values from a color", "Color", InputType = typeof(SKColor), OutputType = typeof(Numeric))] +public class SkColorHsl : Node +{ + + public SkColorHsl() + { + Input = CreateInputPin(); + H = CreateOutputPin("H"); + S = CreateOutputPin("S"); + L = CreateOutputPin("L"); + } + + public InputPin Input { get; } + public OutputPin H { get; } + public OutputPin S { get; } + public OutputPin L { get; } + + #region Overrides of Node + + /// + public override void Evaluate() + { + Input.Value.ToHsl(out float h, out float s, out float l); + + H.Value = h; + S.Value = s; + L.Value = l; + } + + #endregion +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs b/src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs new file mode 100644 index 000000000..95a2dffb1 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs @@ -0,0 +1,36 @@ +using Artemis.Core; +using SkiaSharp; + +namespace Artemis.VisualScripting.Nodes.Color; + +[Node("Color to Hsv", "Outputs H, S and L values from a color", "Color", InputType = typeof(SKColor), OutputType = typeof(Numeric))] +public class SkColorHsv : Node +{ + + public SkColorHsv() + { + Input = CreateInputPin(); + H = CreateOutputPin("H"); + S = CreateOutputPin("S"); + V = CreateOutputPin("V"); + } + + public InputPin Input { get; } + public OutputPin H { get; } + public OutputPin S { get; } + public OutputPin V { get; } + + #region Overrides of Node + + /// + public override void Evaluate() + { + Input.Value.ToHsv(out float h, out float s, out float v); + + H.Value = h; + S.Value = s; + V.Value = v; + } + + #endregion +} \ No newline at end of file From f1c5b2c14f6120fed517f6c746882a4c5edb3e46 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sun, 12 Feb 2023 17:44:03 +0100 Subject: [PATCH 03/11] Updated RGB.NET to stay in sync with plugins --- src/Artemis.Core/Artemis.Core.csproj | 6 +++--- src/Artemis.UI.Shared/Artemis.UI.Shared.csproj | 2 +- src/Artemis.UI/Artemis.UI.csproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index df21cdfd2..ee57c4987 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -42,9 +42,9 @@ - - - + + + diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj index 09c2d5479..c8f440c29 100644 --- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj +++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj @@ -20,7 +20,7 @@ - + diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index bf4ce5d0c..a9446ed2c 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -31,8 +31,8 @@ - - + + From 968b365a2935551d3efddb71a4bcb7ea5415866c Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 12 Feb 2023 21:27:46 +0100 Subject: [PATCH 04/11] Node editor - Fixed a crash when duplicating nodes with pin collections --- .../Services/NodeEditor/Commands/DuplicateNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/DuplicateNode.cs b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/DuplicateNode.cs index 8c60677b6..62340d3a6 100644 --- a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/DuplicateNode.cs +++ b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/DuplicateNode.cs @@ -56,7 +56,7 @@ public class DuplicateNode : INodeEditorCommand, IDisposable if (targetCollection == null) continue; while (targetCollection.Count() < sourceCollection.Count()) - targetCollection.CreatePin(); + targetCollection.Add(targetCollection.CreatePin()); } // Copy the storage From 7a5c018a3f9ea8c9e317bebaa5eee1ec250305b2 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 12 Feb 2023 21:31:25 +0100 Subject: [PATCH 05/11] HSV Node - Fix name --- src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs b/src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs index 95a2dffb1..a0e448cf4 100644 --- a/src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs +++ b/src/Artemis.VisualScripting/Nodes/Color/SkColorHsv.cs @@ -3,7 +3,7 @@ using SkiaSharp; namespace Artemis.VisualScripting.Nodes.Color; -[Node("Color to Hsv", "Outputs H, S and L values from a color", "Color", InputType = typeof(SKColor), OutputType = typeof(Numeric))] +[Node("Color to HSV", "Outputs H, S and L values from a color", "Color", InputType = typeof(SKColor), OutputType = typeof(Numeric))] public class SkColorHsv : Node { From 8dea510eb63ec39702b51e96dc9fe0f55927c911 Mon Sep 17 00:00:00 2001 From: RobertBeekman Date: Mon, 13 Feb 2023 15:52:23 +0100 Subject: [PATCH 06/11] To Numeric Node - Support converting booleans to numeric --- .../Nodes/Conversion/ConvertToNumericNode.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Artemis.VisualScripting/Nodes/Conversion/ConvertToNumericNode.cs b/src/Artemis.VisualScripting/Nodes/Conversion/ConvertToNumericNode.cs index 8a4190098..0dcfb6e1b 100644 --- a/src/Artemis.VisualScripting/Nodes/Conversion/ConvertToNumericNode.cs +++ b/src/Artemis.VisualScripting/Nodes/Conversion/ConvertToNumericNode.cs @@ -1,4 +1,4 @@ -using Artemis.Core; +using Artemis.Core; namespace Artemis.VisualScripting.Nodes.Conversion; @@ -33,6 +33,7 @@ public class ConvertToNumericNode : Node double input => new Numeric(input), float input => new Numeric(input), byte input => new Numeric(input), + bool input => new Numeric(input ? 1 : 0), _ => TryParse(Input.Value) }; } @@ -44,4 +45,4 @@ public class ConvertToNumericNode : Node } #endregion -} \ No newline at end of file +} From acd005e4a2ecc3bf4a524748401cfba9437c5884 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 24 Feb 2023 22:54:17 +0100 Subject: [PATCH 07/11] Implemented most of the updating mechanism --- .../Interfaces/IQueuedActionRepository.cs | 2 + .../Repositories/QueuedActionRepository.cs | 12 ++ .../Converters/BytesToStringConverter.cs | 34 +++ src/Artemis.UI.Shared/Styles/Artemis.axaml | 1 + src/Artemis.UI.Shared/Styles/Skeleton.axaml | 174 +++++++++++++++ .../ApplicationStateManager.cs | 2 - src/Artemis.UI.Windows/Scripts/update.ps1 | 9 + src/Artemis.UI/Artemis.UI.csproj | 11 + src/Artemis.UI/DryIoc/ContainerExtensions.cs | 3 +- src/Artemis.UI/DryIoc/Factories/IVMFactory.cs | 23 +- .../Screens/Settings/SettingsViewModel.cs | 2 + .../Settings/Tabs/ReleasesTabView.axaml | 26 +++ .../Settings/Tabs/ReleasesTabView.axaml.cs | 17 ++ .../Settings/Tabs/ReleasesTabViewModel.cs | 106 +++++++++ .../Updating/ReleaseAvailableView.axaml.cs | 29 --- .../Updating/ReleaseAvailableViewModel.cs | 76 ------- .../Updating/ReleaseInstallerView.axaml | 40 ---- .../Updating/ReleaseInstallerView.axaml.cs | 28 --- .../Updating/ReleaseInstallerViewModel.cs | 81 ------- ...eAvailableView.axaml => ReleaseView.axaml} | 204 ++++++++++++++---- .../Settings/Updating/ReleaseView.axaml.cs | 23 ++ .../Settings/Updating/ReleaseViewModel.cs | 202 +++++++++++++++++ .../Services/Updating/IUpdateService.cs | 9 +- .../Services/Updating/ReleaseInstaller.cs | 124 +++++++---- .../Services/Updating/UpdateService.cs | 87 +++++--- .../Queries/GetReleaseById.graphql | 33 ++- src/Artemis.WebClient.Updating/schema.graphql | 80 ++++++- 27 files changed, 1055 insertions(+), 383 deletions(-) create mode 100644 src/Artemis.UI.Shared/Converters/BytesToStringConverter.cs create mode 100644 src/Artemis.UI.Shared/Styles/Skeleton.axaml create mode 100644 src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml create mode 100644 src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs delete mode 100644 src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableView.axaml.cs delete mode 100644 src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableViewModel.cs delete mode 100644 src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml delete mode 100644 src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml.cs delete mode 100644 src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerViewModel.cs rename src/Artemis.UI/Screens/Settings/Updating/{ReleaseAvailableView.axaml => ReleaseView.axaml} (50%) create mode 100644 src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Settings/Updating/ReleaseViewModel.cs diff --git a/src/Artemis.Storage/Repositories/Interfaces/IQueuedActionRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IQueuedActionRepository.cs index dfcbfbfe7..cb5852eaa 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IQueuedActionRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IQueuedActionRepository.cs @@ -9,4 +9,6 @@ public interface IQueuedActionRepository : IRepository void Remove(QueuedActionEntity queuedActionEntity); List GetAll(); List GetByType(string type); + bool IsTypeQueued(string type); + void ClearByType(string type); } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/QueuedActionRepository.cs b/src/Artemis.Storage/Repositories/QueuedActionRepository.cs index faa6a304f..f5c83cd0e 100644 --- a/src/Artemis.Storage/Repositories/QueuedActionRepository.cs +++ b/src/Artemis.Storage/Repositories/QueuedActionRepository.cs @@ -41,5 +41,17 @@ public class QueuedActionRepository : IQueuedActionRepository return _repository.Query().Where(q => q.Type == type).ToList(); } + /// + public bool IsTypeQueued(string type) + { + return _repository.Query().Where(q => q.Type == type).Count() > 0; + } + + /// + public void ClearByType(string type) + { + _repository.DeleteMany(q => q.Type == type); + } + #endregion } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Converters/BytesToStringConverter.cs b/src/Artemis.UI.Shared/Converters/BytesToStringConverter.cs new file mode 100644 index 000000000..f6f7da7e6 --- /dev/null +++ b/src/Artemis.UI.Shared/Converters/BytesToStringConverter.cs @@ -0,0 +1,34 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; +using Humanizer; +using Humanizer.Bytes; + +namespace Artemis.UI.Shared.Converters; + +/// +/// Converts bytes to a string +/// +public class BytesToStringConverter : IValueConverter +{ + /// + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is int intBytes) + return intBytes.Bytes().Humanize(); + if (value is long longBytes) + return longBytes.Bytes().Humanize(); + if (value is double doubleBytes) + return doubleBytes.Bytes().Humanize(); + + return value; + } + + /// + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is string formatted && ByteSize.TryParse(formatted, out ByteSize result)) + return result.Bytes; + return value; + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Styles/Artemis.axaml b/src/Artemis.UI.Shared/Styles/Artemis.axaml index 97dafc8a1..7b838cdbf 100644 --- a/src/Artemis.UI.Shared/Styles/Artemis.axaml +++ b/src/Artemis.UI.Shared/Styles/Artemis.axaml @@ -21,6 +21,7 @@ + diff --git a/src/Artemis.UI.Shared/Styles/Skeleton.axaml b/src/Artemis.UI.Shared/Styles/Skeleton.axaml new file mode 100644 index 000000000..2596c3fe6 --- /dev/null +++ b/src/Artemis.UI.Shared/Styles/Skeleton.axaml @@ -0,0 +1,174 @@ + + + + + + + + + + This is heading 1 + This is heading 2 + This is heading 3 + This is heading 4 + This is heading 5 + This is heading 6 + This is regular text + This is regular text + This is regular text + + + + + + + + + + + + + + + + + + + + + This is heading 1 + This is heading 2 + This is heading 3 + This is heading 4 + This is heading 5 + This is heading 6 + This is regular text + + + + + + + + + + + + + + + + + + + + + This is heading 1 + This is heading 2 + This is heading 3 + This is heading 4 + This is heading 5 + This is heading 6 + This is regular text + + + + + + + 8 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI.Windows/ApplicationStateManager.cs b/src/Artemis.UI.Windows/ApplicationStateManager.cs index 2eb3ce47f..1a7d8147e 100644 --- a/src/Artemis.UI.Windows/ApplicationStateManager.cs +++ b/src/Artemis.UI.Windows/ApplicationStateManager.cs @@ -108,8 +108,6 @@ public class ApplicationStateManager ProcessStartInfo info = new() { Arguments = $"-File {script} {source} {destination} {args}", - WindowStyle = ProcessWindowStyle.Hidden, - CreateNoWindow = true, FileName = "PowerShell.exe" }; Process.Start(info); diff --git a/src/Artemis.UI.Windows/Scripts/update.ps1 b/src/Artemis.UI.Windows/Scripts/update.ps1 index 4247178dc..7603b013e 100644 --- a/src/Artemis.UI.Windows/Scripts/update.ps1 +++ b/src/Artemis.UI.Windows/Scripts/update.ps1 @@ -4,6 +4,10 @@ param ( [Parameter(Mandatory=$false)][string]$artemisArgs ) +Write-Host "Artemis update script v1" +Write-Host "Please do not close this window, this should not take long" +Write-Host "" + # Wait up to 10 seconds for the process to shut down for ($i=1; $i -le 10; $i++) { $process = Get-Process -Name Artemis.UI.Windows -ErrorAction SilentlyContinue @@ -26,12 +30,17 @@ if (!(Test-Path $destinationDirectory)) { Write-Error "The destination directory does not exist" } + # If the destination directory exists, clear it +Write-Host "Cleaning up old version where needed" Get-ChildItem $destinationDirectory | Remove-Item -Recurse -Force # Move the contents of the source directory to the destination directory +Write-Host "Installing new files" Get-ChildItem $sourceDirectory | Move-Item -Destination $destinationDirectory + +Write-Host "Finished! Restarting Artemis" Start-Sleep -Seconds 1 # When finished, run the updated version diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 086380658..502846ca4 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -43,4 +43,15 @@ + + + + UpdatingTabView.axaml + Code + + + UpdatingTabView.axaml + Code + + \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/ContainerExtensions.cs b/src/Artemis.UI/DryIoc/ContainerExtensions.cs index 58970b2fd..da1dcd815 100644 --- a/src/Artemis.UI/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.UI/DryIoc/ContainerExtensions.cs @@ -31,14 +31,13 @@ public static class UIContainerExtensions container.Register(Reuse.Singleton); container.RegisterMany(thisAssembly, type => type.IsAssignableTo()); - container.RegisterMany(thisAssembly, type => type.IsAssignableTo(), ifAlreadyRegistered: IfAlreadyRegistered.Replace); container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type.IsInterface); container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type != typeof(PropertyVmFactory)); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(); - + container.RegisterMany(thisAssembly, type => type.IsAssignableTo(), Reuse.Singleton); } } \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs index ed71b2c6e..8b3c5fa42 100644 --- a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs +++ b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.Reactive; using Artemis.Core; using Artemis.Core.LayerBrushes; @@ -17,6 +18,7 @@ using Artemis.UI.Screens.ProfileEditor.Properties.Tree; using Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers; using Artemis.UI.Screens.Scripting; using Artemis.UI.Screens.Settings; +using Artemis.UI.Screens.Settings.Updating; using Artemis.UI.Screens.Sidebar; using Artemis.UI.Screens.SurfaceEditor; using Artemis.UI.Screens.VisualScripting; @@ -474,4 +476,23 @@ public class ScriptVmFactory : IScriptVmFactory { return _container.Resolve(new object[] { profile, scriptConfiguration }); } +} + +public interface IReleaseVmFactory : IVmFactory +{ + ReleaseViewModel ReleaseListViewModel(string releaseId, string version, DateTimeOffset createdAt); +} +public class ReleaseVmFactory : IReleaseVmFactory +{ + private readonly IContainer _container; + + public ReleaseVmFactory(IContainer container) + { + _container = container; + } + + public ReleaseViewModel ReleaseListViewModel(string releaseId, string version, DateTimeOffset createdAt) + { + return _container.Resolve(new object[] { releaseId, version, createdAt }); + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs index 0a372c29b..773656c1f 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs @@ -10,6 +10,7 @@ public class SettingsViewModel : MainScreenViewModel GeneralTabViewModel generalTabViewModel, PluginsTabViewModel pluginsTabViewModel, DevicesTabViewModel devicesTabViewModel, + ReleasesTabViewModel releasesTabViewModel, AboutTabViewModel aboutTabViewModel) : base(hostScreen, "settings") { SettingTabs = new ObservableCollection @@ -17,6 +18,7 @@ public class SettingsViewModel : MainScreenViewModel generalTabViewModel, pluginsTabViewModel, devicesTabViewModel, + releasesTabViewModel, aboutTabViewModel }; } diff --git a/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml new file mode 100644 index 000000000..6528d8b04 --- /dev/null +++ b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml.cs b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml.cs new file mode 100644 index 000000000..3421db5a7 --- /dev/null +++ b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Settings; + +public class ReleasesTabView : ReactiveUserControl +{ + public ReleasesTabView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs new file mode 100644 index 000000000..61da057c8 --- /dev/null +++ b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabViewModel.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Linq; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.DryIoc.Factories; +using Artemis.UI.Extensions; +using Artemis.UI.Screens.Settings.Updating; +using Artemis.UI.Services.Updating; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Services; +using Artemis.UI.Shared.Services.Builders; +using Artemis.WebClient.Updating; +using Avalonia.Threading; +using DynamicData; +using DynamicData.Binding; +using ReactiveUI; +using Serilog; +using StrawberryShake; + +namespace Artemis.UI.Screens.Settings; + +public class ReleasesTabViewModel : ActivatableViewModelBase +{ + private readonly ILogger _logger; + private readonly IUpdatingClient _updatingClient; + private readonly INotificationService _notificationService; + private readonly SourceList _releases; + private IGetReleases_PublishedReleases_PageInfo? _lastPageInfo; + private bool _loading; + private ReleaseViewModel? _selectedReleaseViewModel; + + public ReleasesTabViewModel(ILogger logger, IUpdateService updateService, IUpdatingClient updatingClient, IReleaseVmFactory releaseVmFactory, INotificationService notificationService) + { + _logger = logger; + _updatingClient = updatingClient; + _notificationService = notificationService; + + _releases = new SourceList(); + _releases.Connect() + .Sort(SortExpressionComparer.Descending(p => p.CreatedAt)) + .Transform(r => releaseVmFactory.ReleaseListViewModel(r.Id, r.Version, r.CreatedAt)) + .ObserveOn(AvaloniaScheduler.Instance) + .Bind(out ReadOnlyObservableCollection releaseViewModels) + .Subscribe(); + + DisplayName = "Releases"; + ReleaseViewModels = releaseViewModels; + this.WhenActivated(async d => + { + await updateService.CacheLatestRelease(); + await GetMoreReleases(d.AsCancellationToken()); + SelectedReleaseViewModel = ReleaseViewModels.FirstOrDefault(); + }); + } + + public ReadOnlyObservableCollection ReleaseViewModels { get; } + + public ReleaseViewModel? SelectedReleaseViewModel + { + get => _selectedReleaseViewModel; + set => RaiseAndSetIfChanged(ref _selectedReleaseViewModel, value); + } + + public bool Loading + { + get => _loading; + private set => RaiseAndSetIfChanged(ref _loading, value); + } + + public async Task GetMoreReleases(CancellationToken cancellationToken) + { + if (_lastPageInfo != null && !_lastPageInfo.HasNextPage) + return; + + try + { + Loading = true; + + IOperationResult result = await _updatingClient.GetReleases.ExecuteAsync("feature/gh-actions", Platform.Windows, 20, _lastPageInfo?.EndCursor, cancellationToken); + if (result.Data?.PublishedReleases?.Nodes == null) + return; + + _lastPageInfo = result.Data.PublishedReleases.PageInfo; + _releases.AddRange(result.Data.PublishedReleases.Nodes); + } + catch (TaskCanceledException) + { + // ignored + } + catch (Exception e) + { + _logger.Warning(e, "Failed to retrieve releases"); + _notificationService.CreateNotification() + .WithTitle("Failed to retrieve releases") + .WithMessage(e.Message) + .WithSeverity(NotificationSeverity.Warning) + .Show(); + } + finally + { + Loading = false; + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableView.axaml.cs b/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableView.axaml.cs deleted file mode 100644 index ed0373da4..000000000 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableView.axaml.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Artemis.UI.Shared; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Artemis.UI.Screens.Settings.Updating; - -public partial class ReleaseAvailableView : ReactiveCoreWindow -{ - public ReleaseAvailableView() - { - InitializeComponent(); -#if DEBUG - this.AttachDevTools(); -#endif - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - private void Button_OnClick(object? sender, RoutedEventArgs e) - { - Close(); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableViewModel.cs b/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableViewModel.cs deleted file mode 100644 index 118177c7f..000000000 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableViewModel.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System.Reactive; -using System.Reactive.Linq; -using System.Threading; -using System.Threading.Tasks; -using Artemis.Core; -using Artemis.UI.Extensions; -using Artemis.UI.Services.Updating; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Services; -using Artemis.WebClient.Updating; -using ReactiveUI; -using Serilog; -using StrawberryShake; - -namespace Artemis.UI.Screens.Settings.Updating; - -public class ReleaseAvailableViewModel : ActivatableViewModelBase -{ - private readonly string _nextReleaseId; - private readonly ILogger _logger; - private readonly IUpdateService _updateService; - private readonly IUpdatingClient _updatingClient; - private readonly INotificationService _notificationService; - private IGetReleaseById_Release? _release; - - public ReleaseAvailableViewModel(string nextReleaseId, ILogger logger, IUpdateService updateService, IUpdatingClient updatingClient, INotificationService notificationService) - { - _nextReleaseId = nextReleaseId; - _logger = logger; - _updateService = updateService; - _updatingClient = updatingClient; - _notificationService = notificationService; - - CurrentVersion = _updateService.CurrentVersion ?? "Development build"; - Install = ReactiveCommand.Create(ExecuteInstall, this.WhenAnyValue(vm => vm.Release).Select(r => r != null)); - - this.WhenActivated(async d => await RetrieveRelease(d.AsCancellationToken())); - } - - private void ExecuteInstall() - { - _updateService.InstallRelease(_nextReleaseId); - } - - private async Task RetrieveRelease(CancellationToken cancellationToken) - { - IOperationResult result = await _updatingClient.GetReleaseById.ExecuteAsync(_nextReleaseId, cancellationToken); - // Borrow GraphQLClientException for messaging, how lazy of me.. - if (result.Errors.Count > 0) - { - GraphQLClientException exception = new(result.Errors); - _logger.Error(exception, "Failed to retrieve release details"); - _notificationService.CreateNotification().WithTitle("Failed to retrieve release details").WithMessage(exception.Message).Show(); - return; - } - - if (result.Data?.Release == null) - { - _notificationService.CreateNotification().WithTitle("Failed to retrieve release details").WithMessage("Release not found").Show(); - return; - } - - Release = result.Data.Release; - } - - public string CurrentVersion { get; } - - public IGetReleaseById_Release? Release - { - get => _release; - set => RaiseAndSetIfChanged(ref _release, value); - } - - public ReactiveCommand Install { get; } - public ReactiveCommand AskLater { get; } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml b/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml deleted file mode 100644 index 46699f5ae..000000000 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml +++ /dev/null @@ -1,40 +0,0 @@ - - - - Downloading & installing update... - - - - This should not take long, when finished Artemis must restart. - - - - - - - - Done, click restart to apply the update 🫡 - - - Restart when finished - - - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml.cs b/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml.cs deleted file mode 100644 index ec2a689e6..000000000 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerView.axaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Artemis.UI.Shared; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; - -namespace Artemis.UI.Screens.Settings.Updating; - -public partial class ReleaseInstallerView : ReactiveCoreWindow -{ - public ReleaseInstallerView() - { - InitializeComponent(); -#if DEBUG - this.AttachDevTools(); -#endif - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - private void Cancel_OnClick(object? sender, RoutedEventArgs e) - { - Close(); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerViewModel.cs b/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerViewModel.cs deleted file mode 100644 index 79a80aa06..000000000 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseInstallerViewModel.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Reactive; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Threading; -using System.Threading.Tasks; -using Artemis.Core; -using Artemis.UI.Extensions; -using Artemis.UI.Services.Updating; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Services; -using ReactiveUI; - -namespace Artemis.UI.Screens.Settings.Updating; - -public class ReleaseInstallerViewModel : ActivatableViewModelBase -{ - private readonly ReleaseInstaller _releaseInstaller; - private readonly IWindowService _windowService; - private ObservableAsPropertyHelper? _overallProgress; - private ObservableAsPropertyHelper? _stepProgress; - private bool _ready; - private bool _restartWhenFinished; - - public ReleaseInstallerViewModel(ReleaseInstaller releaseInstaller, IWindowService windowService) - { - _releaseInstaller = releaseInstaller; - _windowService = windowService; - - Restart = ReactiveCommand.Create(() => Utilities.ApplyUpdate(false)); - this.WhenActivated(d => - { - _overallProgress = Observable.FromEventPattern(x => _releaseInstaller.OverallProgress.ProgressChanged += x, x => _releaseInstaller.OverallProgress.ProgressChanged -= x) - .Select(e => e.EventArgs) - .ToProperty(this, vm => vm.OverallProgress) - .DisposeWith(d); - _stepProgress = Observable.FromEventPattern(x => _releaseInstaller.StepProgress.ProgressChanged += x, x => _releaseInstaller.StepProgress.ProgressChanged -= x) - .Select(e => e.EventArgs) - .ToProperty(this, vm => vm.StepProgress) - .DisposeWith(d); - - Task.Run(() => InstallUpdate(d.AsCancellationToken())); - }); - } - - public ReactiveCommand Restart { get; } - - public float OverallProgress => _overallProgress?.Value ?? 0; - public float StepProgress => _stepProgress?.Value ?? 0; - - public bool Ready - { - get => _ready; - set => RaiseAndSetIfChanged(ref _ready, value); - } - - public bool RestartWhenFinished - { - get => _restartWhenFinished; - set => RaiseAndSetIfChanged(ref _restartWhenFinished, value); - } - - private async Task InstallUpdate(CancellationToken cancellationToken) - { - try - { - await _releaseInstaller.InstallAsync(cancellationToken); - Ready = true; - if (RestartWhenFinished) - Utilities.ApplyUpdate(false); - } - catch (TaskCanceledException) - { - // ignored - } - catch (Exception e) - { - _windowService.ShowExceptionDialog("Something went wrong while installing the update", e); - } - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableView.axaml b/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml similarity index 50% rename from src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableView.axaml rename to src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml index acf70d5b4..91e1a0a4c 100644 --- a/src/Artemis.UI/Screens/Settings/Updating/ReleaseAvailableView.axaml +++ b/src/Artemis.UI/Screens/Settings/Updating/ReleaseView.axaml @@ -1,49 +1,163 @@ - - + + + + + + + + + + + + + + - - A new Artemis update is available! 🥳 - + + + + + Release info - - Retrieving release... - - + + + + + + + + - - - - - - - - - - + + + - - - + + + + Ready, restart to install + + + + + - + + + + + + Release date + + + + + + Source + + + + + + File size + + + + + + + + + + Release notes + + +