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:
parent
5cae14efd3
commit
21700aaad5
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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 />
|
||||
|
||||
100
src/Artemis.Core/Plugins/PluginBootstrapper.cs
Normal file
100
src/Artemis.Core/Plugins/PluginBootstrapper.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
@ -31,7 +31,7 @@ namespace Artemis.Core
|
||||
Description = attribute?.Description;
|
||||
Icon = attribute?.Icon;
|
||||
AlwaysEnabled = attribute?.AlwaysEnabled ?? false;
|
||||
|
||||
|
||||
if (Icon != null) return;
|
||||
if (typeof(BaseDataModelExpansion).IsAssignableFrom(featureType))
|
||||
Icon = "TableAdd";
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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"
|
||||
@ -42,16 +48,16 @@
|
||||
</Button>
|
||||
|
||||
<!-- Display name column -->
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding FeatureInfo.Name}"
|
||||
Style="{StaticResource MaterialDesignTextBlock}"
|
||||
VerticalAlignment="Center"
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding FeatureInfo.Name}"
|
||||
Style="{StaticResource MaterialDesignTextBlock}"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip="{Binding FeatureInfo.Description}" />
|
||||
|
||||
<!-- Enable toggle column -->
|
||||
<StackPanel Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="8"
|
||||
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay, FallbackValue=Collapsed}"
|
||||
Orientation="Horizontal"
|
||||
@ -63,11 +69,31 @@
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 5 0"
|
||||
Visibility="{Binding ShowShield, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}"
|
||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}"
|
||||
IsChecked="{Binding IsEnabled}"
|
||||
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}">
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -136,24 +136,26 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task RemoveSettings()
|
||||
{
|
||||
bool confirmed = await _dialogService.ShowConfirmDialog("Clear plugin settings", "Are you sure you want to clear the settings of this plugin?");
|
||||
@ -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 } });
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user