mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Plugin prerequisites - Added UI for installing/removing prerequisites
Plugin settings - Added button to reload plugin from disk Confirm dialogs - Made cancel text optional so you can hide the button
This commit is contained in:
parent
f1874d9fe3
commit
0cfddcbbaf
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An exception thrown when a plugin prerequisite-related error occurs
|
||||||
|
/// </summary>
|
||||||
|
public class ArtemisPluginPrerequisiteException : Exception
|
||||||
|
{
|
||||||
|
internal ArtemisPluginPrerequisiteException(Plugin plugin, PluginPrerequisite? pluginPrerequisite)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
PluginPrerequisite = pluginPrerequisite;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ArtemisPluginPrerequisiteException(Plugin plugin, PluginPrerequisite? pluginPrerequisite, string message) : base(message)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
PluginPrerequisite = pluginPrerequisite;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ArtemisPluginPrerequisiteException(Plugin plugin, PluginPrerequisite? pluginPrerequisite, string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
PluginPrerequisite = pluginPrerequisite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -125,6 +125,14 @@ namespace Artemis.Core
|
|||||||
return Info.ToString();
|
return Info.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the prerequisites of this plugin are met
|
||||||
|
/// </summary>
|
||||||
|
public bool ArePrerequisitesMet()
|
||||||
|
{
|
||||||
|
return Prerequisites.All(p => p.IsMet());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the plugin is enabled
|
/// Occurs when the plugin is enabled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -123,7 +123,7 @@ namespace Artemis.Core
|
|||||||
/// Called to determine whether the prerequisite is met
|
/// Called to determine whether the prerequisite is met
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns><see langword="true" /> if the prerequisite is met; otherwise <see langword="false" /></returns>
|
/// <returns><see langword="true" /> if the prerequisite is met; otherwise <see langword="false" /></returns>
|
||||||
public abstract Task<bool> IsMet();
|
public abstract bool IsMet();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called before installation starts
|
/// Called before installation starts
|
||||||
|
|||||||
@ -10,6 +10,8 @@ namespace Artemis.Core
|
|||||||
public abstract class PluginPrerequisiteAction : CorePropertyChanged
|
public abstract class PluginPrerequisiteAction : CorePropertyChanged
|
||||||
{
|
{
|
||||||
private bool _progressIndeterminate;
|
private bool _progressIndeterminate;
|
||||||
|
private bool _showProgressBar;
|
||||||
|
private bool _showSubProgressBar;
|
||||||
private string? _status;
|
private string? _status;
|
||||||
private bool _subProgressIndeterminate;
|
private bool _subProgressIndeterminate;
|
||||||
|
|
||||||
@ -56,6 +58,24 @@ namespace Artemis.Core
|
|||||||
set => SetAndNotify(ref _subProgressIndeterminate, value);
|
set => SetAndNotify(ref _subProgressIndeterminate, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a boolean indicating whether the progress bar should be shown
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowProgressBar
|
||||||
|
{
|
||||||
|
get => _showProgressBar;
|
||||||
|
set => SetAndNotify(ref _showProgressBar, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a boolean indicating whether the sub progress bar should be shown
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowSubProgressBar
|
||||||
|
{
|
||||||
|
get => _showSubProgressBar;
|
||||||
|
set => SetAndNotify(ref _showSubProgressBar, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the progress of the action (0 to 100)
|
/// Gets or sets the progress of the action (0 to 100)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -21,6 +21,9 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
Target = target;
|
Target = target;
|
||||||
|
|
||||||
|
ShowProgressBar = true;
|
||||||
|
ShowSubProgressBar = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Artemis.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a plugin prerequisite action that deletes a file
|
||||||
|
/// </summary>
|
||||||
|
public class DeleteFileAction : PluginPrerequisiteAction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of a copy folder action
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the action</param>
|
||||||
|
/// <param name="target">The target folder to delete recursively</param>
|
||||||
|
public DeleteFileAction(string name, string target) : base(name)
|
||||||
|
{
|
||||||
|
Target = target;
|
||||||
|
ProgressIndeterminate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the target directory
|
||||||
|
/// </summary>
|
||||||
|
public string Target { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override async Task Execute(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
ShowProgressBar = true;
|
||||||
|
Status = $"Removing {Target}";
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
if (File.Exists(Target))
|
||||||
|
File.Delete(Target);
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
|
ShowProgressBar = false;
|
||||||
|
Status = $"Removed {Target}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Artemis.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a plugin prerequisite action that recursively deletes a folder
|
||||||
|
/// </summary>
|
||||||
|
public class DeleteFolderAction : PluginPrerequisiteAction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of a copy folder action
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the action</param>
|
||||||
|
/// <param name="target">The target folder to delete recursively</param>
|
||||||
|
public DeleteFolderAction(string name, string target) : base(name)
|
||||||
|
{
|
||||||
|
if (Enum.GetValues<Environment.SpecialFolder>().Select(Environment.GetFolderPath).Contains(target))
|
||||||
|
throw new ArtemisCoreException($"Cannot delete special folder {target}, silly goose.");
|
||||||
|
|
||||||
|
Target = target;
|
||||||
|
ProgressIndeterminate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the target directory
|
||||||
|
/// </summary>
|
||||||
|
public string Target { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override async Task Execute(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
ShowProgressBar = true;
|
||||||
|
Status = $"Removing {Target}";
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
if (Directory.Exists(Target))
|
||||||
|
Directory.Delete(Target, true);
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
|
ShowProgressBar = false;
|
||||||
|
Status = $"Removed {Target}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Artemis.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a plugin prerequisite action that copies a folder
|
||||||
|
/// </summary>
|
||||||
|
public class WriteBytesToFileAction : PluginPrerequisiteAction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of a copy folder action
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the action</param>
|
||||||
|
/// <param name="target">The target file to write to (will be created if needed)</param>
|
||||||
|
/// <param name="content">The contents to write</param>
|
||||||
|
public WriteBytesToFileAction(string name, string target, byte[] content) : base(name)
|
||||||
|
{
|
||||||
|
Target = target;
|
||||||
|
ByteContent = content ?? throw new ArgumentNullException(nameof(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the target file
|
||||||
|
/// </summary>
|
||||||
|
public string Target { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a boolean indicating whether or not to append to the file if it exists already, if set to
|
||||||
|
/// <see langword="false" /> the file will be deleted and recreated
|
||||||
|
/// </summary>
|
||||||
|
public bool Append { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bytes that will be written
|
||||||
|
/// </summary>
|
||||||
|
public byte[] ByteContent { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override async Task Execute(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
string outputDir = Path.GetDirectoryName(Target)!;
|
||||||
|
Utilities.CreateAccessibleDirectory(outputDir);
|
||||||
|
|
||||||
|
ShowProgressBar = true;
|
||||||
|
Status = $"Writing to {Path.GetFileName(Target)}...";
|
||||||
|
|
||||||
|
if (!Append && File.Exists(Target))
|
||||||
|
File.Delete(Target);
|
||||||
|
|
||||||
|
await using Stream fileStream = File.OpenWrite(Target);
|
||||||
|
await using MemoryStream sourceStream = new(ByteContent);
|
||||||
|
await sourceStream.CopyToAsync(sourceStream.Length, fileStream, Progress, cancellationToken);
|
||||||
|
|
||||||
|
ShowProgressBar = false;
|
||||||
|
Status = $"Finished writing to {Path.GetFileName(Target)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -8,7 +9,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a plugin prerequisite action that copies a folder
|
/// Represents a plugin prerequisite action that copies a folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WriteToFileAction : PluginPrerequisiteAction
|
public class WriteStringToFileAction : PluginPrerequisiteAction
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of a copy folder action
|
/// Creates a new instance of a copy folder action
|
||||||
@ -16,22 +17,12 @@ namespace Artemis.Core
|
|||||||
/// <param name="name">The name of the action</param>
|
/// <param name="name">The name of the action</param>
|
||||||
/// <param name="target">The target file to write to (will be created if needed)</param>
|
/// <param name="target">The target file to write to (will be created if needed)</param>
|
||||||
/// <param name="content">The contents to write</param>
|
/// <param name="content">The contents to write</param>
|
||||||
public WriteToFileAction(string name, string target, string content) : base(name)
|
public WriteStringToFileAction(string name, string target, string content) : base(name)
|
||||||
{
|
|
||||||
Target = target ?? throw new ArgumentNullException(nameof(target));
|
|
||||||
Content = content ?? throw new ArgumentNullException(nameof(content));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of a copy folder action
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the action</param>
|
|
||||||
/// <param name="target">The target file to write to (will be created if needed)</param>
|
|
||||||
/// <param name="content">The contents to write</param>
|
|
||||||
public WriteToFileAction(string name, string target, byte[] content) : base(name)
|
|
||||||
{
|
{
|
||||||
Target = target;
|
Target = target;
|
||||||
ByteContent = content ?? throw new ArgumentNullException(nameof(content));
|
Content = content ?? throw new ArgumentNullException(nameof(content));
|
||||||
|
|
||||||
|
ProgressIndeterminate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -40,30 +31,31 @@ namespace Artemis.Core
|
|||||||
public string Target { get; }
|
public string Target { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the contents that will be written
|
/// Gets or sets a boolean indicating whether or not to append to the file if it exists already, if set to
|
||||||
|
/// <see langword="false" /> the file will be deleted and recreated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Content { get; }
|
public bool Append { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the bytes that will be written
|
/// Gets the string that will be written
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[]? ByteContent { get; }
|
public string Content { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task Execute(CancellationToken cancellationToken)
|
public override async Task Execute(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
string outputDir = Path.GetDirectoryName(Target)!;
|
string outputDir = Path.GetDirectoryName(Target)!;
|
||||||
Utilities.CreateAccessibleDirectory(outputDir);
|
Utilities.CreateAccessibleDirectory(outputDir);
|
||||||
|
|
||||||
ProgressIndeterminate = true;
|
ShowProgressBar = true;
|
||||||
Status = $"Writing to {Path.GetFileName(Target)}...";
|
Status = $"Writing to {Path.GetFileName(Target)}...";
|
||||||
|
|
||||||
if (Content != null)
|
if (Append)
|
||||||
|
await File.AppendAllTextAsync(Target, Content, cancellationToken);
|
||||||
|
else
|
||||||
await File.WriteAllTextAsync(Target, Content, cancellationToken);
|
await File.WriteAllTextAsync(Target, Content, cancellationToken);
|
||||||
else if (ByteContent != null)
|
|
||||||
await File.WriteAllBytesAsync(Target, ByteContent, cancellationToken);
|
|
||||||
|
|
||||||
ProgressIndeterminate = false;
|
ShowProgressBar = false;
|
||||||
Status = $"Finished writing to {Path.GetFileName(Target)}";
|
Status = $"Finished writing to {Path.GetFileName(Target)}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +241,16 @@ namespace Artemis.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (Plugin plugin in _plugins.Where(p => p.Entity.IsEnabled))
|
foreach (Plugin plugin in _plugins.Where(p => p.Entity.IsEnabled))
|
||||||
EnablePlugin(plugin, false, ignorePluginLock);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
EnablePlugin(plugin, false, ignorePluginLock);
|
||||||
|
}
|
||||||
|
catch (ArtemisPluginPrerequisiteException)
|
||||||
|
{
|
||||||
|
_logger.Warning("Skipped enabling plugin {plugin} because not all prerequisites are met", plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_logger.Debug("Enabled {count} plugin(s)", _plugins.Count(p => p.IsEnabled));
|
_logger.Debug("Enabled {count} plugin(s)", _plugins.Count(p => p.IsEnabled));
|
||||||
// ReSharper restore InconsistentlySynchronizedField
|
// ReSharper restore InconsistentlySynchronizedField
|
||||||
@ -372,6 +381,9 @@ namespace Artemis.Core.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!plugin.ArePrerequisitesMet())
|
||||||
|
throw new ArtemisPluginPrerequisiteException(plugin, null, "Cannot enable a plugin whose prerequisites aren't all met");
|
||||||
|
|
||||||
// Create the Ninject child kernel and load the module
|
// Create the Ninject child kernel and load the module
|
||||||
plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin));
|
plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin));
|
||||||
OnPluginEnabling(new PluginEventArgs(plugin));
|
OnPluginEnabling(new PluginEventArgs(plugin));
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
<UserControl x:ClassModifier="internal"
|
<UserControl
|
||||||
x:Class="Artemis.UI.Shared.Screens.Dialogs.ConfirmDialogView"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:dialogs="clr-namespace:Artemis.UI.Shared.Screens.Dialogs"
|
xmlns:dialogs="clr-namespace:Artemis.UI.Shared.Screens.Dialogs"
|
||||||
|
xmlns:Shared="clr-namespace:Artemis.UI.Shared" x:ClassModifier="internal"
|
||||||
|
x:Class="Artemis.UI.Shared.Screens.Dialogs.ConfirmDialogView"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="163.274" d:DesignWidth="254.425"
|
d:DesignHeight="163.274" d:DesignWidth="254.425"
|
||||||
d:DataContext="{d:DesignInstance dialogs:ConfirmDialogViewModel}">
|
d:DataContext="{d:DesignInstance {x:Type dialogs:ConfirmDialogViewModel}}">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<Shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
|
||||||
|
</UserControl.Resources>
|
||||||
<StackPanel Margin="16">
|
<StackPanel Margin="16">
|
||||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Text="{Binding Header}" TextWrapping="Wrap" />
|
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Text="{Binding Header}" TextWrapping="Wrap" />
|
||||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||||
@ -22,7 +26,8 @@
|
|||||||
Focusable="False"
|
Focusable="False"
|
||||||
IsCancel="True"
|
IsCancel="True"
|
||||||
Command="{s:Action Cancel}"
|
Command="{s:Action Cancel}"
|
||||||
Content="{Binding CancelText}" />
|
Content="{Binding CancelText}"
|
||||||
|
Visibility="{Binding CancelText, Converter={StaticResource NullToVisibilityConverter}, Mode=OneWay}" />
|
||||||
<Button x:Name="ConfirmButton"
|
<Button x:Name="ConfirmButton"
|
||||||
Style="{StaticResource MaterialDesignFlatButton}"
|
Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
IsDefault="True"
|
IsDefault="True"
|
||||||
|
|||||||
@ -61,28 +61,30 @@ namespace Artemis.UI.Shared.Services
|
|||||||
return await ShowDialog(identifier, GetBestKernel().Get<T>(parameters));
|
return await ShowDialog(identifier, GetBestKernel().Get<T>(parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string cancelText = "Cancel")
|
public async Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string? cancelText = "Cancel")
|
||||||
{
|
{
|
||||||
|
if (confirmText == null) throw new ArgumentNullException(nameof(confirmText));
|
||||||
IParameter[] arguments =
|
IParameter[] arguments =
|
||||||
{
|
{
|
||||||
new ConstructorArgument("header", header),
|
new ConstructorArgument("header", header),
|
||||||
new ConstructorArgument("text", text),
|
new ConstructorArgument("text", text),
|
||||||
new ConstructorArgument("confirmText", confirmText.ToUpper()),
|
new ConstructorArgument("confirmText", confirmText.ToUpper()),
|
||||||
new ConstructorArgument("cancelText", cancelText.ToUpper())
|
new ConstructorArgument("cancelText", cancelText?.ToUpper())
|
||||||
};
|
};
|
||||||
object? result = await ShowDialog<ConfirmDialogViewModel>(arguments);
|
object? result = await ShowDialog<ConfirmDialogViewModel>(arguments);
|
||||||
return result is bool booleanResult && booleanResult;
|
return result is bool booleanResult && booleanResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ShowConfirmDialogAt(string identifier, string header, string text, string confirmText = "Confirm", string cancelText = "Cancel")
|
public async Task<bool> ShowConfirmDialogAt(string identifier, string header, string text, string confirmText = "Confirm", string? cancelText = "Cancel")
|
||||||
{
|
{
|
||||||
if (identifier == null) throw new ArgumentNullException(nameof(identifier));
|
if (identifier == null) throw new ArgumentNullException(nameof(identifier));
|
||||||
|
if (confirmText == null) throw new ArgumentNullException(nameof(confirmText));
|
||||||
IParameter[] arguments =
|
IParameter[] arguments =
|
||||||
{
|
{
|
||||||
new ConstructorArgument("header", header),
|
new ConstructorArgument("header", header),
|
||||||
new ConstructorArgument("text", text),
|
new ConstructorArgument("text", text),
|
||||||
new ConstructorArgument("confirmText", confirmText.ToUpper()),
|
new ConstructorArgument("confirmText", confirmText.ToUpper()),
|
||||||
new ConstructorArgument("cancelText", cancelText.ToUpper())
|
new ConstructorArgument("cancelText", cancelText?.ToUpper())
|
||||||
};
|
};
|
||||||
object? result = await ShowDialogAt<ConfirmDialogViewModel>(identifier, arguments);
|
object? result = await ShowDialogAt<ConfirmDialogViewModel>(identifier, arguments);
|
||||||
return result is bool booleanResult && booleanResult;
|
return result is bool booleanResult && booleanResult;
|
||||||
|
|||||||
@ -359,6 +359,9 @@
|
|||||||
<Page Update="DefaultTypes\PropertyInput\FloatRangePropertyInputView.xaml">
|
<Page Update="DefaultTypes\PropertyInput\FloatRangePropertyInputView.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Update="Screens\Plugins\PluginPrerequisitesUninstallDialogView.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
</Page>
|
||||||
<Page Update="Screens\ProfileEditor\Dialogs\ProfileEditView.xaml">
|
<Page Update="Screens\ProfileEditor\Dialogs\ProfileEditView.xaml">
|
||||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@ -98,7 +98,7 @@ namespace Artemis.UI.Ninject.Factories
|
|||||||
|
|
||||||
public interface IPrerequisitesVmFactory : IVmFactory
|
public interface IPrerequisitesVmFactory : IVmFactory
|
||||||
{
|
{
|
||||||
PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite);
|
PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move these two
|
// TODO: Move these two
|
||||||
|
|||||||
@ -12,12 +12,12 @@
|
|||||||
<StackPanel>
|
<StackPanel>
|
||||||
<ProgressBar Value="{Binding Action.Progress.Percentage, Mode=OneWay}"
|
<ProgressBar Value="{Binding Action.Progress.Percentage, Mode=OneWay}"
|
||||||
IsIndeterminate="{Binding Action.ProgressIndeterminate, Mode=OneWay}"
|
IsIndeterminate="{Binding Action.ProgressIndeterminate, Mode=OneWay}"
|
||||||
Visibility="{Binding ShowProgressBar, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
Visibility="{Binding Action.ShowProgressBar, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||||
materialDesign:TransitionAssist.DisableTransitions="True"
|
materialDesign:TransitionAssist.DisableTransitions="True"
|
||||||
Margin="0 10"/>
|
Margin="0 10"/>
|
||||||
<ProgressBar Value="{Binding Action.SubProgress.Percentage, Mode=OneWay}"
|
<ProgressBar Value="{Binding Action.SubProgress.Percentage, Mode=OneWay}"
|
||||||
IsIndeterminate="{Binding Action.SubProgressIndeterminate, Mode=OneWay}"
|
IsIndeterminate="{Binding Action.SubProgressIndeterminate, Mode=OneWay}"
|
||||||
Visibility="{Binding ShowSubProgressBar, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
Visibility="{Binding Action.ShowSubProgressBar, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||||
materialDesign:TransitionAssist.DisableTransitions="True"
|
materialDesign:TransitionAssist.DisableTransitions="True"
|
||||||
Margin="0 10"/>
|
Margin="0 10"/>
|
||||||
|
|
||||||
|
|||||||
@ -7,8 +7,7 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
{
|
{
|
||||||
public class PluginPrerequisiteActionViewModel : Screen
|
public class PluginPrerequisiteActionViewModel : Screen
|
||||||
{
|
{
|
||||||
private bool _showProgressBar;
|
|
||||||
private bool _showSubProgressBar;
|
|
||||||
|
|
||||||
public PluginPrerequisiteActionViewModel(PluginPrerequisiteAction action)
|
public PluginPrerequisiteActionViewModel(PluginPrerequisiteAction action)
|
||||||
{
|
{
|
||||||
@ -16,56 +15,5 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PluginPrerequisiteAction Action { get; }
|
public PluginPrerequisiteAction Action { get; }
|
||||||
|
|
||||||
public bool ShowProgressBar
|
|
||||||
{
|
|
||||||
get => _showProgressBar;
|
|
||||||
set => SetAndNotify(ref _showProgressBar, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowSubProgressBar
|
|
||||||
{
|
|
||||||
get => _showSubProgressBar;
|
|
||||||
set => SetAndNotify(ref _showSubProgressBar, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ActionOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName == nameof(Action.ProgressIndeterminate) || e.PropertyName == nameof(Action.SubProgressIndeterminate))
|
|
||||||
UpdateProgress();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProgressReported(object? sender, EventArgs e)
|
|
||||||
{
|
|
||||||
UpdateProgress();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateProgress()
|
|
||||||
{
|
|
||||||
ShowSubProgressBar = Action.SubProgress.Percentage != 0 || Action.SubProgressIndeterminate;
|
|
||||||
ShowProgressBar = ShowSubProgressBar || Action.Progress.Percentage != 0 || Action.ProgressIndeterminate;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Overrides of Screen
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void OnInitialActivate()
|
|
||||||
{
|
|
||||||
Action.Progress.ProgressReported += ProgressReported;
|
|
||||||
Action.SubProgress.ProgressReported += ProgressReported;
|
|
||||||
Action.PropertyChanged += ActionOnPropertyChanged;
|
|
||||||
base.OnInitialActivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void OnClose()
|
|
||||||
{
|
|
||||||
Action.Progress.ProgressReported -= ProgressReported;
|
|
||||||
Action.SubProgress.ProgressReported -= ProgressReported;
|
|
||||||
Action.PropertyChanged -= ActionOnPropertyChanged;
|
|
||||||
base.OnClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12,14 +12,16 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
{
|
{
|
||||||
public class PluginPrerequisiteViewModel : Conductor<PluginPrerequisiteActionViewModel>.Collection.OneActive
|
public class PluginPrerequisiteViewModel : Conductor<PluginPrerequisiteActionViewModel>.Collection.OneActive
|
||||||
{
|
{
|
||||||
|
private readonly bool _uninstall;
|
||||||
private readonly ICoreService _coreService;
|
private readonly ICoreService _coreService;
|
||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
private bool _installing;
|
private bool _installing;
|
||||||
private bool _uninstalling;
|
private bool _uninstalling;
|
||||||
private bool _isMet;
|
private bool _isMet;
|
||||||
|
|
||||||
public PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, ICoreService coreService, IDialogService dialogService)
|
public PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall, ICoreService coreService, IDialogService dialogService)
|
||||||
{
|
{
|
||||||
|
_uninstall = uninstall;
|
||||||
_coreService = coreService;
|
_coreService = coreService;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
|
|
||||||
@ -77,7 +79,7 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Installing = false;
|
Installing = false;
|
||||||
IsMet = await PluginPrerequisite.IsMet();
|
IsMet = PluginPrerequisite.IsMet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,11 +102,11 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Uninstalling = false;
|
Uninstalling = false;
|
||||||
IsMet = await PluginPrerequisite.IsMet();
|
IsMet = PluginPrerequisite.IsMet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PluginPrerequisiteOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
private void PluginPrerequisiteOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.PropertyName == nameof(PluginPrerequisite.CurrentAction))
|
if (e.PropertyName == nameof(PluginPrerequisite.CurrentAction))
|
||||||
ActivateCurrentAction();
|
ActivateCurrentAction();
|
||||||
@ -129,10 +131,12 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
protected override void OnInitialActivate()
|
protected override void OnInitialActivate()
|
||||||
{
|
{
|
||||||
PluginPrerequisite.PropertyChanged -= PluginPrerequisiteOnPropertyChanged;
|
PluginPrerequisite.PropertyChanged -= PluginPrerequisiteOnPropertyChanged;
|
||||||
Task.Run(async () => IsMet = await PluginPrerequisite.IsMet());
|
// Could be slow so take it off of the UI thread
|
||||||
|
Task.Run(() => IsMet = PluginPrerequisite.IsMet());
|
||||||
|
|
||||||
Items.AddRange(PluginPrerequisite.InstallActions.Select(a => new PluginPrerequisiteActionViewModel(a)));
|
Items.AddRange(!_uninstall
|
||||||
Items.AddRange(PluginPrerequisite.UninstallActions.Select(a => new PluginPrerequisiteActionViewModel(a)));
|
? PluginPrerequisite.InstallActions.Select(a => new PluginPrerequisiteActionViewModel(a))
|
||||||
|
: PluginPrerequisite.UninstallActions.Select(a => new PluginPrerequisiteActionViewModel(a)));
|
||||||
|
|
||||||
base.OnInitialActivate();
|
base.OnInitialActivate();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisitesDialogView"
|
<UserControl x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisitesInstallDialogView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@ -9,7 +9,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:PluginPrerequisitesDialogViewModel}">
|
d:DataContext="{d:DesignInstance local:PluginPrerequisitesInstallDialogViewModel}">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
|
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -11,28 +12,30 @@ using Stylet;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.Plugins
|
namespace Artemis.UI.Screens.Plugins
|
||||||
{
|
{
|
||||||
public class PluginPrerequisitesDialogViewModel : DialogViewModelBase
|
public class PluginPrerequisitesInstallDialogViewModel : DialogViewModelBase
|
||||||
{
|
{
|
||||||
|
private readonly IDialogService _dialogService;
|
||||||
private PluginPrerequisiteViewModel _activePrerequisite;
|
private PluginPrerequisiteViewModel _activePrerequisite;
|
||||||
private bool _canInstall;
|
private bool _canInstall;
|
||||||
private bool _isFinished;
|
private bool _isFinished;
|
||||||
private CancellationTokenSource _tokenSource;
|
private CancellationTokenSource _tokenSource;
|
||||||
|
|
||||||
public PluginPrerequisitesDialogViewModel(object pluginOrFeature, IPrerequisitesVmFactory prerequisitesVmFactory)
|
public PluginPrerequisitesInstallDialogViewModel(object pluginOrFeature, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService)
|
||||||
{
|
{
|
||||||
|
_dialogService = dialogService;
|
||||||
// Constructor overloading doesn't work very well with Kernel.Get<T> :(
|
// Constructor overloading doesn't work very well with Kernel.Get<T> :(
|
||||||
if (pluginOrFeature is Plugin plugin)
|
if (pluginOrFeature is Plugin plugin)
|
||||||
{
|
{
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Prerequisites.Select(prerequisitesVmFactory.PluginPrerequisiteViewModel));
|
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
|
||||||
}
|
}
|
||||||
else if (pluginOrFeature is PluginFeature feature)
|
else if (pluginOrFeature is PluginFeature feature)
|
||||||
{
|
{
|
||||||
Feature = feature;
|
Feature = feature;
|
||||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(feature.Prerequisites.Select(prerequisitesVmFactory.PluginPrerequisiteViewModel));
|
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(feature.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new ArtemisUIException($"Expected plugin or feature to be passed to {nameof(PluginPrerequisitesDialogViewModel)}");
|
throw new ArtemisUIException($"Expected plugin or feature to be passed to {nameof(PluginPrerequisitesInstallDialogViewModel)}");
|
||||||
|
|
||||||
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||||
pluginPrerequisiteViewModel.ConductWith(this);
|
pluginPrerequisiteViewModel.ConductWith(this);
|
||||||
@ -81,11 +84,11 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
{
|
{
|
||||||
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||||
{
|
{
|
||||||
ActivePrerequisite = pluginPrerequisiteViewModel;
|
pluginPrerequisiteViewModel.IsMet = pluginPrerequisiteViewModel.PluginPrerequisite.IsMet();
|
||||||
ActivePrerequisite.IsMet = await ActivePrerequisite.PluginPrerequisite.IsMet();
|
if (pluginPrerequisiteViewModel.IsMet)
|
||||||
if (ActivePrerequisite.IsMet)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
ActivePrerequisite = pluginPrerequisiteViewModel;
|
||||||
await ActivePrerequisite.Install(_tokenSource.Token);
|
await ActivePrerequisite.Install(_tokenSource.Token);
|
||||||
|
|
||||||
// Wait after the task finished for the user to process what happened
|
// Wait after the task finished for the user to process what happened
|
||||||
@ -94,7 +97,21 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Prerequisites.All(p => p.IsMet))
|
if (Prerequisites.All(p => p.IsMet))
|
||||||
|
{
|
||||||
IsFinished = true;
|
IsFinished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This shouldn't be happening and the experience isn't very nice for the user (too lazy to make a nice UI for such an edge case)
|
||||||
|
// but at least give some feedback
|
||||||
|
Session?.Close(false);
|
||||||
|
await _dialogService.ShowConfirmDialog(
|
||||||
|
"Plugin prerequisites",
|
||||||
|
"All prerequisites are installed but some still aren't met. \r\nPlease try again or contact the plugin creator.",
|
||||||
|
"Confirm",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{"pluginOrFeature", Plugin}});
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@ -118,8 +135,10 @@ namespace Artemis.UI.Screens.Plugins
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnInitialActivate()
|
protected override void OnInitialActivate()
|
||||||
{
|
{
|
||||||
|
CanInstall = false;
|
||||||
|
Task.Run(() => CanInstall = !Plugin.ArePrerequisitesMet());
|
||||||
|
|
||||||
base.OnInitialActivate();
|
base.OnInitialActivate();
|
||||||
CanInstall = Prerequisites.Any(p => !p.IsMet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
<UserControl x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisitesUninstallDialogView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Plugins"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
d:DataContext="{d:DesignInstance local:PluginPrerequisitesUninstallDialogViewModel}">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid Margin="16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition MinHeight="150"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="300" />
|
||||||
|
<ColumnDefinition Width="500" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Grid.Row="0" Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" Margin="0 0 0 20">
|
||||||
|
Plugin prerequisites
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<ListBox Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
ItemsSource="{Binding Prerequisites}"
|
||||||
|
SelectedItem="{Binding ActivePrerequisite, Mode=OneWay}"
|
||||||
|
HorizontalContentAlignment="Stretch">
|
||||||
|
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate DataType="{x:Type local:PluginPrerequisiteViewModel}">
|
||||||
|
<Border Padding="8" BorderThickness="0 0 0 1" BorderBrush="{DynamicResource MaterialDesignDivider}" VerticalAlignment="Stretch">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<ToggleButton VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource MaterialDesignActionToggleButton}"
|
||||||
|
Focusable="False"
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
IsChecked="{Binding IsMet}">
|
||||||
|
<ToggleButton.Content>
|
||||||
|
<Border Background="#E74C4C" Width="32" Height="32">
|
||||||
|
<materialDesign:PackIcon Kind="Close" VerticalAlignment="Center" HorizontalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ToggleButton.Content>
|
||||||
|
<materialDesign:ToggleButtonAssist.OnContent>
|
||||||
|
<materialDesign:PackIcon Kind="Check" />
|
||||||
|
</materialDesign:ToggleButtonAssist.OnContent>
|
||||||
|
</ToggleButton>
|
||||||
|
|
||||||
|
<StackPanel Margin="8 0 0 0" Grid.Column="1" VerticalAlignment="Stretch">
|
||||||
|
<TextBlock FontWeight="Bold" Text="{Binding PluginPrerequisite.Name}" TextWrapping="Wrap" />
|
||||||
|
<TextBlock Text="{Binding PluginPrerequisite.Description}" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
|
<ContentControl Grid.Row="0"
|
||||||
|
Grid.RowSpan="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
s:View.Model="{Binding ActivePrerequisite}"
|
||||||
|
VerticalContentAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
Margin="10 0"
|
||||||
|
IsTabStop="False"
|
||||||
|
Visibility="{Binding ActivePrerequisite, Converter={StaticResource NullToVisibilityConverter}}"/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||||
|
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.
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 8 0 0"
|
||||||
|
Visibility="{Binding IsFinished, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Focusable="False"
|
||||||
|
IsCancel="True"
|
||||||
|
Command="{s:Action Cancel}"
|
||||||
|
Content="CANCEL" />
|
||||||
|
<Button x:Name="ConfirmButton"
|
||||||
|
Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
IsDefault="True"
|
||||||
|
Focusable="True"
|
||||||
|
Command="{s:Action Uninstall}"
|
||||||
|
Content="REMOVE PREREQUISITES" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 8 0 0"
|
||||||
|
Visibility="{Binding IsFinished, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Focusable="False"
|
||||||
|
IsCancel="True"
|
||||||
|
Command="{s:Action Accept}"
|
||||||
|
Content="FINISH" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,154 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
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;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Plugins
|
||||||
|
{
|
||||||
|
public class PluginPrerequisitesUninstallDialogViewModel : DialogViewModelBase
|
||||||
|
{
|
||||||
|
private readonly IDialogService _dialogService;
|
||||||
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
|
private PluginPrerequisiteViewModel _activePrerequisite;
|
||||||
|
private bool _canUninstall;
|
||||||
|
private bool _isFinished;
|
||||||
|
private CancellationTokenSource _tokenSource;
|
||||||
|
|
||||||
|
public PluginPrerequisitesUninstallDialogViewModel(object pluginOrFeature, 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)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>(plugin.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
|
||||||
|
}
|
||||||
|
else if (pluginOrFeature is PluginFeature feature)
|
||||||
|
{
|
||||||
|
Feature = 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)}");
|
||||||
|
|
||||||
|
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||||
|
pluginPrerequisiteViewModel.ConductWith(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public PluginFeature Feature { get; }
|
||||||
|
public Plugin Plugin { get; }
|
||||||
|
public BindableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||||
|
|
||||||
|
public PluginPrerequisiteViewModel ActivePrerequisite
|
||||||
|
{
|
||||||
|
get => _activePrerequisite;
|
||||||
|
set => SetAndNotify(ref _activePrerequisite, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanUninstall
|
||||||
|
{
|
||||||
|
get => _canUninstall;
|
||||||
|
set => SetAndNotify(ref _canUninstall, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFinished
|
||||||
|
{
|
||||||
|
get => _isFinished;
|
||||||
|
set => SetAndNotify(ref _isFinished, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overrides of DialogViewModelBase
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnDialogClosed(object sender, DialogClosingEventArgs e)
|
||||||
|
{
|
||||||
|
_tokenSource?.Cancel();
|
||||||
|
base.OnDialogClosed(sender, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public async void Uninstall()
|
||||||
|
{
|
||||||
|
CanUninstall = false;
|
||||||
|
|
||||||
|
_pluginManagementService.DisablePlugin(Plugin, true);
|
||||||
|
_tokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||||
|
{
|
||||||
|
pluginPrerequisiteViewModel.IsMet = pluginPrerequisiteViewModel.PluginPrerequisite.IsMet();
|
||||||
|
if (!pluginPrerequisiteViewModel.IsMet)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ActivePrerequisite = pluginPrerequisiteViewModel;
|
||||||
|
await ActivePrerequisite.Uninstall(_tokenSource.Token);
|
||||||
|
|
||||||
|
// Wait after the task finished for the user to process what happened
|
||||||
|
if (pluginPrerequisiteViewModel != Prerequisites.Last())
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Prerequisites.All(p => !p.IsMet))
|
||||||
|
{
|
||||||
|
IsFinished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This shouldn't be happening and the experience isn't very nice for the user (too lazy to make a nice UI for such an edge case)
|
||||||
|
// but at least give some feedback
|
||||||
|
Session?.Close(false);
|
||||||
|
await _dialogService.ShowConfirmDialog(
|
||||||
|
"Plugin prerequisites",
|
||||||
|
"The plugin was not able to fully remove all prerequisites. \r\nPlease try again or contact the plugin creator.",
|
||||||
|
"Confirm",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> {{"pluginOrFeature", Plugin}});
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
CanUninstall = true;
|
||||||
|
_tokenSource.Dispose();
|
||||||
|
_tokenSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Accept()
|
||||||
|
{
|
||||||
|
Session?.Close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overrides of Screen
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnInitialActivate()
|
||||||
|
{
|
||||||
|
CanUninstall = false;
|
||||||
|
// Could be slow so take it off of the UI thread
|
||||||
|
Task.Run(() => CanUninstall = Plugin.Prerequisites.Any(p => p.IsMet()));
|
||||||
|
|
||||||
|
base.OnInitialActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -52,7 +52,7 @@
|
|||||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsDeviceEnabled}">
|
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsDeviceEnabled}">
|
||||||
Device enabled
|
Device enabled
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<materialDesign:PopupBox Style="{StaticResource MaterialDesignToolPopupBox}" Padding="2 0 2 0">
|
<materialDesign:PopupBox Style="{StaticResource MaterialDesignToolPopupBox}" Padding="2 0 2 0" Foreground="{StaticResource MaterialDesignBody}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Button Command="{s:Action OpenPluginDirectory}">
|
<Button Command="{s:Action OpenPluginDirectory}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
|
|||||||
@ -49,7 +49,6 @@
|
|||||||
|
|
||||||
<ListBox Grid.Row="1"
|
<ListBox Grid.Row="1"
|
||||||
ItemsSource="{Binding Items}"
|
ItemsSource="{Binding Items}"
|
||||||
materialDesign:RippleAssist.IsDisabled="True"
|
|
||||||
VirtualizingPanel.ScrollUnit="Pixel"
|
VirtualizingPanel.ScrollUnit="Pixel"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Center"
|
HorizontalContentAlignment="Center"
|
||||||
|
|||||||
@ -12,6 +12,14 @@
|
|||||||
d:DataContext="{d:DesignInstance devices:PluginSettingsViewModel}"
|
d:DataContext="{d:DesignInstance devices:PluginSettingsViewModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary
|
||||||
|
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
<materialDesign:Card Width="900">
|
<materialDesign:Card Width="900">
|
||||||
<Grid Margin="8">
|
<Grid Margin="8">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -61,34 +69,60 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
<StackPanel Grid.Row="1"
|
<StackPanel Grid.Row="1" Grid.Column="0" VerticalAlignment="Bottom" Orientation="Horizontal">
|
||||||
Grid.Column="0"
|
<Button VerticalAlignment="Bottom"
|
||||||
VerticalAlignment="Bottom"
|
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||||
Orientation="Horizontal">
|
ToolTip="Open the plugins settings window"
|
||||||
<Button
|
Margin="4"
|
||||||
VerticalAlignment="Bottom"
|
Command="{s:Action OpenSettings}">
|
||||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
|
||||||
ToolTip="Open the plugins settings window"
|
|
||||||
Margin="4"
|
|
||||||
Command="{s:Action OpenSettings}">
|
|
||||||
SETTINGS
|
SETTINGS
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
VerticalAlignment="Bottom"
|
<materialDesign:PopupBox Style="{StaticResource MaterialDesignToolPopupBox}"
|
||||||
Style="{StaticResource MaterialDesignOutlinedButton}"
|
Padding="2 0 2 0"
|
||||||
ToolTip="Clear plugin settings"
|
Foreground="{StaticResource MaterialDesignBody}"
|
||||||
Margin="4"
|
IsPopupOpen="{Binding IsSettingsPopupOpen, Mode=TwoWay}">
|
||||||
Command="{s:Action RemoveSettings}">
|
<StackPanel>
|
||||||
<materialDesign:PackIcon Kind="DatabaseRemove" />
|
<Button Command="{s:Action OpenPluginDirectory}">
|
||||||
</Button>
|
<StackPanel Orientation="Horizontal">
|
||||||
<Button
|
<materialDesign:PackIcon Kind="FolderOpen" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
VerticalAlignment="Bottom"
|
<TextBlock VerticalAlignment="Center">Open plugin directory</TextBlock>
|
||||||
Style="{StaticResource MaterialDesignOutlinedButton}"
|
</StackPanel>
|
||||||
ToolTip="Remove plugin"
|
</Button>
|
||||||
Margin="4"
|
<Button Command="{s:Action Reload}">
|
||||||
Command="{s:Action Remove}">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon Kind="DeleteForever" />
|
<materialDesign:PackIcon Kind="Reload" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
</Button>
|
<TextBlock VerticalAlignment="Center">Reload plugin</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Separator />
|
||||||
|
<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>
|
||||||
|
<Separator />
|
||||||
|
<Button Command="{s:Action RemoveSettings}" >
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="DatabaseRemove" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Clear plugin settings</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{s:Action Remove}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="DeleteForever" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Remove plugin</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</materialDesign:PopupBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -10,23 +10,24 @@ using Artemis.UI.Ninject.Factories;
|
|||||||
using Artemis.UI.Screens.Plugins;
|
using Artemis.UI.Screens.Plugins;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using MaterialDesignThemes.Wpf;
|
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
using Constants = Artemis.Core.Constants;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||||
{
|
{
|
||||||
public class PluginSettingsViewModel : Conductor<PluginFeatureViewModel>.Collection.AllActive
|
public class PluginSettingsViewModel : Conductor<PluginFeatureViewModel>.Collection.AllActive
|
||||||
{
|
{
|
||||||
|
private readonly ICoreService _coreService;
|
||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
|
private readonly IMessageService _messageService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly ISettingsVmFactory _settingsVmFactory;
|
private readonly ISettingsVmFactory _settingsVmFactory;
|
||||||
private readonly ICoreService _coreService;
|
|
||||||
private readonly IMessageService _messageService;
|
|
||||||
private readonly IWindowManager _windowManager;
|
private readonly IWindowManager _windowManager;
|
||||||
private bool _enabling;
|
private bool _enabling;
|
||||||
private Plugin _plugin;
|
private Plugin _plugin;
|
||||||
|
private bool _isSettingsPopupOpen;
|
||||||
|
private bool _canInstallPrerequisites;
|
||||||
|
private bool _canRemovePrerequisites;
|
||||||
|
|
||||||
public PluginSettingsViewModel(Plugin plugin,
|
public PluginSettingsViewModel(Plugin plugin,
|
||||||
ISettingsVmFactory settingsVmFactory,
|
ISettingsVmFactory settingsVmFactory,
|
||||||
@ -70,6 +71,28 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
set => Task.Run(() => UpdateEnabled(value));
|
set => Task.Run(() => UpdateEnabled(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSettingsPopupOpen
|
||||||
|
{
|
||||||
|
get => _isSettingsPopupOpen;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!SetAndNotify(ref _isSettingsPopupOpen, value)) return;
|
||||||
|
CheckPrerequisites();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanInstallPrerequisites
|
||||||
|
{
|
||||||
|
get => _canInstallPrerequisites;
|
||||||
|
set => SetAndNotify(ref _canInstallPrerequisites, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanRemovePrerequisites
|
||||||
|
{
|
||||||
|
get => _canRemovePrerequisites;
|
||||||
|
set => SetAndNotify(ref _canRemovePrerequisites, value);
|
||||||
|
}
|
||||||
|
|
||||||
public void OpenSettings()
|
public void OpenSettings()
|
||||||
{
|
{
|
||||||
PluginConfigurationDialog configurationViewModel = (PluginConfigurationDialog) Plugin.ConfigurationDialog;
|
PluginConfigurationDialog configurationViewModel = (PluginConfigurationDialog) Plugin.ConfigurationDialog;
|
||||||
@ -88,6 +111,49 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenPluginDirectory()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Plugin.Directory.FullName);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_dialogService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Reload()
|
||||||
|
{
|
||||||
|
bool wasEnabled = IsEnabled;
|
||||||
|
|
||||||
|
_pluginManagementService.UnloadPlugin(Plugin);
|
||||||
|
Items.Clear();
|
||||||
|
|
||||||
|
Plugin = _pluginManagementService.LoadPlugin(Plugin.Directory);
|
||||||
|
foreach (PluginFeatureInfo pluginFeatureInfo in Plugin.Features)
|
||||||
|
Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeatureInfo, false));
|
||||||
|
|
||||||
|
if (wasEnabled)
|
||||||
|
await UpdateEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InstallPrerequisites()
|
||||||
|
{
|
||||||
|
if (Plugin.Prerequisites.Any())
|
||||||
|
await ShowPrerequisitesDialog(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemovePrerequisites()
|
||||||
|
{
|
||||||
|
if (Plugin.Prerequisites.Any(p => p.UninstallActions.Any()))
|
||||||
|
{
|
||||||
|
await ShowPrerequisitesDialog(true);
|
||||||
|
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task RemoveSettings()
|
public async Task RemoveSettings()
|
||||||
{
|
{
|
||||||
bool confirmed = await _dialogService.ShowConfirmDialog("Clear plugin settings", "Are you sure you want to clear the settings of this plugin?");
|
bool confirmed = await _dialogService.ShowConfirmDialog("Clear plugin settings", "Are you sure you want to clear the settings of this plugin?");
|
||||||
@ -109,7 +175,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
|
|
||||||
public async Task Remove()
|
public async Task Remove()
|
||||||
{
|
{
|
||||||
bool confirmed = await _dialogService.ShowConfirmDialog("Delete plugin", "Are you sure you want to delete this plugin?");
|
bool confirmed = await _dialogService.ShowConfirmDialog("Remove plugin", "Are you sure you want to remove this plugin?");
|
||||||
if (!confirmed)
|
if (!confirmed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -170,10 +236,10 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if all prerequisites are met async
|
// Check if all prerequisites are met async
|
||||||
if (!await ArePrerequisitesMetAsync())
|
if (!Plugin.ArePrerequisitesMet())
|
||||||
{
|
{
|
||||||
await _dialogService.ShowDialog<PluginPrerequisitesDialogViewModel>(new Dictionary<string, object> {{"pluginOrFeature", Plugin}});
|
await ShowPrerequisitesDialog(false);
|
||||||
if (!await ArePrerequisitesMetAsync())
|
if (!Plugin.ArePrerequisitesMet())
|
||||||
{
|
{
|
||||||
CancelEnable();
|
CancelEnable();
|
||||||
return;
|
return;
|
||||||
@ -194,9 +260,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
_pluginManagementService.DisablePlugin(Plugin, true);
|
_pluginManagementService.DisablePlugin(Plugin, true);
|
||||||
}
|
|
||||||
|
|
||||||
NotifyOfPropertyChange(nameof(IsEnabled));
|
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||||
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||||
@ -209,19 +273,17 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> ArePrerequisitesMetAsync()
|
private void CheckPrerequisites()
|
||||||
{
|
{
|
||||||
bool needsPrerequisites = false;
|
CanInstallPrerequisites = Plugin.Prerequisites.Any();
|
||||||
foreach (PluginPrerequisite pluginPrerequisite in Plugin.Prerequisites)
|
CanRemovePrerequisites = Plugin.Prerequisites.Any(p => p.UninstallActions.Any());
|
||||||
{
|
}
|
||||||
if (await pluginPrerequisite.IsMet())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
needsPrerequisites = true;
|
private async Task<object> ShowPrerequisitesDialog(bool uninstall)
|
||||||
break;
|
{
|
||||||
}
|
if (uninstall)
|
||||||
|
return await _dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object> { { "pluginOrFeature", Plugin } });
|
||||||
return !needsPrerequisites;
|
return await _dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> { { "pluginOrFeature", Plugin } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user