diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 42b2f16f6..6b20d3e22 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -50,7 +50,6 @@ - diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings index 705d6dc5c..5963c6027 100644 --- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings +++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings @@ -42,6 +42,7 @@ True True True + True True True True diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs index 29ecf764f..36f32cada 100644 --- a/src/Artemis.Core/Constants.cs +++ b/src/Artemis.Core/Constants.cs @@ -12,7 +12,7 @@ namespace Artemis.Core /// /// The full path to the Artemis application folder /// - public static readonly string ApplicationFolder = Path.GetDirectoryName(typeof(Constants).Assembly.Location); + public static readonly string ApplicationFolder = Path.GetDirectoryName(typeof(Constants).Assembly.Location)!; /// /// The full path to the Artemis executable @@ -34,11 +34,16 @@ namespace Artemis.Core /// public static readonly PluginInfo CorePluginInfo = new PluginInfo { - Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core", IsEnabled = true + Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core" }; - internal static readonly CorePluginImplementation CorePluginImplementation = new CorePluginImplementation {PluginInfo = CorePluginInfo}; - internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new EffectPlaceholderPlugin {PluginInfo = CorePluginInfo}; + /// + /// The plugin used by core components of Artemis + /// + public static readonly Plugin CorePlugin = new Plugin(CorePluginInfo, new DirectoryInfo(ApplicationFolder)); + + internal static readonly CorePluginFeature CorePluginFeature = new CorePluginFeature {Plugin = CorePlugin}; + internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new EffectPlaceholderPlugin {Plugin = CorePlugin}; /// /// A read-only collection containing all primitive numeric types diff --git a/src/Artemis.Core/Events/Plugins/PluginFeatureEventArgs.cs b/src/Artemis.Core/Events/Plugins/PluginFeatureEventArgs.cs new file mode 100644 index 000000000..288e46088 --- /dev/null +++ b/src/Artemis.Core/Events/Plugins/PluginFeatureEventArgs.cs @@ -0,0 +1,18 @@ +using System; + +namespace Artemis.Core +{ + public class PluginFeatureEventArgs : EventArgs + { + public PluginFeatureEventArgs() + { + } + + public PluginFeatureEventArgs(PluginFeature pluginFeature) + { + PluginFeature = pluginFeature; + } + + public PluginFeature PluginFeature { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Events/Plugins/PluginImplementationEventArgs.cs b/src/Artemis.Core/Events/Plugins/PluginImplementationEventArgs.cs deleted file mode 100644 index 45f5639c9..000000000 --- a/src/Artemis.Core/Events/Plugins/PluginImplementationEventArgs.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace Artemis.Core -{ - public class PluginImplementationEventArgs : EventArgs - { - public PluginImplementationEventArgs() - { - } - - public PluginImplementationEventArgs(PluginImplementation pluginImplementation) - { - PluginImplementation = pluginImplementation; - } - - public PluginImplementation PluginImplementation { get; } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginFeatureException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginFeatureException.cs new file mode 100644 index 000000000..e15e7e313 --- /dev/null +++ b/src/Artemis.Core/Exceptions/ArtemisPluginFeatureException.cs @@ -0,0 +1,24 @@ +using System; + +namespace Artemis.Core +{ + public class ArtemisPluginFeatureException : Exception + { + public PluginFeature PluginFeature { get; } + + public ArtemisPluginFeatureException(PluginFeature pluginFeature) + { + PluginFeature = pluginFeature; + } + + public ArtemisPluginFeatureException(PluginFeature pluginFeature, string message) : base(message) + { + PluginFeature = pluginFeature; + } + + public ArtemisPluginFeatureException(PluginFeature pluginFeature, string message, Exception inner) : base(message, inner) + { + PluginFeature = pluginFeature; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/MVVM/CorePropertyChanged.cs b/src/Artemis.Core/MVVM/CorePropertyChanged.cs new file mode 100644 index 000000000..d4ff0419f --- /dev/null +++ b/src/Artemis.Core/MVVM/CorePropertyChanged.cs @@ -0,0 +1,72 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace Artemis.Core +{ + /// + /// Represents a basic bindable class which notifies when a property value changes. + /// + public abstract class CorePropertyChanged : INotifyPropertyChanged + { + #region Events + + /// + /// Occurs when a property value changes. + /// + public event PropertyChangedEventHandler PropertyChanged; + + #endregion + + #region Methods + + /// + /// Checks if the property already matches the desirec value or needs to be updated. + /// + /// Type of the property. + /// Reference to the backing-filed. + /// Value to apply. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual bool RequiresUpdate(ref T storage, T value) + { + return !Equals(storage, value); + } + + /// + /// Checks if the property already matches the desired value and updates it if not. + /// + /// Type of the property. + /// Reference to the backing-filed. + /// Value to apply. + /// + /// Name of the property used to notify listeners. This value is optional + /// and can be provided automatically when invoked from compilers that support + /// . + /// + /// true if the value was changed, false if the existing value matched the desired value. + protected virtual bool SetAndNotify(ref T storage, T value, [CallerMemberName] string propertyName = null) + { + if (!RequiresUpdate(ref storage, value)) return false; + + storage = value; + // ReSharper disable once ExplicitCallerInfoArgument + OnPropertyChanged(propertyName); + return true; + } + + /// + /// Triggers the -event when a a property value has changed. + /// + /// + /// Name of the property used to notify listeners. This value is optional + /// and can be provided automatically when invoked from compilers that support + /// . + /// + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs index ae94b9a55..da7a0e1d7 100644 --- a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs +++ b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Runtime.CompilerServices; using Artemis.Core.Properties; using SkiaSharp; -using Stylet; namespace Artemis.Core { @@ -19,13 +18,13 @@ namespace Artemis.Core /// public ColorGradient() { - Stops = new BindableCollection(); + Stops = new List(); } /// /// Gets a list of all the s in the gradient /// - public BindableCollection Stops { get; } + public List Stops { get; } /// /// Gets all the colors in the color gradient diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs index e67e73d78..f99c881a7 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/BaseConditionOperator.cs @@ -22,10 +22,10 @@ namespace Artemis.Core public abstract string Icon { get; } /// - /// Gets the plugin info this condition operator belongs to + /// Gets the plugin this condition operator belongs to /// Note: Not set until after registering /// - public PluginInfo PluginInfo { get; internal set; } + public Plugin Plugin { get; internal set; } /// /// Gets the left side type of this condition operator diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs index f99364cd2..32bb54423 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs @@ -346,7 +346,7 @@ namespace Artemis.Core if (Operator != null) { - Entity.OperatorPluginGuid = Operator.PluginInfo.Guid; + Entity.OperatorPluginGuid = Operator.Plugin.Guid; Entity.OperatorType = Operator.GetType().Name; } } @@ -358,7 +358,7 @@ namespace Artemis.Core private void ConditionOperatorStoreOnConditionOperatorAdded(object? sender, ConditionOperatorStoreEvent e) { BaseConditionOperator conditionOperator = e.Registration.ConditionOperator; - if (Entity.OperatorPluginGuid == conditionOperator.PluginInfo.Guid && Entity.OperatorType == conditionOperator.GetType().Name) + if (Entity.OperatorPluginGuid == conditionOperator.Plugin.Guid && Entity.OperatorType == conditionOperator.GetType().Name) UpdateOperator(conditionOperator); } diff --git a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs index a392ca02b..26768b06c 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs @@ -16,7 +16,7 @@ namespace Artemis.Core { internal EventPredicateWrapperDataModel() { - Implementation = Constants.CorePluginInfo; + Feature = Constants.CorePluginFeature; } [DataModelIgnore] diff --git a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs index 879f3b6c6..bfa4396a5 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs @@ -16,7 +16,7 @@ namespace Artemis.Core { internal ListPredicateWrapperDataModel() { - Implementation = Constants.CorePluginInfo; + Feature = Constants.CorePluginFeature; } [DataModelIgnore] diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs index d4658d212..b3f2ec115 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/BaseDataBindingModifierType.cs @@ -12,10 +12,10 @@ namespace Artemis.Core public abstract class BaseDataBindingModifierType { /// - /// Gets the plugin info this data binding modifier belongs to + /// Gets the plugin this data binding modifier belongs to /// Note: Not set until after registering /// - public PluginInfo PluginInfo { get; internal set; } + public Plugin Plugin { get; internal set; } /// /// Gets the value type of this modifier type diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs index 10732dfd3..02235faa2 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/Direct/DataBindingModifier.cs @@ -238,7 +238,7 @@ namespace Artemis.Core if (ModifierType != null) { Entity.ModifierType = ModifierType.GetType().Name; - Entity.ModifierTypePluginGuid = ModifierType.PluginInfo.Guid; + Entity.ModifierTypePluginGuid = ModifierType.Plugin.Guid; } // General @@ -286,7 +286,7 @@ namespace Artemis.Core return; BaseDataBindingModifierType modifierType = e.TypeRegistration.DataBindingModifierType; - if (modifierType.PluginInfo.Guid == Entity.ModifierTypePluginGuid && modifierType.GetType().Name == Entity.ModifierType) + if (modifierType.Plugin.Guid == Entity.ModifierTypePluginGuid && modifierType.GetType().Name == Entity.ModifierType) UpdateModifierType(modifierType); } diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs index 090e0912f..f7ce3f942 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs @@ -91,9 +91,9 @@ namespace Artemis.Core public DataModel? Target { get; private set; } /// - /// Gets the data model GUID of the if it is a + /// Gets the data model ID of the if it is a /// - public Guid? DataModelGuid => Target?.Implementation.Guid; + public string? DataModelId => Target?.Feature.Id; /// /// Gets the point-separated path associated with this @@ -267,8 +267,8 @@ namespace Artemis.Core { Path = Entity.Path; - if (Target == null && Entity.DataModelGuid != null) - Target = DataModelStore.Get(Entity.DataModelGuid.Value)?.DataModel; + if (Target == null && Entity.DataModelId != null) + Target = DataModelStore.Get(Entity.DataModelId)?.DataModel; } /// @@ -279,7 +279,7 @@ namespace Artemis.Core return; Entity.Path = Path; - Entity.DataModelGuid = DataModelGuid; + Entity.DataModelId = DataModelId; Entity.WrapperType = Target switch { @@ -295,7 +295,7 @@ namespace Artemis.Core private void DataModelStoreOnDataModelAdded(object? sender, DataModelStoreEvent e) { - if (e.Registration.DataModel.Implementation.Guid != Entity.DataModelGuid) + if (e.Registration.DataModel.Feature.Id != Entity.DataModelId) return; Target = e.Registration.DataModel; @@ -304,7 +304,7 @@ namespace Artemis.Core private void DataModelStoreOnDataModelRemoved(object? sender, DataModelStoreEvent e) { - if (e.Registration.DataModel.Implementation.Guid != Entity.DataModelGuid) + if (e.Registration.DataModel.Feature.Id != Entity.DataModelId) return; Target = null; diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index f10f3a0f2..b2de34b23 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -190,9 +190,9 @@ namespace Artemis.Core typeof(PropertyGroupDescriptionAttribute) ); General.GroupDescription = (PropertyGroupDescriptionAttribute) generalAttribute; - General.Initialize(this, "General.", Constants.CorePluginInfo); + General.Initialize(this, "General.", Constants.CorePluginFeature); Transform.GroupDescription = (PropertyGroupDescriptionAttribute) transformAttribute; - Transform.Initialize(this, "Transform.", Constants.CorePluginInfo); + Transform.Initialize(this, "Transform.", Constants.CorePluginFeature); General.ShapeType.CurrentValueSet += ShapeTypeOnCurrentValueSet; ApplyShapeType(); @@ -619,7 +619,7 @@ namespace Artemis.Core BaseLayerBrush brush = LayerBrush; DeactivateLayerBrush(); - LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid && p.Path.StartsWith("LayerBrush.")); + LayerEntity.PropertyEntities.RemoveAll(p => p.FeatureId == brush.ProviderId && p.Path.StartsWith("LayerBrush.")); } internal void ActivateLayerBrush() @@ -628,7 +628,7 @@ namespace Artemis.Core if (current == null) return; - LayerBrushDescriptor descriptor = LayerBrushStore.Get(current.BrushPluginGuid, current.BrushType)?.LayerBrushDescriptor; + LayerBrushDescriptor? descriptor = LayerBrushStore.Get(current.LayerBrushProviderId, current.BrushType)?.LayerBrushDescriptor; descriptor?.CreateInstance(this); OnLayerBrushUpdated(); @@ -662,7 +662,7 @@ namespace Artemis.Core return; LayerBrushReference current = General.BrushReference.CurrentValue; - if (e.Registration.PluginImplementation.PluginInfo.Guid == current.BrushPluginGuid && + if (e.Registration.PluginFeature.Id == current.LayerBrushProviderId && e.Registration.LayerBrushDescriptor.LayerBrushType.Name == current.BrushType) ActivateLayerBrush(); } diff --git a/src/Artemis.Core/Models/Profile/LayerBrushReference.cs b/src/Artemis.Core/Models/Profile/LayerBrushReference.cs index bcad54663..e9cf6d946 100644 --- a/src/Artemis.Core/Models/Profile/LayerBrushReference.cs +++ b/src/Artemis.Core/Models/Profile/LayerBrushReference.cs @@ -1,5 +1,4 @@ -using System; -using Artemis.Core.LayerBrushes; +using Artemis.Core.LayerBrushes; namespace Artemis.Core { @@ -8,24 +7,24 @@ namespace Artemis.Core /// public class LayerBrushReference { - /// - /// The GUID of the plugin the brush descriptor resides in - /// - public Guid BrushPluginGuid { get; set; } - - /// - /// The full type name of the brush descriptor - /// - public string BrushType { get; set; } - public LayerBrushReference() { } public LayerBrushReference(LayerBrushDescriptor descriptor) { - BrushPluginGuid = descriptor.LayerBrushProvider.PluginInfo.Guid; + LayerBrushProviderId = descriptor.Provider.Id; BrushType = descriptor.LayerBrushType.Name; } + + /// + /// The ID of the layer brush provided the brush was provided by + /// + public string LayerBrushProviderId { get; set; } + + /// + /// The full type name of the brush descriptor + /// + public string BrushType { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs index cdade5471..3afe363bd 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs @@ -1,12 +1,11 @@ using System; -using Stylet; namespace Artemis.Core { /// /// Represents a keyframe on a containing a value and a timestamp /// - public class LayerPropertyKeyframe : PropertyChangedBase + public class LayerPropertyKeyframe : CorePropertyChanged { private LayerProperty _layerProperty; private TimeSpan _position; diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs index f27827c74..b3fbfe5ff 100644 --- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs +++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs @@ -28,11 +28,11 @@ namespace Artemis.Core /// Gets the description of this group /// public PropertyGroupDescriptionAttribute GroupDescription { get; internal set; } - + /// - /// Gets the info of the plugin this group is associated with + /// Gets the plugin feature this group is associated with /// - public PluginInfo PluginInfo { get; internal set; } + public PluginFeature Feature { get; set; } /// /// Gets the profile element (such as layer or folder) this group is associated with @@ -145,18 +145,18 @@ namespace Artemis.Core PropertyGroupInitialized?.Invoke(this, EventArgs.Empty); } - internal void Initialize(RenderProfileElement profileElement, [NotNull] string path, PluginInfo pluginInfo) + internal void Initialize(RenderProfileElement profileElement, [NotNull] string path, PluginFeature feature) { if (path == null) throw new ArgumentNullException(nameof(path)); - if (pluginInfo == null) - throw new ArgumentNullException(nameof(pluginInfo)); + if (feature == null) + throw new ArgumentNullException(nameof(feature)); // Doubt this will happen but let's make sure if (PropertiesInitialized) throw new ArtemisCoreException("Layer property group already initialized, wut"); - PluginInfo = pluginInfo; + Feature = feature; ProfileElement = profileElement; Path = path.TrimEnd('.'); @@ -246,7 +246,7 @@ namespace Artemis.Core instance.GroupDescription = propertyGroupDescription; instance.LayerBrush = LayerBrush; instance.LayerEffect = LayerEffect; - instance.Initialize(ProfileElement, $"{path}{propertyInfo.Name}.", PluginInfo); + instance.Initialize(ProfileElement, $"{path}{propertyInfo.Name}.", Feature); propertyInfo.SetValue(this, instance); _layerPropertyGroups.Add(instance); @@ -254,11 +254,11 @@ namespace Artemis.Core private PropertyEntity GetPropertyEntity(RenderProfileElement profileElement, string path, out bool fromStorage) { - PropertyEntity entity = profileElement.RenderElementEntity.PropertyEntities.FirstOrDefault(p => p.PluginGuid == PluginInfo.Guid && p.Path == path); + PropertyEntity entity = profileElement.RenderElementEntity.PropertyEntities.FirstOrDefault(p => p.FeatureId == Feature.Id && p.Path == path); fromStorage = entity != null; if (entity == null) { - entity = new PropertyEntity {PluginGuid = PluginInfo.Guid, Path = path}; + entity = new PropertyEntity {FeatureId = Feature.Id, Path = path}; profileElement.RenderElementEntity.PropertyEntities.Add(entity); } diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index e92a80027..40d61fd06 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using Artemis.Core.Modules; using Artemis.Storage.Entities.Profile; -using Newtonsoft.Json; using SkiaSharp; namespace Artemis.Core @@ -147,7 +146,7 @@ namespace Artemis.Core throw new ObjectDisposedException("Profile"); ProfileEntity.Id = EntityId; - ProfileEntity.PluginGuid = Module.PluginInfo.Guid; + ProfileEntity.ModuleId = Module.Id; ProfileEntity.Name = Name; ProfileEntity.IsActive = IsActivated; diff --git a/src/Artemis.Core/Models/Profile/ProfileElement.cs b/src/Artemis.Core/Models/Profile/ProfileElement.cs index 85cd09919..e55851f38 100644 --- a/src/Artemis.Core/Models/Profile/ProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/ProfileElement.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using SkiaSharp; -using Stylet; namespace Artemis.Core { - public abstract class ProfileElement : PropertyChangedBase, IDisposable + public abstract class ProfileElement : CorePropertyChanged, IDisposable { private bool _enabled; private Guid _entityId; diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs index 302507fca..de9a7726a 100644 --- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -44,7 +44,7 @@ namespace Artemis.Core LayerEffectEntity layerEffectEntity = new LayerEffectEntity { Id = layerEffect.EntityId, - PluginGuid = layerEffect.Descriptor.PlaceholderFor ?? layerEffect.PluginInfo.Guid, + ProviderId = layerEffect.Descriptor.PlaceholderFor ?? layerEffect.ProviderId, EffectType = layerEffect.GetEffectTypeName(), Name = layerEffect.Name, Enabled = layerEffect.Enabled, @@ -215,11 +215,11 @@ namespace Artemis.Core foreach (LayerEffectEntity layerEffectEntity in RenderElementEntity.LayerEffects) { // If there is a non-placeholder existing effect, skip this entity - BaseLayerEffect existing = _layerEffects.FirstOrDefault(e => e.EntityId == layerEffectEntity.Id); + BaseLayerEffect? existing = _layerEffects.FirstOrDefault(e => e.EntityId == layerEffectEntity.Id); if (existing != null && existing.Descriptor.PlaceholderFor == null) continue; - LayerEffectDescriptor descriptor = LayerEffectStore.Get(layerEffectEntity.PluginGuid, layerEffectEntity.EffectType)?.LayerEffectDescriptor; + LayerEffectDescriptor? descriptor = LayerEffectStore.Get(layerEffectEntity.ProviderId, layerEffectEntity.EffectType)?.LayerEffectDescriptor; if (descriptor != null) { // If a descriptor is found but there is an existing placeholder, remove the placeholder @@ -235,7 +235,7 @@ namespace Artemis.Core else if (existing == null) { // If no descriptor was found and there was no existing placeholder, create a placeholder - descriptor = PlaceholderLayerEffectDescriptor.Create(layerEffectEntity.PluginGuid); + descriptor = PlaceholderLayerEffectDescriptor.Create(layerEffectEntity.ProviderId); descriptor.CreateInstance(this, layerEffectEntity); } } @@ -253,22 +253,22 @@ namespace Artemis.Core private void LayerEffectStoreOnLayerEffectRemoved(object sender, LayerEffectStoreEvent e) { // If effects provided by the plugin are on the element, replace them with placeholders - List pluginEffects = _layerEffects.Where(ef => ef.Descriptor.LayerEffectProvider != null && - ef.PluginInfo.Guid == e.Registration.PluginImplementation.PluginInfo.Guid).ToList(); + List pluginEffects = _layerEffects.Where(ef => ef.Descriptor.Provider != null && + ef.ProviderId == e.Registration.PluginFeature.Id).ToList(); foreach (BaseLayerEffect pluginEffect in pluginEffects) { LayerEffectEntity entity = RenderElementEntity.LayerEffects.First(en => en.Id == pluginEffect.EntityId); _layerEffects.Remove(pluginEffect); pluginEffect.Dispose(); - LayerEffectDescriptor descriptor = PlaceholderLayerEffectDescriptor.Create(pluginEffect.PluginInfo.Guid); + LayerEffectDescriptor descriptor = PlaceholderLayerEffectDescriptor.Create(pluginEffect.ProviderId); descriptor.CreateInstance(this, entity); } } private void LayerEffectStoreOnLayerEffectAdded(object sender, LayerEffectStoreEvent e) { - if (RenderElementEntity.LayerEffects.Any(ef => ef.PluginGuid == e.Registration.PluginImplementation.PluginInfo.Guid)) + if (RenderElementEntity.LayerEffects.Any(ef => ef.ProviderId == e.Registration.PluginFeature.Id)) ActivateEffects(); } diff --git a/src/Artemis.Core/Models/Profile/Timeline.cs b/src/Artemis.Core/Models/Profile/Timeline.cs index 1f94376d9..f50e7d922 100644 --- a/src/Artemis.Core/Models/Profile/Timeline.cs +++ b/src/Artemis.Core/Models/Profile/Timeline.cs @@ -3,14 +3,13 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Artemis.Storage.Entities.Profile; -using Stylet; namespace Artemis.Core { /// /// Represents a timeline used by profile elements /// - public class Timeline : PropertyChangedBase, IStorageModel + public class Timeline : CorePropertyChanged, IStorageModel { private const int MaxExtraTimelines = 15; @@ -275,20 +274,20 @@ namespace Artemis.Core if (segment <= TimelineSegment.End) { if (startUpdated || segment < TimelineSegment.End) - NotifyOfPropertyChange(nameof(EndSegmentStartPosition)); - NotifyOfPropertyChange(nameof(EndSegmentEndPosition)); + OnPropertyChanged(nameof(EndSegmentStartPosition)); + OnPropertyChanged(nameof(EndSegmentEndPosition)); } if (segment <= TimelineSegment.Main) { if (startUpdated || segment < TimelineSegment.Main) - NotifyOfPropertyChange(nameof(MainSegmentStartPosition)); - NotifyOfPropertyChange(nameof(MainSegmentEndPosition)); + OnPropertyChanged(nameof(MainSegmentStartPosition)); + OnPropertyChanged(nameof(MainSegmentEndPosition)); } - if (segment <= TimelineSegment.Start) NotifyOfPropertyChange(nameof(StartSegmentEndPosition)); + if (segment <= TimelineSegment.Start) OnPropertyChanged(nameof(StartSegmentEndPosition)); - NotifyOfPropertyChange(nameof(Length)); + OnPropertyChanged(nameof(Length)); } #endregion diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs index 6a9982676..adf4e6d20 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs @@ -4,20 +4,19 @@ using System.Linq; using Artemis.Storage.Entities.Surface; using RGB.NET.Core; using SkiaSharp; -using Stylet; namespace Artemis.Core { - public class ArtemisDevice : PropertyChangedBase + public class ArtemisDevice : CorePropertyChanged { private ReadOnlyCollection _leds; private SKPath _renderPath; private SKRect _renderRectangle; - internal ArtemisDevice(IRGBDevice rgbDevice, PluginImplementation pluginImplementation, ArtemisSurface surface) + internal ArtemisDevice(IRGBDevice rgbDevice, PluginFeature pluginFeature, ArtemisSurface surface) { RgbDevice = rgbDevice; - PluginImplementation = pluginImplementation; + PluginFeature = pluginFeature; Surface = surface; DeviceEntity = new DeviceEntity(); Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly(); @@ -30,10 +29,10 @@ namespace Artemis.Core CalculateRenderProperties(); } - internal ArtemisDevice(IRGBDevice rgbDevice, PluginImplementation pluginImplementation, ArtemisSurface surface, DeviceEntity deviceEntity) + internal ArtemisDevice(IRGBDevice rgbDevice, PluginFeature pluginFeature, ArtemisSurface surface, DeviceEntity deviceEntity) { RgbDevice = rgbDevice; - PluginImplementation = pluginImplementation; + PluginFeature = pluginFeature; Surface = surface; DeviceEntity = deviceEntity; Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly(); @@ -52,7 +51,7 @@ namespace Artemis.Core } public IRGBDevice RgbDevice { get; } - public PluginImplementation PluginImplementation { get; } + public PluginFeature PluginFeature { get; } public ArtemisSurface Surface { get; } public DeviceEntity DeviceEntity { get; } @@ -68,7 +67,7 @@ namespace Artemis.Core set { DeviceEntity.X = value; - NotifyOfPropertyChange(nameof(X)); + OnPropertyChanged(nameof(X)); } } @@ -78,7 +77,7 @@ namespace Artemis.Core set { DeviceEntity.Y = value; - NotifyOfPropertyChange(nameof(Y)); + OnPropertyChanged(nameof(Y)); } } @@ -88,7 +87,7 @@ namespace Artemis.Core set { DeviceEntity.Rotation = value; - NotifyOfPropertyChange(nameof(Rotation)); + OnPropertyChanged(nameof(Rotation)); } } @@ -98,7 +97,7 @@ namespace Artemis.Core set { DeviceEntity.Scale = value; - NotifyOfPropertyChange(nameof(Scale)); + OnPropertyChanged(nameof(Scale)); } } @@ -108,7 +107,7 @@ namespace Artemis.Core set { DeviceEntity.ZIndex = value; - NotifyOfPropertyChange(nameof(ZIndex)); + OnPropertyChanged(nameof(ZIndex)); } } diff --git a/src/Artemis.Core/Models/Surface/ArtemisLed.cs b/src/Artemis.Core/Models/Surface/ArtemisLed.cs index d4f8f0546..0c55c356f 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisLed.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisLed.cs @@ -1,10 +1,9 @@ using RGB.NET.Core; using SkiaSharp; -using Stylet; namespace Artemis.Core { - public class ArtemisLed : PropertyChangedBase + public class ArtemisLed : CorePropertyChanged { private SKRect _absoluteRenderRectangle; private SKRect _renderRectangle; diff --git a/src/Artemis.Core/Models/Surface/ArtemisSurface.cs b/src/Artemis.Core/Models/Surface/ArtemisSurface.cs index 7b0a34376..f79040289 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisSurface.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisSurface.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.Linq; using Artemis.Storage.Entities.Surface; using RGB.NET.Core; -using Stylet; namespace Artemis.Core { - public class ArtemisSurface : PropertyChangedBase + public class ArtemisSurface : CorePropertyChanged { private List _devices; private bool _isActive; diff --git a/src/Artemis.Core/Ninject/PluginSettingsProvider.cs b/src/Artemis.Core/Ninject/PluginSettingsProvider.cs index 559fa4087..e2f303ce7 100644 --- a/src/Artemis.Core/Ninject/PluginSettingsProvider.cs +++ b/src/Artemis.Core/Ninject/PluginSettingsProvider.cs @@ -6,6 +6,7 @@ using Ninject.Activation; namespace Artemis.Core.Ninject { + // TODO: Investigate if this can't just be set as a constant on the plugin child kernel internal class PluginSettingsProvider : Provider { private static readonly List PluginSettings = new List(); @@ -25,21 +26,22 @@ namespace Artemis.Core.Ninject throw new ArtemisCoreException("PluginSettings couldn't be injected, failed to get the injection parent request"); // First try by PluginInfo parameter - PluginInfo pluginInfo = parentRequest.Parameters.FirstOrDefault(p => p.Name == "PluginInfo")?.GetValue(context, null) as PluginInfo; - if (pluginInfo == null) - pluginInfo = _pluginManagementService.GetPluginByAssembly(parentRequest.Service.Assembly)?.PluginInfo; + Plugin? plugin = parentRequest.Parameters.FirstOrDefault(p => p.Name == "Plugin")?.GetValue(context, null) as Plugin; // Fall back to assembly based detection - if (pluginInfo == null) + if (plugin == null) + plugin = _pluginManagementService.GetPluginByAssembly(parentRequest.Service.Assembly); + + if (plugin == null) throw new ArtemisCoreException("PluginSettings can only be injected with the PluginInfo parameter provided " + "or into a class defined in a plugin assembly"); lock (PluginSettings) { - PluginSettings? existingSettings = PluginSettings.FirstOrDefault(p => p.PluginInfo == pluginInfo); + PluginSettings? existingSettings = PluginSettings.FirstOrDefault(p => p.Plugin == plugin); if (existingSettings != null) return existingSettings; - PluginSettings? settings = new PluginSettings(pluginInfo, _pluginRepository); + PluginSettings? settings = new PluginSettings(plugin, _pluginRepository); PluginSettings.Add(settings); return settings; } diff --git a/src/Artemis.Core/Ninject/SettingsServiceProvider.cs b/src/Artemis.Core/Ninject/SettingsServiceProvider.cs index f3dcc8e2c..3a1f3efa0 100644 --- a/src/Artemis.Core/Ninject/SettingsServiceProvider.cs +++ b/src/Artemis.Core/Ninject/SettingsServiceProvider.cs @@ -17,7 +17,7 @@ namespace Artemis.Core.Ninject protected override ISettingsService CreateInstance(IContext context) { IRequest parentRequest = context.Request.ParentRequest; - if (parentRequest == null || typeof(PluginImplementation).IsAssignableFrom(parentRequest.Service)) + if (parentRequest == null || typeof(PluginFeature).IsAssignableFrom(parentRequest.Service)) throw new ArtemisPluginException($"SettingsService can not be injected into a plugin. Inject {nameof(PluginSettings)} instead."); return _instance; diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs index 28f3a22cb..dfbd52efd 100644 --- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs +++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs @@ -14,10 +14,10 @@ namespace Artemis.Core.DataModelExpansions private readonly Dictionary _dynamicDataModels = new Dictionary(); /// - /// Gets the plugin implementation this data model belongs to + /// Gets the plugin feature this data model belongs to /// [DataModelIgnore] - public DataModelPluginImplementation Implementation { get; internal set; } + public DataModelPluginFeature Feature { get; internal set; } /// /// Gets the describing this data model @@ -43,9 +43,9 @@ namespace Artemis.Core.DataModelExpansions /// public ReadOnlyCollection GetHiddenProperties() { - if (Implementation is ProfileModule profileModule) + if (Feature is ProfileModule profileModule) return profileModule.HiddenProperties; - if (Implementation is BaseDataModelExpansion dataModelExpansion) + if (Feature is BaseDataModelExpansion dataModelExpansion) return dataModelExpansion.HiddenProperties; return new List().AsReadOnly(); @@ -81,7 +81,7 @@ namespace Artemis.Core.DataModelExpansions throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " + "because the key is already in use by a static property on this data model."); - dynamicDataModel.Implementation = Implementation; + dynamicDataModel.Feature = Feature; dynamicDataModel.DataModelDescription = new DataModelPropertyAttribute { Name = string.IsNullOrWhiteSpace(name) ? key.Humanize() : name, diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs index f4db43abf..eca795b81 100644 --- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs +++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs @@ -45,7 +45,7 @@ namespace Artemis.Core.DataModelExpansions internal override void InternalEnable() { DataModel = Activator.CreateInstance(); - DataModel.Implementation = PluginInfo; + DataModel.Feature = this; DataModel.DataModelDescription = GetDataModelDescription(); base.InternalEnable(); } diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/Internal/BaseDataModelExpansion.cs b/src/Artemis.Core/Plugins/DataModelExpansions/Internal/BaseDataModelExpansion.cs index 3a66789bb..9ab4f034f 100644 --- a/src/Artemis.Core/Plugins/DataModelExpansions/Internal/BaseDataModelExpansion.cs +++ b/src/Artemis.Core/Plugins/DataModelExpansions/Internal/BaseDataModelExpansion.cs @@ -8,7 +8,7 @@ namespace Artemis.Core.DataModelExpansions /// For internal use only, to implement your own layer property type, extend /// instead. /// - public abstract class BaseDataModelExpansion : DataModelPluginImplementation + public abstract class BaseDataModelExpansion : DataModelPluginFeature { /// /// Gets a list of all properties ignored at runtime using IgnoreProperty(x => x.y) @@ -35,7 +35,7 @@ namespace Artemis.Core.DataModelExpansions /// public virtual DataModelPropertyAttribute GetDataModelDescription() { - return new DataModelPropertyAttribute {Name = PluginInfo.Name, Description = PluginInfo.Description}; + return new DataModelPropertyAttribute {Name = Plugin.Info.Name, Description = Plugin.Info.Description}; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/DataModelPluginImplementation.cs b/src/Artemis.Core/Plugins/DataModelPluginFeature.cs similarity index 81% rename from src/Artemis.Core/Plugins/DataModelPluginImplementation.cs rename to src/Artemis.Core/Plugins/DataModelPluginFeature.cs index 243e3f368..83649847a 100644 --- a/src/Artemis.Core/Plugins/DataModelPluginImplementation.cs +++ b/src/Artemis.Core/Plugins/DataModelPluginFeature.cs @@ -4,9 +4,9 @@ using System.Threading.Tasks; namespace Artemis.Core { /// - /// Represents an implementation of a certain type provided by a plugin with support for data models + /// Represents an feature of a certain type provided by a plugin with support for data models /// - public abstract class DataModelPluginImplementation : PluginImplementation + public abstract class DataModelPluginFeature : PluginFeature { /// /// Registers a timed update that whenever the plugin is enabled calls the provided at the @@ -23,11 +23,11 @@ namespace Artemis.Core { if (action == null) throw new ArgumentNullException(nameof(action)); - return new TimedUpdateRegistration(PluginInfo, interval, action); + return new TimedUpdateRegistration(this, interval, action); } /// - /// Registers a timed update that whenever the plugin is enabled calls the provided at the + /// Registers a timed update that whenever the plugin is enabled calls the provided at the /// provided /// /// @@ -41,7 +41,7 @@ namespace Artemis.Core { if (asyncAction == null) throw new ArgumentNullException(nameof(asyncAction)); - return new TimedUpdateRegistration(PluginInfo, interval, asyncAction); + return new TimedUpdateRegistration(this, interval, asyncAction); } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs b/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs index 58edcbd94..c59446c14 100644 --- a/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs +++ b/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs @@ -10,7 +10,7 @@ namespace Artemis.Core.DeviceProviders /// /// Allows you to implement and register your own device provider /// - public abstract class DeviceProvider : PluginImplementation + public abstract class DeviceProvider : PluginFeature { /// /// Creates a new instance of the class @@ -50,9 +50,9 @@ namespace Artemis.Core.DeviceProviders { // Start from the plugin directory if (e.RelativePart != null && e.FileName != null) - e.FinalPath = Path.Combine(PluginInfo.Directory.FullName, e.RelativePart, e.FileName); + e.FinalPath = Path.Combine(Plugin.Directory.FullName, e.RelativePart, e.FileName); else if (e.RelativePath != null) - e.FinalPath = Path.Combine(PluginInfo.Directory.FullName, e.RelativePath); + e.FinalPath = Path.Combine(Plugin.Directory.FullName, e.RelativePath); IRGBDeviceInfo deviceInfo = ((IRGBDevice) sender).DeviceInfo; if (e.FileName != null && !File.Exists(e.FinalPath)) diff --git a/src/Artemis.Core/Plugins/IPluginBootstrapper.cs b/src/Artemis.Core/Plugins/IPluginBootstrapper.cs new file mode 100644 index 000000000..af4b607d7 --- /dev/null +++ b/src/Artemis.Core/Plugins/IPluginBootstrapper.cs @@ -0,0 +1,20 @@ +namespace Artemis.Core +{ + /// + /// An optional entry point for your plugin + /// + public interface IPluginBootstrapper + { + /// + /// Called when the plugin is activated + /// + /// The plugin instance of your plugin + void Enable(Plugin plugin); + + /// + /// Called when the plugin is deactivated or when Artemis shuts down + /// + /// The plugin instance of your plugin + void Disable(Plugin plugin); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/IPluginConfigurationDialog.cs b/src/Artemis.Core/Plugins/IPluginConfigurationDialog.cs new file mode 100644 index 000000000..c76d777ca --- /dev/null +++ b/src/Artemis.Core/Plugins/IPluginConfigurationDialog.cs @@ -0,0 +1,7 @@ +namespace Artemis.Core +{ + public interface IPluginConfigurationDialog + { + + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/IPluginConfigurationViewModel.cs b/src/Artemis.Core/Plugins/IPluginConfigurationViewModel.cs new file mode 100644 index 000000000..f2e711397 --- /dev/null +++ b/src/Artemis.Core/Plugins/IPluginConfigurationViewModel.cs @@ -0,0 +1,10 @@ +namespace Artemis.Core +{ + /// + /// Represents a view model for a plugin configuration window + /// + public interface IPluginConfigurationViewModel + { + + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerBrushes/ILayerBrushConfigurationDialog.cs b/src/Artemis.Core/Plugins/LayerBrushes/ILayerBrushConfigurationDialog.cs new file mode 100644 index 000000000..c0ad0df9d --- /dev/null +++ b/src/Artemis.Core/Plugins/LayerBrushes/ILayerBrushConfigurationDialog.cs @@ -0,0 +1,9 @@ +namespace Artemis.Core.LayerBrushes +{ + /// + /// Represents the configuration dialog of a layer brush + /// + public interface ILayerBrushConfigurationDialog + { + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs index 847d5cd66..fd399e1ad 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs @@ -1,17 +1,15 @@ using System; -using Artemis.Core.Services; using SkiaSharp; -using Stylet; namespace Artemis.Core.LayerBrushes { /// /// For internal use only, please use or or instead /// - public abstract class BaseLayerBrush : PropertyChangedBase, IDisposable + public abstract class BaseLayerBrush : CorePropertyChanged, IDisposable { private LayerBrushType _brushType; - private LayerBrushConfigurationDialog _configurationDialog; + private ILayerBrushConfigurationDialog _configurationDialog; private LayerBrushDescriptor _descriptor; private Layer _layer; private bool _supportsTransformation = true; @@ -37,7 +35,7 @@ namespace Artemis.Core.LayerBrushes /// /// Gets or sets a configuration dialog complementing the regular properties /// - public LayerBrushConfigurationDialog ConfigurationDialog + public ILayerBrushConfigurationDialog ConfigurationDialog { get => _configurationDialog; protected set => SetAndNotify(ref _configurationDialog, value); @@ -53,9 +51,9 @@ namespace Artemis.Core.LayerBrushes } /// - /// Gets the plugin info that defined this brush + /// Gets the ID of the that provided this effect /// - public PluginInfo PluginInfo => Descriptor.LayerBrushProvider.PluginInfo; + public string ProviderId => Descriptor?.Provider?.Id; /// /// Gets a reference to the layer property group without knowing it's type @@ -72,21 +70,11 @@ namespace Artemis.Core.LayerBrushes protected set { if (value && BrushType == LayerBrushType.RgbNet) - throw new ArtemisPluginException(PluginInfo, "An RGB.NET brush cannot support transformation"); + throw new ArtemisPluginFeatureException(Descriptor.Provider, "An RGB.NET brush cannot support transformation"); _supportsTransformation = value; } } - /// - public void Dispose() - { - DisableLayerBrush(); - BaseProperties.Dispose(); - - Dispose(true); - GC.SuppressFinalize(this); - } - /// /// Called when the layer brush is activated /// @@ -112,6 +100,16 @@ namespace Artemis.Core.LayerBrushes internal virtual void Dispose(bool disposing) { } + + /// + public void Dispose() + { + DisableLayerBrush(); + BaseProperties.Dispose(); + + Dispose(true); + GC.SuppressFinalize(this); + } } /// diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs index 88c2d3421..86cac67a7 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs @@ -37,7 +37,7 @@ namespace Artemis.Core.LayerBrushes Properties = Activator.CreateInstance(); Properties.GroupDescription ??= new PropertyGroupDescriptionAttribute {Name = Descriptor.DisplayName, Description = Descriptor.Description}; Properties.LayerBrush = this; - Properties.Initialize(Layer, "LayerBrush.", PluginInfo); + Properties.Initialize(Layer, "LayerBrush.", Descriptor.Provider); PropertiesInitialized = true; EnableLayerBrush(); diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs index b319ed448..4b1da7753 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs @@ -1,5 +1,4 @@ using System; -using Artemis.Core.Services; using Ninject; namespace Artemis.Core.LayerBrushes @@ -9,13 +8,13 @@ namespace Artemis.Core.LayerBrushes /// public class LayerBrushDescriptor { - internal LayerBrushDescriptor(string displayName, string description, string icon, Type layerBrushType, LayerBrushProvider layerBrushProvider) + internal LayerBrushDescriptor(string displayName, string description, string icon, Type layerBrushType, LayerBrushProvider provider) { DisplayName = displayName; Description = description; Icon = icon; LayerBrushType = layerBrushType; - LayerBrushProvider = layerBrushProvider; + Provider = provider; } /// @@ -42,7 +41,7 @@ namespace Artemis.Core.LayerBrushes /// /// The plugin that provided this /// - public LayerBrushProvider LayerBrushProvider { get; } + public LayerBrushProvider Provider { get; } /// /// Determines whether the provided references to a brush provided by this descriptor @@ -51,7 +50,8 @@ namespace Artemis.Core.LayerBrushes { if (reference == null) return false; - return LayerBrushProvider.PluginInfo.Guid == reference.BrushPluginGuid && LayerBrushType.Name == reference.BrushType; + + return Provider.Id == reference.LayerBrushProviderId && LayerBrushType.Name == reference.BrushType; } /// @@ -62,7 +62,7 @@ namespace Artemis.Core.LayerBrushes if (layer.LayerBrush != null) throw new ArtemisCoreException("Layer already has an instantiated layer brush"); - BaseLayerBrush brush = (BaseLayerBrush) LayerBrushProvider.PluginInfo.Kernel.Get(LayerBrushType); + BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Kernel!.Get(LayerBrushType); brush.Layer = layer; brush.Descriptor = this; brush.Initialize(); diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs index 961873045..a828c8d25 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushProvider.cs @@ -7,7 +7,7 @@ namespace Artemis.Core.LayerBrushes /// /// Allows you to create one or more s usable by profile layers. /// - public abstract class LayerBrushProvider : PluginImplementation + public abstract class LayerBrushProvider : PluginFeature { private readonly List _layerBrushDescriptors; @@ -39,7 +39,7 @@ namespace Artemis.Core.LayerBrushes protected void RegisterLayerBrushDescriptor(string displayName, string description, string icon) where T : BaseLayerBrush { if (!IsEnabled) - throw new ArtemisPluginException(PluginInfo, "Can only add a layer brush descriptor when the plugin is enabled"); + throw new ArtemisPluginException(Plugin, "Can only add a layer brush descriptor when the plugin is enabled"); LayerBrushDescriptor descriptor = new LayerBrushDescriptor(displayName, description, icon, typeof(T), this); _layerBrushDescriptors.Add(descriptor); diff --git a/src/Artemis.Core/Plugins/LayerEffects/IEffectConfigurationViewModel.cs b/src/Artemis.Core/Plugins/LayerEffects/IEffectConfigurationViewModel.cs new file mode 100644 index 000000000..33aa630e9 --- /dev/null +++ b/src/Artemis.Core/Plugins/LayerEffects/IEffectConfigurationViewModel.cs @@ -0,0 +1,6 @@ +namespace Artemis.Core.LayerEffects +{ + public interface IEffectConfigurationViewModel + { + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerEffects/ILayerEffectConfigurationDialog.cs b/src/Artemis.Core/Plugins/LayerEffects/ILayerEffectConfigurationDialog.cs new file mode 100644 index 000000000..bafe13a1d --- /dev/null +++ b/src/Artemis.Core/Plugins/LayerEffects/ILayerEffectConfigurationDialog.cs @@ -0,0 +1,6 @@ +namespace Artemis.Core.LayerEffects +{ + public interface ILayerEffectConfigurationDialog + { + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs index 7e5778301..126a1e700 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/Internal/BaseLayerEffect.cs @@ -1,16 +1,15 @@ using System; using Artemis.Core.Services; using SkiaSharp; -using Stylet; namespace Artemis.Core.LayerEffects { /// /// For internal use only, please use instead /// - public abstract class BaseLayerEffect : PropertyChangedBase, IDisposable + public abstract class BaseLayerEffect : CorePropertyChanged, IDisposable { - private LayerEffectConfigurationDialog _configurationDialog; + private ILayerEffectConfigurationDialog _configurationDialog; private LayerEffectDescriptor _descriptor; private bool _enabled; private Guid _entityId; @@ -77,7 +76,7 @@ namespace Artemis.Core.LayerEffects /// /// Gets the that registered this effect /// - public LayerEffectDescriptor Descriptor + public LayerEffectDescriptor? Descriptor { get => _descriptor; internal set => SetAndNotify(ref _descriptor, value); @@ -86,16 +85,16 @@ namespace Artemis.Core.LayerEffects /// /// Gets or sets a configuration dialog complementing the regular properties /// - public LayerEffectConfigurationDialog ConfigurationDialog + public ILayerEffectConfigurationDialog ConfigurationDialog { get => _configurationDialog; protected set => SetAndNotify(ref _configurationDialog, value); } /// - /// Gets the plugin info that defined this effect + /// Gets the ID of the that provided this effect /// - public PluginInfo PluginInfo => Descriptor.LayerEffectProvider?.PluginInfo; + public string ProviderId => Descriptor?.Provider?.Id; /// /// Gets a reference to the layer property group without knowing it's type diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs index 180e5b1a5..75bcce09e 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffect.cs @@ -37,7 +37,7 @@ namespace Artemis.Core.LayerEffects { Properties = Activator.CreateInstance(); Properties.LayerEffect = this; - Properties.Initialize(ProfileElement, PropertyRootPath, PluginInfo); + Properties.Initialize(ProfileElement, PropertyRootPath, Descriptor.Provider); PropertiesInitialized = true; EnableLayerEffect(); diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs index 97f27da49..33fafb542 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using Artemis.Core.LayerEffects.Placeholder; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; using Ninject; @@ -12,13 +11,13 @@ namespace Artemis.Core.LayerEffects /// public class LayerEffectDescriptor { - internal LayerEffectDescriptor(string displayName, string description, string icon, Type layerEffectType, LayerEffectProvider layerEffectProvider) + internal LayerEffectDescriptor(string displayName, string description, string icon, Type layerEffectType, LayerEffectProvider provider) { DisplayName = displayName; Description = description; Icon = icon; LayerEffectType = layerEffectType; - LayerEffectProvider = layerEffectProvider; + Provider = provider; } /// @@ -45,12 +44,12 @@ namespace Artemis.Core.LayerEffects /// /// The plugin that provided this /// - public LayerEffectProvider LayerEffectProvider { get; } + public LayerEffectProvider? Provider { get; } /// /// Gets the GUID this descriptor is acting as a placeholder for. If null, this descriptor is not a placeholder /// - public Guid? PlaceholderFor { get; internal set; } + public string? PlaceholderFor { get; internal set; } /// /// Creates an instance of the described effect and applies it to the render element @@ -67,7 +66,10 @@ namespace Artemis.Core.LayerEffects return; } - BaseLayerEffect effect = (BaseLayerEffect) LayerEffectProvider.PluginInfo.Kernel.Get(LayerEffectType); + if (Provider == null) + throw new ArtemisCoreException("Cannot create an instance of a layer effect because this descriptor is not a placeholder but is still missing its provider"); + + BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Kernel!.Get(LayerEffectType); effect.ProfileElement = renderElement; effect.EntityId = entity.Id; effect.Order = entity.Order; @@ -83,7 +85,7 @@ namespace Artemis.Core.LayerEffects private void CreatePlaceHolderInstance(RenderProfileElement renderElement, LayerEffectEntity entity) { - PlaceholderLayerEffect effect = new PlaceholderLayerEffect(entity, PlaceholderFor.Value) {ProfileElement = renderElement, Descriptor = this}; + PlaceholderLayerEffect effect = new PlaceholderLayerEffect(entity, PlaceholderFor) {ProfileElement = renderElement, Descriptor = this}; effect.Initialize(); renderElement.ActivateLayerEffect(effect); } diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs index 4f60aeac1..b6b68df7a 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectProvider.cs @@ -7,7 +7,7 @@ namespace Artemis.Core.LayerEffects /// /// Allows you to register one or more s usable by profile layers. /// - public abstract class LayerEffectProvider : PluginImplementation + public abstract class LayerEffectProvider : PluginFeature { private readonly List _layerEffectDescriptors; @@ -39,7 +39,7 @@ namespace Artemis.Core.LayerEffects protected void RegisterLayerEffectDescriptor(string displayName, string description, string icon) where T : BaseLayerEffect { if (!IsEnabled) - throw new ArtemisPluginException(PluginInfo, "Can only add a layer effect descriptor when the plugin is enabled"); + throw new ArtemisPluginFeatureException(this, "Can only add a layer effect descriptor when the plugin is enabled"); LayerEffectDescriptor descriptor = new LayerEffectDescriptor(displayName, description, icon, typeof(T), this); _layerEffectDescriptors.Add(descriptor); diff --git a/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffect.cs index 6447679d0..620425a62 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffect.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffect.cs @@ -1,5 +1,4 @@ -using System; -using Artemis.Storage.Entities.Profile; +using Artemis.Storage.Entities.Profile; using SkiaSharp; namespace Artemis.Core.LayerEffects.Placeholder @@ -9,7 +8,7 @@ namespace Artemis.Core.LayerEffects.Placeholder /// internal class PlaceholderLayerEffect : LayerEffect { - internal PlaceholderLayerEffect(LayerEffectEntity originalEntity, Guid placeholderFor) + internal PlaceholderLayerEffect(LayerEffectEntity originalEntity, string placeholderFor) { OriginalEntity = originalEntity; PlaceholderFor = placeholderFor; @@ -21,8 +20,9 @@ namespace Artemis.Core.LayerEffects.Placeholder HasBeenRenamed = OriginalEntity.HasBeenRenamed; } + public string PlaceholderFor { get; } + internal LayerEffectEntity OriginalEntity { get; } - public Guid PlaceholderFor { get; } /// public override void EnableLayerEffect() @@ -56,7 +56,7 @@ namespace Artemis.Core.LayerEffects.Placeholder } /// - /// This is in place so that the UI has something to show + /// This is in place so that the UI has something to show /// internal class PlaceholderProperties : LayerPropertyGroup { diff --git a/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffectDescriptor.cs b/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffectDescriptor.cs index eec2835fb..762c187d6 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffectDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/Placeholder/PlaceholderLayerEffectDescriptor.cs @@ -1,14 +1,12 @@ -using System; - -namespace Artemis.Core.LayerEffects.Placeholder +namespace Artemis.Core.LayerEffects.Placeholder { internal static class PlaceholderLayerEffectDescriptor { - public static LayerEffectDescriptor Create(Guid missingPluginGuid) + public static LayerEffectDescriptor Create(string missingProviderId) { LayerEffectDescriptor descriptor = new LayerEffectDescriptor("Missing effect", "This effect could not be loaded", "FileQuestion", null, Constants.EffectPlaceholderPlugin) { - PlaceholderFor = missingPluginGuid + PlaceholderFor = missingProviderId }; return descriptor; diff --git a/src/Artemis.Core/Plugins/Modules/IModuleViewModel.cs b/src/Artemis.Core/Plugins/Modules/IModuleViewModel.cs new file mode 100644 index 000000000..861336edc --- /dev/null +++ b/src/Artemis.Core/Plugins/Modules/IModuleViewModel.cs @@ -0,0 +1,10 @@ +namespace Artemis.Core.Modules +{ + /// + /// The base class for any view model that belongs to a module + /// + public interface IModuleViewModel + { + + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Modules/Module.cs b/src/Artemis.Core/Plugins/Modules/Module.cs index 1d6364287..8c3c3ee45 100644 --- a/src/Artemis.Core/Plugins/Modules/Module.cs +++ b/src/Artemis.Core/Plugins/Modules/Module.cs @@ -42,13 +42,13 @@ namespace Artemis.Core.Modules /// public virtual DataModelPropertyAttribute GetDataModelDescription() { - return new DataModelPropertyAttribute {Name = PluginInfo.Name, Description = PluginInfo.Description}; + return new DataModelPropertyAttribute {Name = Plugin.Info.Name, Description = Plugin.Info.Description}; } internal override void InternalEnable() { DataModel = Activator.CreateInstance(); - DataModel.Implementation = PluginInfo; + DataModel.Feature = this; DataModel.DataModelDescription = GetDataModelDescription(); base.InternalEnable(); } @@ -64,7 +64,7 @@ namespace Artemis.Core.Modules /// /// Allows you to add support for new games/applications /// - public abstract class Module : DataModelPluginImplementation + public abstract class Module : DataModelPluginFeature { /// /// The modules display name that's shown in the menu @@ -236,7 +236,7 @@ namespace Artemis.Core.Modules if (Entity == null) Entity = new ModuleSettingsEntity(); - Entity.PluginGuid = PluginInfo.Guid; + Entity.ModuleId = Id; Entity.PriorityCategory = (int) PriorityCategory; Entity.Priority = Priority; } diff --git a/src/Artemis.Core/Plugins/Modules/ModuleTab.cs b/src/Artemis.Core/Plugins/Modules/ModuleTab.cs index 7c868b8bd..1c017964c 100644 --- a/src/Artemis.Core/Plugins/Modules/ModuleTab.cs +++ b/src/Artemis.Core/Plugins/Modules/ModuleTab.cs @@ -3,7 +3,7 @@ namespace Artemis.Core.Modules { /// - public class ModuleTab : ModuleTab where T : ModuleViewModel + public class ModuleTab : ModuleTab where T : IModuleViewModel { /// /// Initializes a new instance of the class diff --git a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs index 8657314fb..90e04a005 100644 --- a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs +++ b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs @@ -46,7 +46,7 @@ namespace Artemis.Core.Modules /// public virtual DataModelPropertyAttribute GetDataModelDescription() { - return new DataModelPropertyAttribute {Name = PluginInfo.Name, Description = PluginInfo.Description}; + return new DataModelPropertyAttribute {Name = Plugin.Info.Name, Description = Plugin.Info.Description}; } /// @@ -74,7 +74,7 @@ namespace Artemis.Core.Modules internal override void InternalEnable() { DataModel = Activator.CreateInstance(); - DataModel.Implementation = PluginInfo; + DataModel.Feature = this; DataModel.DataModelDescription = GetDataModelDescription(); base.InternalEnable(); } @@ -184,7 +184,7 @@ namespace Artemis.Core.Modules internal async Task ChangeActiveProfileAnimated(Profile profile, ArtemisSurface surface) { if (profile != null && profile.Module != this) - throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {PluginInfo}."); + throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {this}."); if (!IsActivated) throw new ArtemisCoreException("Cannot activate a profile on a deactivated module"); @@ -206,7 +206,7 @@ namespace Artemis.Core.Modules internal void ChangeActiveProfile(Profile profile, ArtemisSurface surface) { if (profile != null && profile.Module != this) - throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {PluginInfo}."); + throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {this}."); if (!IsActivated) throw new ArtemisCoreException("Cannot activate a profile on a deactivated module"); diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs index ec42bcdeb..481fa80f0 100644 --- a/src/Artemis.Core/Plugins/Plugin.cs +++ b/src/Artemis.Core/Plugins/Plugin.cs @@ -7,16 +7,15 @@ using System.Reflection; using Artemis.Storage.Entities.Plugins; using McMaster.NETCore.Plugins; using Ninject; -using Stylet; namespace Artemis.Core { /// /// Represents a plugin /// - public class Plugin : PropertyChangedBase, IDisposable + public class Plugin : CorePropertyChanged, IDisposable { - private readonly List _implementations; + private readonly List _features; private bool _isEnabled; @@ -25,7 +24,7 @@ namespace Artemis.Core Info = info; Directory = directory; - _implementations = new List(); + _features = new List(); } /// @@ -46,8 +45,8 @@ namespace Artemis.Core /// /// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins /// - public PluginConfigurationDialog? ConfigurationDialog { get; protected set; } - + public IPluginConfigurationDialog? ConfigurationDialog { get; set; } + /// /// Indicates whether the user enabled the plugin or not /// @@ -58,19 +57,24 @@ namespace Artemis.Core } /// - /// Gets a read-only collection of all implementations this plugin provides + /// Gets a read-only collection of all features this plugin provides /// - public ReadOnlyCollection Implementations => _implementations.AsReadOnly(); + public ReadOnlyCollection Features => _features.AsReadOnly(); /// /// The assembly the plugin code lives in /// - internal Assembly? Assembly { get; set; } + public Assembly? Assembly { get; internal set; } + + /// + /// Gets the plugin bootstrapper + /// + public IPluginBootstrapper? Bootstrapper { get; internal set; } /// /// The Ninject kernel of the plugin /// - internal IKernel? Kernel { get; set; } + public IKernel? Kernel { get; internal set; } /// /// The PluginLoader backing this plugin @@ -80,7 +84,7 @@ namespace Artemis.Core /// /// The entity representing the plugin /// - internal PluginEntity? Entity { get; set; } + internal PluginEntity Entity { get; set; } /// /// Resolves the relative path provided in the parameter to an absolute path @@ -92,25 +96,15 @@ namespace Artemis.Core return path == null ? null : Path.Combine(Directory.FullName, path); } - internal void ApplyToEntity() + /// + /// Looks up the instance of the feature of type + /// Note: This method only returns instances of enabled features + /// + /// The type of feature to find + /// If found, the instance of the feature + public T? GetFeature() where T : PluginFeature { - Entity.Id = Guid; - Entity.IsEnabled = IsEnabled; - } - - internal void AddImplementation(PluginImplementation implementation) - { - implementation.Plugin = this; - _implementations.Add(implementation); - } - - public void SetEnabled(bool enable) - { - if (IsEnabled == enable) - return; - - if (!enable && Implementations.Any(e => e.IsEnabled)) - throw new ArtemisCoreException("Cannot disable this plugin because it still has enabled implementations"); + return _features.FirstOrDefault(i => i is T) as T; } /// @@ -119,13 +113,118 @@ namespace Artemis.Core return Info.ToString(); } + internal void ApplyToEntity() + { + Entity.Id = Guid; + Entity.IsEnabled = IsEnabled; + } + + internal void AddFeature(PluginFeature feature) + { + feature.Plugin = this; + _features.Add(feature); + + OnFeatureAdded(new PluginFeatureEventArgs(feature)); + } + + internal void RemoveFeature(PluginFeature feature) + { + _features.Remove(feature); + feature.InternalDisable(); + feature.Dispose(); + + OnFeatureRemoved(new PluginFeatureEventArgs(feature)); + } + + + internal void SetEnabled(bool enable) + { + if (IsEnabled == enable) + return; + + if (!enable && Features.Any(e => e.IsEnabled)) + throw new ArtemisCoreException("Cannot disable this plugin because it still has enabled features"); + + IsEnabled = enable; + + if (enable) + { + Bootstrapper?.Enable(this); + OnEnabled(); + } + else + { + Bootstrapper?.Disable(this); + OnDisabled(); + } + } + public void Dispose() { - foreach (PluginImplementation pluginImplementation in Implementations) - pluginImplementation.Dispose(); + foreach (PluginFeature feature in Features) + feature.Dispose(); Kernel?.Dispose(); PluginLoader?.Dispose(); + + _features.Clear(); + SetEnabled(false); } + + #region Events + + /// + /// Occurs when the plugin is enabled + /// + public event EventHandler? Enabled; + + /// + /// Occurs when the plugin is disabled + /// + public event EventHandler? Disabled; + + /// + /// Occurs when an feature is loaded and added to the plugin + /// + public event EventHandler? FeatureAdded; + + /// + /// Occurs when an feature is disabled and removed from the plugin + /// + public event EventHandler? FeatureRemoved; + + /// + /// Invokes the Enabled event + /// + protected virtual void OnEnabled() + { + Enabled?.Invoke(this, EventArgs.Empty); + } + + /// + /// Invokes the Disabled event + /// + protected virtual void OnDisabled() + { + Disabled?.Invoke(this, EventArgs.Empty); + } + + /// + /// Invokes the FeatureAdded event + /// + protected virtual void OnFeatureAdded(PluginFeatureEventArgs e) + { + FeatureAdded?.Invoke(this, e); + } + + /// + /// Invokes the FeatureRemoved event + /// + protected virtual void OnFeatureRemoved(PluginFeatureEventArgs e) + { + FeatureRemoved?.Invoke(this, e); + } + + #endregion } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/PluginImplementation.cs b/src/Artemis.Core/Plugins/PluginFeature.cs similarity index 76% rename from src/Artemis.Core/Plugins/PluginImplementation.cs rename to src/Artemis.Core/Plugins/PluginFeature.cs index 2b3524326..0b3f4a152 100644 --- a/src/Artemis.Core/Plugins/PluginImplementation.cs +++ b/src/Artemis.Core/Plugins/PluginFeature.cs @@ -1,24 +1,22 @@ using System; using System.IO; -using System.Threading; using System.Threading.Tasks; using Artemis.Storage.Entities.Plugins; -using Stylet; namespace Artemis.Core { /// - /// Represents an implementation of a certain type provided by a plugin + /// Represents an feature of a certain type provided by a plugin /// - public abstract class PluginImplementation : PropertyChangedBase, IDisposable + public abstract class PluginFeature : CorePropertyChanged, IDisposable { - private Exception? _loadException; private bool _isEnabled; + private Exception? _loadException; /// - /// Gets the plugin that provides this implementation + /// Gets the plugin that provides this feature /// - public Plugin? Plugin { get; internal set; } + public Plugin Plugin { get; internal set; } /// /// Gets whether the plugin is enabled @@ -38,15 +36,20 @@ namespace Artemis.Core internal set => SetAndNotify(ref _loadException, value); } - internal PluginImplementationEntity? Entity { get; set; } + /// + /// Gets the identifier of this plugin feature + /// + public string Id => $"{GetType().FullName}-{Plugin.Guid.ToString().Substring(0, 8)}"; // Not as unique as a GUID but good enough and stays readable + + internal PluginFeatureEntity Entity { get; set; } /// - /// Called when the implementation is activated + /// Called when the feature is activated /// public abstract void Enable(); /// - /// Called when the implementation is deactivated or when Artemis shuts down + /// Called when the feature is deactivated or when Artemis shuts down /// public abstract void Disable(); @@ -56,12 +59,12 @@ namespace Artemis.Core return; if (Plugin == null) - throw new ArtemisCoreException("Cannot enable a plugin implementation that is not associated with a plugin"); + throw new ArtemisCoreException("Cannot enable a plugin feature that is not associated with a plugin"); lock (Plugin) { if (!Plugin.IsEnabled) - throw new ArtemisCoreException("Cannot enable a plugin implementation of a disabled plugin"); + throw new ArtemisCoreException("Cannot enable a plugin feature of a disabled plugin"); if (!enable) { @@ -72,7 +75,7 @@ namespace Artemis.Core OnDisabled(); return; } - + try { if (isAutoEnable && GetLockFileCreated()) @@ -89,19 +92,10 @@ namespace Artemis.Core // Allow up to 15 seconds for plugins to activate. // This means plugins that need more time should do their long running tasks in a background thread, which is intentional - ManualResetEvent wait = new ManualResetEvent(false); - Thread work = new Thread(() => - { - InternalEnable(); - wait.Set(); - }); - work.Start(); - wait.WaitOne(TimeSpan.FromSeconds(15)); - if (work.IsAlive) - { - work.Abort(); + // This would've been a perfect match for Thread.Abort but that didn't make it into .NET Core + Task enableTask = Task.Run(InternalEnable); + if (!enableTask.Wait(TimeSpan.FromSeconds(15))) throw new ArtemisPluginException(Plugin, "Plugin load timeout"); - } LoadException = null; OnEnabled(); @@ -144,7 +138,7 @@ namespace Artemis.Core internal void CreateLockFile() { if (Plugin == null) - throw new ArtemisCoreException("Cannot lock a plugin implementation that is not associated with a plugin"); + throw new ArtemisCoreException("Cannot lock a plugin feature that is not associated with a plugin"); File.Create(Plugin.ResolveRelativePath($"{GetType().FullName}.lock")).Close(); } @@ -152,7 +146,7 @@ namespace Artemis.Core internal void DeleteLockFile() { if (Plugin == null) - throw new ArtemisCoreException("Cannot lock a plugin implementation that is not associated with a plugin"); + throw new ArtemisCoreException("Cannot lock a plugin feature that is not associated with a plugin"); if (GetLockFileCreated()) File.Delete(Plugin.ResolveRelativePath($"{GetType().FullName}.lock")); @@ -161,7 +155,7 @@ namespace Artemis.Core internal bool GetLockFileCreated() { if (Plugin == null) - throw new ArtemisCoreException("Cannot lock a plugin implementation that is not associated with a plugin"); + throw new ArtemisCoreException("Cannot lock a plugin feature that is not associated with a plugin"); return File.Exists(Plugin.ResolveRelativePath($"{GetType().FullName}.lock")); } @@ -171,17 +165,17 @@ namespace Artemis.Core #region Events /// - /// Occurs when the implementation is enabled + /// Occurs when the feature is enabled /// public event EventHandler? Enabled; /// - /// Occurs when the implementation is disabled + /// Occurs when the feature is disabled /// public event EventHandler? Disabled; /// - /// Triggers the PluginEnabled event + /// Triggers the Enabled event /// protected virtual void OnEnabled() { @@ -189,7 +183,7 @@ namespace Artemis.Core } /// - /// Triggers the PluginDisabled event + /// Triggers the Disabled event /// protected virtual void OnDisabled() { diff --git a/src/Artemis.Core/Plugins/PluginInfo.cs b/src/Artemis.Core/Plugins/PluginInfo.cs index def8d63cf..26a3b7e1f 100644 --- a/src/Artemis.Core/Plugins/PluginInfo.cs +++ b/src/Artemis.Core/Plugins/PluginInfo.cs @@ -1,6 +1,5 @@ using System; using Newtonsoft.Json; -using Stylet; namespace Artemis.Core { @@ -8,7 +7,7 @@ namespace Artemis.Core /// Represents basic info about a plugin and contains a reference to the instance of said plugin /// [JsonObject(MemberSerialization.OptIn)] - public class PluginInfo : PropertyChangedBase + public class PluginInfo : CorePropertyChanged { private string _description; private Guid _guid; diff --git a/src/Artemis.Core/Plugins/Settings/PluginSetting.cs b/src/Artemis.Core/Plugins/Settings/PluginSetting.cs index f3b068f83..d8738dd70 100644 --- a/src/Artemis.Core/Plugins/Settings/PluginSetting.cs +++ b/src/Artemis.Core/Plugins/Settings/PluginSetting.cs @@ -2,7 +2,6 @@ using Artemis.Storage.Entities.Plugins; using Artemis.Storage.Repositories.Interfaces; using Newtonsoft.Json; -using Stylet; namespace Artemis.Core { @@ -10,17 +9,18 @@ namespace Artemis.Core /// Represents a setting tied to a plugin of type /// /// The value type of the setting - public class PluginSetting : PropertyChangedBase + public class PluginSetting : CorePropertyChanged { - // ReSharper disable once NotAccessedField.Local - private readonly PluginInfo _pluginInfo; + // TODO: Why? Should have included that... + // ReSharper disable once NotAccessedField.Local + private readonly Plugin _plugin; private readonly IPluginRepository _pluginRepository; private readonly PluginSettingEntity _pluginSettingEntity; private T _value; - internal PluginSetting(PluginInfo pluginInfo, IPluginRepository pluginRepository, PluginSettingEntity pluginSettingEntity) + internal PluginSetting(Plugin plugin, IPluginRepository pluginRepository, PluginSettingEntity pluginSettingEntity) { - _pluginInfo = pluginInfo; + _plugin = plugin; _pluginRepository = pluginRepository; _pluginSettingEntity = pluginSettingEntity; @@ -52,7 +52,7 @@ namespace Artemis.Core _value = value; OnSettingChanged(); - NotifyOfPropertyChange(nameof(Value)); + OnPropertyChanged(nameof(Value)); if (AutoSave) Save(); diff --git a/src/Artemis.Core/Plugins/Settings/PluginSettings.cs b/src/Artemis.Core/Plugins/Settings/PluginSettings.cs index f47f50a68..65a176e2c 100644 --- a/src/Artemis.Core/Plugins/Settings/PluginSettings.cs +++ b/src/Artemis.Core/Plugins/Settings/PluginSettings.cs @@ -14,17 +14,17 @@ namespace Artemis.Core private readonly IPluginRepository _pluginRepository; private readonly Dictionary _settingEntities; - internal PluginSettings(PluginInfo pluginInfo, IPluginRepository pluginRepository) + internal PluginSettings(Plugin plugin, IPluginRepository pluginRepository) { - PluginInfo = pluginInfo; + Plugin = plugin; _pluginRepository = pluginRepository; _settingEntities = new Dictionary(); } /// - /// Gets the info of the plugin this setting belongs to + /// Gets the plugin these settings belong to /// - public PluginInfo PluginInfo { get; } + public Plugin Plugin { get; } /// /// Gets the setting with the provided name. If the setting does not exist yet, it is created. @@ -41,15 +41,15 @@ namespace Artemis.Core if (_settingEntities.ContainsKey(name)) return (PluginSetting) _settingEntities[name]; // Try to find in database - PluginSettingEntity settingEntity = _pluginRepository.GetSettingByNameAndGuid(name, PluginInfo.Guid); + PluginSettingEntity settingEntity = _pluginRepository.GetSettingByNameAndGuid(name, Plugin.Guid); // If not found, create a new one if (settingEntity == null) { - settingEntity = new PluginSettingEntity {Name = name, PluginGuid = PluginInfo.Guid, Value = JsonConvert.SerializeObject(defaultValue)}; + settingEntity = new PluginSettingEntity {Name = name, PluginGuid = Plugin.Guid, Value = JsonConvert.SerializeObject(defaultValue)}; _pluginRepository.AddSetting(settingEntity); } - PluginSetting pluginSetting = new PluginSetting(PluginInfo, _pluginRepository, settingEntity); + PluginSetting pluginSetting = new PluginSetting(Plugin, _pluginRepository, settingEntity); // This overrides null with the default value, I'm not sure if that's desirable because you // might expect something to go null and you might not diff --git a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs index fd9bceea8..2b5720296 100644 --- a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs +++ b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs @@ -8,40 +8,41 @@ namespace Artemis.Core /// /// Represents a registration for a timed plugin update /// - public class TimedUpdateRegistration + public class TimedUpdateRegistration : IDisposable { private DateTime _lastEvent; private Timer _timer; + private bool _disposed; - internal TimedUpdateRegistration(PluginInfo pluginInfo, TimeSpan interval, Action action) + internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Action action) { - PluginInfo = pluginInfo; + Feature = feature; Interval = interval; Action = action; - PluginInfo.Plugin.Enabled += InstanceOnEnabled; - PluginInfo.Plugin.Disabled += InstanceOnDisabled; - if (PluginInfo.Plugin.IsEnabled) + Feature.Enabled += FeatureOnEnabled; + Feature.Disabled += FeatureOnDisabled; + if (Feature.IsEnabled) Start(); } - internal TimedUpdateRegistration(PluginInfo pluginInfo, TimeSpan interval, Func asyncAction) + internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Func asyncAction) { - PluginInfo = pluginInfo; + Feature = feature; Interval = interval; AsyncAction = asyncAction; - - PluginInfo.Plugin.Enabled += InstanceOnEnabled; - PluginInfo.Plugin.Disabled += InstanceOnDisabled; - if (PluginInfo.Plugin.IsEnabled) + + Feature.Enabled += FeatureOnEnabled; + Feature.Disabled += FeatureOnDisabled; + if (Feature.IsEnabled) Start(); } /// - /// Gets the plugin info of the plugin this registration is associated with + /// Gets the plugin feature this registration is associated with /// - public PluginInfo PluginInfo { get; } + public PluginFeature Feature { get; } /// /// Gets the interval at which the update should occur @@ -64,10 +65,13 @@ namespace Artemis.Core /// public void Start() { + if (_disposed) + throw new ObjectDisposedException("TimedUpdateRegistration"); + lock (this) { - if (!PluginInfo.Plugin.IsEnabled) - throw new ArtemisPluginException("Cannot start a timed update for a disabled plugin"); + if (!Feature.IsEnabled) + throw new ArtemisPluginException("Cannot start a timed update for a disabled plugin feature"); if (_timer != null) return; @@ -85,6 +89,9 @@ namespace Artemis.Core /// public void Stop() { + if (_disposed) + throw new ObjectDisposedException("TimedUpdateRegistration"); + lock (this) { if (_timer == null) @@ -99,7 +106,7 @@ namespace Artemis.Core private void TimerOnElapsed(object sender, ElapsedEventArgs e) { - if (!PluginInfo.Plugin.IsEnabled) + if (!Feature.IsEnabled) return; lock (this) @@ -108,7 +115,7 @@ namespace Artemis.Core _lastEvent = DateTime.Now; // Modules don't always want to update, honor that - if (PluginInfo.Plugin is Module module && !module.IsUpdateAllowed) + if (Feature is Module module && !module.IsUpdateAllowed) return; if (Action != null) @@ -121,14 +128,25 @@ namespace Artemis.Core } } - private void InstanceOnEnabled(object sender, EventArgs e) + private void FeatureOnEnabled(object sender, EventArgs e) { Start(); } - private void InstanceOnDisabled(object sender, EventArgs e) + private void FeatureOnDisabled(object sender, EventArgs e) { Stop(); } + + /// + public void Dispose() + { + Stop(); + + Feature.Enabled -= FeatureOnEnabled; + Feature.Disabled -= FeatureOnDisabled; + + _disposed = true; + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 7189d6b98..4bb6ce3e3 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -40,7 +40,7 @@ namespace Artemis.Core.Services IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService, IModuleService moduleService) { Kernel = kernel; - Constants.CorePluginInfo.Kernel = kernel; + Constants.CorePlugin.Kernel = kernel; _logger = logger; _pluginManagementService = pluginManagementService; @@ -133,8 +133,8 @@ namespace Artemis.Core.Services private void UpdatePluginCache() { - _modules = _pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); - _dataModelExpansions = _pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); + _modules = _pluginManagementService.GetFeaturesOfType().Where(p => p.IsEnabled).ToList(); + _dataModelExpansions = _pluginManagementService.GetFeaturesOfType().Where(p => p.IsEnabled).ToList(); } private void ConfigureJsonConvert() diff --git a/src/Artemis.Core/Services/Interfaces/IPluginService.cs b/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs similarity index 56% rename from src/Artemis.Core/Services/Interfaces/IPluginService.cs rename to src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs index acbb28b61..233da594f 100644 --- a/src/Artemis.Core/Services/Interfaces/IPluginService.cs +++ b/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection; +using Artemis.Core.DeviceProviders; using RGB.NET.Core; namespace Artemis.Core.Services @@ -33,69 +34,77 @@ namespace Artemis.Core.Services void UnloadPlugins(); /// - /// Loads the plugin defined in the provided + /// Loads the plugin located in the provided /// - /// The plugin info defining the plugin to load - void LoadPlugin(DirectoryInfo pluginInfo); + /// The directory where the plugin is located + Plugin LoadPlugin(DirectoryInfo directory); /// - /// Unloads the plugin defined in the provided + /// Enables the provided /// - /// The plugin info defining the plugin to unload - void UnloadPlugin(PluginInfo pluginInfo); + /// The plugin to enable + void EnablePlugin(Plugin plugin, bool ignorePluginLock = false); /// - /// Enables the provided plugin + /// Unloads the provided /// - /// + /// The plugin to unload + void UnloadPlugin(Plugin plugin); + + /// + /// Disables the provided + /// + /// The plugin to disable + void DisablePlugin(Plugin plugin); + + /// + /// Enables the provided plugin feature + /// + /// /// If true, fails if there is a lock file present - void EnablePluginImplementation(PluginImplementation pluginImplementation, bool isAutoEnable = false); + void EnablePluginFeature(PluginFeature pluginFeature, bool isAutoEnable = false); /// - /// Disables the provided plugin + /// Disables the provided plugin feature /// - /// - void DisablePluginImplementation(PluginImplementation pluginImplementation); - - /// - /// Finds the plugin info related to the plugin - /// - /// The plugin you want to find the plugin info for - /// The plugins PluginInfo - PluginInfo GetPluginInfo(PluginImplementation pluginImplementation); + /// + void DisablePluginFeature(PluginFeature pluginFeature); /// /// Gets the plugin info of all loaded plugins /// /// A list containing all the plugin info - List GetAllPluginInfo(); + List GetAllPlugins(); /// - /// Finds all enabled instances of + /// Finds all enabled instances of /// - /// Either or a plugin type implementing - /// Returns a list of plugin instances of - List GetPluginsOfType() where T : PluginImplementation; + /// + /// Either or a plugin type implementing + /// + /// + /// Returns a list of feature instances of + List GetFeaturesOfType() where T : PluginFeature; /// /// Gets the plugin that provided the specified assembly /// /// /// - PluginImplementation GetPluginByAssembly(Assembly assembly); + Plugin GetPluginByAssembly(Assembly assembly); + + /// + /// Returns the plugin info of the current call stack + /// + /// If the current call stack contains a plugin, the plugin. Otherwise null + Plugin? GetCallingPlugin(); /// /// Gets the plugin that defined the specified device /// /// /// - PluginImplementation GetPluginByDevice(IRGBDevice device); - - /// - /// Returns the plugin info of the current call stack - /// - /// If the current call stack contains a plugin, the plugin. Otherwise null - PluginImplementation GetCallingPlugin(); + DeviceProvider GetDeviceProviderByDevice(IRGBDevice device); #region Events @@ -134,6 +143,26 @@ namespace Artemis.Core.Services /// event EventHandler PluginDisabled; + /// + /// Occurs when a plugin feature is being enabled + /// + public event EventHandler PluginFeatureEnabling; + + /// + /// Occurs when a plugin feature has been enabled + /// + public event EventHandler PluginFeatureEnabled; + + /// + /// Occurs when a plugin feature could not be enabled + /// + public event EventHandler PluginFeatureEnableFailed; + + /// + /// Occurs when a plugin feature has been disabled + /// + public event EventHandler PluginFeatureDisabled; + #endregion } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/ModuleService.cs b/src/Artemis.Core/Services/ModuleService.cs index a08e06119..97ccf53ce 100644 --- a/src/Artemis.Core/Services/ModuleService.cs +++ b/src/Artemis.Core/Services/ModuleService.cs @@ -26,16 +26,129 @@ namespace Artemis.Core.Services _moduleRepository = moduleRepository; _pluginManagementService = pluginManagementService; _profileService = profileService; - _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled; + _pluginManagementService.PluginFeatureEnabled += OnPluginFeatureEnabled; Timer activationUpdateTimer = new Timer(2000); activationUpdateTimer.Start(); activationUpdateTimer.Elapsed += ActivationUpdateTimerOnElapsed; - foreach (Module module in _pluginManagementService.GetPluginsOfType()) + foreach (Module module in _pluginManagementService.GetFeaturesOfType()) InitialiseOrApplyPriority(module); } + private async void ActivationUpdateTimerOnElapsed(object sender, ElapsedEventArgs e) + { + await UpdateModuleActivation(); + } + + private async Task ActivateModule(Module module) + { + try + { + module.Activate(false); + + // If this is a profile module, activate the last active profile after module activation + if (module is ProfileModule profileModule) + await _profileService.ActivateLastProfileAnimated(profileModule); + } + catch (Exception e) + { + _logger.Error(new ArtemisPluginFeatureException( + module, "Failed to activate module and last profile.", e), "Failed to activate module and last profile" + ); + throw; + } + } + + private async Task DeactivateModule(Module module) + { + try + { + // If this is a profile module, animate profile disable + // module.Deactivate would do the same but without animation + if (module.IsActivated && module is ProfileModule profileModule) + await profileModule.ChangeActiveProfileAnimated(null, null); + + module.Deactivate(false); + } + catch (Exception e) + { + _logger.Error(new ArtemisPluginFeatureException( + module, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile" + ); + throw; + } + } + + private void OverrideActivate(Module module) + { + try + { + if (module.IsActivated) + return; + + // If activating while it should be deactivated, its an override + bool shouldBeActivated = module.EvaluateActivationRequirements(); + module.Activate(!shouldBeActivated); + + // If this is a profile module, activate the last active profile after module activation + if (module is ProfileModule profileModule) + _profileService.ActivateLastProfile(profileModule); + } + catch (Exception e) + { + _logger.Error(new ArtemisPluginFeatureException( + module, "Failed to activate module and last profile.", e), "Failed to activate module and last profile" + ); + throw; + } + } + + private void OverrideDeactivate(Module module, bool clearingOverride) + { + try + { + if (!module.IsActivated) + return; + + // If deactivating while it should be activated, its an override + bool shouldBeActivated = module.EvaluateActivationRequirements(); + // No need to deactivate if it is not in an overridden state + if (shouldBeActivated && !module.IsActivatedOverride && !clearingOverride) + return; + + module.Deactivate(true); + } + catch (Exception e) + { + _logger.Error(new ArtemisPluginFeatureException( + module, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile" + ); + throw; + } + } + + private void OnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e) + { + if (e.PluginFeature is Module module) + InitialiseOrApplyPriority(module); + } + + private void InitialiseOrApplyPriority(Module module) + { + ModulePriorityCategory category = module.DefaultPriorityCategory; + int priority = 1; + + module.Entity = _moduleRepository.GetByModuleId(module.Id); + if (module.Entity != null) + { + category = (ModulePriorityCategory) module.Entity.PriorityCategory; + priority = module.Entity.Priority; + } + + UpdateModulePriority(module, category, priority); + } + public Module ActiveModuleOverride { get; private set; } public async Task SetActiveModuleOverride(Module overrideModule) @@ -46,17 +159,19 @@ namespace Artemis.Core.Services if (ActiveModuleOverride == overrideModule) return; - + if (overrideModule != null) { OverrideActivate(overrideModule); _logger.Information($"Setting active module override to {overrideModule.DisplayName}"); } else + { _logger.Information("Clearing active module override"); + } // Always deactivate all other modules whenever override is called - List modules = _pluginManagementService.GetPluginsOfType().ToList(); + List modules = _pluginManagementService.GetFeaturesOfType().ToList(); foreach (Module module in modules.Where(m => m != overrideModule)) OverrideDeactivate(module, overrideModule != null); @@ -83,13 +198,8 @@ namespace Artemis.Core.Services // the principle is different for this service but not for the module bool shouldBeActivated = ActiveModuleOverride.EvaluateActivationRequirements(); if (shouldBeActivated && ActiveModuleOverride.IsActivatedOverride) - { ActiveModuleOverride.Reactivate(true, false); - } - else if (!shouldBeActivated && !ActiveModuleOverride.IsActivatedOverride) - { - ActiveModuleOverride.Reactivate(false, true); - } + else if (!shouldBeActivated && !ActiveModuleOverride.IsActivatedOverride) ActiveModuleOverride.Reactivate(false, true); return; } @@ -97,10 +207,9 @@ namespace Artemis.Core.Services Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - List modules = _pluginManagementService.GetPluginsOfType().ToList(); + List modules = _pluginManagementService.GetFeaturesOfType().ToList(); List tasks = new List(); foreach (Module module in modules) - { lock (module) { bool shouldBeActivated = module.EvaluateActivationRequirements() && module.IsEnabled; @@ -109,7 +218,6 @@ namespace Artemis.Core.Services else if (!shouldBeActivated && module.IsActivated) tasks.Add(DeactivateModule(module)); } - } await Task.WhenAll(tasks); @@ -128,7 +236,12 @@ namespace Artemis.Core.Services if (module.PriorityCategory == category && module.Priority == priority) return; - List modules = _pluginManagementService.GetPluginsOfType().Where(m => m.PriorityCategory == category).OrderBy(m => m.Priority).ToList(); + List modules = _pluginManagementService + .GetFeaturesOfType() + .Where(m => m.PriorityCategory == category) + .OrderBy(m => m.Priority) + .ToList(); + if (modules.Contains(module)) modules.Remove(module); @@ -149,110 +262,5 @@ namespace Artemis.Core.Services } } } - - private async void ActivationUpdateTimerOnElapsed(object sender, ElapsedEventArgs e) - { - await UpdateModuleActivation(); - } - - private async Task ActivateModule(Module module) - { - try - { - module.Activate(false); - - // If this is a profile module, activate the last active profile after module activation - if (module is ProfileModule profileModule) - await _profileService.ActivateLastProfileAnimated(profileModule); - } - catch (Exception e) - { - _logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to activate module and last profile.", e), "Failed to activate module and last profile"); - throw; - } - } - - private async Task DeactivateModule(Module module) - { - try - { - // If this is a profile module, animate profile disable - // module.Deactivate would do the same but without animation - if (module.IsActivated && module is ProfileModule profileModule) - await profileModule.ChangeActiveProfileAnimated(null, null); - - module.Deactivate(false); - } - catch (Exception e) - { - _logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile"); - throw; - } - } - - private void OverrideActivate(Module module) - { - try - { - if (module.IsActivated) - return; - - // If activating while it should be deactivated, its an override - bool shouldBeActivated = module.EvaluateActivationRequirements(); - module.Activate(!shouldBeActivated); - - // If this is a profile module, activate the last active profile after module activation - if (module is ProfileModule profileModule) - _profileService.ActivateLastProfile(profileModule); - } - catch (Exception e) - { - _logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to activate module and last profile.", e), "Failed to activate module and last profile"); - throw; - } - } - - private void OverrideDeactivate(Module module, bool clearingOverride) - { - try - { - if (!module.IsActivated) - return; - - // If deactivating while it should be activated, its an override - bool shouldBeActivated = module.EvaluateActivationRequirements(); - // No need to deactivate if it is not in an overridden state - if (shouldBeActivated && !module.IsActivatedOverride && !clearingOverride) - return; - - module.Deactivate(true); - } - catch (Exception e) - { - _logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile"); - throw; - } - } - - private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs e) - { - if (e.PluginInfo.Plugin is Module module) - InitialiseOrApplyPriority(module); - } - - private void InitialiseOrApplyPriority(Module module) - { - ModulePriorityCategory category = module.DefaultPriorityCategory; - int priority = 1; - - module.Entity = _moduleRepository.GetByPluginGuid(module.PluginInfo.Guid); - if (module.Entity != null) - { - category = (ModulePriorityCategory) module.Entity.PriorityCategory; - priority = module.Entity.Priority; - } - - UpdateModulePriority(module, category, priority); - } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginManagementService.cs similarity index 56% rename from src/Artemis.Core/Services/PluginService.cs rename to src/Artemis.Core/Services/PluginManagementService.cs index 17b511c51..d64ad5d41 100644 --- a/src/Artemis.Core/Services/PluginService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -41,6 +41,21 @@ namespace Artemis.Core.Services Directory.CreateDirectory(Constants.DataFolder + "plugins"); } + private void CopyBuiltInPlugin(FileInfo zipFileInfo, ZipArchive zipArchive) + { + DirectoryInfo pluginDirectory = new DirectoryInfo(Path.Combine(Constants.DataFolder, "plugins", Path.GetFileNameWithoutExtension(zipFileInfo.Name))); + bool createLockFile = File.Exists(Path.Combine(pluginDirectory.FullName, "artemis.lock")); + + // Remove the old directory if it exists + if (Directory.Exists(pluginDirectory.FullName)) + pluginDirectory.DeleteRecursively(); + Directory.CreateDirectory(pluginDirectory.FullName); + + zipArchive.ExtractToDirectory(pluginDirectory.FullName, true); + if (createLockFile) + File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close(); + } + public bool LoadingPlugins { get; private set; } #region Built in plugins @@ -72,7 +87,9 @@ namespace Artemis.Core.Services // Find the matching plugin in the plugin folder DirectoryInfo? match = pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == Path.GetFileNameWithoutExtension(zipFile.Name)); if (match == null) + { CopyBuiltInPlugin(zipFile, archive); + } else { string metadataFile = Path.Combine(match.FullName, "plugin.json"); @@ -105,6 +122,48 @@ namespace Artemis.Core.Services #endregion + public List GetAllPlugins() + { + return new List(_plugins); + } + + public List GetFeaturesOfType() where T : PluginFeature + { + return _plugins.Where(p => p.IsEnabled).SelectMany(p => p.Features.Where(i => i.IsEnabled && i is T)).Cast().ToList(); + } + + public Plugin? GetPluginByAssembly(Assembly assembly) + { + return _plugins.FirstOrDefault(p => p.Assembly == assembly); + } + + // TODO: move to a more appropriate service + public DeviceProvider GetDeviceProviderByDevice(IRGBDevice rgbDevice) + { + return GetFeaturesOfType().First(d => d.RgbDeviceProvider.Devices != null && d.RgbDeviceProvider.Devices.Contains(rgbDevice)); + } + + public Plugin? GetCallingPlugin() + { + StackTrace stackTrace = new StackTrace(); // get call stack + StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + foreach (StackFrame stackFrame in stackFrames) + { + Assembly assembly = stackFrame.GetMethod().DeclaringType.Assembly; + Plugin plugin = GetPluginByAssembly(assembly); + if (plugin != null) + return plugin; + } + + return null; + } + + public void Dispose() + { + UnloadPlugins(); + } + #region Plugins public void LoadPlugins(bool ignorePluginLock) @@ -125,7 +184,8 @@ namespace Artemis.Core.Services { try { - LoadPlugin(subDirectory); + Plugin plugin = LoadPlugin(subDirectory); + EnablePlugin(plugin, ignorePluginLock); } catch (Exception e) { @@ -133,22 +193,6 @@ namespace Artemis.Core.Services } } - // Activate plugins after they are all loaded - foreach (Plugin plugin in _plugins.Where(p => p.Entity.IsEnabled)) - { - foreach (PluginImplementation pluginImplementation in plugin.Implementations.Where(i => i.Entity.IsEnabled)) - { - try - { - EnablePluginImplementation(pluginImplementation, !ignorePluginLock); - } - catch (Exception) - { - // ignored, logged in EnablePlugin - } - } - } - LoadingPlugins = false; } } @@ -165,29 +209,32 @@ namespace Artemis.Core.Services } } - public void LoadPlugin(DirectoryInfo pluginDirectory) + public Plugin LoadPlugin(DirectoryInfo directory) { lock (_plugins) { - _logger.Debug("Loading plugin from {directory}", pluginDirectory.FullName); + _logger.Debug("Loading plugin from {directory}", directory.FullName); // Load the metadata - string metadataFile = Path.Combine(pluginDirectory.FullName, "plugin.json"); + string metadataFile = Path.Combine(directory.FullName, "plugin.json"); if (!File.Exists(metadataFile)) _logger.Warning(new ArtemisPluginException("Couldn't find the plugins metadata file at " + metadataFile), "Plugin exception"); // PluginInfo contains the ID which we need to move on PluginInfo pluginInfo = JsonConvert.DeserializeObject(File.ReadAllText(metadataFile)); + if (pluginInfo.Guid == Constants.CorePluginInfo.Guid) + throw new ArtemisPluginException($"Plugin cannot use reserved GUID {pluginInfo.Guid}"); + // Ensure the plugin is not already loaded if (_plugins.Any(p => p.Guid == pluginInfo.Guid)) throw new ArtemisCoreException("Cannot load a plugin that is already loaded"); - Plugin plugin = new Plugin(pluginInfo, pluginDirectory); + Plugin plugin = new Plugin(pluginInfo, directory); OnPluginLoading(new PluginEventArgs(plugin)); // Load the entity and fall back on creating a new one - plugin.Entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid) ?? new PluginEntity { Id = plugin.Guid, IsEnabled = true }; + plugin.Entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid) ?? new PluginEntity {Id = plugin.Guid, IsEnabled = true}; // Locate the main assembly entry string? mainFile = plugin.ResolveRelativePath(plugin.Info.Main); @@ -210,55 +257,94 @@ namespace Artemis.Core.Services throw new ArtemisPluginException(plugin, "Failed to load the plugins assembly", e); } - // Get the Plugin implementation from the main assembly and if there is only one, instantiate it - List implementationTypes; - try - { - implementationTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginImplementation).IsAssignableFrom(t)).ToList(); - } - catch (ReflectionTypeLoadException e) - { - throw new ArtemisPluginException(plugin, "Failed to initialize the plugin assembly", new AggregateException(e.LoaderExceptions)); - } - - // Create the Ninject child kernel and load the module - plugin.Kernel = new ChildKernel(_kernel); - plugin.Kernel.Load(new PluginModule(pluginInfo)); - - if (!implementationTypes.Any()) - _logger.Warning("Plugin {plugin} contains no implementations", plugin); - - // Create instances of each implementation and add them to the plugin - // Construction should be simple and not contain any logic so failure at this point means the entire plugin fails - foreach (Type implementationType in implementationTypes) - { - try - { - PluginImplementation instance = (PluginImplementation)plugin.Kernel.Get(implementationType); - plugin.AddImplementation(instance); - } - catch (Exception e) - { - throw new ArtemisPluginException(plugin, "Failed to load instantiate implementation", e); - } - } + List bootstrappers = plugin.Assembly.GetTypes().Where(t => typeof(IPluginBootstrapper).IsAssignableFrom(t)).ToList(); + if (bootstrappers.Count > 1) + _logger.Warning($"{plugin} has more than one bootstrapper, only initializing {bootstrappers.First().FullName}"); + if (bootstrappers.Any()) + plugin.Bootstrapper = (IPluginBootstrapper?) Activator.CreateInstance(bootstrappers.First()); _plugins.Add(plugin); + OnPluginLoaded(new PluginEventArgs(plugin)); + + return plugin; } } + public void EnablePlugin(Plugin plugin, bool ignorePluginLock) + { + if (plugin.Assembly == null) + throw new ArtemisPluginException(plugin, "Cannot enable a plugin that hasn't successfully been loaded"); + + // Create the Ninject child kernel and load the module + plugin.Kernel = new ChildKernel(_kernel); + plugin.Kernel.Bind().ToConstant(plugin); + plugin.Kernel.Load(new PluginModule(plugin.Info)); + + plugin.SetEnabled(true); + + // Get the Plugin feature from the main assembly and if there is only one, instantiate it + List featureTypes; + try + { + featureTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginFeature).IsAssignableFrom(t)).ToList(); + } + catch (ReflectionTypeLoadException e) + { + throw new ArtemisPluginException(plugin, "Failed to initialize the plugin assembly", new AggregateException(e.LoaderExceptions)); + } + + if (!featureTypes.Any()) + _logger.Warning("Plugin {plugin} contains no features", plugin); + + // Create instances of each feature and add them to the plugin + // Construction should be simple and not contain any logic so failure at this point means the entire plugin fails + foreach (Type featureType in featureTypes) + { + try + { + // Include Plugin as a parameter for the PluginSettingsProvider + IParameter[] parameters = {new Parameter("Plugin", plugin, false)}; + PluginFeature instance = (PluginFeature) plugin.Kernel.Get(featureType, parameters); + plugin.AddFeature(instance); + + // Load the enabled state and if not found, default to true + instance.Entity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureType.FullName) ?? + new PluginFeatureEntity {IsEnabled = true, Type = featureType.FullName}; + } + catch (Exception e) + { + throw new ArtemisPluginException(plugin, "Failed to load instantiate feature", e); + } + } + + // Activate plugins after they are all loaded + foreach (PluginFeature pluginFeature in plugin.Features.Where(i => i.Entity.IsEnabled)) + { + try + { + EnablePluginFeature(pluginFeature, !ignorePluginLock); + } + catch (Exception) + { + // ignored, logged in EnablePluginFeature + } + } + + OnPluginEnabled(new PluginEventArgs(plugin)); + } + public void UnloadPlugin(Plugin plugin) { lock (_plugins) { try { - plugin.SetEnabled(false); + DisablePlugin(plugin); } - catch (Exception) + catch (Exception e) { - // TODO: Log these + _logger.Warning(new ArtemisPluginException(plugin, "Exception during DisablePlugin call for UnloadPlugin", e), "Failed to unload plugin"); } finally { @@ -267,38 +353,59 @@ namespace Artemis.Core.Services plugin.Dispose(); _plugins.Remove(plugin); - - OnPluginUnloaded(new PluginEventArgs(plugin)); } } + public void DisablePlugin(Plugin plugin) + { + if (!plugin.IsEnabled) + return; + + while (plugin.Features.Any()) + { + PluginFeature feature = plugin.Features[0]; + plugin.RemoveFeature(feature); + OnPluginFeatureDisabled(new PluginFeatureEventArgs(feature)); + } + + plugin.SetEnabled(false); + + plugin.Kernel.Dispose(); + plugin.Kernel = null; + + OnPluginDisabled(new PluginEventArgs(plugin)); + } + #endregion + #region Features - #region Implementations - - public void EnablePluginImplementation(PluginImplementation pluginImplementation, bool isAutoEnable = false) + public void EnablePluginFeature(PluginFeature pluginFeature, bool isAutoEnable = false) { - _logger.Debug("Enabling plugin implementation {implementation} - {plugin}", pluginImplementation, pluginImplementation.Plugin); + _logger.Debug("Enabling plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin); lock (_plugins) { + OnPluginFeatureEnabling(new PluginFeatureEventArgs(pluginFeature)); try { // A device provider may be queued for disable on next restart, this undoes that - if (pluginImplementation is DeviceProvider && pluginImplementation.IsEnabled && !pluginImplementation.PluginInfo.IsEnabled) + if (pluginFeature is DeviceProvider && pluginFeature.IsEnabled && !pluginFeature.Entity.IsEnabled) { - pluginImplementation.PluginInfo.IsEnabled = true; - pluginImplementation.PluginInfo.ApplyToEntity(); - _pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity); + pluginFeature.Entity.IsEnabled = true; + SavePlugin(pluginFeature.Plugin); return; } - pluginImplementation.SetEnabled(true, isAutoEnable); + pluginFeature.SetEnabled(true, isAutoEnable); + pluginFeature.Entity.IsEnabled = true; } catch (Exception e) { - _logger.Warning(new ArtemisPluginException(pluginImplementation.PluginInfo, "Exception during SetEnabled(true)", e), "Failed to enable plugin"); + _logger.Warning( + new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e), + "Failed to enable plugin" + ); throw; } finally @@ -306,108 +413,83 @@ namespace Artemis.Core.Services // On an auto-enable, ensure PluginInfo.Enabled is true even if enable failed, that way a failure on auto-enable does // not affect the user's settings if (isAutoEnable) - pluginImplementation.PluginInfo.IsEnabled = true; + pluginFeature.Entity.IsEnabled = true; - pluginImplementation.PluginInfo.ApplyToEntity(); - _pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity); + SavePlugin(pluginFeature.Plugin); - if (pluginImplementation.PluginInfo.IsEnabled) - _logger.Debug("Successfully enabled plugin {pluginInfo}", pluginImplementation.PluginInfo); + if (pluginFeature.IsEnabled) + { + _logger.Debug("Successfully enabled plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin); + OnPluginFeatureEnabled(new PluginFeatureEventArgs(pluginFeature)); + } + else + { + OnPluginFeatureEnableFailed(new PluginFeatureEventArgs(pluginFeature)); + } } } - - OnPluginImplementationEnabled(new PluginImplementationEventArgs(pluginImplementation)); } - public void DisablePluginImplementation(PluginImplementation pluginImplementation) + public void DisablePluginFeature(PluginFeature pluginFeature) { lock (_plugins) { - _logger.Debug("Disabling plugin {pluginInfo}", pluginImplementation.PluginInfo); - - // Device providers cannot be disabled at runtime simply queue a disable for next restart - if (pluginImplementation is DeviceProvider) + try { - // Don't call SetEnabled(false) but simply update enabled state and save it - pluginImplementation.PluginInfo.IsEnabled = false; - pluginImplementation.PluginInfo.ApplyToEntity(); - _pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity); - return; + _logger.Debug("Disabling plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin); + + // Device providers cannot be disabled at runtime simply queue a disable for next restart + if (pluginFeature is DeviceProvider) + { + // Don't call SetEnabled(false) but simply update enabled state and save it + pluginFeature.Entity.IsEnabled = false; + SavePlugin(pluginFeature.Plugin); + return; + } + + pluginFeature.SetEnabled(false); } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + finally + { + pluginFeature.Entity.IsEnabled = false; + SavePlugin(pluginFeature.Plugin); - pluginImplementation.SetEnabled(false); - pluginImplementation.PluginInfo.ApplyToEntity(); - _pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity); - - _logger.Debug("Successfully disabled plugin {pluginInfo}", pluginImplementation.PluginInfo); + if (!pluginFeature.IsEnabled) + { + _logger.Debug("Successfully disabled plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin); + OnPluginFeatureDisabled(new PluginFeatureEventArgs(pluginFeature)); + } + } } - - OnPluginDisabled(new PluginEventArgs(pluginImplementation.PluginInfo)); } #endregion + #region Storage - public PluginInfo GetPluginInfo(PluginImplementation pluginImplementation) + private void SavePlugin(Plugin plugin) { - return _plugins.FirstOrDefault(p => p.Plugin == pluginImplementation); - } - - public List GetAllPluginInfo() - { - return new List(_plugins); - } - - public List GetPluginsOfType() where T : PluginImplementation - { - return _plugins.Where(p => p.IsEnabled && p.Plugin is T).Select(p => (T) p.Plugin).ToList(); - } - - public PluginImplementation GetPluginByAssembly(Assembly assembly) - { - return _plugins.FirstOrDefault(p => p.Assembly == assembly)?.Plugin; - } - - public PluginImplementation GetPluginByDevice(IRGBDevice rgbDevice) - { - return GetPluginsOfType().First(d => d.RgbDeviceProvider.Devices != null && d.RgbDeviceProvider.Devices.Contains(rgbDevice)); - } - - public PluginImplementation GetCallingPlugin() - { - StackTrace stackTrace = new StackTrace(); // get call stack - StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) - - foreach (StackFrame stackFrame in stackFrames) + foreach (PluginFeature pluginFeature in plugin.Features) { - Assembly assembly = stackFrame.GetMethod().DeclaringType.Assembly; - PluginImplementation pluginImplementation = GetPluginByAssembly(assembly); - if (pluginImplementation != null) - return pluginImplementation; + if (plugin.Entity.Features.All(i => i.Type != pluginFeature.GetType().FullName)) + plugin.Entity.Features.Add(pluginFeature.Entity); } - return null; + _pluginRepository.SavePlugin(plugin.Entity); } - public void Dispose() + private PluginFeatureEntity GetOrCreateFeatureEntity(PluginFeature feature) { - UnloadPlugins(); + return feature.Plugin.Entity.Features.FirstOrDefault(i => i.Type == feature.GetType().FullName) ?? + new PluginFeatureEntity {IsEnabled = true, Type = feature.GetType().FullName}; } - private void CopyBuiltInPlugin(FileInfo zipFileInfo, ZipArchive zipArchive) - { - DirectoryInfo pluginDirectory = new DirectoryInfo(Path.Combine(Constants.DataFolder, "plugins", Path.GetFileNameWithoutExtension(zipFileInfo.Name))); - bool createLockFile = File.Exists(Path.Combine(pluginDirectory.FullName, "artemis.lock")); - - // Remove the old directory if it exists - if (Directory.Exists(pluginDirectory.FullName)) - pluginDirectory.DeleteRecursively(); - Directory.CreateDirectory(pluginDirectory.FullName); - - zipArchive.ExtractToDirectory(pluginDirectory.FullName, true); - if (createLockFile) - File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close(); - } + #endregion #region Events @@ -419,8 +501,10 @@ namespace Artemis.Core.Services public event EventHandler PluginEnabled; public event EventHandler PluginDisabled; - public event EventHandler PluginImplementationEnabled; - public event EventHandler PluginImplementationDisabled; + public event EventHandler PluginFeatureEnabling; + public event EventHandler PluginFeatureEnabled; + public event EventHandler PluginFeatureDisabled; + public event EventHandler PluginFeatureEnableFailed; protected virtual void OnCopyingBuildInPlugins() { @@ -457,14 +541,24 @@ namespace Artemis.Core.Services PluginDisabled?.Invoke(this, e); } - protected virtual void OnPluginImplementationDisabled(PluginImplementationEventArgs e) + protected virtual void OnPluginFeatureEnabling(PluginFeatureEventArgs e) { - PluginImplementationDisabled?.Invoke(this, e); + PluginFeatureEnabling?.Invoke(this, e); } - protected virtual void OnPluginImplementationEnabled(PluginImplementationEventArgs e) + protected virtual void OnPluginFeatureEnabled(PluginFeatureEventArgs e) { - PluginImplementationEnabled?.Invoke(this, e); + PluginFeatureEnabled?.Invoke(this, e); + } + + protected virtual void OnPluginFeatureDisabled(PluginFeatureEventArgs e) + { + PluginFeatureDisabled?.Invoke(this, e); + } + + protected virtual void OnPluginFeatureEnableFailed(PluginFeatureEventArgs e) + { + PluginFeatureEnableFailed?.Invoke(this, e); } #endregion diff --git a/src/Artemis.Core/Services/Registration/ConditionOperatorService.cs b/src/Artemis.Core/Services/Registration/ConditionOperatorService.cs index a296efd4f..122b43813 100644 --- a/src/Artemis.Core/Services/Registration/ConditionOperatorService.cs +++ b/src/Artemis.Core/Services/Registration/ConditionOperatorService.cs @@ -12,14 +12,14 @@ namespace Artemis.Core.Services RegisterBuiltInConditionOperators(); } - public ConditionOperatorRegistration RegisterConditionOperator(PluginInfo pluginInfo, BaseConditionOperator conditionOperator) + public ConditionOperatorRegistration RegisterConditionOperator(Plugin plugin, BaseConditionOperator conditionOperator) { - if (pluginInfo == null) - throw new ArgumentNullException(nameof(pluginInfo)); + if (plugin == null) + throw new ArgumentNullException(nameof(plugin)); if (conditionOperator == null) throw new ArgumentNullException(nameof(conditionOperator)); - conditionOperator.PluginInfo = pluginInfo; + conditionOperator.Plugin = plugin; return ConditionOperatorStore.Add(conditionOperator); } @@ -43,30 +43,30 @@ namespace Artemis.Core.Services private void RegisterBuiltInConditionOperators() { // General usage for any type - RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new EqualsConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new NotEqualConditionOperator()); // Numeric operators - RegisterConditionOperator(Constants.CorePluginInfo, new NumberEqualsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new NumberNotEqualConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanOrEqualConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new NumberEqualsConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new NumberNotEqualConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new LessThanConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new GreaterThanConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new LessThanOrEqualConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new GreaterThanOrEqualConditionOperator()); // String operators - RegisterConditionOperator(Constants.CorePluginInfo, new StringEqualsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringNotEqualConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringContainsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringNotContainsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringStartsWithConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringEndsWithConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringMatchesRegexConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new StringEqualsConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new StringNotEqualConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new StringContainsConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new StringNotContainsConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new StringStartsWithConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new StringEndsWithConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new StringMatchesRegexConditionOperator()); // Null checks, at the bottom // TODO: Implement a priority mechanism - RegisterConditionOperator(Constants.CorePluginInfo, new NullConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new NotNullConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new NullConditionOperator()); + RegisterConditionOperator(Constants.CorePlugin, new NotNullConditionOperator()); } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/DataBindingService.cs b/src/Artemis.Core/Services/Registration/DataBindingService.cs index 48f853641..08afb30c3 100644 --- a/src/Artemis.Core/Services/Registration/DataBindingService.cs +++ b/src/Artemis.Core/Services/Registration/DataBindingService.cs @@ -12,14 +12,14 @@ namespace Artemis.Core.Services RegisterBuiltInModifiers(); } - public DataBindingModifierTypeRegistration RegisterModifierType(PluginInfo pluginInfo, BaseDataBindingModifierType dataBindingModifierType) + public DataBindingModifierTypeRegistration RegisterModifierType(Plugin plugin, BaseDataBindingModifierType dataBindingModifierType) { - if (pluginInfo == null) - throw new ArgumentNullException(nameof(pluginInfo)); + if (plugin == null) + throw new ArgumentNullException(nameof(plugin)); if (dataBindingModifierType == null) throw new ArgumentNullException(nameof(dataBindingModifierType)); - dataBindingModifierType.PluginInfo = pluginInfo; + dataBindingModifierType.Plugin = plugin; return DataBindingModifierTypeStore.Add(dataBindingModifierType); } @@ -43,41 +43,41 @@ namespace Artemis.Core.Services private void RegisterBuiltInModifiers() { // Numbers - General - RegisterModifierType(Constants.CorePluginInfo, new SumModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SubtractModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new MultiplicationModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new DivideModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new PercentageOfModifierType()); + RegisterModifierType(Constants.CorePlugin, new SumModifierType()); + RegisterModifierType(Constants.CorePlugin, new SubtractModifierType()); + RegisterModifierType(Constants.CorePlugin, new MultiplicationModifierType()); + RegisterModifierType(Constants.CorePlugin, new DivideModifierType()); + RegisterModifierType(Constants.CorePlugin, new PercentageOfModifierType()); // Numbers - Advanced - RegisterModifierType(Constants.CorePluginInfo, new MaxModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new MinModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new ModuloModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new AbsoluteModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new PowerModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SquareRootModifierType()); + RegisterModifierType(Constants.CorePlugin, new MaxModifierType()); + RegisterModifierType(Constants.CorePlugin, new MinModifierType()); + RegisterModifierType(Constants.CorePlugin, new ModuloModifierType()); + RegisterModifierType(Constants.CorePlugin, new AbsoluteModifierType()); + RegisterModifierType(Constants.CorePlugin, new PowerModifierType()); + RegisterModifierType(Constants.CorePlugin, new SquareRootModifierType()); // Numbers - Rounding - RegisterModifierType(Constants.CorePluginInfo, new FloorModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new RoundModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new CeilingModifierType()); + RegisterModifierType(Constants.CorePlugin, new FloorModifierType()); + RegisterModifierType(Constants.CorePlugin, new RoundModifierType()); + RegisterModifierType(Constants.CorePlugin, new CeilingModifierType()); // Numbers - Trigonometric - RegisterModifierType(Constants.CorePluginInfo, new SineModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new CosineModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new TangentModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new CotangentModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SecantModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new CosecantModifierType()); + RegisterModifierType(Constants.CorePlugin, new SineModifierType()); + RegisterModifierType(Constants.CorePlugin, new CosineModifierType()); + RegisterModifierType(Constants.CorePlugin, new TangentModifierType()); + RegisterModifierType(Constants.CorePlugin, new CotangentModifierType()); + RegisterModifierType(Constants.CorePlugin, new SecantModifierType()); + RegisterModifierType(Constants.CorePlugin, new CosecantModifierType()); // Colors - RegisterModifierType(Constants.CorePluginInfo, new SKColorSumModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SKColorSaturateModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SKColorDesaturateModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SKColorBrightenModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SKColorDarkenModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SKColorRotateHueModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new SKColorInvertModifierType()); + RegisterModifierType(Constants.CorePlugin, new SKColorSumModifierType()); + RegisterModifierType(Constants.CorePlugin, new SKColorSaturateModifierType()); + RegisterModifierType(Constants.CorePlugin, new SKColorDesaturateModifierType()); + RegisterModifierType(Constants.CorePlugin, new SKColorBrightenModifierType()); + RegisterModifierType(Constants.CorePlugin, new SKColorDarkenModifierType()); + RegisterModifierType(Constants.CorePlugin, new SKColorRotateHueModifierType()); + RegisterModifierType(Constants.CorePlugin, new SKColorInvertModifierType()); } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/DataModelService.cs b/src/Artemis.Core/Services/Registration/DataModelService.cs index acfb0f1bf..b583439be 100644 --- a/src/Artemis.Core/Services/Registration/DataModelService.cs +++ b/src/Artemis.Core/Services/Registration/DataModelService.cs @@ -11,15 +11,16 @@ namespace Artemis.Core.Services public DataModelService(IPluginManagementService pluginManagementService) { // Add data models of already loaded plugins - foreach (Module module in pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled)) + foreach (Module module in pluginManagementService.GetFeaturesOfType().Where(p => p.IsEnabled)) AddModuleDataModel(module); - foreach (BaseDataModelExpansion dataModelExpansion in pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled)) + foreach (BaseDataModelExpansion dataModelExpansion in pluginManagementService.GetFeaturesOfType().Where(p => p.IsEnabled)) AddDataModelExpansionDataModel(dataModelExpansion); // Add data models of new plugins when they get enabled - pluginManagementService.PluginEnabled += PluginServiceOnPluginEnabled; + pluginManagementService.PluginFeatureEnabled += OnPluginFeatureEnabled; } + public DataModelRegistration RegisterDataModel(DataModel dataModel) { if (dataModel == null) @@ -44,21 +45,16 @@ namespace Artemis.Core.Services return (T) DataModelStore.GetAll().FirstOrDefault(d => d.DataModel is T)?.DataModel; } - public DataModel GetPluginDataModel(PluginImplementation pluginImplementation) + public DataModel? GetPluginDataModel(PluginFeature pluginFeature) { - return DataModelStore.Get(pluginImplementation.PluginInfo.Guid)?.DataModel; + return DataModelStore.Get(pluginFeature.Id)?.DataModel; } - - public DataModel GetPluginDataModel(Guid pluginGuid) + + private void OnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e) { - return DataModelStore.Get(pluginGuid)?.DataModel; - } - - private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) - { - if (e.PluginInfo.Plugin is Module module) + if (e.PluginFeature is Module module) AddModuleDataModel(module); - else if (e.PluginInfo.Plugin is BaseDataModelExpansion dataModelExpansion) + else if (e.PluginFeature is BaseDataModelExpansion dataModelExpansion) AddDataModelExpansionDataModel(dataModelExpansion); } @@ -68,7 +64,7 @@ namespace Artemis.Core.Services return; if (module.InternalDataModel.DataModelDescription == null) - throw new ArtemisPluginException(module.PluginInfo, "Module overrides GetDataModelDescription but returned null"); + throw new ArtemisPluginFeatureException(module, "Module overrides GetDataModelDescription but returned null"); module.InternalDataModel.IsExpansion = module.InternalExpandsMainDataModel; RegisterDataModel(module.InternalDataModel); @@ -77,7 +73,7 @@ namespace Artemis.Core.Services private void AddDataModelExpansionDataModel(BaseDataModelExpansion dataModelExpansion) { if (dataModelExpansion.InternalDataModel.DataModelDescription == null) - throw new ArtemisPluginException(dataModelExpansion.PluginInfo, "Data model expansion overrides GetDataModelDescription but returned null"); + throw new ArtemisPluginFeatureException(dataModelExpansion, "Data model expansion overrides GetDataModelDescription but returned null"); dataModelExpansion.InternalDataModel.IsExpansion = true; RegisterDataModel(dataModelExpansion.InternalDataModel); diff --git a/src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs b/src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs index 49cf60b16..359fec8d9 100644 --- a/src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs +++ b/src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs @@ -12,9 +12,9 @@ namespace Artemis.Core.Services /// /// Registers a new condition operator for use in layer conditions /// - /// The PluginInfo of the plugin this condition operator belongs to + /// The plugin this condition operator belongs to /// The condition operator to register - ConditionOperatorRegistration RegisterConditionOperator([NotNull] PluginInfo pluginInfo, [NotNull] BaseConditionOperator conditionOperator); + ConditionOperatorRegistration RegisterConditionOperator([NotNull] Plugin plugin, [NotNull] BaseConditionOperator conditionOperator); /// /// Removes a condition operator so it is no longer available for use in layer conditions diff --git a/src/Artemis.Core/Services/Registration/Interfaces/IDataBindingService.cs b/src/Artemis.Core/Services/Registration/Interfaces/IDataBindingService.cs index bf33b1867..27ca01ab3 100644 --- a/src/Artemis.Core/Services/Registration/Interfaces/IDataBindingService.cs +++ b/src/Artemis.Core/Services/Registration/Interfaces/IDataBindingService.cs @@ -12,9 +12,9 @@ namespace Artemis.Core.Services /// /// Registers a new modifier type for use in data bindings /// - /// The PluginInfo of the plugin this modifier type belongs to + /// The plugin this modifier type belongs to /// The modifier type to register - DataBindingModifierTypeRegistration RegisterModifierType([NotNull] PluginInfo pluginInfo, [NotNull] BaseDataBindingModifierType dataBindingModifierType); + DataBindingModifierTypeRegistration RegisterModifierType([NotNull] Plugin plugin, [NotNull] BaseDataBindingModifierType dataBindingModifierType); /// /// Removes a modifier type so it is no longer available for use in data bindings diff --git a/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs b/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs index 81f374a50..2f07006b6 100644 --- a/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs +++ b/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs @@ -34,13 +34,7 @@ namespace Artemis.Core.Services /// /// If found, returns the data model of the provided plugin /// - /// The plugin to find the data model of - DataModel GetPluginDataModel(PluginImplementation pluginImplementation); - - /// - /// If found, returns the data model of the provided plugin GUID - /// - /// The GUID of the plugin to find the data model of - DataModel GetPluginDataModel(Guid pluginGuid); + /// The plugin to find the data model of + DataModel? GetPluginDataModel(PluginFeature pluginFeature); } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/LayerBrushService.cs b/src/Artemis.Core/Services/Registration/LayerBrushService.cs index 0ddca99ec..de738d6c4 100644 --- a/src/Artemis.Core/Services/Registration/LayerBrushService.cs +++ b/src/Artemis.Core/Services/Registration/LayerBrushService.cs @@ -38,11 +38,11 @@ namespace Artemis.Core.Services { PluginSetting defaultReference = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference { - BrushPluginGuid = Guid.Parse("92a9d6ba-6f7a-4937-94d5-c1d715b4141a"), + LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba", BrushType = "ColorBrush" }); - return LayerBrushStore.Get(defaultReference.Value.BrushPluginGuid, defaultReference.Value.BrushType)?.LayerBrushDescriptor; + return LayerBrushStore.Get(defaultReference.Value.LayerBrushProviderId, defaultReference.Value.BrushType)?.LayerBrushDescriptor; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/SettingsService.cs b/src/Artemis.Core/Services/SettingsService.cs index 24b267e63..b00f5cee4 100644 --- a/src/Artemis.Core/Services/SettingsService.cs +++ b/src/Artemis.Core/Services/SettingsService.cs @@ -9,7 +9,7 @@ namespace Artemis.Core.Services internal SettingsService(IPluginRepository pluginRepository) { - _pluginSettings = new PluginSettings(Constants.CorePluginInfo, pluginRepository); + _pluginSettings = new PluginSettings(Constants.CorePlugin, pluginRepository); } public PluginSetting GetSetting(string name, T defaultValue = default) diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 469526f73..e142952d5 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -38,13 +38,13 @@ namespace Artemis.Core.Services public List GetProfileDescriptors(ProfileModule module) { - List profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid); + List profileEntities = _profileRepository.GetByModuleId(module.Id); return profileEntities.Select(e => new ProfileDescriptor(module, e)).ToList(); } public ProfileDescriptor CreateProfileDescriptor(ProfileModule module, string name) { - ProfileEntity profileEntity = new ProfileEntity {Id = Guid.NewGuid(), Name = name, PluginGuid = module.PluginInfo.Guid}; + ProfileEntity profileEntity = new ProfileEntity {Id = Guid.NewGuid(), Name = name, ModuleId = module.Id}; _profileRepository.Add(profileEntity); return new ProfileDescriptor(module, profileEntity); @@ -258,7 +258,7 @@ namespace Artemis.Core.Services public ProfileDescriptor GetLastActiveProfile(ProfileModule module) { - List moduleProfiles = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid); + List moduleProfiles = _profileRepository.GetByModuleId(module.Id); if (!moduleProfiles.Any()) return CreateProfileDescriptor(module, "Default"); @@ -271,7 +271,7 @@ namespace Artemis.Core.Services if (module.ActiveProfile == null) return; - List profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid); + List profileEntities = _profileRepository.GetByModuleId(module.Id); foreach (ProfileEntity profileEntity in profileEntities) { profileEntity.IsActive = module.ActiveProfile.EntityId == profileEntity.Id; @@ -285,7 +285,7 @@ namespace Artemis.Core.Services /// private void ActiveProfilesPopulateLeds(ArtemisSurface surface) { - List profileModules = _pluginManagementService.GetPluginsOfType(); + List profileModules = _pluginManagementService.GetFeaturesOfType(); foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList()) profileModule.ActiveProfile.PopulateLeds(surface); } diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs index 24265e06e..6b1fc1861 100644 --- a/src/Artemis.Core/Services/Storage/SurfaceService.cs +++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs @@ -44,8 +44,8 @@ namespace Artemis.Core.Services // Add all current devices foreach (IRGBDevice rgbDevice in _rgbService.LoadedDevices) { - PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice); - configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginImplementation, configuration)); + PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice); + configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginFeature, configuration)); } lock (_surfaceConfigurations) @@ -136,8 +136,8 @@ namespace Artemis.Core.Services IRGBDevice device = _rgbService.Surface.Devices.FirstOrDefault(d => d.GetDeviceIdentifier() == position.DeviceIdentifier); if (device != null) { - PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(device); - surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginImplementation, surfaceConfiguration, position)); + PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(device); + surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginFeature, surfaceConfiguration, position)); } } @@ -178,8 +178,8 @@ namespace Artemis.Core.Services DeviceEntity existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier); if (existingDeviceConfig != null) { - PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice); - device = new ArtemisDevice(rgbDevice, pluginImplementation, surface, existingDeviceConfig); + PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice); + device = new ArtemisDevice(rgbDevice, pluginFeature, surface, existingDeviceConfig); } // Fall back on creating a new device else @@ -189,8 +189,8 @@ namespace Artemis.Core.Services rgbDevice.DeviceInfo, deviceIdentifier ); - PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice); - device = new ArtemisDevice(rgbDevice, pluginImplementation, surface); + PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice); + device = new ArtemisDevice(rgbDevice, pluginFeature, surface); } surface.Devices.Add(device); diff --git a/src/Artemis.Core/Stores/ConditionOperatorStore.cs b/src/Artemis.Core/Stores/ConditionOperatorStore.cs index 0873bafa9..3247d648d 100644 --- a/src/Artemis.Core/Stores/ConditionOperatorStore.cs +++ b/src/Artemis.Core/Stores/ConditionOperatorStore.cs @@ -16,7 +16,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.ConditionOperator == conditionOperator)) throw new ArtemisCoreException($"Condition operator store store already contains operator '{conditionOperator.Description}'"); - registration = new ConditionOperatorRegistration(conditionOperator, conditionOperator.PluginInfo.Plugin) {IsInStore = true}; + registration = new ConditionOperatorRegistration(conditionOperator, conditionOperator.Plugin) {IsInStore = true}; Registrations.Add(registration); } @@ -42,7 +42,7 @@ namespace Artemis.Core { lock (Registrations) { - return Registrations.FirstOrDefault(r => r.PluginImplementation.PluginInfo.Guid == pluginGuid && r.ConditionOperator.GetType().Name == type); + return Registrations.FirstOrDefault(r => r.Plugin.Guid == pluginGuid && r.ConditionOperator.GetType().Name == type); } } diff --git a/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs index bb83a7aef..302f32241 100644 --- a/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs +++ b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs @@ -16,7 +16,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.DataBindingModifierType == modifierType)) throw new ArtemisCoreException($"Data binding modifier type store already contains modifier '{modifierType.Name}'"); - typeRegistration = new DataBindingModifierTypeRegistration(modifierType, modifierType.PluginInfo.Plugin) { IsInStore = true }; + typeRegistration = new DataBindingModifierTypeRegistration(modifierType, modifierType.Plugin) { IsInStore = true }; Registrations.Add(typeRegistration); } @@ -42,7 +42,7 @@ namespace Artemis.Core { lock (Registrations) { - return Registrations.FirstOrDefault(r => r.PluginImplementation.PluginInfo.Guid == pluginGuid && r.DataBindingModifierType.GetType().Name == type); + return Registrations.FirstOrDefault(r => r.Plugin.Guid == pluginGuid && r.DataBindingModifierType.GetType().Name == type); } } diff --git a/src/Artemis.Core/Stores/DataModelStore.cs b/src/Artemis.Core/Stores/DataModelStore.cs index 30c1da751..713ee90c2 100644 --- a/src/Artemis.Core/Stores/DataModelStore.cs +++ b/src/Artemis.Core/Stores/DataModelStore.cs @@ -17,7 +17,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.DataModel == dataModel)) throw new ArtemisCoreException($"Data model store already contains data model '{dataModel.DataModelDescription}'"); - registration = new DataModelRegistration(dataModel, dataModel.Implementation.Instance) {IsInStore = true}; + registration = new DataModelRegistration(dataModel, dataModel.Feature) {IsInStore = true}; Registrations.Add(registration); } @@ -47,11 +47,11 @@ namespace Artemis.Core } } - public static DataModelRegistration Get(Guid pluginGuid) + public static DataModelRegistration Get(string id) { lock (Registrations) { - return Registrations.FirstOrDefault(d => d.PluginImplementation.PluginInfo.Guid == pluginGuid); + return Registrations.FirstOrDefault(d => d.PluginFeature.Id == id); } } diff --git a/src/Artemis.Core/Stores/LayerBrushStore.cs b/src/Artemis.Core/Stores/LayerBrushStore.cs index 3d5c59c96..fb05da802 100644 --- a/src/Artemis.Core/Stores/LayerBrushStore.cs +++ b/src/Artemis.Core/Stores/LayerBrushStore.cs @@ -17,7 +17,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.LayerBrushDescriptor == descriptor)) throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'"); - registration = new LayerBrushRegistration(descriptor, descriptor.LayerBrushProvider.PluginInfo.Plugin) {IsInStore = true}; + registration = new LayerBrushRegistration(descriptor, descriptor.Provider) {IsInStore = true}; Registrations.Add(registration); } @@ -47,11 +47,11 @@ namespace Artemis.Core } } - public static LayerBrushRegistration Get(Guid pluginGuid, string typeName) + public static LayerBrushRegistration? Get(string id, string typeName) { lock (Registrations) { - return Registrations.FirstOrDefault(d => d.PluginImplementation.PluginInfo.Guid == pluginGuid && + return Registrations.FirstOrDefault(d => d.PluginFeature.Id == id && d.LayerBrushDescriptor.LayerBrushType.Name == typeName); } } diff --git a/src/Artemis.Core/Stores/LayerEffectStore.cs b/src/Artemis.Core/Stores/LayerEffectStore.cs index 420edb464..ac3060bd9 100644 --- a/src/Artemis.Core/Stores/LayerEffectStore.cs +++ b/src/Artemis.Core/Stores/LayerEffectStore.cs @@ -17,7 +17,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.LayerEffectDescriptor == descriptor)) throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'"); - registration = new LayerEffectRegistration(descriptor, descriptor.LayerEffectProvider.PluginInfo.Plugin) { IsInStore = true }; + registration = new LayerEffectRegistration(descriptor, descriptor.Provider) { IsInStore = true }; Registrations.Add(registration); } @@ -47,11 +47,11 @@ namespace Artemis.Core } } - public static LayerEffectRegistration Get(Guid pluginGuid, string typeName) + public static LayerEffectRegistration? Get(string providerId, string typeName) { lock (Registrations) { - return Registrations.FirstOrDefault(d => d.PluginImplementation.PluginInfo.Guid == pluginGuid && d.LayerEffectDescriptor.LayerEffectType.Name == typeName); + return Registrations.FirstOrDefault(d => d.PluginFeature.Id == providerId && d.LayerEffectDescriptor.LayerEffectType.Name == typeName); } } diff --git a/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs b/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs index d9ac7775e..46cb22068 100644 --- a/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs +++ b/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs @@ -7,12 +7,12 @@ namespace Artemis.Core /// public class ConditionOperatorRegistration { - internal ConditionOperatorRegistration(BaseConditionOperator conditionOperator, PluginImplementation pluginImplementation) + internal ConditionOperatorRegistration(BaseConditionOperator conditionOperator, Plugin plugin) { ConditionOperator = conditionOperator; - PluginImplementation = pluginImplementation; + Plugin = plugin; - PluginImplementation.Disabled += OnDisabled; + Plugin.Disabled += OnDisabled; } /// @@ -23,7 +23,7 @@ namespace Artemis.Core /// /// Gets the plugin the condition operator is associated with /// - public PluginImplementation PluginImplementation { get; } + public Plugin Plugin { get; } /// /// Gets a boolean indicating whether the registration is in the internal Core store @@ -32,7 +32,7 @@ namespace Artemis.Core private void OnDisabled(object sender, EventArgs e) { - PluginImplementation.Disabled -= OnDisabled; + Plugin.Disabled -= OnDisabled; if (IsInStore) ConditionOperatorStore.Remove(this); } diff --git a/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs b/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs index 2a556dda2..b0ff66088 100644 --- a/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs +++ b/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs @@ -7,12 +7,12 @@ namespace Artemis.Core /// public class DataBindingModifierTypeRegistration { - internal DataBindingModifierTypeRegistration(BaseDataBindingModifierType dataBindingModifierType, PluginImplementation pluginImplementation) + internal DataBindingModifierTypeRegistration(BaseDataBindingModifierType dataBindingModifierType, Plugin plugin) { DataBindingModifierType = dataBindingModifierType; - PluginImplementation = pluginImplementation; + Plugin = plugin; - PluginImplementation.Disabled += OnDisabled; + Plugin.Disabled += OnDisabled; } /// @@ -23,7 +23,7 @@ namespace Artemis.Core /// /// Gets the plugin the data binding modifier is associated with /// - public PluginImplementation PluginImplementation { get; } + public Plugin Plugin { get; } /// /// Gets a boolean indicating whether the registration is in the internal Core store @@ -32,7 +32,7 @@ namespace Artemis.Core private void OnDisabled(object sender, EventArgs e) { - PluginImplementation.Disabled -= OnDisabled; + Plugin.Disabled -= OnDisabled; if (IsInStore) DataBindingModifierTypeStore.Remove(this); } diff --git a/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs index 879c81ff2..7a1812e02 100644 --- a/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs +++ b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs @@ -8,12 +8,12 @@ namespace Artemis.Core /// public class DataModelRegistration { - internal DataModelRegistration(DataModel dataModel, PluginImplementation pluginImplementation) + internal DataModelRegistration(DataModel dataModel, PluginFeature pluginFeature) { DataModel = dataModel; - PluginImplementation = pluginImplementation; + PluginFeature = pluginFeature; - PluginImplementation.Disabled += OnDisabled; + PluginFeature.Disabled += OnDisabled; } /// @@ -24,7 +24,7 @@ namespace Artemis.Core /// /// Gets the plugin the data model is associated with /// - public PluginImplementation PluginImplementation { get; } + public PluginFeature PluginFeature { get; } /// /// Gets a boolean indicating whether the registration is in the internal Core store @@ -33,7 +33,7 @@ namespace Artemis.Core private void OnDisabled(object sender, EventArgs e) { - PluginImplementation.Disabled -= OnDisabled; + PluginFeature.Disabled -= OnDisabled; if (IsInStore) DataModelStore.Remove(this); } diff --git a/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs b/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs index 15e2bf422..8e35bf905 100644 --- a/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs +++ b/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs @@ -8,12 +8,12 @@ namespace Artemis.Core /// public class LayerBrushRegistration { - internal LayerBrushRegistration(LayerBrushDescriptor descriptor, PluginImplementation pluginImplementation) + internal LayerBrushRegistration(LayerBrushDescriptor descriptor, PluginFeature pluginFeature) { LayerBrushDescriptor = descriptor; - PluginImplementation = pluginImplementation; + PluginFeature = pluginFeature; - PluginImplementation.Disabled += OnDisabled; + PluginFeature.Disabled += OnDisabled; } /// @@ -24,7 +24,7 @@ namespace Artemis.Core /// /// Gets the plugin the layer brush is associated with /// - public PluginImplementation PluginImplementation { get; } + public PluginFeature PluginFeature { get; } /// /// Gets a boolean indicating whether the registration is in the internal Core store @@ -33,7 +33,7 @@ namespace Artemis.Core private void OnDisabled(object sender, EventArgs e) { - PluginImplementation.Disabled -= OnDisabled; + PluginFeature.Disabled -= OnDisabled; if (IsInStore) LayerBrushStore.Remove(this); } diff --git a/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs b/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs index 693985560..0b74524f0 100644 --- a/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs +++ b/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs @@ -8,12 +8,12 @@ namespace Artemis.Core /// public class LayerEffectRegistration { - internal LayerEffectRegistration(LayerEffectDescriptor descriptor, PluginImplementation pluginImplementation) + internal LayerEffectRegistration(LayerEffectDescriptor descriptor, PluginFeature pluginFeature) { LayerEffectDescriptor = descriptor; - PluginImplementation = pluginImplementation; + PluginFeature = pluginFeature; - PluginImplementation.Disabled += OnDisabled; + PluginFeature.Disabled += OnDisabled; } /// @@ -24,7 +24,7 @@ namespace Artemis.Core /// /// Gets the plugin the layer effect is associated with /// - public PluginImplementation PluginImplementation { get; } + public PluginFeature PluginFeature { get; } /// /// Gets a boolean indicating whether the registration is in the internal Core store @@ -33,7 +33,7 @@ namespace Artemis.Core private void OnDisabled(object sender, EventArgs e) { - PluginImplementation.Disabled -= OnDisabled; + PluginFeature.Disabled -= OnDisabled; if (IsInStore) LayerEffectStore.Remove(this); } diff --git a/src/Artemis.Core/Utilities/CorePluginImplementation.cs b/src/Artemis.Core/Utilities/CorePluginFeature.cs similarity index 70% rename from src/Artemis.Core/Utilities/CorePluginImplementation.cs rename to src/Artemis.Core/Utilities/CorePluginFeature.cs index f7a5d4310..897c46b88 100644 --- a/src/Artemis.Core/Utilities/CorePluginImplementation.cs +++ b/src/Artemis.Core/Utilities/CorePluginFeature.cs @@ -3,13 +3,13 @@ namespace Artemis.Core { /// - /// An empty plugin used by + /// An empty data model plugin feature used by /// - internal class CorePluginImplementation : PluginImplementation + internal class CorePluginFeature : DataModelPluginFeature { - public CorePluginImplementation() + public CorePluginFeature() { - Constants.CorePluginInfo.Plugin = this; + Constants.CorePlugin.AddFeature(this); IsEnabled = true; } diff --git a/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs b/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs index 464aa628f..4c3a03463 100644 --- a/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs +++ b/src/Artemis.Core/Utilities/CurrentProcessUtilities.cs @@ -1,6 +1,6 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Windows; -using Stylet; namespace Artemis.Core { @@ -37,8 +37,8 @@ namespace Artemis.Core if (!Debugger.IsAttached) Process.Start(info); - // Also attempt a graceful shutdown on the UI thread - Execute.OnUIThread(() => Application.Current.Shutdown()); + // Request a graceful shutdown, whatever UI we're running can pick this up + OnShutdownRequested(); } /// @@ -64,5 +64,18 @@ namespace Artemis.Core { return Process.GetCurrentProcess().MainModule.FileName; } + + #region Events + + public static event EventHandler ShutdownRequested; + + private static void OnShutdownRequested() + { + ShutdownRequested?.Invoke(null, EventArgs.Empty); + } + + #endregion + + } } \ No newline at end of file diff --git a/src/Artemis.Core/packages.lock.json b/src/Artemis.Core/packages.lock.json index e6ecc5b44..253535ea9 100644 --- a/src/Artemis.Core/packages.lock.json +++ b/src/Artemis.Core/packages.lock.json @@ -121,15 +121,6 @@ "System.Memory": "4.5.3" } }, - "Stylet": { - "type": "Direct", - "requested": "[1.3.4, )", - "resolved": "1.3.4", - "contentHash": "bCEdA+AIi+TM9SQQGLYMsFRIfzZcDUDg2Mznyr72kOkcC/cdBj01/jel4/v2aoKwbFcxVjiqmpgnbsFgMEZ4zQ==", - "dependencies": { - "System.Drawing.Common": "4.6.0" - } - }, "System.Buffers": { "type": "Direct", "requested": "[4.5.0, )", @@ -192,8 +183,8 @@ }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "3.0.0", - "contentHash": "TsETIgVJb/AKoYfSP+iCxkuly5d3inZjTdx/ItZLk2CxY85v8083OBS3uai84kK3/baLnS5/b5XGs6zR7SuuHQ==" + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -210,14 +201,6 @@ "System.Runtime": "4.3.0" } }, - "Microsoft.Win32.SystemEvents": { - "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "Edg+pFW5C8WJb680Za2kTV8TqUi6Ahl/WldRVoOVJ23UQLpDHFspa+umgFjkWZw24ETsU99Cg+ErZz683M4chg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.0.0" - } - }, "NETStandard.Library": { "type": "Transitive", "resolved": "1.6.1", @@ -557,15 +540,6 @@ "System.Runtime": "4.3.0" } }, - "System.Drawing.Common": { - "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "2A3spjjoPZnvpVh/sDTzd+0H8ZqTdr+hH/6obB8MMfG81EJ85PmxCKDBxhBVQiA25PliKAZ1sKogDcq9mSnFEA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.0.0", - "Microsoft.Win32.SystemEvents": "4.6.0" - } - }, "System.Dynamic.Runtime": { "type": "Transitive", "resolved": "4.3.0", diff --git a/src/Artemis.Storage/Entities/Module/ModuleSettingsEntity.cs b/src/Artemis.Storage/Entities/Module/ModuleSettingsEntity.cs index 296a5ca8a..3cddf93b7 100644 --- a/src/Artemis.Storage/Entities/Module/ModuleSettingsEntity.cs +++ b/src/Artemis.Storage/Entities/Module/ModuleSettingsEntity.cs @@ -10,7 +10,7 @@ namespace Artemis.Storage.Entities.Module } public Guid Id { get; set; } - public Guid PluginGuid { get; set; } + public string ModuleId { get; set; } public int PriorityCategory { get; set; } public int Priority { get; set; } } diff --git a/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs b/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs index 3cfa1088e..4ac4db668 100644 --- a/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs +++ b/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs @@ -8,16 +8,21 @@ namespace Artemis.Storage.Entities.Plugins /// public class PluginEntity { + public PluginEntity() + { + Features = new List(); + } + public Guid Id { get; set; } public bool IsEnabled { get; set; } - public List Implementations { get; set; } + public List Features { get; set; } } /// - /// Represents the configuration of a plugin implementation, each implementation has one configuration + /// Represents the configuration of a plugin feature, each feature has one configuration /// - public class PluginImplementationEntity + public class PluginFeatureEntity { public string Type { get; set; } public bool IsEnabled { get; set; } diff --git a/src/Artemis.Storage/Entities/Profile/DataModelPathEntity.cs b/src/Artemis.Storage/Entities/Profile/DataModelPathEntity.cs index b4a2b03b5..7ab2806db 100644 --- a/src/Artemis.Storage/Entities/Profile/DataModelPathEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/DataModelPathEntity.cs @@ -5,7 +5,7 @@ namespace Artemis.Storage.Entities.Profile public class DataModelPathEntity { public string Path { get; set; } - public Guid? DataModelGuid { get; set; } + public string DataModelId { get; set; } public PathWrapperType WrapperType { get; set; } } diff --git a/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs b/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs index d6dce29be..6c8503e42 100644 --- a/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs @@ -5,7 +5,7 @@ namespace Artemis.Storage.Entities.Profile public class LayerEffectEntity { public Guid Id { get; set; } - public Guid PluginGuid { get; set; } + public string ProviderId { get; set; } public string EffectType { get; set; } public string Name { get; set; } public bool Enabled { get; set; } diff --git a/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs b/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs index ecd08497b..177d8c00b 100644 --- a/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs @@ -13,7 +13,7 @@ namespace Artemis.Storage.Entities.Profile } public Guid Id { get; set; } - public Guid PluginGuid { get; set; } + public string ModuleId { get; set; } public string Name { get; set; } public bool IsActive { get; set; } diff --git a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs index c26baa1ce..6c04025d4 100644 --- a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Artemis.Storage.Entities.Profile.DataBindings; namespace Artemis.Storage.Entities.Profile @@ -12,7 +11,7 @@ namespace Artemis.Storage.Entities.Profile DataBindingEntities = new List(); } - public Guid PluginGuid { get; set; } + public string FeatureId { get; set; } public string Path { get; set; } public string Value { get; set; } diff --git a/src/Artemis.Storage/Repositories/Interfaces/IModuleRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IModuleRepository.cs index 5780e7bc0..918efb361 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IModuleRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IModuleRepository.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Artemis.Storage.Entities.Module; namespace Artemis.Storage.Repositories.Interfaces @@ -7,7 +6,7 @@ namespace Artemis.Storage.Repositories.Interfaces public interface IModuleRepository : IRepository { void Add(ModuleSettingsEntity moduleSettingsEntity); - ModuleSettingsEntity GetByPluginGuid(Guid guid); + ModuleSettingsEntity GetByModuleId(string moduleId); List GetAll(); List GetByCategory(int category); void Save(ModuleSettingsEntity moduleSettingsEntity); diff --git a/src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs index d0f559b16..a42c74966 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs @@ -10,7 +10,7 @@ namespace Artemis.Storage.Repositories.Interfaces void Remove(ProfileEntity profileEntity); List GetAll(); ProfileEntity Get(Guid id); - List GetByPluginGuid(Guid pluginGuid); + List GetByModuleId(string moduleId); void Save(ProfileEntity profileEntity); } } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/ModuleRepository.cs b/src/Artemis.Storage/Repositories/ModuleRepository.cs index 6f3ad34b7..ff9d4953b 100644 --- a/src/Artemis.Storage/Repositories/ModuleRepository.cs +++ b/src/Artemis.Storage/Repositories/ModuleRepository.cs @@ -13,7 +13,7 @@ namespace Artemis.Storage.Repositories internal ModuleRepository(LiteRepository repository) { _repository = repository; - _repository.Database.GetCollection().EnsureIndex(s => s.PluginGuid, true); + _repository.Database.GetCollection().EnsureIndex(s => s.ModuleId, true); } public void Add(ModuleSettingsEntity moduleSettingsEntity) @@ -21,9 +21,9 @@ namespace Artemis.Storage.Repositories _repository.Insert(moduleSettingsEntity); } - public ModuleSettingsEntity GetByPluginGuid(Guid guid) + public ModuleSettingsEntity GetByModuleId(string moduleId) { - return _repository.FirstOrDefault(s => s.PluginGuid == guid); + return _repository.FirstOrDefault(s => s.ModuleId == moduleId); } public List GetAll() diff --git a/src/Artemis.Storage/Repositories/ProfileRepository.cs b/src/Artemis.Storage/Repositories/ProfileRepository.cs index 5ca90ea2e..288b40fcb 100644 --- a/src/Artemis.Storage/Repositories/ProfileRepository.cs +++ b/src/Artemis.Storage/Repositories/ProfileRepository.cs @@ -36,12 +36,12 @@ namespace Artemis.Storage.Repositories return _repository.FirstOrDefault(p => p.Id == id); } - public List GetByPluginGuid(Guid pluginGuid) + public List GetByModuleId(string moduleId) { return _repository.Query() .Include(p => p.Folders) .Include(p => p.Layers) - .Where(s => s.PluginGuid == pluginGuid) + .Where(s => s.ModuleId == moduleId) .ToList(); } diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj.DotSettings b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj.DotSettings index 1292ea906..5229191ac 100644 --- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj.DotSettings +++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj.DotSettings @@ -8,6 +8,7 @@ True True True + True True True True diff --git a/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs b/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs index e3a66bc8a..5ed47be76 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs @@ -11,22 +11,22 @@ namespace Artemis.UI.Shared public DataModelVisualizationRegistration(IDataModelUIService dataModelUIService, RegistrationType registrationType, - PluginInfo pluginInfo, + Plugin plugin, Type supportedType, Type viewModelType) { _dataModelUIService = dataModelUIService; RegistrationType = registrationType; - PluginInfo = pluginInfo; + Plugin = plugin; SupportedType = supportedType; ViewModelType = viewModelType; - if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Plugin.Disabled += InstanceOnDisabled; + if (Plugin != Constants.CorePlugin) + Plugin.Disabled += InstanceOnDisabled; } public RegistrationType RegistrationType { get; } - public PluginInfo PluginInfo { get; } + public Plugin Plugin { get; } public Type SupportedType { get; } public Type ViewModelType { get; } @@ -34,8 +34,8 @@ namespace Artemis.UI.Shared internal void Unsubscribe() { - if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Plugin.Disabled -= InstanceOnDisabled; + if (Plugin != Constants.CorePlugin) + Plugin.Disabled -= InstanceOnDisabled; } private void InstanceOnDisabled(object sender, EventArgs e) diff --git a/src/Artemis.Core/Plugins/LayerBrushes/BrushConfigurationViewModel.cs b/src/Artemis.UI.Shared/Plugins/LayerBrushes/BrushConfigurationViewModel.cs similarity index 92% rename from src/Artemis.Core/Plugins/LayerBrushes/BrushConfigurationViewModel.cs rename to src/Artemis.UI.Shared/Plugins/LayerBrushes/BrushConfigurationViewModel.cs index 34a928f94..0c61885b0 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/BrushConfigurationViewModel.cs +++ b/src/Artemis.UI.Shared/Plugins/LayerBrushes/BrushConfigurationViewModel.cs @@ -1,6 +1,7 @@ -using Stylet; +using Artemis.Core.LayerBrushes; +using Stylet; -namespace Artemis.Core.LayerBrushes +namespace Artemis.UI.Shared.LayerBrushes { /// /// Represents a view model for a brush configuration window diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushConfigurationDialog.cs b/src/Artemis.UI.Shared/Plugins/LayerBrushes/LayerBrushConfigurationDialog.cs similarity index 80% rename from src/Artemis.Core/Plugins/LayerBrushes/LayerBrushConfigurationDialog.cs rename to src/Artemis.UI.Shared/Plugins/LayerBrushes/LayerBrushConfigurationDialog.cs index 5074e8d02..ed20b670b 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushConfigurationDialog.cs +++ b/src/Artemis.UI.Shared/Plugins/LayerBrushes/LayerBrushConfigurationDialog.cs @@ -1,6 +1,7 @@ using System; +using Artemis.Core.LayerBrushes; -namespace Artemis.Core.LayerBrushes +namespace Artemis.UI.Shared.LayerBrushes { /// public class LayerBrushConfigurationDialog : LayerBrushConfigurationDialog where T : BrushConfigurationViewModel @@ -12,7 +13,7 @@ namespace Artemis.Core.LayerBrushes /// /// Describes a UI tab for a layer brush /// - public abstract class LayerBrushConfigurationDialog + public abstract class LayerBrushConfigurationDialog : ILayerBrushConfigurationDialog { /// /// The layer brush this dialog belongs to diff --git a/src/Artemis.Core/Plugins/LayerEffects/EffectConfigurationViewModel.cs b/src/Artemis.UI.Shared/Plugins/LayerEffects/EffectConfigurationViewModel.cs similarity index 92% rename from src/Artemis.Core/Plugins/LayerEffects/EffectConfigurationViewModel.cs rename to src/Artemis.UI.Shared/Plugins/LayerEffects/EffectConfigurationViewModel.cs index effc967a3..aac795039 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/EffectConfigurationViewModel.cs +++ b/src/Artemis.UI.Shared/Plugins/LayerEffects/EffectConfigurationViewModel.cs @@ -1,6 +1,7 @@ -using Stylet; +using Artemis.Core.LayerEffects; +using Stylet; -namespace Artemis.Core.LayerEffects +namespace Artemis.UI.Shared.LayerEffects { /// /// Represents a view model for an effect configuration window diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectConfigurationDialog.cs b/src/Artemis.UI.Shared/Plugins/LayerEffects/LayerEffectConfigurationDialog.cs similarity index 80% rename from src/Artemis.Core/Plugins/LayerEffects/LayerEffectConfigurationDialog.cs rename to src/Artemis.UI.Shared/Plugins/LayerEffects/LayerEffectConfigurationDialog.cs index 674d3897e..604214b8c 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectConfigurationDialog.cs +++ b/src/Artemis.UI.Shared/Plugins/LayerEffects/LayerEffectConfigurationDialog.cs @@ -1,6 +1,7 @@ using System; +using Artemis.Core.LayerEffects; -namespace Artemis.Core.LayerEffects +namespace Artemis.UI.Shared.LayerEffects { /// public class LayerEffectConfigurationDialog : LayerEffectConfigurationDialog where T : EffectConfigurationViewModel @@ -12,7 +13,7 @@ namespace Artemis.Core.LayerEffects /// /// Describes a UI tab for a specific layer effect /// - public abstract class LayerEffectConfigurationDialog + public abstract class LayerEffectConfigurationDialog : ILayerEffectConfigurationDialog { /// /// The layer effect this dialog belongs to diff --git a/src/Artemis.Core/Plugins/Modules/ModuleViewModel.cs b/src/Artemis.UI.Shared/Plugins/Modules/ModuleViewModel.cs similarity index 83% rename from src/Artemis.Core/Plugins/Modules/ModuleViewModel.cs rename to src/Artemis.UI.Shared/Plugins/Modules/ModuleViewModel.cs index 7aeed4311..05222aed1 100644 --- a/src/Artemis.Core/Plugins/Modules/ModuleViewModel.cs +++ b/src/Artemis.UI.Shared/Plugins/Modules/ModuleViewModel.cs @@ -1,11 +1,12 @@ -using Stylet; +using Artemis.Core.Modules; +using Stylet; -namespace Artemis.Core.Modules +namespace Artemis.UI.Shared.Modules { /// /// The base class for any view model that belongs to a module /// - public abstract class ModuleViewModel : Screen + public abstract class ModuleViewModel : Screen, IModuleViewModel { /// /// The base class for any view model that belongs to a module diff --git a/src/Artemis.Core/Plugins/PluginConfigurationDialog.cs b/src/Artemis.UI.Shared/Plugins/PluginConfigurationDialog.cs similarity index 76% rename from src/Artemis.Core/Plugins/PluginConfigurationDialog.cs rename to src/Artemis.UI.Shared/Plugins/PluginConfigurationDialog.cs index 288caefa8..7c7e62886 100644 --- a/src/Artemis.Core/Plugins/PluginConfigurationDialog.cs +++ b/src/Artemis.UI.Shared/Plugins/PluginConfigurationDialog.cs @@ -1,6 +1,7 @@ using System; +using Artemis.Core; -namespace Artemis.Core +namespace Artemis.UI.Shared { /// public class PluginConfigurationDialog : PluginConfigurationDialog where T : PluginConfigurationViewModel @@ -12,12 +13,12 @@ namespace Artemis.Core /// /// Describes a configuration dialog for a specific plugin /// - public abstract class PluginConfigurationDialog + public abstract class PluginConfigurationDialog : IPluginConfigurationDialog { /// /// The layer brush this dialog belongs to /// - internal PluginImplementation PluginImplementation { get; set; } + internal PluginFeature PluginFeature { get; set; } /// /// The type of view model the tab contains diff --git a/src/Artemis.Core/Plugins/PluginConfigurationViewModel.cs b/src/Artemis.UI.Shared/Plugins/PluginConfigurationViewModel.cs similarity index 50% rename from src/Artemis.Core/Plugins/PluginConfigurationViewModel.cs rename to src/Artemis.UI.Shared/Plugins/PluginConfigurationViewModel.cs index e4a60afbc..61e88a503 100644 --- a/src/Artemis.Core/Plugins/PluginConfigurationViewModel.cs +++ b/src/Artemis.UI.Shared/Plugins/PluginConfigurationViewModel.cs @@ -1,34 +1,35 @@ -using Stylet; +using Artemis.Core; +using Stylet; -namespace Artemis.Core +namespace Artemis.UI.Shared { /// /// Represents a view model for a plugin configuration window /// - public abstract class PluginConfigurationViewModel : Screen + public abstract class PluginConfigurationViewModel : Screen, IPluginConfigurationViewModel { /// /// Creates a new instance of the class /// - /// - protected PluginConfigurationViewModel(PluginImplementation pluginImplementation) + /// + protected PluginConfigurationViewModel(Plugin plugin) { - PluginImplementation = pluginImplementation; + Plugin = plugin; } /// /// Creates a new instance of the class with a validator /// - /// + /// /// - protected PluginConfigurationViewModel(PluginImplementation pluginImplementation, IModelValidator validator) : base(validator) + protected PluginConfigurationViewModel(Plugin plugin, IModelValidator validator) : base(validator) { - PluginImplementation = pluginImplementation; + Plugin = plugin; } /// /// Gets the plugin this configuration view model is associated with /// - public PluginImplementation PluginImplementation { get; } + public Plugin Plugin { get; } } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs b/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs index cebb27fcc..3db1233fc 100644 --- a/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs +++ b/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs @@ -8,25 +8,25 @@ namespace Artemis.UI.Shared { private readonly IProfileEditorService _profileEditorService; - internal PropertyInputRegistration(IProfileEditorService profileEditorService, PluginInfo pluginInfo, Type supportedType, Type viewModelType) + internal PropertyInputRegistration(IProfileEditorService profileEditorService, Plugin plugin, Type supportedType, Type viewModelType) { _profileEditorService = profileEditorService; - PluginInfo = pluginInfo; + Plugin = plugin; SupportedType = supportedType; ViewModelType = viewModelType; - if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Plugin.Disabled += InstanceOnDisabled; + if (Plugin != Constants.CorePlugin) + Plugin.Disabled += InstanceOnDisabled; } - public PluginInfo PluginInfo { get; } + public Plugin Plugin { get; } public Type SupportedType { get; } public Type ViewModelType { get; } internal void Unsubscribe() { - if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Plugin.Disabled -= InstanceOnDisabled; + if (Plugin != Constants.CorePlugin) + Plugin.Disabled -= InstanceOnDisabled; } private void InstanceOnDisabled(object sender, EventArgs e) diff --git a/src/Artemis.UI.Shared/Services/DataModelUIService.cs b/src/Artemis.UI.Shared/Services/DataModelUIService.cs index 1493fbd2d..d2399a3b8 100644 --- a/src/Artemis.UI.Shared/Services/DataModelUIService.cs +++ b/src/Artemis.UI.Shared/Services/DataModelUIService.cs @@ -42,24 +42,24 @@ namespace Artemis.UI.Shared.Services return viewModel; } - public DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginImplementation pluginImplementation, bool includeMainDataModel) + public DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginFeature pluginFeature, bool includeMainDataModel) { if (includeMainDataModel) { DataModelPropertiesViewModel mainDataModel = GetMainDataModelVisualization(); // If the main data model already includes the plugin data model we're done - if (mainDataModel.Children.Any(c => c.DataModel.Implementation.Instance == pluginImplementation)) + if (mainDataModel.Children.Any(c => c.DataModel.Feature == pluginFeature)) return mainDataModel; // Otherwise get just the plugin data model and add it - DataModelPropertiesViewModel pluginDataModel = GetPluginDataModelVisualization(pluginImplementation, false); + DataModelPropertiesViewModel pluginDataModel = GetPluginDataModelVisualization(pluginFeature, false); if (pluginDataModel != null) mainDataModel.Children.Add(pluginDataModel); return mainDataModel; } - DataModel dataModel = _dataModelService.GetPluginDataModel(pluginImplementation); + DataModel dataModel = _dataModelService.GetPluginDataModel(pluginFeature); if (dataModel == null) return null; @@ -72,7 +72,7 @@ namespace Artemis.UI.Shared.Services return viewModel; } - public DataModelVisualizationRegistration RegisterDataModelInput(PluginInfo pluginInfo, IReadOnlyCollection compatibleConversionTypes = null) where T : DataModelInputViewModel + public DataModelVisualizationRegistration RegisterDataModelInput(Plugin plugin, IReadOnlyCollection compatibleConversionTypes = null) where T : DataModelInputViewModel { if (compatibleConversionTypes == null) compatibleConversionTypes = new List(); @@ -83,19 +83,16 @@ namespace Artemis.UI.Shared.Services DataModelVisualizationRegistration existing = _registeredDataModelEditors.FirstOrDefault(r => r.SupportedType == supportedType); if (existing != null) { - if (existing.PluginInfo != pluginInfo) - { - throw new ArtemisPluginException($"Cannot register data model input for type {supportedType.Name} " + - $"because an editor was already registered by {pluginInfo.Name}"); - } - + if (existing.Plugin != plugin) + throw new ArtemisPluginException($"Cannot register data model input for type {supportedType.Name} because an editor was already" + + $" registered by {existing.Plugin}"); return existing; } _kernel.Bind(viewModelType).ToSelf(); // Create the registration - DataModelVisualizationRegistration registration = new DataModelVisualizationRegistration(this, RegistrationType.Input, pluginInfo, supportedType, viewModelType) + DataModelVisualizationRegistration registration = new DataModelVisualizationRegistration(this, RegistrationType.Input, plugin, supportedType, viewModelType) { // Apply the compatible conversion types to the registration CompatibleConversionTypes = compatibleConversionTypes @@ -106,7 +103,7 @@ namespace Artemis.UI.Shared.Services } } - public DataModelVisualizationRegistration RegisterDataModelDisplay(PluginInfo pluginInfo) where T : DataModelDisplayViewModel + public DataModelVisualizationRegistration RegisterDataModelDisplay(Plugin plugin) where T : DataModelDisplayViewModel { Type viewModelType = typeof(T); lock (_registeredDataModelDisplays) @@ -115,17 +112,14 @@ namespace Artemis.UI.Shared.Services DataModelVisualizationRegistration existing = _registeredDataModelDisplays.FirstOrDefault(r => r.SupportedType == supportedType); if (existing != null) { - if (existing.PluginInfo != pluginInfo) - { - throw new ArtemisPluginException($"Cannot register data model display for type {supportedType.Name} " + - $"because an editor was already registered by {pluginInfo.Name}"); - } - + if (existing.Plugin != plugin) + throw new ArtemisPluginException($"Cannot register data model display for type {supportedType.Name} because an editor was already" + + $" registered by {existing.Plugin}"); return existing; } _kernel.Bind(viewModelType).ToSelf(); - DataModelVisualizationRegistration registration = new DataModelVisualizationRegistration(this, RegistrationType.Display, pluginInfo, supportedType, viewModelType); + DataModelVisualizationRegistration registration = new DataModelVisualizationRegistration(this, RegistrationType.Display, plugin, supportedType, viewModelType); _registeredDataModelDisplays.Add(registration); return registration; } @@ -167,7 +161,7 @@ namespace Artemis.UI.Shared.Services DataModelVisualizationRegistration match = _registeredDataModelDisplays.FirstOrDefault(d => d.SupportedType == propertyType); if (match != null) - result = (DataModelDisplayViewModel) match.PluginInfo.Kernel.Get(match.ViewModelType); + result = (DataModelDisplayViewModel) match.Plugin.Kernel.Get(match.ViewModelType); else if (!fallBackToDefault) result = null; else @@ -220,11 +214,12 @@ namespace Artemis.UI.Shared.Services if (initialValue != null && initialValue.GetType() != registration.SupportedType) initialValue = Convert.ChangeType(initialValue, registration.SupportedType); - IParameter[] parameters = { + IParameter[] parameters = + { new ConstructorArgument("targetDescription", description), new ConstructorArgument("initialValue", initialValue) }; - DataModelInputViewModel viewModel = (DataModelInputViewModel) registration.PluginInfo.Kernel.Get(registration.ViewModelType, parameters); + DataModelInputViewModel viewModel = (DataModelInputViewModel) registration.Plugin.Kernel.Get(registration.ViewModelType, parameters); viewModel.CompatibleConversionTypes = registration.CompatibleConversionTypes; return viewModel; } diff --git a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs index 25066daff..a62dcf014 100644 --- a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs +++ b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs @@ -109,11 +109,12 @@ namespace Artemis.UI.Shared.Services private async Task ShowDialogAt(string identifier, IParameter[] parameters) where T : DialogViewModelBase { - PluginImplementation callingPluginImplementation = _pluginManagementService.GetCallingPlugin(); - if (parameters == null) throw new ArgumentNullException(nameof(parameters)); + Plugin callingPlugin = _pluginManagementService.GetCallingPlugin(); + if (parameters == null) + throw new ArgumentNullException(nameof(parameters)); - if (callingPluginImplementation != null) - return await ShowDialog(identifier, callingPluginImplementation.PluginInfo.Kernel.Get(parameters)); + if (callingPlugin != null) + return await ShowDialog(identifier, callingPlugin.Kernel.Get(parameters)); return await ShowDialog(identifier, _kernel.Get(parameters)); } diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs index 7e6fdd399..d32adef6e 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs @@ -12,10 +12,10 @@ namespace Artemis.UI.Shared.Services IReadOnlyCollection RegisteredDataModelEditors { get; } IReadOnlyCollection RegisteredDataModelDisplays { get; } DataModelPropertiesViewModel GetMainDataModelVisualization(); - DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginImplementation pluginImplementation, bool includeMainDataModel); + DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginFeature pluginFeature, bool includeMainDataModel); - DataModelVisualizationRegistration RegisterDataModelInput(PluginInfo pluginInfo, IReadOnlyCollection compatibleConversionTypes) where T : DataModelInputViewModel; - DataModelVisualizationRegistration RegisterDataModelDisplay(PluginInfo pluginInfo) where T : DataModelDisplayViewModel; + DataModelVisualizationRegistration RegisterDataModelInput(Plugin plugin, IReadOnlyCollection compatibleConversionTypes) where T : DataModelInputViewModel; + DataModelVisualizationRegistration RegisterDataModelDisplay(Plugin plugin) where T : DataModelDisplayViewModel; void RemoveDataModelInput(DataModelVisualizationRegistration registration); void RemoveDataModelDisplay(DataModelVisualizationRegistration registration); diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs index 8cb46338d..92f712a02 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs @@ -71,9 +71,9 @@ namespace Artemis.UI.Shared.Services /// /// Note: Registration will remove itself on plugin disable so you don't have to /// - /// + /// /// - PropertyInputRegistration RegisterPropertyInput(PluginInfo pluginInfo) where T : PropertyInputViewModel; + PropertyInputRegistration RegisterPropertyInput(Plugin plugin) where T : PropertyInputViewModel; /// /// Registers a new property input view model used in the profile editor for the generic type defined in @@ -81,9 +81,9 @@ namespace Artemis.UI.Shared.Services /// Note: Registration will remove itself on plugin disable so you don't have to /// /// - /// + /// /// - PropertyInputRegistration RegisterPropertyInput(Type viewModelType, PluginInfo pluginInfo); + PropertyInputRegistration RegisterPropertyInput(Type viewModelType, Plugin plugin); void RemovePropertyInput(PropertyInputRegistration registration); diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index f50b80185..0dca8e593 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -177,12 +177,12 @@ namespace Artemis.UI.Shared.Services return true; } - public PropertyInputRegistration RegisterPropertyInput(PluginInfo pluginInfo) where T : PropertyInputViewModel + public PropertyInputRegistration RegisterPropertyInput(Plugin plugin) where T : PropertyInputViewModel { - return RegisterPropertyInput(typeof(T), pluginInfo); + return RegisterPropertyInput(typeof(T), plugin); } - public PropertyInputRegistration RegisterPropertyInput(Type viewModelType, PluginInfo pluginInfo) + public PropertyInputRegistration RegisterPropertyInput(Type viewModelType, Plugin plugin) { if (!typeof(PropertyInputViewModel).IsAssignableFrom(viewModelType)) throw new ArtemisSharedUIException($"Property input VM type must implement {nameof(PropertyInputViewModel)}"); @@ -201,13 +201,14 @@ namespace Artemis.UI.Shared.Services PropertyInputRegistration existing = _registeredPropertyEditors.FirstOrDefault(r => r.SupportedType == supportedType); if (existing != null) { - if (existing.PluginInfo != pluginInfo) - throw new ArtemisPluginException($"Cannot register property editor for type {supportedType.Name} because an editor was already registered by {existing.PluginInfo.Name}"); + if (existing.Plugin != plugin) + throw new ArtemisPluginException($"Cannot register property editor for type {supportedType.Name} because an editor was already " + + $"registered by {existing.Plugin}"); return existing; } Kernel.Bind(viewModelType).ToSelf(); - PropertyInputRegistration registration = new PropertyInputRegistration(this, pluginInfo, supportedType, viewModelType); + PropertyInputRegistration registration = new PropertyInputRegistration(this, plugin, supportedType, viewModelType); _registeredPropertyEditors.Add(registration); return registration; } @@ -281,7 +282,7 @@ namespace Artemis.UI.Shared.Services return null; ConstructorArgument parameter = new ConstructorArgument("layerProperty", layerProperty); - IKernel kernel = registration != null ? registration.PluginInfo.Kernel : Kernel; + IKernel kernel = registration != null ? registration.Plugin.Kernel : Kernel; return (PropertyInputViewModel) kernel.Get(viewModelType, parameter); } diff --git a/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs b/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs index 140b104bd..cdf75ad1c 100644 --- a/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs +++ b/src/Artemis.UI.Shared/Utilities/PluginUtilities.cs @@ -14,13 +14,13 @@ namespace Artemis.UI.Shared /// /// Transforms the provided icon so that it is usable by the control /// - /// The info of the plugin the icon belongs to + /// The plugin the icon belongs to /// /// The icon, may be a string representation of a or a relative path /// pointing to a .svg file /// /// - public static object GetPluginIcon(PluginInfo pluginInfo, string icon) + public static object GetPluginIcon(Plugin plugin, string icon) { if (icon == null) return PackIconKind.QuestionMarkCircle; @@ -28,7 +28,7 @@ namespace Artemis.UI.Shared // Icon is provided as a path if (icon.EndsWith(".svg")) { - string iconPath = pluginInfo.ResolveRelativePath(icon); + string iconPath = plugin.ResolveRelativePath(icon); if (!File.Exists(iconPath)) return PackIconKind.QuestionMarkCircle; return iconPath; diff --git a/src/Artemis.UI.Shared/packages.lock.json b/src/Artemis.UI.Shared/packages.lock.json index 6f3d41d90..7df90fbc1 100644 --- a/src/Artemis.UI.Shared/packages.lock.json +++ b/src/Artemis.UI.Shared/packages.lock.json @@ -1300,7 +1300,6 @@ "Serilog.Sinks.Debug": "1.0.1", "Serilog.Sinks.File": "4.1.0", "SkiaSharp": "1.68.3", - "Stylet": "1.3.4", "System.Buffers": "4.5.0", "System.Numerics.Vectors": "4.5.0", "System.Reflection.Metadata": "1.8.0", diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs index dbced1ec0..7eb1fec3f 100644 --- a/src/Artemis.UI/Bootstrapper.cs +++ b/src/Artemis.UI/Bootstrapper.cs @@ -39,6 +39,8 @@ namespace Artemis.UI protected override void Launch() { + Core.Utilities.ShutdownRequested += UtilitiesOnShutdownRequested; + ILogger logger = Kernel.Get(); IViewManager viewManager = Kernel.Get(); @@ -84,6 +86,11 @@ namespace Artemis.UI }); } + private void UtilitiesOnShutdownRequested(object? sender, EventArgs e) + { + Execute.OnUIThread(() => Application.Current.Shutdown()); + } + protected override void ConfigureIoC(IKernel kernel) { kernel.Settings.InjectNonPublic = true; diff --git a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs index a7a3b0e53..9f4699243 100644 --- a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs @@ -39,7 +39,7 @@ namespace Artemis.UI.PropertyInput public void UpdateEnumValues() { - List layerBrushProviders = _pluginManagementService.GetPluginsOfType(); + List layerBrushProviders = _pluginManagementService.GetFeaturesOfType(); Descriptors = new BindableCollection(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); NotifyOfPropertyChange(nameof(SelectedDescriptor)); } diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs index 3115c8e19..b73ccea26 100644 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -35,7 +35,8 @@ namespace Artemis.UI.Ninject.Factories public interface ISettingsVmFactory : IVmFactory { - PluginSettingsViewModel CreatePluginSettingsViewModel(PluginImplementation pluginImplementation); + PluginSettingsViewModel CreatePluginSettingsViewModel(Plugin plugin); + PluginFeatureViewModel CreatePluginFeatureViewModel(PluginFeature feature); DeviceSettingsViewModel CreateDeviceSettingsViewModel(ArtemisDevice device); } diff --git a/src/Artemis.UI/Ninject/PluginUIModule.cs b/src/Artemis.UI/Ninject/PluginUIModule.cs index 5cccc2033..ae4d0d409 100644 --- a/src/Artemis.UI/Ninject/PluginUIModule.cs +++ b/src/Artemis.UI/Ninject/PluginUIModule.cs @@ -10,19 +10,19 @@ namespace Artemis.UI.Ninject { public class PluginUIModule : NinjectModule { - public PluginUIModule(PluginInfo pluginInfo) + public PluginUIModule(Plugin plugin) { - PluginInfo = pluginInfo ?? throw new ArgumentNullException(nameof(pluginInfo)); + Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin)); } - public PluginInfo PluginInfo { get; } + public Plugin Plugin { get; } public override void Load() { Bind(typeof(IModelValidator<>)).To(typeof(FluentValidationAdapter<>)); Kernel.Bind(x => { - x.From(PluginInfo.Assembly) + x.From(Plugin.Assembly) .SelectAllClasses() .InheritedFrom() .BindAllInterfaces(); diff --git a/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs b/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs index 1986f77b0..90b7e1330 100644 --- a/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs +++ b/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs @@ -2,6 +2,7 @@ using System.Linq; using Artemis.Core.Modules; using Artemis.UI.Ninject.Factories; +using Artemis.UI.Shared.Modules; using Ninject; using Ninject.Parameters; using Stylet; @@ -45,7 +46,7 @@ namespace Artemis.UI.Screens.Modules ConstructorArgument module = new ConstructorArgument("module", Module); ConstructorArgument displayName = new ConstructorArgument("displayName", DisplayName); - ModuleViewModel viewModel = (ModuleViewModel) Module.PluginInfo.Kernel.Get(moduleTab.Type, module, displayName); + ModuleViewModel viewModel = (ModuleViewModel) Module.Plugin.Kernel.Get(moduleTab.Type, module, displayName); Items.Add(viewModel); } } diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs index 8ab195a6f..c3e43e965 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs @@ -35,7 +35,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects public void PopulateDescriptors() { - List layerBrushProviders = _pluginManagementService.GetPluginsOfType(); + List layerBrushProviders = _pluginManagementService.GetFeaturesOfType(); List descriptors = layerBrushProviders.SelectMany(l => l.LayerEffectDescriptors).ToList(); Items.AddRange(descriptors.Except(Items)); Items.RemoveRange(Items.Except(descriptors)); diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs index 48d37fe72..a78c57aae 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs @@ -9,6 +9,8 @@ using Artemis.Core.LayerEffects; using Artemis.UI.Exceptions; using Artemis.UI.Screens.ProfileEditor.Dialogs; using Artemis.UI.Screens.ProfileEditor.Windows; +using Artemis.UI.Shared.LayerBrushes; +using Artemis.UI.Shared.LayerEffects; using Artemis.UI.Shared.Services; using Ninject; using Ninject.Parameters; @@ -18,6 +20,15 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree { public class TreeGroupViewModel : PropertyChangedBase { + public enum LayerPropertyGroupType + { + General, + Transform, + LayerBrushRoot, + LayerEffectRoot, + None + } + private readonly IDialogService _dialogService; private readonly IKernel _kernel; private readonly IProfileEditorService _profileEditorService; @@ -55,7 +66,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree public void OpenBrushSettings() { BaseLayerBrush layerBrush = LayerPropertyGroup.LayerBrush; - LayerBrushConfigurationDialog configurationViewModel = layerBrush.ConfigurationDialog; + LayerBrushConfigurationDialog configurationViewModel = (LayerBrushConfigurationDialog) layerBrush.ConfigurationDialog; if (configurationViewModel == null) return; @@ -69,7 +80,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree // Find the BaseLayerBrush parameter, it is required by the base constructor so its there for sure ParameterInfo brushParameter = constructors.First().GetParameters().First(p => typeof(BaseLayerBrush).IsAssignableFrom(p.ParameterType)); ConstructorArgument argument = new ConstructorArgument(brushParameter.Name, layerBrush); - BrushConfigurationViewModel viewModel = (BrushConfigurationViewModel) layerBrush.PluginInfo.Kernel.Get(configurationViewModel.Type, argument); + BrushConfigurationViewModel viewModel = (BrushConfigurationViewModel) layerBrush.Descriptor.Provider.Plugin.Kernel.Get(configurationViewModel.Type, argument); _windowManager.ShowDialog(new LayerBrushSettingsWindowViewModel(viewModel)); } @@ -82,7 +93,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree public void OpenEffectSettings() { BaseLayerEffect layerEffect = LayerPropertyGroup.LayerEffect; - LayerEffectConfigurationDialog configurationViewModel = layerEffect.ConfigurationDialog; + LayerEffectConfigurationDialog configurationViewModel = (LayerEffectConfigurationDialog) layerEffect.ConfigurationDialog; if (configurationViewModel == null) return; @@ -95,7 +106,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree ParameterInfo effectParameter = constructors.First().GetParameters().First(p => typeof(BaseLayerEffect).IsAssignableFrom(p.ParameterType)); ConstructorArgument argument = new ConstructorArgument(effectParameter.Name, layerEffect); - EffectConfigurationViewModel viewModel = (EffectConfigurationViewModel) layerEffect.PluginInfo.Kernel.Get(configurationViewModel.Type, argument); + EffectConfigurationViewModel viewModel = (EffectConfigurationViewModel) layerEffect.Descriptor.Provider.Plugin.Kernel.Get(configurationViewModel.Type, argument); _windowManager.ShowDialog(new LayerEffectSettingsWindowViewModel(viewModel)); } catch (Exception e) @@ -169,14 +180,5 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree else GroupType = LayerPropertyGroupType.None; } - - public enum LayerPropertyGroupType - { - General, - Transform, - LayerBrushRoot, - LayerEffectRoot, - None - } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerBrushSettingsWindowViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerBrushSettingsWindowViewModel.cs index a1601ce90..682be6025 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerBrushSettingsWindowViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerBrushSettingsWindowViewModel.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.LayerBrushes; +using Artemis.UI.Shared.LayerBrushes; using Stylet; namespace Artemis.UI.Screens.ProfileEditor.Windows diff --git a/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerEffectSettingsWindowViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerEffectSettingsWindowViewModel.cs index cf759dde2..6d2438bdf 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerEffectSettingsWindowViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Windows/LayerEffectSettingsWindowViewModel.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.LayerEffects; +using Artemis.UI.Shared.LayerEffects; using Stylet; namespace Artemis.UI.Screens.ProfileEditor.Windows diff --git a/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs index 198d0f846..f5b534518 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugViewModel.cs @@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.Settings.Debug { try { - Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginImplementation.PluginInfo.Directory.FullName); + Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginFeature.Plugin.Directory.FullName); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs index 2bd2a2b79..9b1e61659 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs @@ -117,7 +117,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs private void PopulateModules() { - Modules = _pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); + Modules = _pluginManagementService.GetFeaturesOfType().Where(p => p.IsEnabled).ToList(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs index 5093f01df..a89933790 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs @@ -60,7 +60,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices { try { - Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginImplementation.PluginInfo.Directory.FullName); + Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginFeature.Plugin.Directory.FullName); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs index d9d405546..06c65f3c4 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs @@ -46,12 +46,12 @@ namespace Artemis.UI.Screens.Settings.Tabs.General // Anything else is kinda broken right now SampleSizes = new List {1, 9}; - List layerBrushProviders = pluginManagementService.GetPluginsOfType(); + List layerBrushProviders = pluginManagementService.GetFeaturesOfType(); LayerBrushDescriptors = new BindableCollection(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); _defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference { - BrushPluginGuid = Guid.Parse("92a9d6ba-6f7a-4937-94d5-c1d715b4141a"), + LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba", BrushType = "ColorBrush" }); } diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs index a0e92df46..ec0d8ad41 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs @@ -20,7 +20,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Modules _pluginManagementService = pluginManagementService; _moduleService = moduleService; - _modules = new List(pluginManagementService.GetPluginsOfType().Select(m => new ModuleOrderModuleViewModel(m))); + _modules = new List(pluginManagementService.GetFeaturesOfType().Select(m => new ModuleOrderModuleViewModel(m))); _defaultDropHandler = new DefaultDropHandler(); NormalModules = new BindableCollection(); diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml new file mode 100644 index 000000000..8ef815d40 --- /dev/null +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + Feature enabled + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureViewModel.cs new file mode 100644 index 000000000..9ee01e301 --- /dev/null +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureViewModel.cs @@ -0,0 +1,160 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using Artemis.Core; +using Artemis.Core.DataModelExpansions; +using Artemis.Core.DeviceProviders; +using Artemis.Core.LayerBrushes; +using Artemis.Core.LayerEffects; +using Artemis.Core.Modules; +using Artemis.Core.Services; +using Artemis.UI.Shared.Services; +using Humanizer; +using MaterialDesignThemes.Wpf; +using Stylet; + +namespace Artemis.UI.Screens.Settings.Tabs.Plugins +{ + public class PluginFeatureViewModel : Screen + { + private readonly IDialogService _dialogService; + private readonly IPluginManagementService _pluginManagementService; + private readonly ISnackbarMessageQueue _snackbarMessageQueue; + private bool _enabling; + private bool _isEnabled; + + public PluginFeatureViewModel(PluginFeature feature, + IDialogService dialogService, + IPluginManagementService pluginManagementService, + ISnackbarMessageQueue snackbarMessageQueue) + { + _dialogService = dialogService; + _pluginManagementService = pluginManagementService; + _snackbarMessageQueue = snackbarMessageQueue; + + Feature = feature; + Icon = GetIconKind(); + + IsEnabled = Feature.IsEnabled; + } + + public PluginFeature Feature { get; } + public PackIconKind Icon { get; } + + public string Name => Feature.GetType().Name.Humanize(); + + public Exception LoadException => Feature.LoadException; + + public bool Enabling + { + get => _enabling; + set => SetAndNotify(ref _enabling, value); + } + + public bool IsEnabled + { + get => _isEnabled; + set => SetAndNotify(ref _isEnabled, value); + } + + public void ShowLogsFolder() + { + try + { + Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs")); + } + catch (Exception e) + { + _dialogService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e); + } + } + + protected override void OnInitialActivate() + { + base.OnInitialActivate(); + _pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling; + _pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped; + _pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped; + } + + protected override void OnClose() + { + base.OnClose(); + _pluginManagementService.PluginFeatureEnabling -= OnFeatureEnabling; + _pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped; + _pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped; + } + + private async Task UpdateEnabled(bool enable) + { + if (IsEnabled == enable) + { + NotifyOfPropertyChange(nameof(IsEnabled)); + return; + } + + if (enable) + { + Enabling = true; + + try + { + await Task.Run(() => _pluginManagementService.EnablePluginFeature(Feature)); + } + catch (Exception e) + { + _snackbarMessageQueue.Enqueue($"Failed to enable {Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder); + } + finally + { + Enabling = false; + } + } + else + { + _pluginManagementService.DisablePluginFeature(Feature); + } + } + + private PackIconKind GetIconKind() + { + switch (Feature) + { + case BaseDataModelExpansion _: + return PackIconKind.TableAdd; + case DeviceProvider _: + return PackIconKind.Devices; + case ProfileModule _: + return PackIconKind.VectorRectangle; + case Module _: + return PackIconKind.GearBox; + case LayerBrushProvider _: + return PackIconKind.Brush; + case LayerEffectProvider _: + return PackIconKind.AutoAwesome; + } + + return PackIconKind.Plugin; + } + + #region Event handlers + + private void OnFeatureEnabling(object? sender, PluginFeatureEventArgs e) + { + if (e.PluginFeature != Feature) return; + Enabling = true; + } + + private void OnFeatureEnableStopped(object? sender, PluginFeatureEventArgs e) + { + if (e.PluginFeature != Feature) return; + Enabling = false; + IsEnabled = e.PluginFeature.IsEnabled; + + NotifyOfPropertyChange(nameof(LoadException)); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs index 82488df16..34861783a 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs @@ -11,7 +11,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins { private readonly IPluginManagementService _pluginManagementService; private readonly ISettingsVmFactory _settingsVmFactory; - private BindableCollection _plugins; public PluginSettingsTabViewModel(IPluginManagementService pluginManagementService, ISettingsVmFactory settingsVmFactory) { @@ -29,8 +28,8 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins Items.Clear(); await Task.Delay(200); - List instances = _pluginManagementService.GetAllPluginInfo().Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p.Plugin)).ToList(); - foreach (PluginSettingsViewModel pluginSettingsViewModel in instances) + List instances = _pluginManagementService.GetAllPlugins().Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p)).ToList(); + foreach (PluginSettingsViewModel pluginSettingsViewModel in instances.OrderBy(i => i.Plugin.Info.Name)) Items.Add(pluginSettingsViewModel); }); diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml index 0a5b1baf8..ac3de8a64 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml @@ -6,17 +6,19 @@ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:s="https://github.com/canton7/Stylet" xmlns:devices="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins" + xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared" d:DataContext="{d:DesignInstance devices:PluginSettingsViewModel}" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> - + - + + - + @@ -24,45 +26,27 @@ - - - - - - + + + @@ -82,6 +66,23 @@ Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"> + + + + Plugin features + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs index 69f9076da..a67c87fe4 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs @@ -2,64 +2,50 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Threading.Tasks; using Artemis.Core; -using Artemis.Core.DataModelExpansions; -using Artemis.Core.DeviceProviders; -using Artemis.Core.LayerBrushes; -using Artemis.Core.LayerEffects; -using Artemis.Core.Modules; using Artemis.Core.Services; -using Artemis.UI.Exceptions; +using Artemis.UI.Ninject.Factories; +using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using MaterialDesignThemes.Wpf; using Ninject; -using Ninject.Parameters; -using Serilog; using Stylet; -using Module = Artemis.Core.Modules.Module; namespace Artemis.UI.Screens.Settings.Tabs.Plugins { - public class PluginSettingsViewModel : PropertyChangedBase + public class PluginSettingsViewModel : Conductor.Collection.AllActive { private readonly IDialogService _dialogService; - private readonly ILogger _logger; private readonly IPluginManagementService _pluginManagementService; + private readonly ISettingsVmFactory _settingsVmFactory; private readonly ISnackbarMessageQueue _snackbarMessageQueue; private readonly IWindowManager _windowManager; private bool _enabling; - private PluginImplementation _pluginImplementation; - private PluginInfo _pluginInfo; + private Plugin _plugin; - public PluginSettingsViewModel(PluginImplementation pluginImplementation, - ILogger logger, + public PluginSettingsViewModel(Plugin plugin, + ISettingsVmFactory settingsVmFactory, IWindowManager windowManager, IDialogService dialogService, IPluginManagementService pluginManagementService, ISnackbarMessageQueue snackbarMessageQueue) { - PluginImplementation = pluginImplementation; - PluginInfo = pluginImplementation.PluginInfo; + Plugin = plugin; - _logger = logger; + _settingsVmFactory = settingsVmFactory; _windowManager = windowManager; _dialogService = dialogService; _pluginManagementService = pluginManagementService; _snackbarMessageQueue = snackbarMessageQueue; + + Icon = PluginUtilities.GetPluginIcon(Plugin, Plugin.Info.Icon); } - public PluginImplementation PluginImplementation + public Plugin Plugin { - get => _pluginImplementation; - set => SetAndNotify(ref _pluginImplementation, value); - } - - public PluginInfo PluginInfo - { - get => _pluginInfo; - set => SetAndNotify(ref _pluginInfo, value); + get => _plugin; + set => SetAndNotify(ref _plugin, value); } public bool Enabling @@ -68,34 +54,25 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins set => SetAndNotify(ref _enabling, value); } - public PackIconKind Icon => GetIconKind(); - public string Type => PluginImplementation.GetType().BaseType?.Name ?? PluginImplementation.GetType().Name; - public bool CanOpenSettings => IsEnabled && PluginImplementation.ConfigurationDialog != null; - public bool DisplayLoadFailed => !Enabling && PluginInfo.LoadException != null; - public bool RequiresRestart => PluginImplementation.IsEnabled && !PluginInfo.IsEnabled; + public object Icon { get; set; } + public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name; + public bool CanOpenSettings => IsEnabled && Plugin.ConfigurationDialog != null; public bool IsEnabled { - get => PluginImplementation.PluginInfo.IsEnabled; + get => Plugin.IsEnabled; set => Task.Run(() => UpdateEnabled(value)); } public void OpenSettings() { - PluginConfigurationDialog configurationViewModel = PluginImplementation.ConfigurationDialog; + PluginConfigurationDialog configurationViewModel = (PluginConfigurationDialog) Plugin.ConfigurationDialog; if (configurationViewModel == null) return; try { - // Limit to one constructor, there's no need to have more and it complicates things anyway - ConstructorInfo[] constructors = configurationViewModel.Type.GetConstructors(); - if (constructors.Length != 1) - throw new ArtemisUIException("Plugin configuration dialogs must have exactly one constructor"); - - ParameterInfo pluginParameter = constructors.First().GetParameters().First(p => typeof(PluginImplementation).IsAssignableFrom(p.ParameterType)); - ConstructorArgument plugin = new ConstructorArgument(pluginParameter.Name, PluginImplementation); - PluginConfigurationViewModel viewModel = (PluginConfigurationViewModel) PluginInfo.Kernel.Get(configurationViewModel.Type, plugin); + PluginConfigurationViewModel viewModel = (PluginConfigurationViewModel) Plugin.Kernel.Get(configurationViewModel.Type); _windowManager.ShowDialog(new PluginSettingsWindowViewModel(viewModel, Icon)); } catch (Exception e) @@ -117,49 +94,22 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins } } - public void ShowLoadException() + protected override void OnInitialActivate() { - if (PluginInfo.LoadException == null) - return; + Plugin.FeatureAdded += PluginOnFeatureAdded; + Plugin.FeatureRemoved += PluginOnFeatureRemoved; + foreach (PluginFeature pluginFeature in Plugin.Features) + Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeature)); - _dialogService.ShowExceptionDialog("The plugin failed to load: " + PluginInfo.LoadException.Message, PluginInfo.LoadException); + base.OnInitialActivate(); } - public async Task Restart() + protected override void OnClose() { - _logger.Debug("Restarting for device provider disable {pluginInfo}", PluginImplementation.PluginInfo); + Plugin.FeatureAdded -= PluginOnFeatureAdded; + Plugin.FeatureRemoved -= PluginOnFeatureRemoved; - // Give the logger a chance to write, might not always be enough but oh well - await Task.Delay(500); - Core.Utilities.Shutdown(2, true); - } - - private PackIconKind GetIconKind() - { - if (PluginInfo.Icon != null) - { - bool parsedIcon = Enum.TryParse(PluginInfo.Icon, true, out PackIconKind iconEnum); - if (parsedIcon) - return iconEnum; - } - - switch (PluginImplementation) - { - case BaseDataModelExpansion _: - return PackIconKind.TableAdd; - case DeviceProvider _: - return PackIconKind.Devices; - case ProfileModule _: - return PackIconKind.VectorRectangle; - case Module _: - return PackIconKind.GearBox; - case LayerBrushProvider _: - return PackIconKind.Brush; - case LayerEffectProvider _: - return PackIconKind.AutoAwesome; - } - - return PackIconKind.Plugin; + base.OnClose(); } private async Task UpdateEnabled(bool enable) @@ -170,24 +120,17 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins return; } - if (!enable && PluginImplementation is DeviceProvider) - { - await DisableDeviceProvider(); - return; - } - if (enable) { Enabling = true; - NotifyOfPropertyChange(nameof(DisplayLoadFailed)); try { - _pluginManagementService.EnablePluginImplementation(PluginImplementation); + await Task.Run(() => _pluginManagementService.EnablePlugin(Plugin)); } catch (Exception e) { - _snackbarMessageQueue.Enqueue($"Failed to enable plugin {PluginInfo.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder); + _snackbarMessageQueue.Enqueue($"Failed to enable plugin {Plugin.Info.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder); } finally { @@ -195,44 +138,24 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins } } else - _pluginManagementService.DisablePluginImplementation(PluginImplementation); + { + _pluginManagementService.DisablePlugin(Plugin); + } NotifyOfPropertyChange(nameof(IsEnabled)); NotifyOfPropertyChange(nameof(CanOpenSettings)); - NotifyOfPropertyChange(nameof(RequiresRestart)); - NotifyOfPropertyChange(nameof(DisplayLoadFailed)); } - private async Task DisableDeviceProvider() + private void PluginOnFeatureRemoved(object? sender, PluginFeatureEventArgs e) { - bool restart = false; + PluginFeatureViewModel viewModel = Items.FirstOrDefault(i => i.Feature == e.PluginFeature); + if (viewModel != null) + Items.Remove(viewModel); + } - // If any plugin already requires a restart, don't ask the user again - bool restartQueued = _pluginManagementService.GetAllPluginInfo().Any(p => p.Plugin != null && !p.IsEnabled && p.Plugin.IsEnabled); - // If the plugin isn't enabled (load failed), it can be disabled without a restart - if (!restartQueued && PluginImplementation.IsEnabled) - { - restart = await _dialogService.ShowConfirmDialog( - "Disable device provider", - "You are disabling a device provider, Artemis has to restart to \r\nfully disable this type of plugin", - "Restart now", - "Restart later" - ); - } - - _pluginManagementService.DisablePluginImplementation(PluginImplementation); - if (restart) - { - _logger.Debug("Restarting for device provider disable {pluginInfo}", PluginImplementation.PluginInfo); - - // Give the logger a chance to write, might not always be enough but oh well - await Task.Delay(500); - Core.Utilities.Shutdown(2, true); - } - - NotifyOfPropertyChange(nameof(IsEnabled)); - NotifyOfPropertyChange(nameof(RequiresRestart)); - NotifyOfPropertyChange(nameof(DisplayLoadFailed)); + private void PluginOnFeatureAdded(object? sender, PluginFeatureEventArgs e) + { + Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(e.PluginFeature)); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml index 87d080ca3..f8bbfa6a6 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml @@ -23,7 +23,7 @@ Identifier="PluginSettingsDialog" DialogTheme="Inherit"> - + diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs index 4693ebba6..7f4a229f8 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs @@ -1,6 +1,5 @@ using System; -using Artemis.Core; -using MaterialDesignThemes.Wpf; +using Artemis.UI.Shared; using Stylet; namespace Artemis.UI.Screens.Settings.Tabs.Plugins @@ -9,12 +8,14 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins { private readonly PluginConfigurationViewModel _configurationViewModel; - public PluginSettingsWindowViewModel(PluginConfigurationViewModel configurationViewModel, PackIconKind icon) + public PluginSettingsWindowViewModel(PluginConfigurationViewModel configurationViewModel, object icon) { _configurationViewModel = configurationViewModel ?? throw new ArgumentNullException(nameof(configurationViewModel)); Icon = icon; } + public object Icon { get; } + protected override void OnInitialActivate() { ActiveItem = _configurationViewModel; @@ -23,8 +24,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins base.OnInitialActivate(); } - public PackIconKind Icon { get; } - private void ActiveItemOnClosed(object sender, CloseEventArgs e) { ActiveItem.Closed -= ActiveItemOnClosed; diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs index 6b77f99bf..b18d39f74 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using System.Timers; -using System.Windows.Media.Imaging; using Artemis.Core; using Artemis.Core.Modules; using Artemis.Core.Services; @@ -49,8 +47,8 @@ namespace Artemis.UI.Screens.Sidebar _activeModulesUpdateTimer.Start(); _activeModulesUpdateTimer.Elapsed += ActiveModulesUpdateTimerOnElapsed; - _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled; - _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementDisabled; + _pluginManagementService.PluginFeatureEnabled += OnFeatureEnabled; + _pluginManagementService.PluginFeatureDisabled += OnFeatureDisabled; SetupSidebar(); eventAggregator.Subscribe(this); @@ -91,18 +89,6 @@ namespace Artemis.UI.Screens.Sidebar } } - public void Dispose() - { - SelectedItem?.Deactivate(); - SelectedItem = null; - - _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementEnabled; - _pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementDisabled; - - _activeModulesUpdateTimer.Stop(); - _activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed; - } - public void SetupSidebar() { SidebarItems.Clear(); @@ -118,7 +104,7 @@ namespace Artemis.UI.Screens.Sidebar // Add all activated modules SidebarItems.Add(new DividerNavigationItem()); SidebarItems.Add(new SubheaderNavigationItem {Subheader = "Modules"}); - List modules = _pluginManagementService.GetPluginsOfType().ToList(); + List modules = _pluginManagementService.GetFeaturesOfType().ToList(); foreach (Module module in modules) AddModule(module); @@ -146,7 +132,7 @@ namespace Artemis.UI.Screens.Sidebar FirstLevelNavigationItem sidebarItem = new FirstLevelNavigationItem { - Icon = PluginUtilities.GetPluginIcon(module.PluginInfo, module.DisplayIcon), + Icon = PluginUtilities.GetPluginIcon(module.Plugin, module.DisplayIcon), Label = module.DisplayName }; SidebarItems.Add(sidebarItem); @@ -208,17 +194,29 @@ namespace Artemis.UI.Screens.Sidebar SelectedItem = SidebarModules.ContainsKey(sidebarItem) ? _moduleVmFactory.CreateModuleRootViewModel(SidebarModules[sidebarItem]) : null; } + public void Dispose() + { + SelectedItem?.Deactivate(); + SelectedItem = null; + + _pluginManagementService.PluginFeatureEnabled -= OnFeatureEnabled; + _pluginManagementService.PluginFeatureDisabled -= OnFeatureDisabled; + + _activeModulesUpdateTimer.Stop(); + _activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed; + } + #region Event handlers - private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs e) + private void OnFeatureEnabled(object? sender, PluginFeatureEventArgs e) { - if (e.PluginInfo.Plugin is Module module) + if (e.PluginFeature is Module module) AddModule(module); } - private void PluginManagementServiceOnPluginManagementDisabled(object sender, PluginEventArgs e) + private void OnFeatureDisabled(object? sender, PluginFeatureEventArgs e) { - if (e.PluginInfo.Plugin is Module module) + if (e.PluginFeature is Module module) RemoveModule(module); } diff --git a/src/Artemis.UI/Screens/Splash/SplashViewModel.cs b/src/Artemis.UI/Screens/Splash/SplashViewModel.cs index e4fc1c2a4..dcb747bf6 100644 --- a/src/Artemis.UI/Screens/Splash/SplashViewModel.cs +++ b/src/Artemis.UI/Screens/Splash/SplashViewModel.cs @@ -2,6 +2,7 @@ using System.Windows.Input; using Artemis.Core; using Artemis.Core.Services; +using Humanizer; using MaterialDesignExtensions.Controls; using Stylet; @@ -42,6 +43,8 @@ namespace Artemis.UI.Screens.Splash _pluginManagementService.PluginLoaded += OnPluginManagementServiceOnPluginManagementLoaded; _pluginManagementService.PluginEnabling += PluginManagementServiceOnPluginManagementEnabling; _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled; + _pluginManagementService.PluginFeatureEnabling += PluginManagementServiceOnPluginFeatureEnabling; + _pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureEnabled; base.OnInitialActivate(); } @@ -53,6 +56,8 @@ namespace Artemis.UI.Screens.Splash _pluginManagementService.PluginLoaded -= OnPluginManagementServiceOnPluginManagementLoaded; _pluginManagementService.PluginEnabling -= PluginManagementServiceOnPluginManagementEnabling; _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementEnabled; + _pluginManagementService.PluginFeatureEnabling -= PluginManagementServiceOnPluginFeatureEnabling; + _pluginManagementService.PluginFeatureEnabled -= PluginManagementServiceOnPluginFeatureEnabled; base.OnClose(); } @@ -63,7 +68,7 @@ namespace Artemis.UI.Screens.Splash private void OnPluginManagementServiceOnPluginManagementLoading(object sender, PluginEventArgs args) { - Status = "Loading plugin: " + args.PluginInfo.Name; + Status = "Loading plugin: " + args.Plugin.Info.Name; } private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs args) @@ -73,7 +78,17 @@ namespace Artemis.UI.Screens.Splash private void PluginManagementServiceOnPluginManagementEnabling(object sender, PluginEventArgs args) { - Status = "Enabling plugin: " + args.PluginInfo.Name; + Status = "Enabling plugin: " + args.Plugin.Info.Name; + } + + private void PluginManagementServiceOnPluginFeatureEnabling(object? sender, PluginFeatureEventArgs e) + { + Status = "Enabling: " + e.PluginFeature.GetType().Name.Humanize(); + } + + private void PluginManagementServiceOnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e) + { + Status = "Initializing UI"; } private void OnPluginManagementServiceOnCopyingBuildInPluginsManagement(object sender, EventArgs args) diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index c60671476..d70fb3db7 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -33,7 +33,7 @@ namespace Artemis.UI.Services if (_registeredBuiltInDataModelDisplays) return; - _dataModelUIService.RegisterDataModelDisplay(Constants.CorePluginInfo); + _dataModelUIService.RegisterDataModelDisplay(Constants.CorePlugin); _registeredBuiltInDataModelDisplays = true; } @@ -43,12 +43,12 @@ namespace Artemis.UI.Services if (_registeredBuiltInDataModelInputs) return; - _dataModelUIService.RegisterDataModelInput(Constants.CorePluginInfo, Constants.FloatNumberTypes); - _dataModelUIService.RegisterDataModelInput(Constants.CorePluginInfo, Constants.IntegralNumberTypes); - _dataModelUIService.RegisterDataModelInput(Constants.CorePluginInfo, null); - _dataModelUIService.RegisterDataModelInput(Constants.CorePluginInfo, null); - _dataModelUIService.RegisterDataModelInput(Constants.CorePluginInfo, null); - _dataModelUIService.RegisterDataModelInput(Constants.CorePluginInfo, null); + _dataModelUIService.RegisterDataModelInput(Constants.CorePlugin, Constants.FloatNumberTypes); + _dataModelUIService.RegisterDataModelInput(Constants.CorePlugin, Constants.IntegralNumberTypes); + _dataModelUIService.RegisterDataModelInput(Constants.CorePlugin, null); + _dataModelUIService.RegisterDataModelInput(Constants.CorePlugin, null); + _dataModelUIService.RegisterDataModelInput(Constants.CorePlugin, null); + _dataModelUIService.RegisterDataModelInput(Constants.CorePlugin, null); _registeredBuiltInDataModelInputs = true; } @@ -58,30 +58,30 @@ namespace Artemis.UI.Services if (_registeredBuiltInPropertyEditors) return; - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(typeof(EnumPropertyInputViewModel<>), Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); - _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(typeof(EnumPropertyInputViewModel<>), Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); + _profileEditorService.RegisterPropertyInput(Constants.CorePlugin); _registeredBuiltInPropertyEditors = true; } private void PluginServiceOnPluginLoaded(object? sender, PluginEventArgs e) { - e.PluginInfo.Kernel.Load(new[] { new PluginUIModule(e.PluginInfo) }); + e.Plugin.Kernel.Load(new[] {new PluginUIModule(e.Plugin)}); } private void LoadPluginModules() { - foreach (PluginInfo pluginInfo in _pluginManagementService.GetAllPluginInfo()) - pluginInfo.Kernel.Load(new[] { new PluginUIModule(pluginInfo) }); + foreach (Plugin plugin in _pluginManagementService.GetAllPlugins()) + plugin.Kernel.Load(new[] {new PluginUIModule(plugin)}); } } diff --git a/src/Artemis.UI/packages.lock.json b/src/Artemis.UI/packages.lock.json index 49487b577..4a4eefa79 100644 --- a/src/Artemis.UI/packages.lock.json +++ b/src/Artemis.UI/packages.lock.json @@ -1363,7 +1363,6 @@ "Serilog.Sinks.Debug": "1.0.1", "Serilog.Sinks.File": "4.1.0", "SkiaSharp": "1.68.3", - "Stylet": "1.3.4", "System.Buffers": "4.5.0", "System.Numerics.Vectors": "4.5.0", "System.Reflection.Metadata": "1.8.0", diff --git a/src/Artemis.sln.DotSettings b/src/Artemis.sln.DotSettings index d11049d68..2df38068d 100644 --- a/src/Artemis.sln.DotSettings +++ b/src/Artemis.sln.DotSettings @@ -222,4 +222,7 @@ True True True + True + + True \ No newline at end of file