diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml
index 50416a113..044774480 100644
--- a/.github/workflows/docfx.yml
+++ b/.github/workflows/docfx.yml
@@ -1,6 +1,6 @@
name: Master - DocFX
-on:
+on:
workflow_dispatch:
push:
branches:
@@ -16,7 +16,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
- dotnet-version: '6.0.x'
+ dotnet-version: "7.0.x"
- name: Setup DocFX
run: choco install docfx -y
- name: Build Core
@@ -32,4 +32,4 @@ jobs:
username: ${{ secrets.FTP_USER }}
password: ${{ secrets.FTP_PASSWORD }}
local-dir: docfx/docfx_project/_site/
- server-dir: /httpdocs/docs/
\ No newline at end of file
+ server-dir: /httpdocs/docs/
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 36d37e0d3..96762a278 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -1,8 +1,10 @@
name: Master - Build
-on:
+on:
workflow_dispatch:
push:
+ branches:
+ - master
jobs:
version:
@@ -26,11 +28,11 @@ jobs:
# If we're not in master, add the branch name to the version so it counts as prerelease
if ($BranchName -ne "master") { $VersionNumber += "-$BranchName" }
"version-number=$VersionNumber" >> $Env:GITHUB_OUTPUT
-
+
build:
needs: version
strategy:
- matrix:
+ matrix:
include:
- os: windows-latest
rid: win10-x64
diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml
index c45941a79..05daa25f3 100644
--- a/.github/workflows/nuget.yml
+++ b/.github/workflows/nuget.yml
@@ -1,8 +1,10 @@
name: Publish Nuget packages
-on:
+on:
workflow_dispatch:
push:
+ branches:
+ - master
jobs:
version:
@@ -43,4 +45,4 @@ jobs:
- name: Pack Artemis.UI.Shared
run: dotnet pack -c Release -p:Version=${{ needs.version.outputs.version-number }} src/Artemis.UI.Shared/Artemis.UI.Shared.csproj
- name: Push Nugets
- run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
\ No newline at end of file
+ run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
index 53f9fd30f..547ce8ead 100644
--- a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
+++ b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
@@ -44,31 +44,9 @@ public class ArtemisPluginException : Exception
public ArtemisPluginException(string message, Exception inner) : base(message, inner)
{
}
-
- ///
- /// Creates a new instance of the class
- ///
- public ArtemisPluginException(string message, string helpDocument) : base(message)
- {
- HelpDocument = helpDocument;
- }
-
- ///
- /// Creates a new instance of the class
- ///
- public ArtemisPluginException(string message, Exception inner, string helpDocument) : base(message, inner)
- {
- HelpDocument = helpDocument;
- }
///
/// Gets the plugin the error is related to
///
public Plugin? Plugin { get; }
-
- ///
- /// Gets or sets the help document related to this exception.
- ///
- public string? HelpDocument { get; }
-
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/BreakableModel.cs b/src/Artemis.Core/Models/BreakableModel.cs
index 1910cc2cc..f0338cd0f 100644
--- a/src/Artemis.Core/Models/BreakableModel.cs
+++ b/src/Artemis.Core/Models/BreakableModel.cs
@@ -59,7 +59,7 @@ public abstract class BreakableModel : CorePropertyChanged, IBreakableModel
}
///
- public void SetBrokenState(string state, Exception? exception)
+ public void SetBrokenState(string state, Exception? exception = null)
{
BrokenState = state ?? throw new ArgumentNullException(nameof(state));
BrokenStateException = exception;
diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs
index a92aabc35..85683eb49 100644
--- a/src/Artemis.Core/Models/Profile/Layer.cs
+++ b/src/Artemis.Core/Models/Profile/Layer.cs
@@ -16,6 +16,9 @@ namespace Artemis.Core;
///
public sealed class Layer : RenderProfileElement
{
+ private const string BROKEN_STATE_BRUSH_NOT_FOUND = "Failed to load layer brush, ensure the plugin is enabled";
+ private const string BROKEN_STATE_INIT_FAILED = "Failed to initialize layer brush";
+
private readonly List _renderCopies = new();
private LayerGeneralProperties _general = new();
private LayerTransformProperties _transform = new();
@@ -261,7 +264,10 @@ public sealed class Layer : RenderProfileElement
private void LayerBrushStoreOnLayerBrushRemoved(object? sender, LayerBrushStoreEvent e)
{
if (LayerBrush?.Descriptor == e.Registration.LayerBrushDescriptor)
+ {
DeactivateLayerBrush();
+ SetBrokenState(BROKEN_STATE_BRUSH_NOT_FOUND);
+ }
}
private void LayerBrushStoreOnLayerBrushAdded(object? sender, LayerBrushStoreEvent e)
@@ -807,33 +813,46 @@ public sealed class Layer : RenderProfileElement
///
/// Changes the current layer brush to the provided layer brush and activates it
///
- public void ChangeLayerBrush(BaseLayerBrush? layerBrush)
+ public void ChangeLayerBrush(BaseLayerBrush layerBrush)
{
- BaseLayerBrush? oldLayerBrush = LayerBrush;
+ if (layerBrush == null)
+ throw new ArgumentNullException(nameof(layerBrush));
- General.BrushReference.SetCurrentValue(layerBrush != null ? new LayerBrushReference(layerBrush.Descriptor) : null);
+ BaseLayerBrush? oldLayerBrush = LayerBrush;
+ General.BrushReference.SetCurrentValue(new LayerBrushReference(layerBrush.Descriptor));
LayerBrush = layerBrush;
+ // Don't dispose the brush, only disable it
+ // That way an undo-action does not need to worry about disposed brushes
oldLayerBrush?.InternalDisable();
-
- if (LayerBrush != null)
- ActivateLayerBrush();
- else
- OnLayerBrushUpdated();
+ ActivateLayerBrush();
}
- internal void ActivateLayerBrush()
+ private void ActivateLayerBrush()
{
try
{
+ // If the brush is null, try to instantiate it
if (LayerBrush == null)
{
- // If the brush is null, try to instantiate it
+ // Ensure the provider is loaded and still provides the expected brush
LayerBrushReference? brushReference = General.BrushReference.CurrentValue;
if (brushReference?.LayerBrushProviderId != null && brushReference.BrushType != null)
- ChangeLayerBrush(LayerBrushStore.Get(brushReference.LayerBrushProviderId, brushReference.BrushType)?.LayerBrushDescriptor.CreateInstance(this, LayerEntity.LayerBrush));
- // If that's not possible there's nothing to do
- return;
+ {
+ // Only apply the brush if it is successfully retrieved from the store and instantiated
+ BaseLayerBrush? layerBrush = LayerBrushStore.Get(brushReference.LayerBrushProviderId, brushReference.BrushType)?.LayerBrushDescriptor.CreateInstance(this, LayerEntity.LayerBrush);
+ if (layerBrush != null)
+ {
+ ClearBrokenState(BROKEN_STATE_BRUSH_NOT_FOUND);
+ ChangeLayerBrush(layerBrush);
+ }
+ // If that's not possible there's nothing to do
+ else
+ {
+ SetBrokenState(BROKEN_STATE_BRUSH_NOT_FOUND);
+ return;
+ }
+ }
}
General.ShapeType.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation;
@@ -846,15 +865,15 @@ public sealed class Layer : RenderProfileElement
}
OnLayerBrushUpdated();
- ClearBrokenState("Failed to initialize layer brush");
+ ClearBrokenState(BROKEN_STATE_INIT_FAILED);
}
catch (Exception e)
{
- SetBrokenState("Failed to initialize layer brush", e);
+ SetBrokenState(BROKEN_STATE_INIT_FAILED, e);
}
}
- internal void DeactivateLayerBrush()
+ private void DeactivateLayerBrush()
{
if (LayerBrush == null)
return;
diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs
index 45b469146..ff90181bc 100644
--- a/src/Artemis.Core/Plugins/Plugin.cs
+++ b/src/Artemis.Core/Plugins/Plugin.cs
@@ -57,7 +57,7 @@ public class Plugin : CorePropertyChanged, IDisposable
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
///
public IPluginConfigurationDialog? ConfigurationDialog { get; set; }
-
+
///
/// Indicates whether the user enabled the plugin or not
///
diff --git a/src/Artemis.Core/Plugins/PluginInfo.cs b/src/Artemis.Core/Plugins/PluginInfo.cs
index 6421749f8..e8c3f5d50 100644
--- a/src/Artemis.Core/Plugins/PluginInfo.cs
+++ b/src/Artemis.Core/Plugins/PluginInfo.cs
@@ -27,6 +27,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
private bool _requiresAdmin;
private string _version = null!;
private Uri? _website;
+ private Uri? _helpPage;
internal PluginInfo()
{
@@ -91,6 +92,16 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
get => _repository;
set => SetAndNotify(ref _repository, value);
}
+
+ ///
+ /// Gets or sets the help page of this plugin
+ ///
+ [JsonProperty]
+ public Uri? HelpPage
+ {
+ get => _helpPage;
+ set => SetAndNotify(ref _helpPage, value);
+ }
///
/// The plugins display icon that's shown in the settings see for
diff --git a/src/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs b/src/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs
index e3785eea9..616b7977a 100644
--- a/src/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs
+++ b/src/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs
@@ -78,6 +78,6 @@ public class OpenFileDialogBuilder
public async Task ShowAsync()
{
IReadOnlyList files = await _parent.StorageProvider.OpenFilePickerAsync(_options);
- return files.Select(f => f.Path.AbsolutePath).ToArray();
+ return files.Select(f => f.Path.LocalPath).ToArray();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs b/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs
index 1c9a508c2..ce92133d6 100644
--- a/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs
+++ b/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ChangeLayerBrush.cs
@@ -54,7 +54,8 @@ public class ChangeLayerBrush : IProfileEditorCommand, IDisposable
///
public void Undo()
{
- _layer.ChangeLayerBrush(_previousBrush);
+ if (_previousBrush != null)
+ _layer.ChangeLayerBrush(_previousBrush);
_executed = false;
}
diff --git a/src/Artemis.UI.Shared/Styles/Artemis.axaml b/src/Artemis.UI.Shared/Styles/Artemis.axaml
index 9907a4b20..988213ad4 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/BrokenState.axaml b/src/Artemis.UI.Shared/Styles/BrokenState.axaml
new file mode 100644
index 000000000..65ef465c0
--- /dev/null
+++ b/src/Artemis.UI.Shared/Styles/BrokenState.axaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index 4e6b4e383..a1252420a 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -52,5 +52,17 @@
UpdatingTabView.axaml
Code
+
+ PluginFeatureView.axaml
+ Code
+
+
+ PluginPrerequisiteActionView.axaml
+ Code
+
+
+ PluginPrerequisiteView.axaml
+ Code
+
\ 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 7d3e344aa..d410e3cfc 100644
--- a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs
+++ b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs
@@ -7,6 +7,8 @@ using Artemis.Core.LayerEffects;
using Artemis.Core.ScriptingProviders;
using Artemis.UI.Screens.Device;
using Artemis.UI.Screens.Plugins;
+using Artemis.UI.Screens.Plugins.Features;
+using Artemis.UI.Screens.Plugins.Prerequisites;
using Artemis.UI.Screens.ProfileEditor;
using Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
diff --git a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogView.axaml b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogView.axaml
index 305c68324..9ac570871 100644
--- a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogView.axaml
+++ b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogView.axaml
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:plugins="clr-namespace:Artemis.UI.Screens.Plugins"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
+ xmlns:prerequisites="clr-namespace:Artemis.UI.Screens.Plugins.Prerequisites"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisitesInstallDialogView"
x:DataType="plugins:PluginPrerequisitesInstallDialogViewModel">
@@ -34,7 +35,7 @@
SelectedItem="{CompiledBinding ActivePrerequisite, Mode=OneWay}"
IsHitTestVisible="False">
-
+
diff --git a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs
index a8de70fbd..649698e0d 100644
--- a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs
+++ b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs
@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.DryIoc.Factories;
+using Artemis.UI.Screens.Plugins.Prerequisites;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Avalonia.Threading;
diff --git a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogView.axaml b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogView.axaml
index d2c15c7fd..0acb85de7 100644
--- a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogView.axaml
+++ b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogView.axaml
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:plugins="clr-namespace:Artemis.UI.Screens.Plugins"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
+ xmlns:prerequisites="clr-namespace:Artemis.UI.Screens.Plugins.Prerequisites"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisitesUninstallDialogView"
x:DataType="plugins:PluginPrerequisitesUninstallDialogViewModel">
@@ -34,7 +35,7 @@
SelectedItem="{CompiledBinding ActivePrerequisite, Mode=OneWay}"
IsHitTestVisible="False">
-
+
diff --git a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs
index b65e72d23..b443de9b1 100644
--- a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs
+++ b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs
@@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories;
+using Artemis.UI.Screens.Plugins.Prerequisites;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Avalonia.Threading;
diff --git a/src/Artemis.UI/Screens/Plugins/PluginFeatureView.axaml b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureView.axaml
similarity index 95%
rename from src/Artemis.UI/Screens/Plugins/PluginFeatureView.axaml
rename to src/Artemis.UI/Screens/Plugins/Features/PluginFeatureView.axaml
index 790c38f82..0b8bd3873 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginFeatureView.axaml
+++ b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureView.axaml
@@ -5,9 +5,10 @@
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:plugins="clr-namespace:Artemis.UI.Screens.Plugins"
+ xmlns:features="clr-namespace:Artemis.UI.Screens.Plugins.Features"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
- x:Class="Artemis.UI.Screens.Plugins.PluginFeatureView"
- x:DataType="plugins:PluginFeatureViewModel">
+ x:Class="Artemis.UI.Screens.Plugins.Features.PluginFeatureView"
+ x:DataType="features:PluginFeatureViewModel">
diff --git a/src/Artemis.UI/Screens/Plugins/PluginFeatureView.axaml.cs b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureView.axaml.cs
similarity index 74%
rename from src/Artemis.UI/Screens/Plugins/PluginFeatureView.axaml.cs
rename to src/Artemis.UI/Screens/Plugins/Features/PluginFeatureView.axaml.cs
index 7f21c9ce0..1beddfbbf 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginFeatureView.axaml.cs
+++ b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureView.axaml.cs
@@ -1,7 +1,6 @@
-using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
-namespace Artemis.UI.Screens.Plugins;
+namespace Artemis.UI.Screens.Plugins.Features;
public partial class PluginFeatureView : ReactiveUserControl
{
diff --git a/src/Artemis.UI/Screens/Plugins/PluginFeatureViewModel.cs b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureViewModel.cs
similarity index 90%
rename from src/Artemis.UI/Screens/Plugins/PluginFeatureViewModel.cs
rename to src/Artemis.UI/Screens/Plugins/Features/PluginFeatureViewModel.cs
index 5c2abaea2..2d83d9e6c 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginFeatureViewModel.cs
+++ b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureViewModel.cs
@@ -18,12 +18,11 @@ using Avalonia.Threading;
using Material.Icons;
using ReactiveUI;
-namespace Artemis.UI.Screens.Plugins;
+namespace Artemis.UI.Screens.Plugins.Features;
public class PluginFeatureViewModel : ActivatableViewModelBase
{
private readonly ICoreService _coreService;
- private readonly INotificationService _notificationService;
private readonly IPluginManagementService _pluginManagementService;
private readonly IWindowService _windowService;
private bool _enabling;
@@ -32,12 +31,10 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
bool showShield,
ICoreService coreService,
IWindowService windowService,
- INotificationService notificationService,
IPluginManagementService pluginManagementService)
{
_coreService = coreService;
_windowService = windowService;
- _notificationService = notificationService;
_pluginManagementService = pluginManagementService;
FeatureInfo = pluginFeatureInfo;
@@ -176,11 +173,7 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
if (FeatureInfo.Instance == null)
{
this.RaisePropertyChanged(nameof(IsEnabled));
- _notificationService.CreateNotification()
- .WithMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .WithSeverity(NotificationSeverity.Error)
- .Show();
+ await ShowFailureDialog($"Failed to enable '{FeatureInfo.Name}'", $"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.");
return;
}
@@ -215,11 +208,7 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
}
catch (Exception e)
{
- _notificationService.CreateNotification()
- .WithMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .WithSeverity(NotificationSeverity.Error)
- .Show();
+ await ShowFailureDialog($"Failed to enable '{FeatureInfo.Name}'", e.Message);
}
finally
{
@@ -254,4 +243,17 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
{
this.RaisePropertyChanged(nameof(CanToggleEnabled));
}
+
+ private async Task ShowFailureDialog(string action, string message)
+ {
+ ContentDialogBuilder builder = _windowService.CreateContentDialog()
+ .WithTitle(action)
+ .WithContent(message)
+ .HavingPrimaryButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder));
+ // If available, add a secondary button pointing to the support page
+ if (FeatureInfo.Plugin.Info.HelpPage != null)
+ builder = builder.HavingSecondaryButton(b => b.WithText("Open support page").WithAction(() => Utilities.OpenUrl(FeatureInfo.Plugin.Info.HelpPage.ToString())));
+
+ await builder.ShowAsync();
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs
index 9d3e64329..81d287b42 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs
+++ b/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories;
+using Artemis.UI.Screens.Plugins.Features;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using ReactiveUI;
diff --git a/src/Artemis.UI/Screens/Plugins/PluginSettingsWindowView.axaml b/src/Artemis.UI/Screens/Plugins/PluginSettingsWindowView.axaml
index 12dd5b763..a38d666b6 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginSettingsWindowView.axaml
+++ b/src/Artemis.UI/Screens/Plugins/PluginSettingsWindowView.axaml
@@ -3,10 +3,12 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia"
+ xmlns:plugins="clr-namespace:Artemis.UI.Screens.Plugins"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Plugins.PluginSettingsWindowView"
+ x:DataType="plugins:PluginSettingsWindowViewModel"
Icon="/Assets/Images/Logo/application.ico"
- Title="{Binding DisplayName}"
+ Title="{CompiledBinding DisplayName}"
Width="800"
Height="800"
WindowStartupLocation="CenterOwner">
diff --git a/src/Artemis.UI/Screens/Plugins/PluginView.axaml b/src/Artemis.UI/Screens/Plugins/PluginView.axaml
index 27c47a631..640279366 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginView.axaml
+++ b/src/Artemis.UI/Screens/Plugins/PluginView.axaml
@@ -46,9 +46,9 @@
-
-
-
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+ NavigateUri="{CompiledBinding Plugin.Info.Website}"
+ ToolTip.Tip="{CompiledBinding Plugin.Info.Website}">
+ NavigateUri="{CompiledBinding Plugin.Info.Repository}"
+ ToolTip.Tip="{CompiledBinding Plugin.Info.Repository}">
diff --git a/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs b/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs
index 35d37aa0e..96ec6e772 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs
+++ b/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs
@@ -28,7 +28,7 @@ public class PluginViewModel : ActivatableViewModelBase
private bool _canRemovePrerequisites;
private bool _enabling;
private Plugin _plugin;
- private Window? _window;
+ private Window? _settingsWindow;
public PluginViewModel(Plugin plugin,
ReactiveCommand? reload,
@@ -72,7 +72,7 @@ public class PluginViewModel : ActivatableViewModelBase
{
Plugin.Enabled -= OnPluginToggled;
Plugin.Disabled -= OnPluginToggled;
- _window?.Close();
+ _settingsWindow?.Close();
}).DisposeWith(d);
});
}
@@ -128,11 +128,7 @@ public class PluginViewModel : ActivatableViewModelBase
}
catch (Exception e)
{
- await Dispatcher.UIThread.InvokeAsync(() => _notificationService.CreateNotification()
- .WithSeverity(NotificationSeverity.Error)
- .WithMessage($"Failed to disable plugin {Plugin.Info.Name}\r\n{e.Message}")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .Show());
+ await ShowUpdateEnableFailure(enable, e);
}
finally
{
@@ -167,11 +163,7 @@ public class PluginViewModel : ActivatableViewModelBase
}
catch (Exception e)
{
- await Dispatcher.UIThread.InvokeAsync(() => _notificationService.CreateNotification()
- .WithSeverity(NotificationSeverity.Error)
- .WithMessage($"Failed to enable plugin {Plugin.Info.Name}\r\n{e.Message}")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .Show());
+ await ShowUpdateEnableFailure(enable, e);
}
finally
{
@@ -180,7 +172,6 @@ public class PluginViewModel : ActivatableViewModelBase
}
}
-
public void CheckPrerequisites()
{
CanInstallPrerequisites = false;
@@ -199,10 +190,10 @@ public class PluginViewModel : ActivatableViewModelBase
if (Plugin.ConfigurationDialog == null)
return;
- if (_window != null)
+ if (_settingsWindow != null)
{
- _window.WindowState = WindowState.Normal;
- _window.Activate();
+ _settingsWindow.WindowState = WindowState.Normal;
+ _settingsWindow.Activate();
return;
}
@@ -211,8 +202,8 @@ public class PluginViewModel : ActivatableViewModelBase
if (Plugin.Resolve(Plugin.ConfigurationDialog.Type) is not PluginConfigurationViewModel viewModel)
throw new ArtemisUIException($"The type of a plugin configuration dialog must inherit {nameof(PluginConfigurationViewModel)}");
- _window = _windowService.ShowWindow(new PluginSettingsWindowViewModel(viewModel));
- _window.Closed += (_, _) => _window = null;
+ _settingsWindow = _windowService.ShowWindow(new PluginSettingsWindowViewModel(viewModel));
+ _settingsWindow.Closed += (_, _) => _settingsWindow = null;
}
catch (Exception e)
{
@@ -306,6 +297,20 @@ public class PluginViewModel : ActivatableViewModelBase
_windowService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
}
}
+
+ private async Task ShowUpdateEnableFailure(bool enable, Exception e)
+ {
+ string action = enable ? "enable" : "disable";
+ ContentDialogBuilder builder = _windowService.CreateContentDialog()
+ .WithTitle($"Failed to {action} plugin {Plugin.Info.Name}")
+ .WithContent(e.Message)
+ .HavingPrimaryButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder));
+ // If available, add a secondary button pointing to the support page
+ if (Plugin.Info.HelpPage != null)
+ builder = builder.HavingSecondaryButton(b => b.WithText("Open support page").WithAction(() => Utilities.OpenUrl(Plugin.Info.HelpPage.ToString())));
+
+ await builder.ShowAsync();
+ }
private void OnPluginToggled(object? sender, EventArgs e)
{
@@ -313,7 +318,7 @@ public class PluginViewModel : ActivatableViewModelBase
{
this.RaisePropertyChanged(nameof(IsEnabled));
if (!IsEnabled)
- _window?.Close();
+ _settingsWindow?.Close();
});
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/PluginPrerequisiteActionView.axaml b/src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteActionView.axaml
similarity index 82%
rename from src/Artemis.UI/Screens/Plugins/PluginPrerequisiteActionView.axaml
rename to src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteActionView.axaml
index 0cc1745d7..d7a09a975 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginPrerequisiteActionView.axaml
+++ b/src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteActionView.axaml
@@ -3,9 +3,10 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:plugins="clr-namespace:Artemis.UI.Screens.Plugins"
+ xmlns:prerequisites="clr-namespace:Artemis.UI.Screens.Plugins.Prerequisites"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
- x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisiteActionView"
- x:DataType="plugins:PluginPrerequisiteActionViewModel">
+ x:Class="Artemis.UI.Screens.Plugins.Prerequisites.PluginPrerequisiteActionView"
+ x:DataType="prerequisites:PluginPrerequisiteActionViewModel">
+ x:Class="Artemis.UI.Screens.Plugins.Prerequisites.PluginPrerequisiteView"
+ x:DataType="prerequisites:PluginPrerequisiteViewModel">
diff --git a/src/Artemis.UI/Screens/Plugins/PluginPrerequisiteView.axaml.cs b/src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteView.axaml.cs
similarity index 65%
rename from src/Artemis.UI/Screens/Plugins/PluginPrerequisiteView.axaml.cs
rename to src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteView.axaml.cs
index 50cbd2c39..043fbce7b 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginPrerequisiteView.axaml.cs
+++ b/src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteView.axaml.cs
@@ -1,7 +1,6 @@
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
+using Avalonia.ReactiveUI;
-namespace Artemis.UI.Screens.Plugins;
+namespace Artemis.UI.Screens.Plugins.Prerequisites;
public partial class PluginPrerequisiteView : ReactiveUserControl
{
diff --git a/src/Artemis.UI/Screens/Plugins/PluginPrerequisiteViewModel.cs b/src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteViewModel.cs
similarity index 98%
rename from src/Artemis.UI/Screens/Plugins/PluginPrerequisiteViewModel.cs
rename to src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteViewModel.cs
index a9ed4a8b4..58cce5d2e 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginPrerequisiteViewModel.cs
+++ b/src/Artemis.UI/Screens/Plugins/Prerequisites/PluginPrerequisiteViewModel.cs
@@ -8,7 +8,7 @@ using Artemis.Core;
using Artemis.UI.Shared;
using ReactiveUI;
-namespace Artemis.UI.Screens.Plugins;
+namespace Artemis.UI.Screens.Plugins.Prerequisites;
public class PluginPrerequisiteViewModel : ActivatableViewModelBase
{
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml
index b9301627e..60f0456da 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml
@@ -4,21 +4,19 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:profileTree="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree"
+ xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.FolderTreeItemView"
x:DataType="profileTree:FolderTreeItemViewModel">
-
+
-
+
-
-
-
+
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeView.axaml b/src/Artemis.UI/Screens/VisualScripting/NodeView.axaml
index 7adfdbbdf..62838e70c 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeView.axaml
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeView.axaml
@@ -39,21 +39,16 @@
Background="{DynamicResource ContentDialogBackground}">
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file