mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Meta - Replace WPF projects with Avalonia projects
This commit is contained in:
1 parent
fcf0376a9a
commit
d7f3ee1190
1110 files changed
+10872
-52240
No files matched your search
+38
-51
@@ -1,86 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Stylet;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginPrerequisitesInstallDialogViewModel : DialogViewModelBase
|
||||
public class PluginPrerequisitesInstallDialogViewModel : DialogViewModelBase<bool>
|
||||
{
|
||||
private PluginPrerequisiteViewModel _activePrerequisite;
|
||||
private CancellationTokenSource _tokenSource;
|
||||
private bool _showProgress;
|
||||
private bool _showIntro = true;
|
||||
private PluginPrerequisiteViewModel? _activePrerequisite;
|
||||
private bool _canInstall;
|
||||
private bool _showFailed;
|
||||
private bool _showInstall = true;
|
||||
private bool _canInstall;
|
||||
private bool _showIntro = true;
|
||||
private bool _showProgress;
|
||||
private CancellationTokenSource? _tokenSource;
|
||||
|
||||
public PluginPrerequisitesInstallDialogViewModel(List<IPrerequisitesSubject> subjects, IPrerequisitesVmFactory prerequisitesVmFactory, IDialogService dialogService)
|
||||
public PluginPrerequisitesInstallDialogViewModel(List<IPrerequisitesSubject> subjects, IPrerequisitesVmFactory prerequisitesVmFactory)
|
||||
{
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>();
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in subjects)
|
||||
Prerequisites.AddRange(prerequisitesSubject.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, false)));
|
||||
Prerequisites = new ObservableCollection<PluginPrerequisiteViewModel>();
|
||||
foreach (PluginPrerequisite prerequisite in subjects.SelectMany(prerequisitesSubject => prerequisitesSubject.Prerequisites))
|
||||
Prerequisites.Add(prerequisitesVmFactory.PluginPrerequisiteViewModel(prerequisite, false));
|
||||
|
||||
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||
pluginPrerequisiteViewModel.ConductWith(this);
|
||||
CanInstall = false;
|
||||
Task.Run(() => CanInstall = Prerequisites.Any(p => !p.PluginPrerequisite.IsMet()));
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
_tokenSource?.Cancel();
|
||||
_tokenSource?.Dispose();
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public BindableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||
public ObservableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||
|
||||
public PluginPrerequisiteViewModel ActivePrerequisite
|
||||
public PluginPrerequisiteViewModel? ActivePrerequisite
|
||||
{
|
||||
get => _activePrerequisite;
|
||||
set => SetAndNotify(ref _activePrerequisite, value);
|
||||
set => RaiseAndSetIfChanged(ref _activePrerequisite, value);
|
||||
}
|
||||
|
||||
public bool ShowProgress
|
||||
{
|
||||
get => _showProgress;
|
||||
set => SetAndNotify(ref _showProgress, value);
|
||||
set => RaiseAndSetIfChanged(ref _showProgress, value);
|
||||
}
|
||||
|
||||
public bool ShowIntro
|
||||
{
|
||||
get => _showIntro;
|
||||
set => SetAndNotify(ref _showIntro, value);
|
||||
set => RaiseAndSetIfChanged(ref _showIntro, value);
|
||||
}
|
||||
|
||||
public bool ShowFailed
|
||||
{
|
||||
get => _showFailed;
|
||||
set => SetAndNotify(ref _showFailed, value);
|
||||
set => RaiseAndSetIfChanged(ref _showFailed, value);
|
||||
}
|
||||
|
||||
public bool ShowInstall
|
||||
{
|
||||
get => _showInstall;
|
||||
set => SetAndNotify(ref _showInstall, value);
|
||||
set => RaiseAndSetIfChanged(ref _showInstall, value);
|
||||
}
|
||||
|
||||
public bool CanInstall
|
||||
{
|
||||
get => _canInstall;
|
||||
set => SetAndNotify(ref _canInstall, value);
|
||||
set => RaiseAndSetIfChanged(ref _canInstall, value);
|
||||
}
|
||||
|
||||
#region Overrides of DialogViewModelBase
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDialogClosed(object sender, DialogClosingEventArgs e)
|
||||
{
|
||||
_tokenSource?.Cancel();
|
||||
base.OnDialogClosed(sender, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public async void Install()
|
||||
public async Task Install()
|
||||
{
|
||||
CanInstall = false;
|
||||
ShowFailed = false;
|
||||
@@ -128,25 +128,12 @@ namespace Artemis.UI.Screens.Plugins
|
||||
|
||||
public void Accept()
|
||||
{
|
||||
Session?.Close(true);
|
||||
Close(true);
|
||||
}
|
||||
|
||||
public static Task<object> Show(IDialogService dialogService, List<IPrerequisitesSubject> subjects)
|
||||
public static async Task<bool> Show(IWindowService windowService, List<IPrerequisitesSubject> subjects)
|
||||
{
|
||||
return dialogService.ShowDialog<PluginPrerequisitesInstallDialogViewModel>(new Dictionary<string, object> {{"subjects", subjects}});
|
||||
return await windowService.ShowDialogAsync<PluginPrerequisitesInstallDialogViewModel, bool>(("subjects", subjects));
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
CanInstall = false;
|
||||
Task.Run(() => CanInstall = Prerequisites.Any(p => !p.PluginPrerequisite.IsMet()));
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+46
-71
@@ -1,97 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Stylet;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginPrerequisitesUninstallDialogViewModel : DialogViewModelBase
|
||||
public class PluginPrerequisitesUninstallDialogViewModel : DialogViewModelBase<bool>
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly List<IPrerequisitesSubject> _subjects;
|
||||
private PluginPrerequisiteViewModel _activePrerequisite;
|
||||
private readonly IWindowService _windowService;
|
||||
private PluginPrerequisiteViewModel? _activePrerequisite;
|
||||
private bool _canUninstall;
|
||||
private bool _isFinished;
|
||||
private CancellationTokenSource _tokenSource;
|
||||
private CancellationTokenSource? _tokenSource;
|
||||
|
||||
public PluginPrerequisitesUninstallDialogViewModel(List<IPrerequisitesSubject> subjects, string cancelLabel, IPrerequisitesVmFactory prerequisitesVmFactory,
|
||||
IDialogService dialogService, IPluginManagementService pluginManagementService)
|
||||
public PluginPrerequisitesUninstallDialogViewModel(List<IPrerequisitesSubject> subjects, string cancelLabel, IPrerequisitesVmFactory prerequisitesVmFactory, IWindowService windowService,
|
||||
IPluginManagementService pluginManagementService)
|
||||
{
|
||||
_subjects = subjects;
|
||||
_dialogService = dialogService;
|
||||
_windowService = windowService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
|
||||
CancelLabel = cancelLabel;
|
||||
Prerequisites = new BindableCollection<PluginPrerequisiteViewModel>();
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in subjects)
|
||||
Prerequisites.AddRange(prerequisitesSubject.Prerequisites.Select(p => prerequisitesVmFactory.PluginPrerequisiteViewModel(p, true)));
|
||||
Prerequisites = new ObservableCollection<PluginPrerequisiteViewModel>();
|
||||
foreach (PluginPrerequisite prerequisite in subjects.SelectMany(prerequisitesSubject => prerequisitesSubject.Prerequisites))
|
||||
Prerequisites.Add(prerequisitesVmFactory.PluginPrerequisiteViewModel(prerequisite, true));
|
||||
|
||||
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||
pluginPrerequisiteViewModel.ConductWith(this);
|
||||
// Could be slow so take it off of the UI thread
|
||||
Task.Run(() => CanUninstall = Prerequisites.Any(p => p.PluginPrerequisite.IsMet()));
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
_tokenSource?.Cancel();
|
||||
_tokenSource?.Dispose();
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public string CancelLabel { get; }
|
||||
public BindableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||
public ObservableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||
|
||||
public PluginPrerequisiteViewModel ActivePrerequisite
|
||||
public PluginPrerequisiteViewModel? ActivePrerequisite
|
||||
{
|
||||
get => _activePrerequisite;
|
||||
set => SetAndNotify(ref _activePrerequisite, value);
|
||||
set => RaiseAndSetIfChanged(ref _activePrerequisite, value);
|
||||
}
|
||||
|
||||
public bool CanUninstall
|
||||
{
|
||||
get => _canUninstall;
|
||||
set => SetAndNotify(ref _canUninstall, value);
|
||||
set => RaiseAndSetIfChanged(ref _canUninstall, value);
|
||||
}
|
||||
|
||||
public bool IsFinished
|
||||
{
|
||||
get => _isFinished;
|
||||
set => SetAndNotify(ref _isFinished, value);
|
||||
set => RaiseAndSetIfChanged(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()
|
||||
public async Task Uninstall()
|
||||
{
|
||||
CanUninstall = false;
|
||||
|
||||
// Disable all subjects that are plugins, this will disable their features too
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in _subjects)
|
||||
{
|
||||
if (prerequisitesSubject is PluginInfo pluginInfo)
|
||||
_pluginManagementService.DisablePlugin(pluginInfo.Plugin, true);
|
||||
if (prerequisitesSubject is PluginInfo pluginInfo) _pluginManagementService.DisablePlugin(pluginInfo.Plugin, true);
|
||||
}
|
||||
|
||||
// Disable all subjects that are features if still required
|
||||
foreach (IPrerequisitesSubject prerequisitesSubject in _subjects)
|
||||
{
|
||||
if (prerequisitesSubject is not PluginFeatureInfo featureInfo)
|
||||
continue;
|
||||
if (prerequisitesSubject is not PluginFeatureInfo featureInfo) continue;
|
||||
|
||||
// Disable the parent plugin if the feature is AlwaysEnabled
|
||||
if (featureInfo.AlwaysEnabled)
|
||||
_pluginManagementService.DisablePlugin(featureInfo.Plugin, true);
|
||||
else if (featureInfo.Instance != null)
|
||||
_pluginManagementService.DisablePluginFeature(featureInfo.Instance, true);
|
||||
else if (featureInfo.Instance != null) _pluginManagementService.DisablePluginFeature(featureInfo.Instance, true);
|
||||
}
|
||||
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
@@ -101,15 +98,13 @@ namespace Artemis.UI.Screens.Plugins
|
||||
foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites)
|
||||
{
|
||||
pluginPrerequisiteViewModel.IsMet = pluginPrerequisiteViewModel.PluginPrerequisite.IsMet();
|
||||
if (!pluginPrerequisiteViewModel.IsMet)
|
||||
continue;
|
||||
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 (pluginPrerequisiteViewModel != Prerequisites.Last()) await Task.Delay(1000);
|
||||
}
|
||||
|
||||
if (Prerequisites.All(p => !p.IsMet))
|
||||
@@ -120,14 +115,12 @@ namespace Artemis.UI.Screens.Plugins
|
||||
|
||||
// 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 Show(_dialogService, _subjects);
|
||||
Close(false);
|
||||
await _windowService.CreateContentDialog()
|
||||
.WithTitle("Plugin prerequisites")
|
||||
.WithContent("The plugin was not able to fully remove all prerequisites. \r\nPlease try again or contact the plugin creator.")
|
||||
.ShowAsync();
|
||||
await Show(_windowService, _subjects);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -143,30 +136,12 @@ namespace Artemis.UI.Screens.Plugins
|
||||
|
||||
public void Accept()
|
||||
{
|
||||
Session?.Close(true);
|
||||
Close(true);
|
||||
}
|
||||
|
||||
public static Task<object> Show(IDialogService dialogService, List<IPrerequisitesSubject> subjects, string cancelLabel = "CANCEL")
|
||||
public static async Task<object> Show(IWindowService windowService, List<IPrerequisitesSubject> subjects, string cancelLabel = "Cancel")
|
||||
{
|
||||
return dialogService.ShowDialog<PluginPrerequisitesUninstallDialogViewModel>(new Dictionary<string, object>
|
||||
{
|
||||
{"subjects", subjects},
|
||||
{"cancelLabel", cancelLabel},
|
||||
});
|
||||
return await windowService.ShowDialogAsync<PluginPrerequisitesUninstallDialogViewModel, bool>(("subjects", subjects), ("cancelLabel", cancelLabel));
|
||||
}
|
||||
|
||||
#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 = Prerequisites.Any(p => p.PluginPrerequisite.IsMet()));
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Plugins.PluginFeatureView">
|
||||
<Grid ColumnDefinitions="30,*,Auto">
|
||||
<Grid.ContextFlyout>
|
||||
<MenuFlyout>
|
||||
<MenuItem Header="Install prerequisites" Command="{Binding InstallPrerequisites}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="CheckAll" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Remove prerequisites" Command="{Binding RemovePrerequisites}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="Delete" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</Grid.ContextFlyout>
|
||||
|
||||
<!-- Icon column -->
|
||||
<controls:ArtemisIcon Grid.Column="0"
|
||||
Icon="{Binding FeatureInfo.ResolvedIcon}"
|
||||
Width="20"
|
||||
Height="20"
|
||||
IsVisible="{Binding LoadException, Converter={x:Static ObjectConverters.IsNull}}" />
|
||||
|
||||
<Button Grid.Column="0"
|
||||
Classes="AppBarButton icon-button"
|
||||
IsVisible="{Binding LoadException, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||
Foreground="#E74C4C"
|
||||
ToolTip.Tip="An exception occurred while enabling this feature, click to view"
|
||||
Command="{Binding ViewLoadException}">
|
||||
<avalonia:MaterialIcon Kind="AlertCircle" />
|
||||
</Button>
|
||||
|
||||
<!-- Display name column -->
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding FeatureInfo.Name}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip.Tip="{Binding FeatureInfo.Description}" />
|
||||
|
||||
<!-- Enable toggle column -->
|
||||
<StackPanel Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="{Binding !Enabling}"
|
||||
Orientation="Horizontal"
|
||||
ToolTip.Tip="This feature cannot be disabled without disabling the whole plugin">
|
||||
<avalonia:MaterialIcon Kind="ShieldHalfFull"
|
||||
ToolTip.Tip="Plugin requires admin rights"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 5 0"
|
||||
IsVisible="{Binding ShowShield}" />
|
||||
|
||||
<CheckBox IsChecked="{Binding IsEnabled}" IsEnabled="{Binding CanToggleEnabled}">
|
||||
Feature enabled
|
||||
</CheckBox>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="7" IsVisible="{Binding Enabling}">
|
||||
<ProgressBar Value="0" IsIndeterminate="True" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public partial class PluginFeatureView : ReactiveUserControl<PluginFeatureViewModel>
|
||||
{
|
||||
public PluginFeatureView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services.Builders;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Avalonia;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginFeatureViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly IWindowService _windowService;
|
||||
private bool _enabling;
|
||||
|
||||
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
|
||||
bool showShield,
|
||||
ICoreService coreService,
|
||||
IWindowService windowService,
|
||||
INotificationService notificationService,
|
||||
IPluginManagementService pluginManagementService)
|
||||
{
|
||||
_coreService = coreService;
|
||||
_windowService = windowService;
|
||||
_notificationService = notificationService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
|
||||
FeatureInfo = pluginFeatureInfo;
|
||||
ShowShield = FeatureInfo.Plugin.Info.RequiresAdmin && showShield;
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
_pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling;
|
||||
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped;
|
||||
_pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped;
|
||||
|
||||
FeatureInfo.Plugin.Enabled += PluginOnToggled;
|
||||
FeatureInfo.Plugin.Disabled += PluginOnToggled;
|
||||
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
_pluginManagementService.PluginFeatureEnabling -= OnFeatureEnabling;
|
||||
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped;
|
||||
_pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped;
|
||||
|
||||
FeatureInfo.Plugin.Enabled -= PluginOnToggled;
|
||||
FeatureInfo.Plugin.Disabled -= PluginOnToggled;
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public PluginFeatureInfo FeatureInfo { get; }
|
||||
public Exception? LoadException => FeatureInfo.LoadException;
|
||||
|
||||
public bool ShowShield { get; }
|
||||
|
||||
public bool Enabling
|
||||
{
|
||||
get => _enabling;
|
||||
set => RaiseAndSetIfChanged(ref _enabling, value);
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => FeatureInfo.Instance != null && FeatureInfo.Instance.IsEnabled;
|
||||
set => Dispatcher.UIThread.InvokeAsync(() => UpdateEnabled(value));
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
try
|
||||
{
|
||||
Utilities.OpenFolder(Constants.LogsFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_windowService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void ViewLoadException()
|
||||
{
|
||||
if (LoadException != null)
|
||||
_windowService.ShowExceptionDialog("Feature failed to enable", LoadException);
|
||||
}
|
||||
|
||||
public async Task InstallPrerequisites()
|
||||
{
|
||||
if (FeatureInfo.Prerequisites.Any())
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_windowService, new List<IPrerequisitesSubject> {FeatureInfo});
|
||||
}
|
||||
|
||||
public async Task RemovePrerequisites()
|
||||
{
|
||||
if (FeatureInfo.Prerequisites.Any(p => p.UninstallActions.Any()))
|
||||
{
|
||||
await PluginPrerequisitesUninstallDialogViewModel.Show(_windowService, new List<IPrerequisitesSubject> {FeatureInfo});
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateEnabled(bool enable)
|
||||
{
|
||||
if (IsEnabled == enable)
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
return;
|
||||
}
|
||||
|
||||
if (FeatureInfo.Instance == null)
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
_notificationService.CreateNotification()
|
||||
.WithMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.")
|
||||
.HavingButton(b => b.WithText("View logs").WithAction(ShowLogsFolder))
|
||||
.WithSeverity(NotificationSeverity.Error)
|
||||
.Show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
{
|
||||
Enabling = true;
|
||||
|
||||
try
|
||||
{
|
||||
if (FeatureInfo.Plugin.Info.RequiresAdmin && !_coreService.IsElevated)
|
||||
{
|
||||
bool confirmed = await _windowService.ShowConfirmContentDialog("Enable feature", "The plugin of this feature requires admin rights, are you sure you want to enable it?");
|
||||
if (!confirmed)
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all prerequisites are met async
|
||||
if (!FeatureInfo.ArePrerequisitesMet())
|
||||
{
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_windowService, new List<IPrerequisitesSubject> {FeatureInfo});
|
||||
if (!FeatureInfo.ArePrerequisitesMet())
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() => _pluginManagementService.EnablePluginFeature(FeatureInfo.Instance!, true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_notificationService.CreateNotification()
|
||||
.WithMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}")
|
||||
.HavingButton(b => b.WithText("View logs").WithAction(ShowLogsFolder))
|
||||
.WithSeverity(NotificationSeverity.Error)
|
||||
.Show();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Enabling = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_pluginManagementService.DisablePluginFeature(FeatureInfo.Instance, true);
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFeatureEnabling(object? sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature != FeatureInfo.Instance) return;
|
||||
|
||||
Enabling = true;
|
||||
}
|
||||
|
||||
private void OnFeatureEnableStopped(object? sender, PluginFeatureEventArgs e)
|
||||
{
|
||||
if (e.PluginFeature != FeatureInfo.Instance) return;
|
||||
|
||||
Enabling = false;
|
||||
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
this.RaisePropertyChanged(nameof(LoadException));
|
||||
}
|
||||
|
||||
private void PluginOnToggled(object? sender, EventArgs e)
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(CanToggleEnabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisiteActionView"
|
||||
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:PluginPrerequisiteActionViewModel}">
|
||||
<StackPanel>
|
||||
<ProgressBar Value="{Binding Action.Progress.Percentage, Mode=OneWay}"
|
||||
IsIndeterminate="{Binding Action.ProgressIndeterminate, Mode=OneWay}"
|
||||
Visibility="{Binding Action.ShowProgressBar, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||
materialDesign:TransitionAssist.DisableTransitions="True"
|
||||
Margin="0 10"/>
|
||||
<ProgressBar Value="{Binding Action.SubProgress.Percentage, Mode=OneWay}"
|
||||
IsIndeterminate="{Binding Action.SubProgressIndeterminate, Mode=OneWay}"
|
||||
Visibility="{Binding Action.ShowSubProgressBar, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||
materialDesign:TransitionAssist.DisableTransitions="True"
|
||||
Margin="0 10"/>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" Text="{Binding Action.Status, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,14 +1,10 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Artemis.Core;
|
||||
using Stylet;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginPrerequisiteActionViewModel : Screen
|
||||
public class PluginPrerequisiteActionViewModel : ViewModelBase
|
||||
{
|
||||
|
||||
|
||||
public PluginPrerequisiteActionViewModel(PluginPrerequisiteAction action)
|
||||
{
|
||||
Action = action;
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisiteView"
|
||||
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:PluginPrerequisiteViewModel}">
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" Text="{Binding PluginPrerequisite.Name, Mode=OneWay}" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" TextWrapping="Wrap" Text="{Binding PluginPrerequisite.Description, Mode=OneWay}" Margin="0 0 0 15" />
|
||||
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding HasMultipleActions, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Run Text="Step" />
|
||||
<Run Text="{Binding ActiveStemNumber, Mode=OneWay}" /><Run Text="/" /><Run Text="{Binding Items.Count, Mode=OneWay}" />
|
||||
<Run Text="-" />
|
||||
<Run Text="{Binding ActiveItem.Action.Name, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||
TextWrapping="Wrap"
|
||||
Text="{Binding ActiveItem.Action.Name, Mode=OneWay}"
|
||||
Visibility="{Binding HasMultipleActions, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}" />
|
||||
<ContentControl s:View.Model="{Binding ActiveItem}"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
IsTabStop="False"
|
||||
Margin="0 10 0 0" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,26 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
using Artemis.UI.Shared;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginPrerequisiteViewModel : Conductor<PluginPrerequisiteActionViewModel>.Collection.OneActive
|
||||
public class PluginPrerequisiteViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<int> _activeStepNumber;
|
||||
private readonly ObservableAsPropertyHelper<bool> _busy;
|
||||
private readonly bool _uninstall;
|
||||
|
||||
private PluginPrerequisiteActionViewModel? _activeAction;
|
||||
|
||||
private bool _installing;
|
||||
private bool _uninstalling;
|
||||
private bool _isMet;
|
||||
private bool _uninstalling;
|
||||
|
||||
public PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall)
|
||||
{
|
||||
_uninstall = uninstall;
|
||||
|
||||
PluginPrerequisite = pluginPrerequisite;
|
||||
Actions = new ObservableCollection<PluginPrerequisiteActionViewModel>(!_uninstall
|
||||
? PluginPrerequisite.InstallActions.Select(a => new PluginPrerequisiteActionViewModel(a))
|
||||
: PluginPrerequisite.UninstallActions.Select(a => new PluginPrerequisiteActionViewModel(a)));
|
||||
|
||||
this.WhenAnyValue(x => x.Installing, x => x.Uninstalling, (i, u) => i || u).ToProperty(this, x => x.Busy, out _busy);
|
||||
this.WhenAnyValue(x => x.ActiveAction, a => Actions.IndexOf(a!)).ToProperty(this, x => x.ActiveStepNumber, out _activeStepNumber);
|
||||
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
PluginPrerequisite.PropertyChanged += PluginPrerequisiteOnPropertyChanged;
|
||||
Disposable.Create(() => PluginPrerequisite.PropertyChanged -= PluginPrerequisiteOnPropertyChanged).DisposeWith(d);
|
||||
});
|
||||
|
||||
// Could be slow so take it off of the UI thread
|
||||
Task.Run(() => IsMet = PluginPrerequisite.IsMet());
|
||||
}
|
||||
|
||||
public ObservableCollection<PluginPrerequisiteActionViewModel> Actions { get; }
|
||||
|
||||
public PluginPrerequisiteActionViewModel? ActiveAction
|
||||
{
|
||||
get => _activeAction;
|
||||
set => RaiseAndSetIfChanged(ref _activeAction, value);
|
||||
}
|
||||
|
||||
public PluginPrerequisite PluginPrerequisite { get; }
|
||||
@@ -28,32 +58,24 @@ namespace Artemis.UI.Screens.Plugins
|
||||
public bool Installing
|
||||
{
|
||||
get => _installing;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _installing, value);
|
||||
NotifyOfPropertyChange(nameof(Busy));
|
||||
}
|
||||
set => RaiseAndSetIfChanged(ref _installing, value);
|
||||
}
|
||||
|
||||
public bool Uninstalling
|
||||
{
|
||||
get => _uninstalling;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _uninstalling, value);
|
||||
NotifyOfPropertyChange(nameof(Busy));
|
||||
}
|
||||
set => RaiseAndSetIfChanged(ref _uninstalling, value);
|
||||
}
|
||||
|
||||
public bool IsMet
|
||||
{
|
||||
get => _isMet;
|
||||
set => SetAndNotify(ref _isMet, value);
|
||||
set => RaiseAndSetIfChanged(ref _isMet, value);
|
||||
}
|
||||
|
||||
public bool Busy => Installing || Uninstalling;
|
||||
public int ActiveStemNumber => Items.IndexOf(ActiveItem) + 1;
|
||||
public bool HasMultipleActions => Items.Count > 1;
|
||||
public bool Busy => _busy.Value;
|
||||
public int ActiveStepNumber => _activeStepNumber.Value;
|
||||
public bool HasMultipleActions => Actions.Count > 1;
|
||||
|
||||
public async Task Install(CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -89,7 +111,7 @@ namespace Artemis.UI.Screens.Plugins
|
||||
}
|
||||
}
|
||||
|
||||
private void PluginPrerequisiteOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
private void PluginPrerequisiteOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(PluginPrerequisite.CurrentAction))
|
||||
ActivateCurrentAction();
|
||||
@@ -97,37 +119,11 @@ namespace Artemis.UI.Screens.Plugins
|
||||
|
||||
private void ActivateCurrentAction()
|
||||
{
|
||||
PluginPrerequisiteActionViewModel newActiveItem = Items.FirstOrDefault(i => i.Action == PluginPrerequisite.CurrentAction);
|
||||
if (newActiveItem == null)
|
||||
PluginPrerequisiteActionViewModel? activeAction = Actions.FirstOrDefault(i => i.Action == PluginPrerequisite.CurrentAction);
|
||||
if (activeAction == null)
|
||||
return;
|
||||
|
||||
ActiveItem = newActiveItem;
|
||||
NotifyOfPropertyChange(nameof(ActiveStemNumber));
|
||||
ActiveAction = activeAction;
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
PluginPrerequisite.PropertyChanged -= PluginPrerequisiteOnPropertyChanged;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
PluginPrerequisite.PropertyChanged += PluginPrerequisiteOnPropertyChanged;
|
||||
// Could be slow so take it off of the UI thread
|
||||
Task.Run(() => IsMet = PluginPrerequisite.IsMet());
|
||||
|
||||
Items.AddRange(!_uninstall
|
||||
? PluginPrerequisite.InstallActions.Select(a => new PluginPrerequisiteActionViewModel(a))
|
||||
: PluginPrerequisite.UninstallActions.Select(a => new PluginPrerequisiteActionViewModel(a)));
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.Plugins.PluginPrerequisitesInstallDialogView"
|
||||
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"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:PluginPrerequisitesInstallDialogViewModel}">
|
||||
<UserControl.Resources>
|
||||
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
|
||||
<converters:NullToBooleanConverter x:Key="NullToBooleanConverter" />
|
||||
<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/feature 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 ShowProgress, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="10 0"
|
||||
Visibility="{Binding ShowIntro, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
In order for this plugin/feature to function certain prerequisites must be met. <LineBreak /><LineBreak />
|
||||
On the left side you can see all prerequisites and whether they are currently met or not.
|
||||
Clicking install prerequisites will automatically set everything up for you.
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignBody1TextBlock}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="10 0"
|
||||
Visibility="{Binding ShowFailed, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
Installing <Run Text="{Binding ActivePrerequisite.PluginPrerequisite.Name, Mode=OneWay}" FontWeight="SemiBold" /> failed. <LineBreak /><LineBreak />
|
||||
You may try again to see if that helps, otherwise install the prerequisite manually or contact the plugin developer.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0 8 0 0"
|
||||
Visibility="{Binding ShowInstall, Converter={x:Static s:BoolToVisibilityConverter.Instance}, 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"
|
||||
IsEnabled="{Binding ShowProgress, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
|
||||
Command="{s:Action Install}"
|
||||
Content="INSTALL PREREQUISITES" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0 8 0 0"
|
||||
Visibility="{Binding ShowInstall, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||
Focusable="False"
|
||||
IsCancel="True"
|
||||
Command="{s:Action Accept}"
|
||||
Content="FINISH" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,125 +0,0 @@
|
||||
<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/feature 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/feature installed certain prerequisites in order to function. <LineBreak /><LineBreak />
|
||||
In this screen you can chose to remove these, this will mean the plugin/feature will no longer work until you reinstall the prerequisites.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
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="{Binding CancelLabel}" />
|
||||
<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,118 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Plugins.PluginSettingsView">
|
||||
<Border Classes="card" Padding="15" Margin="0 5">
|
||||
<Grid RowDefinitions="*,Auto" ColumnDefinitions="4*,5*">
|
||||
<Grid Grid.Row="0" RowDefinitions="Auto,Auto,*" ColumnDefinitions="80,*">
|
||||
<controls1:ArtemisIcon Icon="{Binding Plugin.Info.ResolvedIcon}"
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="0 5 0 0"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Top" />
|
||||
|
||||
<TextBlock Grid.Column="1" Grid.Row="0" Classes="h5 no-margin" Text="{Binding Plugin.Info.Name}" />
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Classes="subtitle"
|
||||
Text="{Binding Plugin.Info.Author}"
|
||||
IsVisible="{Binding Plugin.Info.Author, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
Grid.Row="2"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0 5"
|
||||
Text="{Binding Plugin.Info.Description}" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="0" ColumnDefinitions="*,Auto">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<controls:SplitButton Content="Settings" Command="{Binding OpenSettings}">
|
||||
<controls:SplitButton.Flyout>
|
||||
<MenuFlyout Placement="Bottom">
|
||||
<MenuItem Header="Open plugin directory" Command="{Binding OpenPluginDirectory}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="FolderOpen" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Reload plugin" Command="{Binding Reload}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="Reload" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Install prerequisites" Command="{Binding InstallPrerequisites}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="CheckAll" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Remove prerequisites" Command="{Binding RemovePrerequisites}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="Delete" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Clear plugin settings" Command="{Binding RemoveSettings}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="DatabaseRemove" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Remove plugin" Command="{Binding Remove}">
|
||||
<MenuItem.Icon>
|
||||
<avalonia:MaterialIcon Kind="DeleteForever" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</controls:SplitButton.Flyout>
|
||||
</controls:SplitButton>
|
||||
|
||||
<controls:HyperlinkButton Classes="icon-button icon-button-large"
|
||||
Margin="5 0"
|
||||
IsVisible="{Binding Plugin.Info.Website, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
NavigateUri="{Binding Plugin.Info.Website}">
|
||||
<avalonia:MaterialIcon Kind="Web" />
|
||||
</controls:HyperlinkButton>
|
||||
<controls:HyperlinkButton Classes="icon-button icon-button-large"
|
||||
Margin="5 0"
|
||||
IsVisible="{Binding Plugin.Info.Repository, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
NavigateUri="{Binding Plugin.Info.Repository}">
|
||||
<avalonia:MaterialIcon Kind="Git" />
|
||||
</controls:HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="{Binding !Enabling}"
|
||||
IsChecked="{Binding IsEnabled}">
|
||||
<StackPanel x:Name="EnableText" Orientation="Horizontal">
|
||||
<TextBlock>Plugin enabled</TextBlock>
|
||||
<avalonia:MaterialIcon Kind="ShieldHalfFull"
|
||||
Margin="5 0 0 0"
|
||||
ToolTip.Tip="Plugin requires admin rights"
|
||||
IsVisible="{Binding Plugin.Info.RequiresAdmin}" />
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
|
||||
<ProgressBar Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="{Binding Enabling}"
|
||||
IsIndeterminate="True" />
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" BorderBrush="{DynamicResource ButtonBorderBrush}" BorderThickness="1 0 0 0" Margin="10 0 0 0" Padding="10 0 0 0">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<TextBlock Classes="h5">Plugin features</TextBlock>
|
||||
<ListBox Grid.Row="1" MaxHeight="135" Items="{Binding PluginFeatures}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public partial class PluginSettingsView : ReactiveUserControl<PluginSettingsViewModel>
|
||||
{
|
||||
public PluginSettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Avalonia.Threading;
|
||||
using Ninject;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginSettingsViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly ISettingsVmFactory _settingsVmFactory;
|
||||
private readonly IWindowService _windowService;
|
||||
private bool _canInstallPrerequisites;
|
||||
private bool _canRemovePrerequisites;
|
||||
private bool _enabling;
|
||||
private bool _isSettingsPopupOpen;
|
||||
private Plugin _plugin;
|
||||
|
||||
public PluginSettingsViewModel(Plugin plugin,
|
||||
ISettingsVmFactory settingsVmFactory,
|
||||
ICoreService coreService,
|
||||
IWindowService windowService,
|
||||
INotificationService notificationService,
|
||||
IPluginManagementService pluginManagementService)
|
||||
{
|
||||
_plugin = plugin;
|
||||
|
||||
_settingsVmFactory = settingsVmFactory;
|
||||
_coreService = coreService;
|
||||
_windowService = windowService;
|
||||
_notificationService = notificationService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
|
||||
PluginFeatures = new ObservableCollection<PluginFeatureViewModel>();
|
||||
foreach (PluginFeatureInfo pluginFeatureInfo in Plugin.Features)
|
||||
PluginFeatures.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeatureInfo, false));
|
||||
|
||||
|
||||
|
||||
OpenSettings = ReactiveCommand.Create(ExecuteOpenSettings, this.WhenAnyValue(x => x.IsEnabled).Select(isEnabled => isEnabled && Plugin.ConfigurationDialog != null));
|
||||
InstallPrerequisites = ReactiveCommand.CreateFromTask(ExecuteInstallPrerequisites, this.WhenAnyValue(x => x.CanInstallPrerequisites));
|
||||
RemovePrerequisites = ReactiveCommand.CreateFromTask<bool>(ExecuteRemovePrerequisites, this.WhenAnyValue(x => x.CanRemovePrerequisites));
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
_pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginToggled;
|
||||
_pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginToggled;
|
||||
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
_pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginToggled;
|
||||
_pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginToggled;
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> OpenSettings { get; }
|
||||
public ReactiveCommand<Unit, Unit> InstallPrerequisites { get; }
|
||||
public ReactiveCommand<bool, Unit> RemovePrerequisites { get; }
|
||||
|
||||
public ObservableCollection<PluginFeatureViewModel> PluginFeatures { get; }
|
||||
|
||||
public Plugin Plugin
|
||||
{
|
||||
get => _plugin;
|
||||
set => RaiseAndSetIfChanged(ref _plugin, value);
|
||||
}
|
||||
|
||||
public bool Enabling
|
||||
{
|
||||
get => _enabling;
|
||||
set => RaiseAndSetIfChanged(ref _enabling, value);
|
||||
}
|
||||
|
||||
public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name;
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => Plugin.IsEnabled;
|
||||
set => Task.Run(() => UpdateEnabled(value));
|
||||
}
|
||||
|
||||
public bool IsSettingsPopupOpen
|
||||
{
|
||||
get => _isSettingsPopupOpen;
|
||||
set
|
||||
{
|
||||
if (!RaiseAndSetIfChanged(ref _isSettingsPopupOpen, value)) return;
|
||||
CheckPrerequisites();
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanInstallPrerequisites
|
||||
{
|
||||
get => _canInstallPrerequisites;
|
||||
set => RaiseAndSetIfChanged(ref _canInstallPrerequisites, value);
|
||||
}
|
||||
|
||||
public bool CanRemovePrerequisites
|
||||
{
|
||||
get => _canRemovePrerequisites;
|
||||
set => RaiseAndSetIfChanged(ref _canRemovePrerequisites, value);
|
||||
}
|
||||
|
||||
private void ExecuteOpenSettings()
|
||||
{
|
||||
if (Plugin.ConfigurationDialog == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
PluginConfigurationViewModel? viewModel = Plugin.Kernel!.Get(Plugin.ConfigurationDialog.Type) as PluginConfigurationViewModel;
|
||||
if (viewModel == null)
|
||||
throw new ArtemisUIException($"The type of a plugin configuration dialog must inherit {nameof(PluginConfigurationViewModel)}");
|
||||
|
||||
_windowService.ShowWindow(new PluginSettingsWindowViewModel(viewModel));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_windowService.ShowExceptionDialog("An exception occured while trying to show the plugin's settings window", e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenPluginDirectory()
|
||||
{
|
||||
try
|
||||
{
|
||||
Utilities.OpenFolder(Plugin.Directory.FullName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_windowService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Reload()
|
||||
{
|
||||
bool wasEnabled = IsEnabled;
|
||||
|
||||
await Task.Run(() => _pluginManagementService.UnloadPlugin(Plugin));
|
||||
|
||||
PluginFeatures.Clear();
|
||||
|
||||
Plugin = _pluginManagementService.LoadPlugin(Plugin.Directory);
|
||||
foreach (PluginFeatureInfo pluginFeatureInfo in Plugin.Features)
|
||||
PluginFeatures.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeatureInfo, false));
|
||||
|
||||
if (wasEnabled)
|
||||
await UpdateEnabled(true);
|
||||
|
||||
_notificationService.CreateNotification().WithTitle("Reloaded plugin.").Show();
|
||||
}
|
||||
|
||||
public async Task ExecuteInstallPrerequisites()
|
||||
{
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(Plugin.Features.Where(f => f.AlwaysEnabled));
|
||||
|
||||
if (subjects.Any(s => s.Prerequisites.Any()))
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_windowService, subjects);
|
||||
}
|
||||
|
||||
public async Task ExecuteRemovePrerequisites(bool forPluginRemoval = false)
|
||||
{
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(!forPluginRemoval ? Plugin.Features.Where(f => f.AlwaysEnabled) : Plugin.Features);
|
||||
|
||||
if (subjects.Any(s => s.Prerequisites.Any(p => p.UninstallActions.Any())))
|
||||
{
|
||||
await PluginPrerequisitesUninstallDialogViewModel.Show(_windowService, subjects, forPluginRemoval ? "Skip, remove plugin" : "Cancel");
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RemoveSettings()
|
||||
{
|
||||
bool confirmed = await _windowService.ShowConfirmContentDialog("Clear plugin settings", "Are you sure you want to clear the settings of this plugin?");
|
||||
if (!confirmed)
|
||||
return;
|
||||
|
||||
bool wasEnabled = IsEnabled;
|
||||
|
||||
if (IsEnabled)
|
||||
await UpdateEnabled(false);
|
||||
|
||||
_pluginManagementService.RemovePluginSettings(Plugin);
|
||||
|
||||
if (wasEnabled)
|
||||
await UpdateEnabled(true);
|
||||
|
||||
_notificationService.CreateNotification().WithTitle("Cleared plugin settings.").Show();
|
||||
}
|
||||
|
||||
public async Task Remove()
|
||||
{
|
||||
bool confirmed = await _windowService.ShowConfirmContentDialog("Remove plugin", "Are you sure you want to remove this plugin?");
|
||||
if (!confirmed)
|
||||
return;
|
||||
|
||||
// If the plugin or any of its features has uninstall actions, offer to run these
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(Plugin.Features);
|
||||
if (subjects.Any(s => s.Prerequisites.Any(p => p.UninstallActions.Any())))
|
||||
await ExecuteRemovePrerequisites(true);
|
||||
|
||||
try
|
||||
{
|
||||
_pluginManagementService.RemovePlugin(Plugin, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_windowService.ShowExceptionDialog("Failed to remove plugin", e);
|
||||
throw;
|
||||
}
|
||||
|
||||
_notificationService.CreateNotification().WithTitle("Removed plugin.").Show();
|
||||
}
|
||||
|
||||
public void ShowLogsFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
Utilities.OpenFolder(Constants.LogsFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_windowService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenUri(Uri uri)
|
||||
{
|
||||
Utilities.OpenUrl(uri.ToString());
|
||||
}
|
||||
|
||||
private void PluginManagementServiceOnPluginToggled(object? sender, PluginEventArgs e)
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
|
||||
private async Task UpdateEnabled(bool enable)
|
||||
{
|
||||
if (IsEnabled == enable)
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
{
|
||||
Enabling = true;
|
||||
|
||||
if (Plugin.Info.RequiresAdmin && !_coreService.IsElevated)
|
||||
{
|
||||
bool confirmed = await _windowService.ShowConfirmContentDialog("Enable plugin", "This plugin requires admin rights, are you sure you want to enable it?");
|
||||
if (!confirmed)
|
||||
{
|
||||
CancelEnable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all prerequisites are met async
|
||||
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||
subjects.AddRange(Plugin.Features.Where(f => f.AlwaysEnabled || f.EnabledInStorage));
|
||||
|
||||
if (subjects.Any(s => !s.ArePrerequisitesMet()))
|
||||
{
|
||||
await PluginPrerequisitesInstallDialogViewModel.Show(_windowService, subjects);
|
||||
if (!subjects.All(s => s.ArePrerequisitesMet()))
|
||||
{
|
||||
CancelEnable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_pluginManagementService.EnablePlugin(Plugin, true, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await Dispatcher.UIThread.InvokeAsync(() => _notificationService.CreateNotification()
|
||||
.WithMessage($"Failed to enable plugin {Plugin.Info.Name}\r\n{e.Message}")
|
||||
.HavingButton(b => b.WithText("View logs").WithAction(ShowLogsFolder))
|
||||
.Show());
|
||||
}
|
||||
finally
|
||||
{
|
||||
Enabling = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_pluginManagementService.DisablePlugin(Plugin, true);
|
||||
}
|
||||
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
|
||||
private void CancelEnable()
|
||||
{
|
||||
Enabling = false;
|
||||
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
|
||||
private void CheckPrerequisites()
|
||||
{
|
||||
CanInstallPrerequisites = Plugin.Info.Prerequisites.Any() ||
|
||||
Plugin.Features.Where(f => f.AlwaysEnabled).Any(f => f.Prerequisites.Any());
|
||||
CanRemovePrerequisites = Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any()) ||
|
||||
Plugin.Features.Where(f => f.AlwaysEnabled).Any(f => f.Prerequisites.Any(p => p.UninstallActions.Any()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<controls:CoreWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Plugins.PluginSettingsWindowView"
|
||||
Icon="/Assets/Images/Logo/application.ico"
|
||||
Title="{Binding DisplayName}"
|
||||
Width="800"
|
||||
Height="800"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Panel>
|
||||
<ContentControl Content="{Binding ConfigurationViewModel}"></ContentControl>
|
||||
<StackPanel Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
|
||||
</Panel>
|
||||
</controls:CoreWindow>
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginSettingsWindowView : ReactiveCoreWindow<PluginSettingsWindowViewModel>
|
||||
{
|
||||
public PluginSettingsWindowView()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
Observable.FromEventPattern(
|
||||
x => ViewModel!.ConfigurationViewModel.CloseRequested += x,
|
||||
x => ViewModel!.ConfigurationViewModel.CloseRequested -= x
|
||||
)
|
||||
.Subscribe(_ => Close())
|
||||
.DisposeWith(disposables);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
|
||||
namespace Artemis.UI.Screens.Plugins
|
||||
{
|
||||
public class PluginSettingsWindowViewModel : ActivatableViewModelBase
|
||||
{
|
||||
public PluginSettingsWindowViewModel(PluginConfigurationViewModel configurationViewModel)
|
||||
{
|
||||
ConfigurationViewModel = configurationViewModel ?? throw new ArgumentNullException(nameof(configurationViewModel));
|
||||
Plugin = configurationViewModel.Plugin;
|
||||
|
||||
DisplayName = $"{Plugin.Info.Name} | Settings";
|
||||
}
|
||||
|
||||
public PluginConfigurationViewModel ConfigurationViewModel { get; }
|
||||
public Plugin Plugin { get; }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user