1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-01-02 10:43:31 +00:00

Plugins - Fixed GetFeature<T> always returning null

Plugins - Added AlwaysEnabled property to [PluginFeature] attribute
This commit is contained in:
Robert 2021-03-26 19:39:48 +01:00
parent 0a7c724de0
commit 5545bdb783
7 changed files with 72 additions and 19 deletions

View File

@ -107,7 +107,7 @@ namespace Artemis.Core
/// <returns>If found, the instance of the feature</returns> /// <returns>If found, the instance of the feature</returns>
public T? GetFeature<T>() where T : PluginFeature public T? GetFeature<T>() where T : PluginFeature
{ {
return _features.FirstOrDefault(i => i.Instance is T) as T; return _features.FirstOrDefault(i => i.Instance is T)?.Instance as T;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -164,6 +164,11 @@ namespace Artemis.Core
} }
} }
internal bool HasEnabledFeatures()
{
return Entity.Features.Any(f => f.IsEnabled) || Features.Any(f => f.AlwaysEnabled);
}
#region IDisposable #region IDisposable
/// <summary> /// <summary>

View File

@ -23,5 +23,10 @@ namespace Artemis.Core
/// available icons /// available icons
/// </summary> /// </summary>
public string? Icon { get; set; } public string? Icon { get; set; }
/// <summary>
/// Marks the feature to always be enabled as long as the plugin is enabled
/// </summary>
public bool AlwaysEnabled { get; set; }
} }
} }

View File

@ -28,6 +28,7 @@ namespace Artemis.Core
Name = attribute?.Name ?? featureType.Name.Humanize(LetterCasing.Title); Name = attribute?.Name ?? featureType.Name.Humanize(LetterCasing.Title);
Description = attribute?.Description; Description = attribute?.Description;
Icon = attribute?.Icon; Icon = attribute?.Icon;
AlwaysEnabled = attribute?.AlwaysEnabled ?? false;
if (Icon != null) return; if (Icon != null) return;
if (typeof(BaseDataModelExpansion).IsAssignableFrom(featureType)) if (typeof(BaseDataModelExpansion).IsAssignableFrom(featureType))
@ -55,6 +56,7 @@ namespace Artemis.Core
Name = attribute?.Name ?? instance.GetType().Name.Humanize(LetterCasing.Title); Name = attribute?.Name ?? instance.GetType().Name.Humanize(LetterCasing.Title);
Description = attribute?.Description; Description = attribute?.Description;
Icon = attribute?.Icon; Icon = attribute?.Icon;
AlwaysEnabled = attribute?.AlwaysEnabled ?? false;
Instance = instance; Instance = instance;
if (Icon != null) return; if (Icon != null) return;
@ -111,6 +113,12 @@ namespace Artemis.Core
set => SetAndNotify(ref _icon, value); set => SetAndNotify(ref _icon, value);
} }
/// <summary>
/// Marks the feature to always be enabled as long as the plugin is enabled and cannot be disabled
/// </summary>
[JsonProperty]
public bool AlwaysEnabled { get; }
/// <summary> /// <summary>
/// Gets the feature this info is associated with /// Gets the feature this info is associated with
/// </summary> /// </summary>

View File

@ -207,7 +207,7 @@ namespace Artemis.Core.Services
// ReSharper disable InconsistentlySynchronizedField - It's read-only, idc // ReSharper disable InconsistentlySynchronizedField - It's read-only, idc
_logger.Debug("Loaded {count} plugin(s)", _plugins.Count); _logger.Debug("Loaded {count} plugin(s)", _plugins.Count);
bool adminRequired = _plugins.Any(p => p.Info.RequiresAdmin && p.Entity.IsEnabled && p.Entity.Features.Any(f => f.IsEnabled)); bool adminRequired = _plugins.Any(p => p.Info.RequiresAdmin && p.Entity.IsEnabled && p.HasEnabledFeatures());
if (!isElevated && adminRequired) if (!isElevated && adminRequired)
{ {
_logger.Information("Restarting because one or more plugins requires elevation"); _logger.Information("Restarting because one or more plugins requires elevation");
@ -340,7 +340,7 @@ namespace Artemis.Core.Services
if (plugin.Assembly == null) if (plugin.Assembly == null)
throw new ArtemisPluginException(plugin, "Cannot enable a plugin that hasn't successfully been loaded"); throw new ArtemisPluginException(plugin, "Cannot enable a plugin that hasn't successfully been loaded");
if (plugin.Info.RequiresAdmin && plugin.Entity.Features.Any(f => f.IsEnabled) && !_isElevated) if (plugin.Info.RequiresAdmin && plugin.HasEnabledFeatures() && !_isElevated)
{ {
if (!saveState) if (!saveState)
throw new ArtemisCoreException("Cannot enable a plugin that requires elevation without saving it's state."); throw new ArtemisCoreException("Cannot enable a plugin that requires elevation without saving it's state.");
@ -387,7 +387,7 @@ namespace Artemis.Core.Services
} }
// Activate features after they are all loaded // Activate features after they are all loaded
foreach (PluginFeatureInfo pluginFeature in plugin.Features.Where(f => f.Instance != null && f.Instance.Entity.IsEnabled)) foreach (PluginFeatureInfo pluginFeature in plugin.Features.Where(f => f.Instance != null && (f.Instance.Entity.IsEnabled || f.AlwaysEnabled)))
{ {
try try
{ {

View File

@ -50,13 +50,17 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="8" Margin="8"
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay, FallbackValue=Collapsed}" Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay, FallbackValue=Collapsed}"
Orientation="Horizontal"> Orientation="Horizontal"
ToolTip="This feature cannot be disabled without disabling the whole plugin"
ToolTipService.IsEnabled="{Binding FeatureInfo.AlwaysEnabled}">
<materialDesign:PackIcon Kind="ShieldHalfFull" <materialDesign:PackIcon Kind="ShieldHalfFull"
ToolTip="Plugin requires admin rights" ToolTip="Plugin requires admin rights"
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="0 0 5 0" Margin="0 0 5 0"
Visibility="{Binding ShowShield, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" /> Visibility="{Binding ShowShield, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsEnabled}" IsEnabled="{Binding FeatureInfo.Plugin.IsEnabled}"> <CheckBox Style="{StaticResource MaterialDesignCheckBox}"
IsChecked="{Binding IsEnabled}"
IsEnabled="{Binding CanToggleEnabled}">
Feature enabled Feature enabled
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>

View File

@ -16,6 +16,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
private readonly IPluginManagementService _pluginManagementService; private readonly IPluginManagementService _pluginManagementService;
private bool _enabling; private bool _enabling;
private readonly IMessageService _messageService; private readonly IMessageService _messageService;
private bool _canToggleEnabled;
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
bool showShield, bool showShield,
@ -50,6 +51,8 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
set => Task.Run(() => UpdateEnabled(value)); set => Task.Run(() => UpdateEnabled(value));
} }
public bool CanToggleEnabled => FeatureInfo.Plugin.IsEnabled && !FeatureInfo.AlwaysEnabled;
public void ShowLogsFolder() public void ShowLogsFolder()
{ {
try try
@ -76,6 +79,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped; _pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped;
_pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped; _pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped;
FeatureInfo.Plugin.Enabled += PluginOnToggled;
FeatureInfo.Plugin.Disabled += PluginOnToggled;
base.OnInitialActivate(); base.OnInitialActivate();
} }
@ -85,6 +91,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped; _pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped;
_pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped; _pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped;
FeatureInfo.Plugin.Enabled -= PluginOnToggled;
FeatureInfo.Plugin.Disabled -= PluginOnToggled;
base.OnClose(); base.OnClose();
} }
@ -147,6 +156,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
NotifyOfPropertyChange(nameof(LoadException)); NotifyOfPropertyChange(nameof(LoadException));
} }
private void PluginOnToggled(object sender, EventArgs e)
{
NotifyOfPropertyChange(nameof(CanToggleEnabled));
}
#endregion #endregion
} }
} }

View File

@ -1,6 +1,9 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeEditing/GenerateMemberBody/DocumentationGenerationKind/@EntryValue">Inherit</s:String>
<s:Boolean x:Key="/Default/CodeEditing/GenerateMemberBody/WrapIntoRegions/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeNotEvident/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeNotEvident/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuspiciousTypeConversion_002EGlobal/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Built-in: Full Cleanup</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Built-in: Full Cleanup</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/APPLY_ON_COMPLETION/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/APPLY_ON_COMPLETION/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
@ -128,17 +131,6 @@
&lt;Name /&gt;&#xD; &lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD; &lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD; &lt;/Entry&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Public Enums"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Static Fields and Constants"&gt;&#xD; &lt;Entry DisplayName="Static Fields and Constants"&gt;&#xD;
&lt;Entry.Match&gt;&#xD; &lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD; &lt;Or&gt;&#xD;
@ -207,16 +199,41 @@
&lt;ImplementsInterface Immediate="True" /&gt;&#xD; &lt;ImplementsInterface Immediate="True" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD; &lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD; &lt;/Entry&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Public Enums"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Region Name="Events" /&gt;&#xD;
&lt;Region Name="Event handlers" /&gt;&#xD;
&lt;Region Name="IDisposable"&gt;&#xD;
&lt;Region.GroupBy&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/Region.GroupBy&gt;&#xD;
&lt;/Region&gt;&#xD;
&lt;/TypePattern&gt;&#xD; &lt;/TypePattern&gt;&#xD;
&lt;/Patterns&gt;</s:String> &lt;/Patterns&gt;</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FElsewhere/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FElsewhere/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">ERROR</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=DisposePattern/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=DisposePattern/Options/=ChangeDispose/@EntryIndexedValue">Replace</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Formatting/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Formatting/Options/=UseNameOf/@EntryIndexedValue">True</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">True</s:String>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String> <s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Async/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String> <s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNotificationDisabled/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNotificationDisabled/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGB/@EntryIndexedValue">RGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SK/@EntryIndexedValue">SK</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SK/@EntryIndexedValue">SK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>