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

Plugins - Don't dispose Plugin when disabling after it has been injected into a feature

This commit is contained in:
Robert 2022-07-22 23:25:35 +02:00
parent 75d85985a9
commit 289a411545
9 changed files with 58 additions and 33 deletions

View File

@ -22,7 +22,7 @@ namespace Artemis.Core.Ninject
Kernel.Components.Remove<IMissingBindingResolver, SelfBindingResolver>(); Kernel.Components.Remove<IMissingBindingResolver, SelfBindingResolver>();
Kernel.Bind<Plugin>().ToConstant(Plugin); Kernel.Bind<Plugin>().ToConstant(Plugin).InTransientScope();
// Bind plugin service interfaces // Bind plugin service interfaces
Kernel.Bind(x => Kernel.Bind(x =>

View File

@ -97,7 +97,7 @@ namespace Artemis.UI.Shared
/// Occurs when a LED of the device has been clicked /// Occurs when a LED of the device has been clicked
/// </summary> /// </summary>
public event EventHandler<LedClickedEventArgs>? LedClicked; public event EventHandler<LedClickedEventArgs>? LedClicked;
/// <summary> /// <summary>
/// Occurs when the device was clicked but not on a LED. /// Occurs when the device was clicked but not on a LED.
/// </summary> /// </summary>
@ -259,8 +259,6 @@ namespace Artemis.UI.Shared
private void SetupForDevice() private void SetupForDevice()
{ {
_deviceImage?.Dispose();
_deviceImage = null;
_highlightedLeds = new List<DeviceVisualizerLed>(); _highlightedLeds = new List<DeviceVisualizerLed>();
_dimmedLeds = new List<DeviceVisualizerLed>(); _dimmedLeds = new List<DeviceVisualizerLed>();
@ -296,7 +294,11 @@ namespace Artemis.UI.Shared
Task.Run(() => Task.Run(() =>
{ {
if (device.Layout?.Image == null || !File.Exists(device.Layout.Image.LocalPath)) if (device.Layout?.Image == null || !File.Exists(device.Layout.Image.LocalPath))
{
_deviceImage?.Dispose();
_deviceImage = null;
return; return;
}
try try
{ {
@ -312,6 +314,7 @@ namespace Artemis.UI.Shared
deviceVisualizerLed.DrawBitmap(context); deviceVisualizerLed.DrawBitmap(context);
} }
_deviceImage?.Dispose();
_deviceImage = renderTargetBitmap; _deviceImage = renderTargetBitmap;
Dispatcher.UIThread.Post(InvalidateMeasure); Dispatcher.UIThread.Post(InvalidateMeasure);
@ -337,7 +340,5 @@ namespace Artemis.UI.Shared
} }
#endregion #endregion
} }
} }

View File

@ -44,6 +44,10 @@
<ToggleButton Classes="icon-button"> <ToggleButton Classes="icon-button">
<avalonia:MaterialIcon Kind="BlockChain" /> <avalonia:MaterialIcon Kind="BlockChain" />
</ToggleButton> </ToggleButton>
<Button Classes="icon-button">
<avalonia:MaterialIcon Kind="Cog" />
</Button>
</StackPanel> </StackPanel>
</Border> </Border>
</Design.PreviewWith> </Design.PreviewWith>

View File

@ -35,19 +35,10 @@
IsHitTestVisible="False"> IsHitTestVisible="False">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type plugins:PluginPrerequisiteViewModel}"> <DataTemplate DataType="{x:Type plugins:PluginPrerequisiteViewModel}">
<Grid ColumnDefinitions="Auto,*" Margin="0 6"> <StackPanel Margin="0 6" VerticalAlignment="Stretch">
<Border Grid.Row="0" Grid.Column="0" Classes="status-border" IsVisible="{CompiledBinding !IsMet}" Background="#ff3838"> <TextBlock FontWeight="Bold" Text="{CompiledBinding PluginPrerequisite.Name}" TextWrapping="Wrap" />
<avalonia:MaterialIcon Kind="Close" /> <TextBlock Text="{CompiledBinding PluginPrerequisite.Description}" TextWrapping="Wrap" />
</Border> </StackPanel>
<Border Grid.Row="0" Grid.Column="0" Classes="status-border" IsVisible="{CompiledBinding IsMet}" Background="#32a852">
<avalonia:MaterialIcon Kind="Check" />
</Border>
<StackPanel Margin="8 0 0 0" Grid.Column="1" VerticalAlignment="Stretch">
<TextBlock FontWeight="Bold" Text="{CompiledBinding PluginPrerequisite.Name}" TextWrapping="Wrap" />
<TextBlock Text="{CompiledBinding PluginPrerequisite.Description}" TextWrapping="Wrap" />
</StackPanel>
</Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>

View File

@ -88,7 +88,8 @@ namespace Artemis.UI.Screens.Plugins
// Disable all subjects that are features if still required // Disable all subjects that are features if still required
foreach (IPrerequisitesSubject prerequisitesSubject in _subjects) 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 // Disable the parent plugin if the feature is AlwaysEnabled
if (featureInfo.AlwaysEnabled) if (featureInfo.AlwaysEnabled)

View File

@ -11,12 +11,12 @@
<Grid ColumnDefinitions="30,*,Auto"> <Grid ColumnDefinitions="30,*,Auto">
<Grid.ContextFlyout> <Grid.ContextFlyout>
<MenuFlyout> <MenuFlyout>
<MenuItem Header="Install prerequisites" Command="{Binding InstallPrerequisites}"> <MenuItem Header="Install prerequisites" Command="{CompiledBinding InstallPrerequisites}">
<MenuItem.Icon> <MenuItem.Icon>
<avalonia:MaterialIcon Kind="CheckAll" /> <avalonia:MaterialIcon Kind="CheckAll" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Remove prerequisites" Command="{Binding RemovePrerequisites}"> <MenuItem Header="Remove prerequisites" Command="{CompiledBinding RemovePrerequisites}">
<MenuItem.Icon> <MenuItem.Icon>
<avalonia:MaterialIcon Kind="Delete" /> <avalonia:MaterialIcon Kind="Delete" />
</MenuItem.Icon> </MenuItem.Icon>
@ -58,12 +58,30 @@
ToolTip.Tip="Plugin requires admin rights" ToolTip.Tip="Plugin requires admin rights"
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="0 0 5 0" Margin="0 0 5 0"
IsVisible="{Binding ShowShield}" /> IsVisible="{CompiledBinding ShowShield}" />
<CheckBox IsChecked="{CompiledBinding IsEnabled}" IsEnabled="{CompiledBinding CanToggleEnabled}"> <CheckBox IsChecked="{CompiledBinding IsEnabled}" IsEnabled="{CompiledBinding CanToggleEnabled}">
Enable feature Enable feature
</CheckBox> </CheckBox>
<Button Classes="icon-button" Margin="5 0 0 0" IsVisible="{CompiledBinding CanInstallPrerequisites}">
<Button.Flyout>
<MenuFlyout Placement="Bottom" >
<MenuItem Header="Install prerequisites" Command="{CompiledBinding InstallPrerequisites}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="CheckAll" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Remove prerequisites" Command="{CompiledBinding RemovePrerequisites}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Delete" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Button.Flyout>
<avalonia:MaterialIcon Kind="DotsVertical"></avalonia:MaterialIcon>
</Button>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="7" IsVisible="{CompiledBinding Enabling}"> <StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="7" IsVisible="{CompiledBinding Enabling}">
<ProgressBar Value="0" IsIndeterminate="True" /> <ProgressBar Value="0" IsIndeterminate="True" />

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
@ -37,6 +38,11 @@ namespace Artemis.UI.Screens.Plugins
FeatureInfo = pluginFeatureInfo; FeatureInfo = pluginFeatureInfo;
ShowShield = FeatureInfo.Plugin.Info.RequiresAdmin && showShield; ShowShield = FeatureInfo.Plugin.Info.RequiresAdmin && showShield;
ShowLogsFolder = ReactiveCommand.Create(ExecuteShowLogsFolder);
ViewLoadException = ReactiveCommand.Create(ExecuteViewLoadException);
InstallPrerequisites = ReactiveCommand.CreateFromTask(ExecuteInstallPrerequisites);
RemovePrerequisites = ReactiveCommand.CreateFromTask(ExecuteRemovePrerequisites);
this.WhenActivated(d => this.WhenActivated(d =>
{ {
_pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling; _pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling;
@ -58,6 +64,11 @@ namespace Artemis.UI.Screens.Plugins
}); });
} }
public ReactiveCommand<Unit, Unit> ShowLogsFolder { get; }
public ReactiveCommand<Unit, Unit> ViewLoadException { get; }
public ReactiveCommand<Unit, Unit> InstallPrerequisites { get; }
public ReactiveCommand<Unit, Unit> RemovePrerequisites { get; }
public PluginFeatureInfo FeatureInfo { get; } public PluginFeatureInfo FeatureInfo { get; }
public Exception? LoadException => FeatureInfo.LoadException; public Exception? LoadException => FeatureInfo.LoadException;
@ -80,7 +91,7 @@ namespace Artemis.UI.Screens.Plugins
public bool CanRemovePrerequisites => FeatureInfo.PlatformPrerequisites.Any(p => p.UninstallActions.Any()); public bool CanRemovePrerequisites => FeatureInfo.PlatformPrerequisites.Any(p => p.UninstallActions.Any());
public bool IsPopupEnabled => CanInstallPrerequisites || CanRemovePrerequisites; public bool IsPopupEnabled => CanInstallPrerequisites || CanRemovePrerequisites;
public void ShowLogsFolder() private void ExecuteShowLogsFolder()
{ {
try try
{ {
@ -92,19 +103,19 @@ namespace Artemis.UI.Screens.Plugins
} }
} }
public void ViewLoadException() private void ExecuteViewLoadException()
{ {
if (LoadException != null) if (LoadException != null)
_windowService.ShowExceptionDialog("Feature failed to enable", LoadException); _windowService.ShowExceptionDialog("Feature failed to enable", LoadException);
} }
public async Task InstallPrerequisites() private async Task ExecuteInstallPrerequisites()
{ {
if (FeatureInfo.PlatformPrerequisites.Any()) if (FeatureInfo.PlatformPrerequisites.Any())
await PluginPrerequisitesInstallDialogViewModel.Show(_windowService, new List<IPrerequisitesSubject> {FeatureInfo}); await PluginPrerequisitesInstallDialogViewModel.Show(_windowService, new List<IPrerequisitesSubject> {FeatureInfo});
} }
public async Task RemovePrerequisites() private async Task ExecuteRemovePrerequisites()
{ {
if (FeatureInfo.PlatformPrerequisites.Any(p => p.UninstallActions.Any())) if (FeatureInfo.PlatformPrerequisites.Any(p => p.UninstallActions.Any()))
{ {
@ -126,7 +137,7 @@ namespace Artemis.UI.Screens.Plugins
this.RaisePropertyChanged(nameof(IsEnabled)); this.RaisePropertyChanged(nameof(IsEnabled));
_notificationService.CreateNotification() _notificationService.CreateNotification()
.WithMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.") .WithMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.")
.HavingButton(b => b.WithText("View logs").WithAction(ShowLogsFolder)) .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
.WithSeverity(NotificationSeverity.Error) .WithSeverity(NotificationSeverity.Error)
.Show(); .Show();
return; return;
@ -165,7 +176,7 @@ namespace Artemis.UI.Screens.Plugins
{ {
_notificationService.CreateNotification() _notificationService.CreateNotification()
.WithMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}") .WithMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}")
.HavingButton(b => b.WithText("View logs").WithAction(ShowLogsFolder)) .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
.WithSeverity(NotificationSeverity.Error) .WithSeverity(NotificationSeverity.Error)
.Show(); .Show();
} }

View File

@ -31,9 +31,8 @@ namespace Artemis.UI.Screens.Plugins
? PluginPrerequisite.InstallActions.Select(a => new PluginPrerequisiteActionViewModel(a)) ? PluginPrerequisite.InstallActions.Select(a => new PluginPrerequisiteActionViewModel(a))
: PluginPrerequisite.UninstallActions.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); _busy = this.WhenAnyValue(x => x.Installing, x => x.Uninstalling, (i, u) => i || u).ToProperty(this, x => x.Busy);
this.WhenAnyValue(x => x.ActiveAction, a => Actions.IndexOf(a!)).ToProperty(this, x => x.ActiveStepNumber, out _activeStepNumber); _activeStepNumber = this.WhenAnyValue(x => x.ActiveAction, a => Actions.IndexOf(a!) + 1).ToProperty(this, x => x.ActiveStepNumber);
this.WhenActivated(d => this.WhenActivated(d =>
{ {

View File

@ -16,7 +16,7 @@
<Button Grid.Row="0" Grid.Column="1" Classes="accent" Command="{CompiledBinding ImportPlugin}" HorizontalAlignment="Right">Import plugin</Button> <Button Grid.Row="0" Grid.Column="1" Classes="accent" Command="{CompiledBinding ImportPlugin}" HorizontalAlignment="Right">Import plugin</Button>
</Grid> </Grid>
<ScrollViewer Grid.Row="1" Grid.Column="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer Grid.Row="1" Grid.Column="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" VerticalAlignment="Top">
<ItemsControl Items="{CompiledBinding Plugins}" MaxWidth="900" VerticalAlignment="Center"/> <ItemsControl Items="{CompiledBinding Plugins}" MaxWidth="900" VerticalAlignment="Center"/>
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>