mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Prerequisites - Finalized UI logic surrounding install/remove
This commit is contained in:
parent
21700aaad5
commit
77be79dde5
@ -7,32 +7,24 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public class ArtemisPluginPrerequisiteException : Exception
|
||||
{
|
||||
internal ArtemisPluginPrerequisiteException(Plugin plugin, PluginPrerequisite? pluginPrerequisite)
|
||||
internal ArtemisPluginPrerequisiteException(IPrerequisitesSubject subject)
|
||||
{
|
||||
Plugin = plugin;
|
||||
PluginPrerequisite = pluginPrerequisite;
|
||||
Subject = subject;
|
||||
}
|
||||
|
||||
internal ArtemisPluginPrerequisiteException(Plugin plugin, PluginPrerequisite? pluginPrerequisite, string message) : base(message)
|
||||
internal ArtemisPluginPrerequisiteException(IPrerequisitesSubject subject, string message) : base(message)
|
||||
{
|
||||
Plugin = plugin;
|
||||
PluginPrerequisite = pluginPrerequisite;
|
||||
Subject = subject;
|
||||
}
|
||||
|
||||
internal ArtemisPluginPrerequisiteException(Plugin plugin, PluginPrerequisite? pluginPrerequisite, string message, Exception inner) : base(message, inner)
|
||||
internal ArtemisPluginPrerequisiteException(IPrerequisitesSubject subject, string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
Plugin = plugin;
|
||||
PluginPrerequisite = pluginPrerequisite;
|
||||
Subject = subject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin the error is related to
|
||||
/// Gets the subject the error is related to
|
||||
/// </summary>
|
||||
public Plugin Plugin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin prerequisite the error is related to
|
||||
/// </summary>
|
||||
public PluginPrerequisite? PluginPrerequisite { get; }
|
||||
public IPrerequisitesSubject Subject { get; }
|
||||
}
|
||||
}
|
||||
@ -25,6 +25,7 @@ namespace Artemis.Core
|
||||
Info = info;
|
||||
Directory = directory;
|
||||
Entity = pluginEntity ?? new PluginEntity {Id = Guid, IsEnabled = true};
|
||||
Info.Plugin = this;
|
||||
|
||||
_features = new List<PluginFeatureInfo>();
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ using Artemis.Core.DeviceProviders;
|
||||
using Artemis.Core.LayerBrushes;
|
||||
using Artemis.Core.LayerEffects;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Storage.Entities.Plugins;
|
||||
using Humanizer;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@ -22,10 +23,11 @@ namespace Artemis.Core
|
||||
private PluginFeature? _instance;
|
||||
private string _name = null!;
|
||||
|
||||
internal PluginFeatureInfo(Plugin plugin, Type featureType, PluginFeatureAttribute? attribute)
|
||||
internal PluginFeatureInfo(Plugin plugin, Type featureType, PluginFeatureEntity pluginFeatureEntity, PluginFeatureAttribute? attribute)
|
||||
{
|
||||
Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin));
|
||||
FeatureType = featureType ?? throw new ArgumentNullException(nameof(featureType));
|
||||
Entity = pluginFeatureEntity;
|
||||
|
||||
Name = attribute?.Name ?? featureType.Name.Humanize(LetterCasing.Title);
|
||||
Description = attribute?.Description;
|
||||
@ -121,6 +123,11 @@ namespace Artemis.Core
|
||||
[JsonProperty]
|
||||
public bool AlwaysEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the feature is enabled in persistent storage
|
||||
/// </summary>
|
||||
public bool EnabledInStorage => Entity.IsEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the feature this info is associated with
|
||||
/// </summary>
|
||||
@ -136,6 +143,8 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public bool ArePrerequisitesMet() => Prerequisites.All(p => p.IsMet());
|
||||
|
||||
internal PluginFeatureEntity Entity { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Humanizer;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a plugin prerequisite action that downloads a file
|
||||
/// </summary>
|
||||
public class DownloadFileAction : PluginPrerequisiteAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of a copy folder action
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the action</param>
|
||||
/// <param name="source">The source URL to download</param>
|
||||
/// <param name="target">The target file to save as (will be created if needed)</param>
|
||||
public DownloadFileAction(string name, string source, string target) : base(name)
|
||||
{
|
||||
Source = source ?? throw new ArgumentNullException(nameof(source));
|
||||
Target = target ?? throw new ArgumentNullException(nameof(target));
|
||||
|
||||
ShowProgressBar = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source URL to download
|
||||
/// </summary>
|
||||
public string Source { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target file to save as (will be created if needed)
|
||||
/// </summary>
|
||||
public string Target { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task Execute(CancellationToken cancellationToken)
|
||||
{
|
||||
using HttpClient client = new();
|
||||
await using FileStream destinationStream = File.Create(Target);
|
||||
|
||||
void ProgressOnProgressReported(object? sender, EventArgs e)
|
||||
{
|
||||
if (Progress.ProgressPerSecond != 0)
|
||||
Status = $"Downloading {Target} - {Progress.ProgressPerSecond.Bytes().Humanize("#.##")}/sec";
|
||||
else
|
||||
Status = $"Downloading {Target}";
|
||||
}
|
||||
|
||||
Progress.ProgressReported += ProgressOnProgressReported;
|
||||
|
||||
// Get the http headers first to examine the content length
|
||||
using HttpResponseMessage response = await client.GetAsync(Target, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||
await using Stream download = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
long? contentLength = response.Content.Headers.ContentLength;
|
||||
|
||||
// Ignore progress reporting when no progress reporter was
|
||||
// passed or when the content length is unknown
|
||||
if (!contentLength.HasValue)
|
||||
{
|
||||
ProgressIndeterminate = true;
|
||||
await download.CopyToAsync(destinationStream, Progress, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgressIndeterminate = false;
|
||||
await download.CopyToAsync(contentLength.Value, destinationStream, Progress, cancellationToken);
|
||||
}
|
||||
|
||||
Progress.ProgressReported -= ProgressOnProgressReported;
|
||||
|
||||
Progress.Report((1, 1));
|
||||
Status = "Finished downloading";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,7 +340,12 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
|
||||
foreach (Type featureType in featureTypes)
|
||||
plugin.AddFeature(new PluginFeatureInfo(plugin, featureType, (PluginFeatureAttribute?) Attribute.GetCustomAttribute(featureType, typeof(PluginFeatureAttribute))));
|
||||
{
|
||||
// Load the enabled state and if not found, default to true
|
||||
PluginFeatureEntity featureEntity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureType.FullName) ??
|
||||
new PluginFeatureEntity { IsEnabled = plugin.Info.AutoEnableFeatures, Type = featureType.FullName! };
|
||||
plugin.AddFeature(new PluginFeatureInfo(plugin, featureType, featureEntity, (PluginFeatureAttribute?) Attribute.GetCustomAttribute(featureType, typeof(PluginFeatureAttribute))));
|
||||
}
|
||||
|
||||
if (!featureTypes.Any())
|
||||
_logger.Warning("Plugin {plugin} contains no features", plugin);
|
||||
@ -382,7 +387,7 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
|
||||
if (!plugin.Info.ArePrerequisitesMet())
|
||||
throw new ArtemisPluginPrerequisiteException(plugin, null, "Cannot enable a plugin whose prerequisites aren't all met");
|
||||
throw new ArtemisPluginPrerequisiteException(plugin.Info, "Cannot enable a plugin whose prerequisites aren't all met");
|
||||
|
||||
// Create the Ninject child kernel and load the module
|
||||
plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin));
|
||||
@ -406,10 +411,7 @@ namespace Artemis.Core.Services
|
||||
featureInfo.Instance = instance;
|
||||
instance.Info = featureInfo;
|
||||
instance.Plugin = plugin;
|
||||
|
||||
// Load the enabled state and if not found, default to true
|
||||
instance.Entity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureInfo.FeatureType.FullName) ??
|
||||
new PluginFeatureEntity {IsEnabled = plugin.Info.AutoEnableFeatures, Type = featureInfo.FeatureType.FullName!};
|
||||
instance.Entity = featureInfo.Entity;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -418,17 +420,8 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
|
||||
// Activate features after they are all loaded
|
||||
foreach (PluginFeatureInfo pluginFeature in plugin.Features.Where(f => f.Instance != null && (f.Instance.Entity.IsEnabled || f.AlwaysEnabled)))
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (PluginFeatureInfo pluginFeature in plugin.Features.Where(f => f.Instance != null && (f.EnabledInStorage || f.AlwaysEnabled)))
|
||||
EnablePluginFeature(pluginFeature.Instance!, false, !ignorePluginLock);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored, logged in EnablePluginFeature
|
||||
}
|
||||
}
|
||||
|
||||
if (saveState)
|
||||
{
|
||||
@ -585,7 +578,10 @@ namespace Artemis.Core.Services
|
||||
if (pluginFeature.Plugin.Info.RequiresAdmin && !_isElevated)
|
||||
{
|
||||
if (!saveState)
|
||||
{
|
||||
OnPluginFeatureEnableFailed(new PluginFeatureEventArgs(pluginFeature));
|
||||
throw new ArtemisCoreException("Cannot enable a feature that requires elevation without saving it's state.");
|
||||
}
|
||||
|
||||
pluginFeature.Entity.IsEnabled = true;
|
||||
pluginFeature.Plugin.Entity.IsEnabled = true;
|
||||
@ -596,6 +592,12 @@ namespace Artemis.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pluginFeature.Info.ArePrerequisitesMet())
|
||||
{
|
||||
OnPluginFeatureEnableFailed(new PluginFeatureEventArgs(pluginFeature));
|
||||
throw new ArtemisPluginPrerequisiteException(pluginFeature.Info, "Cannot enable a plugin feature whose prerequisites aren't all met");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
pluginFeature.SetEnabled(true, isAutoEnable);
|
||||
@ -608,7 +610,6 @@ namespace Artemis.Core.Services
|
||||
new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e),
|
||||
"Failed to enable plugin"
|
||||
);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
<ColumnDefinition Width="500" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="0" Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" Margin="0 0 0 20">
|
||||
Plugin prerequisites
|
||||
Plugin/feature prerequisites
|
||||
</TextBlock>
|
||||
|
||||
<ListBox Grid.Row="1"
|
||||
@ -83,7 +83,7 @@
|
||||
TextWrapping="Wrap"
|
||||
Margin="10 0"
|
||||
Visibility="{Binding ActivePrerequisite, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
|
||||
In order for this plugin to function certain prerequisites must be met. <LineBreak /><LineBreak />
|
||||
In order for this plugin/feature to function certain prerequisites must be met. <LineBreak /><LineBreak />
|
||||
On the left side you can see all prerequisites and whether they are currently met or not.
|
||||
Clicking install prerequisites will automatically set everything up for you.
|
||||
</TextBlock>
|
||||
|
||||
@ -4,7 +4,6 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
@ -15,35 +14,25 @@ namespace Artemis.UI.Screens.Plugins
|
||||
public class PluginPrerequisitesInstallDialogViewModel : DialogViewModelBase
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly List<IPrerequisitesSubject> _subjects;
|
||||
private PluginPrerequisiteViewModel _activePrerequisite;
|
||||
private bool _canInstall;
|
||||
private bool _isFinished;
|
||||
private CancellationTokenSource _tokenSource;
|
||||
|
||||
public PluginPrerequisitesInstallDialogViewModel(IPrerequisitesSubject subject, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService)
|
||||
public PluginPrerequisitesInstallDialogViewModel(List<IPrerequisitesSubject> subjects, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService)
|
||||
{
|
||||
_subjects = subjects;
|
||||
_dialogService = dialogService;
|
||||
// Constructor overloading doesn't work very well with Kernel.Get<T> :(
|
||||
if (subject is PluginInfo plugin)
|
||||
{
|
||||
PluginInfo = plugin;
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
|
||||
}
|
||||
else if (subject is PluginFeatureInfo feature)
|
||||
{
|
||||
FeatureInfo = feature;
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(feature.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
|
||||
}
|
||||
else
|
||||
throw new ArtemisUIException($"Expected plugin or feature to be passed to {nameof(PluginPrerequisitesInstallDialogViewModel)}");
|
||||
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>();
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in subjects)
|
||||
Prerequisites.AddRange(prerequisitesSubject.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
|
||||
|
||||
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||
pluginPrerequisiteViewModel.ConductWith(this);
|
||||
}
|
||||
|
||||
|
||||
public PluginInfo PluginInfo { get; }
|
||||
public PluginFeatureInfo FeatureInfo { get; }
|
||||
public BindableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||
|
||||
public PluginPrerequisiteViewModel ActivePrerequisite
|
||||
@ -64,9 +53,6 @@ namespace Artemis.UI.Screens.Plugins
|
||||
set => SetAndNotify(ref _isFinished, value);
|
||||
}
|
||||
|
||||
public bool IsSubjectPlugin => PluginInfo != null;
|
||||
public bool IsSubjectFeature => FeatureInfo != null;
|
||||
|
||||
#region Overrides of DialogViewModelBase
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -114,7 +100,7 @@ namespace Artemis.UI.Screens.Plugins
|
||||
"Confirm",
|
||||
""
|
||||
);
|
||||
await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{"subject", PluginInfo}});
|
||||
await Show(_dialogService, _subjects);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@ -133,16 +119,18 @@ namespace Artemis.UI.Screens.Plugins
|
||||
Session?.Close(true);
|
||||
}
|
||||
|
||||
public static Task<object> Show(IDialogService dialogService, List<IPrerequisitesSubject> subjects)
|
||||
{
|
||||
return dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{"subjects", subjects}});
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
CanInstall = false;
|
||||
if (PluginInfo != null)
|
||||
Task.Run(() => CanInstall = !PluginInfo.ArePrerequisitesMet());
|
||||
else
|
||||
Task.Run(() => CanInstall = !FeatureInfo.ArePrerequisitesMet());
|
||||
Task.Run(() => CanInstall = Prerequisites.Any(p => !p.PluginPrerequisite.IsMet()));
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
<ColumnDefinition Width="500" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="0" Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" Margin="0 0 0 20">
|
||||
Plugin prerequisites
|
||||
Plugin/feature prerequisites
|
||||
</TextBlock>
|
||||
|
||||
<ListBox Grid.Row="1"
|
||||
@ -83,8 +83,8 @@
|
||||
TextWrapping="Wrap"
|
||||
Margin="10 0"
|
||||
Visibility="{Binding ActivePrerequisite, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
|
||||
This plugin installed certain prerequisites in order to function. <LineBreak /><LineBreak />
|
||||
In this screen you can chose to remove these, this will mean the plugin will no longer work until you reinstall the prerequisites.
|
||||
This plugin/feature installed certain prerequisites in order to function. <LineBreak /><LineBreak />
|
||||
In this screen you can chose to remove these, this will mean the plugin/feature will no longer work until you reinstall the prerequisites.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
@ -98,7 +98,7 @@
|
||||
Focusable="False"
|
||||
IsCancel="True"
|
||||
Command="{s:Action Cancel}"
|
||||
Content="CANCEL" />
|
||||
Content="{Binding CancelLabel}" />
|
||||
<Button x:Name="ConfirmButton"
|
||||
Style="{StaticResource MaterialDesignFlatButton}"
|
||||
IsDefault="True"
|
||||
|
||||
@ -5,7 +5,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
@ -17,38 +16,29 @@ namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly List<IPrerequisitesSubject> _subjects;
|
||||
private PluginPrerequisiteViewModel _activePrerequisite;
|
||||
private bool _canUninstall;
|
||||
private bool _isFinished;
|
||||
private CancellationTokenSource _tokenSource;
|
||||
|
||||
public PluginPrerequisitesUninstallDialogViewModel(IPrerequisitesSubject subject, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService,
|
||||
IPluginManagementService pluginManagementService)
|
||||
public PluginPrerequisitesUninstallDialogViewModel(List<IPrerequisitesSubject> subjects, string cancelLabel, IPrerequisitesVmFactory prerequisitesVmFactory,
|
||||
IDialogService dialogService, IPluginManagementService pluginManagementService)
|
||||
{
|
||||
_subjects = subjects;
|
||||
_dialogService = dialogService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
|
||||
// Constructor overloading doesn't work very well with Kernel.Get<T> :(
|
||||
if (subject is PluginInfo plugin)
|
||||
{
|
||||
PluginInfo = plugin;
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
|
||||
}
|
||||
else if (subject is PluginFeatureInfo feature)
|
||||
{
|
||||
FeatureInfo = feature;
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(feature.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
|
||||
}
|
||||
else
|
||||
throw new ArtemisUIException($"Expected plugin or feature to be passed to {nameof(PluginPrerequisitesInstallDialogViewModel)}");
|
||||
CancelLabel = cancelLabel;
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>();
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in subjects)
|
||||
Prerequisites.AddRange(prerequisitesSubject.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
|
||||
|
||||
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||
pluginPrerequisiteViewModel.ConductWith(this);
|
||||
}
|
||||
|
||||
|
||||
public PluginFeatureInfo FeatureInfo { get; }
|
||||
public PluginInfo PluginInfo { get; }
|
||||
public string CancelLabel { get; }
|
||||
public BindableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||
|
||||
public PluginPrerequisiteViewModel ActivePrerequisite
|
||||
@ -69,9 +59,6 @@ namespace Artemis.UI.Screens.Plugins
|
||||
set => SetAndNotify(ref _isFinished, value);
|
||||
}
|
||||
|
||||
public bool IsSubjectPlugin => PluginInfo != null;
|
||||
public bool IsSubjectFeature => FeatureInfo != null;
|
||||
|
||||
#region Overrides of DialogViewModelBase
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -87,10 +74,26 @@ namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
CanUninstall = false;
|
||||
|
||||
if (PluginInfo != null)
|
||||
_pluginManagementService.DisablePlugin(PluginInfo.Plugin, true);
|
||||
else if (FeatureInfo?.Instance != null)
|
||||
_pluginManagementService.DisablePluginFeature(FeatureInfo.Instance, true);
|
||||
// Disable all subjects that are plugins, this will disable their features too
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in _subjects)
|
||||
{
|
||||
if (prerequisitesSubject is PluginInfo pluginInfo)
|
||||
_pluginManagementService.DisablePlugin(pluginInfo.Plugin, true);
|
||||
}
|
||||
|
||||
// Disable all subjects that are features if still required
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in _subjects)
|
||||
{
|
||||
if (prerequisitesSubject is not PluginFeatureInfo featureInfo)
|
||||
continue;
|
||||
|
||||
// Disable the parent plugin if the feature is AlwaysEnabled
|
||||
if (featureInfo.AlwaysEnabled)
|
||||
_pluginManagementService.DisablePlugin(featureInfo.Plugin, true);
|
||||
else if (featureInfo.Instance != null)
|
||||
_pluginManagementService.DisablePluginFeature(featureInfo.Instance, true);
|
||||
}
|
||||
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
@ -124,7 +127,7 @@ namespace Artemis.UI.Screens.Plugins
|
||||
"Confirm",
|
||||
""
|
||||
);
|
||||
await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> {{"subject", PluginInfo}});
|
||||
await Show(_dialogService, _subjects);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@ -143,6 +146,15 @@ namespace Artemis.UI.Screens.Plugins
|
||||
Session?.Close(true);
|
||||
}
|
||||
|
||||
public static Task<object> Show(IDialogService dialogService, List<IPrerequisitesSubject> subjects, string cancelLabel = "CANCEL")
|
||||
{
|
||||
return dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object>
|
||||
{
|
||||
{"subjects", subjects},
|
||||
{"cancelLabel", cancelLabel},
|
||||
});
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -150,10 +162,7 @@ namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
CanUninstall = false;
|
||||
// Could be slow so take it off of the UI thread
|
||||
if (PluginInfo != null)
|
||||
Task.Run(() => CanUninstall = PluginInfo.Prerequisites.Any(p => p.IsMet()));
|
||||
else
|
||||
Task.Run(() => CanUninstall = FeatureInfo.Prerequisites.Any(p => p.IsMet()));
|
||||
Task.Run(() => CanUninstall = Prerequisites.Any(p => p.PluginPrerequisite.IsMet()));
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
@ -16,12 +16,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IMessageService _messageService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private bool _enabling;
|
||||
private readonly IMessageService _messageService;
|
||||
private bool _isSettingsPopupOpen;
|
||||
private bool _canInstallPrerequisites;
|
||||
private bool _canRemovePrerequisites;
|
||||
|
||||
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
|
||||
bool showShield,
|
||||
@ -81,6 +78,21 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
_dialogService.ShowExceptionDialog("Feature failed to enable", LoadException);
|
||||
}
|
||||
|
||||
public async Task InstallPrerequisites()
|
||||
{
|
||||
if (FeatureInfo.Prerequisites.Any())
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> { FeatureInfo });
|
||||
}
|
||||
|
||||
public async Task RemovePrerequisites()
|
||||
{
|
||||
if (FeatureInfo.Prerequisites.Any(p => p.UninstallActions.Any()))
|
||||
{
|
||||
await PluginPrerequisitesUninstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
|
||||
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
_pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling;
|
||||
@ -105,21 +117,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
public async Task InstallPrerequisites()
|
||||
{
|
||||
if (FeatureInfo.Prerequisites.Any())
|
||||
await ShowPrerequisitesDialog(false, FeatureInfo);
|
||||
}
|
||||
|
||||
public async Task RemovePrerequisites()
|
||||
{
|
||||
if (FeatureInfo.Prerequisites.Any(p => p.UninstallActions.Any()))
|
||||
{
|
||||
await ShowPrerequisitesDialog(true, FeatureInfo);
|
||||
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateEnabled(bool enable)
|
||||
{
|
||||
if (IsEnabled == enable || FeatureInfo.Instance == null)
|
||||
@ -147,7 +144,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
// Check if all prerequisites are met async
|
||||
if (!FeatureInfo.ArePrerequisitesMet())
|
||||
{
|
||||
await ShowPrerequisitesDialog(false, FeatureInfo);
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> { FeatureInfo });
|
||||
if (!FeatureInfo.ArePrerequisitesMet())
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||
@ -173,15 +170,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<object> ShowPrerequisitesDialog(bool uninstall, IPrerequisitesSubject subject)
|
||||
{
|
||||
if (uninstall)
|
||||
return await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> { { "subject", subject } });
|
||||
return await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> { { "subject", subject } });
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void OnFeatureEnabling(object sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature != FeatureInfo.Instance) return;
|
||||
@ -201,7 +189,5 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(CanToggleEnabled));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -23,11 +23,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly ISettingsVmFactory _settingsVmFactory;
|
||||
private readonly IWindowManager _windowManager;
|
||||
private bool _enabling;
|
||||
private Plugin _plugin;
|
||||
private bool _isSettingsPopupOpen;
|
||||
private bool _canInstallPrerequisites;
|
||||
private bool _canRemovePrerequisites;
|
||||
private bool _enabling;
|
||||
private bool _isSettingsPopupOpen;
|
||||
private Plugin _plugin;
|
||||
|
||||
public PluginSettingsViewModel(Plugin plugin,
|
||||
ISettingsVmFactory settingsVmFactory,
|
||||
@ -142,15 +142,21 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
|
||||
public async Task InstallPrerequisites()
|
||||
{
|
||||
if (Plugin.Info.Prerequisites.Any())
|
||||
await ShowPrerequisitesDialog(false, Plugin.Info);
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(Plugin.Features.Where(f => f.AlwaysEnabled));
|
||||
|
||||
if (subjects.Any(s => s.Prerequisites.Any()))
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, subjects);
|
||||
}
|
||||
|
||||
public async Task RemovePrerequisites()
|
||||
public async Task RemovePrerequisites(bool forPluginRemoval = false)
|
||||
{
|
||||
if (Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any()))
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(!forPluginRemoval ? Plugin.Features.Where(f => f.AlwaysEnabled) : Plugin.Features);
|
||||
|
||||
if (subjects.Any(s => s.Prerequisites.Any(p => p.UninstallActions.Any())))
|
||||
{
|
||||
await ShowPrerequisitesDialog(true, Plugin.Info);
|
||||
await PluginPrerequisitesUninstallDialogViewModel.Show(_dialogService, subjects, forPluginRemoval ? "SKIP, REMOVE PLUGIN" : "CANCEL");
|
||||
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||
}
|
||||
@ -182,32 +188,10 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
return;
|
||||
|
||||
// If the plugin or any of its features has uninstall actions, offer to run these
|
||||
List<PluginFeatureInfo> featuresToUninstall = Plugin.Features.Where(f => f.Prerequisites.Any(fp => fp.UninstallActions.Any())).ToList();
|
||||
if (Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any()) || Plugin.Features.Any(f => f.Prerequisites.Any(fp => fp.UninstallActions.Any())))
|
||||
{
|
||||
bool remove = await _dialogService.ShowConfirmDialog(
|
||||
"Remove plugin",
|
||||
"This plugin installed one or more prerequisites.\r\nDo you want to remove these?",
|
||||
"Uninstall",
|
||||
"Skip"
|
||||
);
|
||||
if (remove)
|
||||
{
|
||||
if (Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any()))
|
||||
{
|
||||
object result = await ShowPrerequisitesDialog(true, Plugin.Info);
|
||||
if (result is bool resultBool && !resultBool)
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (PluginFeatureInfo pluginFeatureInfo in featuresToUninstall)
|
||||
{
|
||||
object result = await ShowPrerequisitesDialog(true, pluginFeatureInfo);
|
||||
if (result is bool resultBool && !resultBool)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(Plugin.Features);
|
||||
if (subjects.Any(s => s.Prerequisites.Any(p => p.UninstallActions.Any())))
|
||||
await RemovePrerequisites(true);
|
||||
|
||||
try
|
||||
{
|
||||
@ -235,12 +219,10 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
private void PluginManagementServiceOnPluginToggled(object? sender, PluginEventArgs e)
|
||||
{
|
||||
foreach (PluginFeatureInfo pluginFeatureInfo in Plugin.Features)
|
||||
Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeatureInfo, false));
|
||||
|
||||
base.OnInitialActivate();
|
||||
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||
}
|
||||
|
||||
private async Task UpdateEnabled(bool enable)
|
||||
@ -266,19 +248,24 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
}
|
||||
|
||||
// Check if all prerequisites are met async
|
||||
if (!Plugin.Info.ArePrerequisitesMet())
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(Plugin.Features.Where(f => f.AlwaysEnabled || f.EnabledInStorage));
|
||||
|
||||
if (subjects.Any(s => !s.ArePrerequisitesMet()))
|
||||
{
|
||||
await ShowPrerequisitesDialog(false, Plugin.Info);
|
||||
if (!Plugin.Info.ArePrerequisitesMet())
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, subjects);
|
||||
if (!subjects.All(s => s.ArePrerequisitesMet()))
|
||||
{
|
||||
CancelEnable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Run(() => _pluginManagementService.EnablePlugin(Plugin, true, true));
|
||||
_pluginManagementService.EnablePlugin(Plugin, true, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -288,6 +275,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
{
|
||||
Enabling = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
_pluginManagementService.DisablePlugin(Plugin, true);
|
||||
@ -305,15 +293,31 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
|
||||
private void CheckPrerequisites()
|
||||
{
|
||||
CanInstallPrerequisites = Plugin.Info.Prerequisites.Any();
|
||||
CanRemovePrerequisites = Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any());
|
||||
CanInstallPrerequisites = Plugin.Info.Prerequisites.Any() ||
|
||||
Plugin.Features.Where(f => f.AlwaysEnabled).Any(f => f.Prerequisites.Any());
|
||||
CanRemovePrerequisites = Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any()) ||
|
||||
Plugin.Features.Where(f => f.AlwaysEnabled).Any(f => f.Prerequisites.Any(p => p.UninstallActions.Any()));
|
||||
}
|
||||
|
||||
private async Task<object> ShowPrerequisitesDialog(bool uninstall, IPrerequisitesSubject subject)
|
||||
#region Overrides of Screen
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
if (uninstall)
|
||||
return await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> {{"subject", subject } });
|
||||
return await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{ "subject", subject } });
|
||||
foreach (PluginFeatureInfo pluginFeatureInfo in Plugin.Features)
|
||||
Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeatureInfo, false));
|
||||
|
||||
_pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginToggled;
|
||||
_pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginToggled;
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
_pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginToggled;
|
||||
_pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginToggled;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user