1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Plugins - Reworked bootstrapper

This commit is contained in:
Robert 2021-04-30 17:39:58 +02:00
parent 5cae14efd3
commit 21700aaad5
13 changed files with 288 additions and 135 deletions

View File

@ -1,26 +0,0 @@
namespace Artemis.Core
{
/// <summary>
/// An optional entry point for your plugin
/// </summary>
public interface IPluginBootstrapper
{
/// <summary>
/// Called when the plugin is loaded
/// </summary>
/// <param name="plugin"></param>
void OnPluginLoaded(Plugin plugin);
/// <summary>
/// Called when the plugin is activated
/// </summary>
/// <param name="plugin">The plugin instance of your plugin</param>
void OnPluginEnabled(Plugin plugin);
/// <summary>
/// Called when the plugin is deactivated or when Artemis shuts down
/// </summary>
/// <param name="plugin">The plugin instance of your plugin</param>
void OnPluginDisabled(Plugin plugin);
}
}

View File

@ -71,7 +71,7 @@ namespace Artemis.Core
/// <summary>
/// Gets the plugin bootstrapper
/// </summary>
public IPluginBootstrapper? Bootstrapper { get; internal set; }
public PluginBootstrapper? Bootstrapper { get; internal set; }
/// <summary>
/// The Ninject kernel of the plugin
@ -118,10 +118,11 @@ namespace Artemis.Core
/// Looks up the feature info the feature of type <typeparamref name="T" />
/// </summary>
/// <typeparam name="T">The type of feature to find</typeparam>
/// <returns>If found, feature info of the feature</returns>
public PluginFeatureInfo? GetFeatureInfo<T>() where T : PluginFeature
/// <returns>Feature info of the feature</returns>
public PluginFeatureInfo GetFeatureInfo<T>() where T : PluginFeature
{
return _features.FirstOrDefault(i => i.FeatureType == typeof(T));
// This should be a safe assumption because any type of PluginFeature is registered and added
return _features.First(i => i.FeatureType == typeof(T));
}
/// <inheritdoc />

View File

@ -0,0 +1,100 @@
namespace Artemis.Core
{
/// <summary>
/// An optional entry point for your plugin
/// </summary>
public abstract class PluginBootstrapper
{
private Plugin? _plugin;
/// <summary>
/// Called when the plugin is loaded
/// </summary>
/// <param name="plugin"></param>
public virtual void OnPluginLoaded(Plugin plugin)
{
}
/// <summary>
/// Called when the plugin is activated
/// </summary>
/// <param name="plugin">The plugin instance of your plugin</param>
public virtual void OnPluginEnabled(Plugin plugin)
{
}
/// <summary>
/// Called when the plugin is deactivated or when Artemis shuts down
/// </summary>
/// <param name="plugin">The plugin instance of your plugin</param>
public virtual void OnPluginDisabled(Plugin plugin)
{
}
/// <summary>
/// Adds the provided prerequisite to the plugin.
/// </summary>
/// <param name="prerequisite">The prerequisite to add</param>
public void AddPluginPrerequisite(PluginPrerequisite prerequisite)
{
// TODO: We can keep track of them and add them after load, same goes for the others
if (_plugin == null)
throw new ArtemisPluginException("Cannot add plugin prerequisites before the plugin is loaded");
if (!_plugin.Info.Prerequisites.Contains(prerequisite))
_plugin.Info.Prerequisites.Add(prerequisite);
}
/// <summary>
/// Removes the provided prerequisite from the plugin.
/// </summary>
/// <param name="prerequisite">The prerequisite to remove</param>
/// <returns>
/// <see langword="true" /> is successfully removed; otherwise <see langword="false" />. This method also returns
/// <see langword="false" /> if the prerequisite was not found.
/// </returns>
public bool RemovePluginPrerequisite(PluginPrerequisite prerequisite)
{
if (_plugin == null)
throw new ArtemisPluginException("Cannot add plugin prerequisites before the plugin is loaded");
return _plugin.Info.Prerequisites.Remove(prerequisite);
}
/// <summary>
/// Adds the provided prerequisite to the feature of type <typeparamref name="T"/>.
/// </summary>
/// <param name="prerequisite">The prerequisite to add</param>
public void AddFeaturePrerequisite<T>(PluginPrerequisite prerequisite) where T : PluginFeature
{
if (_plugin == null)
throw new ArtemisPluginException("Cannot add feature prerequisites before the plugin is loaded");
PluginFeatureInfo info = _plugin.GetFeatureInfo<T>();
if (!info.Prerequisites.Contains(prerequisite))
info.Prerequisites.Add(prerequisite);
}
/// <summary>
/// Removes the provided prerequisite from the feature of type <typeparamref name="T"/>.
/// </summary>
/// <param name="prerequisite">The prerequisite to remove</param>
/// <returns>
/// <see langword="true" /> is successfully removed; otherwise <see langword="false" />. This method also returns
/// <see langword="false" /> if the prerequisite was not found.
/// </returns>
public bool RemoveFeaturePrerequisite<T>(PluginPrerequisite prerequisite) where T : PluginFeature
{
if (_plugin == null)
throw new ArtemisPluginException("Cannot add feature prerequisites before the plugin is loaded");
return _plugin.GetFeatureInfo<T>().Prerequisites.Remove(prerequisite);
}
internal void InternalOnPluginLoaded(Plugin plugin)
{
_plugin = plugin;
OnPluginLoaded(plugin);
}
}
}

View File

@ -15,7 +15,7 @@ namespace Artemis.Core
/// Represents basic info about a plugin feature and contains a reference to the instance of said feature
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public class PluginFeatureInfo : CorePropertyChanged
public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
{
private string? _description;
private string? _icon;
@ -130,18 +130,11 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _instance, value);
}
/// <summary>
/// Gets a list of prerequisites for this plugin feature
/// </summary>
/// <inheritdoc />
public List<PluginPrerequisite> Prerequisites { get; } = new();
/// <summary>
/// Determines whether the prerequisites of this feature are met
/// </summary>
public bool ArePrerequisitesMet()
{
return Prerequisites.All(p => p.IsMet());
}
/// <inheritdoc />
public bool ArePrerequisitesMet() => Prerequisites.All(p => p.IsMet());
/// <inheritdoc />
public override string ToString()

View File

@ -10,7 +10,7 @@ namespace Artemis.Core
/// Represents basic info about a plugin and contains a reference to the instance of said plugin
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public class PluginInfo : CorePropertyChanged
public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
{
private bool _autoEnableFeatures = true;
private string? _description;
@ -119,19 +119,11 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _plugin, value);
}
/// <summary>
/// Gets a list of prerequisites for this plugin
/// </summary>
/// <inheritdoc />
public List<PluginPrerequisite> Prerequisites { get; } = new();
/// <summary>
/// Determines whether the prerequisites of this plugin are met
/// </summary>
public bool ArePrerequisitesMet()
{
return Prerequisites.All(p => p.IsMet());
}
/// <inheritdoc />
public bool ArePrerequisitesMet() => Prerequisites.All(p => p.IsMet());
/// <inheritdoc />
public override string ToString()

View File

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Linq;
namespace Artemis.Core
{
/// <summary>
/// Represents a type that has prerequisites
/// </summary>
public interface IPrerequisitesSubject
{
/// <summary>
/// Gets a list of prerequisites for this plugin
/// </summary>
List<PluginPrerequisite> Prerequisites { get; }
/// <summary>
/// Determines whether the prerequisites of this plugin are met
/// </summary>
bool ArePrerequisitesMet();
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@ -11,24 +12,6 @@ namespace Artemis.Core
{
private PluginPrerequisiteAction? _currentAction;
/// <summary>
/// Creates a new instance of the <see cref="PluginPrerequisite" /> class
/// </summary>
/// <param name="plugin">The plugin this is a prerequisite for</param>
protected PluginPrerequisite(Plugin plugin)
{
Plugin = plugin;
}
/// <summary>
/// Creates a new instance of the <see cref="PluginPrerequisite" /> class
/// </summary>
/// <param name="pluginFeature">The plugin feature this is a prerequisite for</param>
protected PluginPrerequisite(PluginFeature pluginFeature)
{
PluginFeature = pluginFeature;
}
/// <summary>
/// Gets the name of the prerequisite
/// </summary>
@ -63,18 +46,6 @@ namespace Artemis.Core
private set => SetAndNotify(ref _currentAction, value);
}
/// <summary>
/// Gets or sets the plugin this prerequisite is for
/// <para>Note: Only one plugin or a plugin feature can be set at once</para>
/// </summary>
public Plugin? Plugin { get; }
/// <summary>
/// Gets or sets the feature this prerequisite is for
/// <para>Note: Only one plugin or a plugin feature can be set at once</para>
/// </summary>
public PluginFeature? PluginFeature { get; }
/// <summary>
/// Execute all install actions
/// </summary>

View File

@ -345,13 +345,13 @@ namespace Artemis.Core.Services
if (!featureTypes.Any())
_logger.Warning("Plugin {plugin} contains no features", plugin);
List<Type> bootstrappers = plugin.Assembly.GetTypes().Where(t => typeof(IPluginBootstrapper).IsAssignableFrom(t)).ToList();
List<Type> bootstrappers = plugin.Assembly.GetTypes().Where(t => typeof(PluginBootstrapper).IsAssignableFrom(t)).ToList();
if (bootstrappers.Count > 1)
_logger.Warning($"{plugin} has more than one bootstrapper, only initializing {bootstrappers.First().FullName}");
if (bootstrappers.Any())
{
plugin.Bootstrapper = (IPluginBootstrapper?) Activator.CreateInstance(bootstrappers.First());
plugin.Bootstrapper?.OnPluginLoaded(plugin);
plugin.Bootstrapper = (PluginBootstrapper?) Activator.CreateInstance(bootstrappers.First());
plugin.Bootstrapper?.InternalOnPluginLoaded(plugin);
}
lock (_plugins)

View File

@ -20,19 +20,19 @@ namespace Artemis.UI.Screens.Plugins
private bool _isFinished;
private CancellationTokenSource _tokenSource;
public PluginPrerequisitesInstallDialogViewModel(object pluginOrFeature, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService)
public PluginPrerequisitesInstallDialogViewModel(IPrerequisitesSubject subject, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService)
{
_dialogService = dialogService;
// Constructor overloading doesn't work very well with Kernel.Get<T> :(
if (pluginOrFeature is Plugin plugin)
if (subject is PluginInfo plugin)
{
Plugin = plugin;
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Info.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
PluginInfo = plugin;
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
}
else if (pluginOrFeature is PluginFeature feature)
else if (subject is PluginFeatureInfo feature)
{
Feature = feature;
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(feature.Info.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
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)}");
@ -42,8 +42,8 @@ namespace Artemis.UI.Screens.Plugins
}
public PluginFeature Feature { get; }
public Plugin Plugin { get; }
public PluginInfo PluginInfo { get; }
public PluginFeatureInfo FeatureInfo { get; }
public BindableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
public PluginPrerequisiteViewModel ActivePrerequisite
@ -64,6 +64,9 @@ 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 />
@ -111,7 +114,7 @@ namespace Artemis.UI.Screens.Plugins
"Confirm",
""
);
await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{"pluginOrFeature", Plugin}});
await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{"subject", PluginInfo}});
}
catch (OperationCanceledException)
{
@ -136,10 +139,10 @@ namespace Artemis.UI.Screens.Plugins
protected override void OnInitialActivate()
{
CanInstall = false;
if (Plugin != null)
Task.Run(() => CanInstall = !Plugin.Info.ArePrerequisitesMet());
if (PluginInfo != null)
Task.Run(() => CanInstall = !PluginInfo.ArePrerequisitesMet());
else
Task.Run(() => CanInstall = !Feature.Info.ArePrerequisitesMet());
Task.Run(() => CanInstall = !FeatureInfo.ArePrerequisitesMet());
base.OnInitialActivate();
}

View File

@ -22,22 +22,22 @@ namespace Artemis.UI.Screens.Plugins
private bool _isFinished;
private CancellationTokenSource _tokenSource;
public PluginPrerequisitesUninstallDialogViewModel(object pluginOrFeature, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService,
public PluginPrerequisitesUninstallDialogViewModel(IPrerequisitesSubject subject, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService,
IPluginManagementService pluginManagementService)
{
_dialogService = dialogService;
_pluginManagementService = pluginManagementService;
// Constructor overloading doesn't work very well with Kernel.Get<T> :(
if (pluginOrFeature is Plugin plugin)
if (subject is PluginInfo plugin)
{
Plugin = plugin;
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Info.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
PluginInfo = plugin;
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
}
else if (pluginOrFeature is PluginFeature feature)
else if (subject is PluginFeatureInfo feature)
{
Feature = feature;
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(feature.Info.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
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)}");
@ -47,8 +47,8 @@ namespace Artemis.UI.Screens.Plugins
}
public PluginFeature Feature { get; }
public Plugin Plugin { get; }
public PluginFeatureInfo FeatureInfo { get; }
public PluginInfo PluginInfo { get; }
public BindableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
public PluginPrerequisiteViewModel ActivePrerequisite
@ -69,6 +69,9 @@ 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 />
@ -84,7 +87,10 @@ namespace Artemis.UI.Screens.Plugins
{
CanUninstall = false;
_pluginManagementService.DisablePlugin(Plugin, true);
if (PluginInfo != null)
_pluginManagementService.DisablePlugin(PluginInfo.Plugin, true);
else if (FeatureInfo?.Instance != null)
_pluginManagementService.DisablePluginFeature(FeatureInfo.Instance, true);
_tokenSource = new CancellationTokenSource();
try
@ -118,7 +124,7 @@ namespace Artemis.UI.Screens.Plugins
"Confirm",
""
);
await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> {{"pluginOrFeature", Plugin}});
await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> {{"subject", PluginInfo}});
}
catch (OperationCanceledException)
{
@ -144,10 +150,10 @@ namespace Artemis.UI.Screens.Plugins
{
CanUninstall = false;
// Could be slow so take it off of the UI thread
if (Plugin != null)
Task.Run(() => CanUninstall = Plugin.Info.Prerequisites.Any(p => p.IsMet()));
if (PluginInfo != null)
Task.Run(() => CanUninstall = PluginInfo.Prerequisites.Any(p => p.IsMet()));
else
Task.Run(() => CanUninstall = Feature.Info.Prerequisites.Any(p => p.IsMet()));
Task.Run(() => CanUninstall = FeatureInfo.Prerequisites.Any(p => p.IsMet()));
base.OnInitialActivate();
}

View File

@ -12,7 +12,13 @@
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:PluginFeatureViewModel}">
<UserControl.Resources>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
</ResourceDictionary.MergedDictionaries>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid Margin="-3 -8">
<Grid.ColumnDefinitions>
@ -23,11 +29,11 @@
<!-- Icon column -->
<shared:ArtemisIcon Grid.Column="0"
Icon="{Binding FeatureInfo.Icon}"
Width="20"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted, FallbackValue=Collapsed}" />
Icon="{Binding FeatureInfo.Icon}"
Width="20"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted, FallbackValue=Collapsed}" />
<Button Grid.Column="0"
Margin="-8"
@ -68,6 +74,26 @@
IsEnabled="{Binding CanToggleEnabled}">
Feature enabled
</CheckBox>
<materialDesign:PopupBox Style="{StaticResource MaterialDesignToolPopupBox}"
Margin="0 -4 -10 -4"
Foreground="{StaticResource MaterialDesignBody}"
IsEnabled="{Binding IsPopupEnabled}">
<StackPanel>
<Button Command="{s:Action InstallPrerequisites}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="CheckAll" Margin="0 0 10 0 " VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center">Install prerequisites</TextBlock>
</StackPanel>
</Button>
<Button Command="{s:Action RemovePrerequisites}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Delete" Margin="0 0 10 0 " VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center">Remove prerequisites</TextBlock>
</StackPanel>
</Button>
</StackPanel>
</materialDesign:PopupBox>
</StackPanel>
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="7"
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay, FallbackValue=Collapsed}">

View File

@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Screens.Plugins;
using Artemis.UI.Shared.Services;
using Stylet;
@ -16,6 +19,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
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,
@ -51,6 +57,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
public bool CanToggleEnabled => FeatureInfo.Plugin.IsEnabled && !FeatureInfo.AlwaysEnabled;
public bool CanInstallPrerequisites => FeatureInfo.Prerequisites.Any();
public bool CanRemovePrerequisites => FeatureInfo.Prerequisites.Any(p => p.UninstallActions.Any());
public bool IsPopupEnabled => CanInstallPrerequisites || CanRemovePrerequisites;
public void ShowLogsFolder()
{
@ -96,6 +105,21 @@ 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)
@ -120,7 +144,18 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
}
await Task.Run(() => _pluginManagementService.EnablePluginFeature(FeatureInfo.Instance, true));
// Check if all prerequisites are met async
if (!FeatureInfo.ArePrerequisitesMet())
{
await ShowPrerequisitesDialog(false, FeatureInfo);
if (!FeatureInfo.ArePrerequisitesMet())
{
NotifyOfPropertyChange(nameof(IsEnabled));
return;
}
}
await Task.Run(() => _pluginManagementService.EnablePluginFeature(FeatureInfo.Instance!, true));
}
catch (Exception e)
{
@ -138,6 +173,13 @@ 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)

View File

@ -136,19 +136,21 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
if (wasEnabled)
await UpdateEnabled(true);
_messageService.ShowMessage("Reloaded plugin.");
}
public async Task InstallPrerequisites()
{
if (Plugin.Info.Prerequisites.Any())
await ShowPrerequisitesDialog(false);
await ShowPrerequisitesDialog(false, Plugin.Info);
}
public async Task RemovePrerequisites()
{
if (Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any()))
{
await ShowPrerequisitesDialog(true);
await ShowPrerequisitesDialog(true, Plugin.Info);
NotifyOfPropertyChange(nameof(IsEnabled));
NotifyOfPropertyChange(nameof(CanOpenSettings));
}
@ -180,9 +182,31 @@ 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;
}
}
}
try
@ -244,7 +268,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
// Check if all prerequisites are met async
if (!Plugin.Info.ArePrerequisitesMet())
{
await ShowPrerequisitesDialog(false);
await ShowPrerequisitesDialog(false, Plugin.Info);
if (!Plugin.Info.ArePrerequisitesMet())
{
CancelEnable();
@ -285,11 +309,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
CanRemovePrerequisites = Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any());
}
private async Task<object> ShowPrerequisitesDialog(bool uninstall)
private async Task<object> ShowPrerequisitesDialog(bool uninstall, IPrerequisitesSubject subject)
{
if (uninstall)
return await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> { { "pluginOrFeature", Plugin } });
return await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> { { "pluginOrFeature", Plugin } });
return await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> {{"subject", subject } });
return await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{ "subject", subject } });
}
}
}