1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 13:28:33 +00:00

Profiles - Added IPluginFeatureDependent interface and implement throughout profiles (#842)

* Profiles - Added IPluginFeatureDependent interface and implement througout profiles
* Workshop - Include dependencies in profile upload request
This commit is contained in:
RobertBeekman 2024-03-03 20:19:36 +01:00 committed by GitHub
parent 28640f9502
commit e5a5f10286
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 209 additions and 24 deletions

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace Artemis.Core;
/// <summary>
/// Represents a class that depends on plugin features
/// </summary>
public interface IPluginFeatureDependent
{
/// <summary>
/// Gets the plugin features this class depends on, may contain the same plugin feature twice if depending on it in multiple ways.
/// </summary>
/// <returns>A <see cref="List{T}"/> of <see cref="PluginFeature"/> this class depends on.</returns>
public IEnumerable<PluginFeature> GetFeatureDependencies();
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
@ -82,4 +83,14 @@ public class AlwaysOnCondition : ICondition
}
#endregion
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return [];
}
#endregion
}

View File

@ -325,4 +325,14 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
}
#endregion
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return Script.GetFeatureDependencies().Concat(EventPath?.GetFeatureDependencies() ?? []);
}
#endregion
}

View File

@ -6,7 +6,7 @@ namespace Artemis.Core;
/// <summary>
/// Represents a condition applied to a <see cref="ProfileElement" />
/// </summary>
public interface ICondition : IDisposable, IStorageModel
public interface ICondition : IDisposable, IStorageModel, IPluginFeatureDependent
{
/// <summary>
/// Gets the entity used to store this condition

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
@ -82,4 +83,14 @@ public class PlayOnceCondition : ICondition
}
#endregion
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return [];
}
#endregion
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
@ -159,6 +160,16 @@ public class StaticCondition : CorePropertyChanged, INodeScriptCondition
}
#endregion
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return Script.GetFeatureDependencies();
}
#endregion
}
/// <summary>

View File

@ -243,4 +243,14 @@ public class DataBinding<TLayerProperty> : IDataBinding
}
#endregion
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return Script.GetFeatureDependencies();
}
#endregion
}

View File

@ -8,7 +8,7 @@ namespace Artemis.Core;
/// Represents a data binding that binds a certain <see cref="LayerProperty{T}" /> to a value inside a
/// <see cref="DataModel" />
/// </summary>
public interface IDataBinding : IStorageModel, IDisposable
public interface IDataBinding : IStorageModel, IDisposable, IPluginFeatureDependent
{
/// <summary>
/// Gets the layer property the data binding is applied to

View File

@ -11,7 +11,7 @@ namespace Artemis.Core;
/// <summary>
/// Represents a path that points to a property in data model
/// </summary>
public class DataModelPath : IStorageModel, IDisposable
public class DataModelPath : IStorageModel, IDisposable, IPluginFeatureDependent
{
private readonly LinkedList<DataModelPathSegment> _segments;
private Expression<Func<object, object>>? _accessorLambda;
@ -188,6 +188,14 @@ public class DataModelPath : IStorageModel, IDisposable
return string.IsNullOrWhiteSpace(Path) ? "this" : Path;
}
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
if (Target == null)
return [];
return [Target.Module];
}
/// <summary>
/// Occurs whenever the path becomes invalid
/// </summary>

View File

@ -179,6 +179,14 @@ public sealed class Folder : RenderProfileElement
return $"[Folder] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
}
/// <inheritdoc />
public override IEnumerable<PluginFeature> GetFeatureDependencies()
{
return LayerEffects.SelectMany(e => e.GetFeatureDependencies())
.Concat(Children.SelectMany(c => c.GetFeatureDependencies()))
.Concat(DisplayCondition.GetFeatureDependencies());
}
#region Rendering
/// <inheritdoc />

View File

@ -189,6 +189,16 @@ public sealed class Layer : RenderProfileElement
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
}
/// <inheritdoc />
public override IEnumerable<PluginFeature> GetFeatureDependencies()
{
return LayerEffects.SelectMany(e => e.GetFeatureDependencies())
.Concat(LayerBrush?.GetFeatureDependencies() ?? [])
.Concat(General.GetFeatureDependencies())
.Concat(Transform.GetFeatureDependencies())
.Concat(DisplayCondition.GetFeatureDependencies());
}
/// <summary>
/// Occurs when a property affecting the rendering properties of this layer has been updated
/// </summary>
@ -768,7 +778,7 @@ public sealed class Layer : RenderProfileElement
if (!_leds.Remove(led))
return;
CalculateRenderProperties();
}

View File

@ -11,7 +11,7 @@ namespace Artemis.Core;
/// initialize these for you.
/// </para>
/// </summary>
public interface ILayerProperty : IStorageModel, IDisposable
public interface ILayerProperty : IStorageModel, IDisposable, IPluginFeatureDependent
{
/// <summary>
/// Gets the description attribute applied to this property

View File

@ -54,6 +54,12 @@ public class LayerProperty<T> : CorePropertyChanged, ILayerProperty
return $"{Path} - {CurrentValue} ({PropertyType})";
}
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return DataBinding.GetFeatureDependencies();
}
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>

View File

@ -15,7 +15,7 @@ namespace Artemis.Core;
/// initialize these for you.
/// </para>
/// </summary>
public abstract class LayerPropertyGroup : IDisposable
public abstract class LayerPropertyGroup : IDisposable, IPluginFeatureDependent
{
private readonly List<ILayerProperty> _layerProperties;
private readonly List<LayerPropertyGroup> _layerPropertyGroups;
@ -343,4 +343,14 @@ public abstract class LayerPropertyGroup : IDisposable
Dispose(true);
GC.SuppressFinalize(this);
}
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return LayerProperties.SelectMany(p => p.GetFeatureDependencies()).Concat(LayerPropertyGroups.SelectMany(g => g.GetFeatureDependencies()));
}
#endregion
}

View File

@ -171,6 +171,12 @@ public sealed class Profile : ProfileElement
return $"[Profile] {nameof(Name)}: {Name}";
}
/// <inheritdoc />
public override IEnumerable<PluginFeature> GetFeatureDependencies()
{
return GetRootFolder().GetFeatureDependencies().Concat(Scripts.Select(c => c.ScriptingProvider));
}
/// <summary>
/// Populates all the LEDs on the elements in this profile
/// </summary>

View File

@ -9,7 +9,7 @@ namespace Artemis.Core;
/// <summary>
/// Represents an element of a <see cref="Profile" />
/// </summary>
public abstract class ProfileElement : BreakableModel, IDisposable
public abstract class ProfileElement : BreakableModel, IDisposable, IPluginFeatureDependent
{
internal readonly List<ProfileElement> ChildrenList;
private Guid _entityId;
@ -122,6 +122,9 @@ public abstract class ProfileElement : BreakableModel, IDisposable
return $"{nameof(EntityId)}: {EntityId}, {nameof(Order)}: {Order}, {nameof(Name)}: {Name}";
}
/// <inheritdoc />
public abstract IEnumerable<PluginFeature> GetFeatureDependencies();
/// <summary>
/// Occurs when a child was added to the <see cref="Children" /> list
/// </summary>

View File

@ -9,13 +9,13 @@ namespace Artemis.Core;
/// <summary>
/// Represents the configuration of a profile, contained in a <see cref="ProfileCategory" />
/// </summary>
public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable, IPluginFeatureDependent
{
/// <summary>
/// Represents an empty profile.
/// </summary>
public static readonly ProfileConfiguration Empty = new(ProfileCategory.Empty, "Empty", "Empty");
private ActivationBehaviour _activationBehaviour;
private bool _activationConditionMet;
private ProfileCategory _category;
@ -146,7 +146,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
get => _activationConditionMet;
private set => SetAndNotify(ref _activationConditionMet, value);
}
/// <summary>
/// Gets the profile of this profile configuration
/// </summary>
@ -159,8 +159,8 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
/// <summary>
/// Gets or sets a boolean indicating whether this profile should fade in and out when enabling or disabling
/// </summary>
public bool FadeInAndOut
{
public bool FadeInAndOut
{
get => _fadeInAndOut;
set => SetAndNotify(ref _fadeInAndOut, value);
}
@ -188,7 +188,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
/// alongside any activation requirements of the <see cref="Module" />, if set
/// </summary>
public NodeScript<bool> ActivationCondition { get; }
/// <summary>
/// Gets the entity used by this profile config
/// </summary>
@ -247,6 +247,19 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
return $"[ProfileConfiguration] {nameof(Name)}: {Name}";
}
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
if (_disposed)
throw new ObjectDisposedException("ProfileConfiguration");
if (Profile == null)
throw new InvalidOperationException("Cannot determine feature dependencies when the profile is not loaded.");
return ActivationCondition.GetFeatureDependencies()
.Concat(Profile.GetFeatureDependencies())
.Concat(Module != null ? [Module] : []);
}
internal void LoadModules(List<Module> enabledModules)
{
if (_disposed)

View File

@ -9,7 +9,7 @@ namespace Artemis.Core.LayerBrushes;
/// <summary>
/// For internal use only, please use <see cref="LayerBrush{T}" /> or <see cref="PerLedLayerBrush{T}" /> or instead
/// </summary>
public abstract class BaseLayerBrush : BreakableModel, IDisposable
public abstract class BaseLayerBrush : BreakableModel, IDisposable, IPluginFeatureDependent
{
private LayerBrushType _brushType;
private ILayerBrushConfigurationDialog? _configurationDialog;
@ -199,6 +199,20 @@ public abstract class BaseLayerBrush : BreakableModel, IDisposable
Dispose(true);
GC.SuppressFinalize(this);
}
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
IEnumerable<PluginFeature> result = [Descriptor.Provider];
if (BaseProperties != null)
result = result.Concat(BaseProperties.GetFeatureDependencies());
return result;
}
#endregion
}
/// <summary>

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Storage.Entities.Profile;
using SkiaSharp;
@ -7,7 +9,7 @@ namespace Artemis.Core.LayerEffects;
/// <summary>
/// For internal use only, please use <see cref="LayerEffect{T}" /> instead
/// </summary>
public abstract class BaseLayerEffect : BreakableModel, IDisposable, IStorageModel
public abstract class BaseLayerEffect : BreakableModel, IDisposable, IStorageModel, IPluginFeatureDependent
{
private ILayerEffectConfigurationDialog? _configurationDialog;
private LayerEffectDescriptor _descriptor;
@ -164,7 +166,7 @@ public abstract class BaseLayerEffect : BreakableModel, IDisposable, IStorageMod
// Not only is this needed to initialize properties on the layer effects, it also prevents implementing anything
// but LayerEffect<T> outside the core
internal abstract void Initialize();
internal void InternalUpdate(Timeline timeline)
{
BaseProperties?.Update(timeline);
@ -235,4 +237,18 @@ public abstract class BaseLayerEffect : BreakableModel, IDisposable, IStorageMod
BaseProperties?.ApplyToEntity();
LayerEffectEntity.PropertyGroup = BaseProperties?.PropertyGroupEntity;
}
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
IEnumerable<PluginFeature> result = [Descriptor.Provider];
if (BaseProperties != null)
result = result.Concat(BaseProperties.GetFeatureDependencies());
return result;
}
#endregion
}

View File

@ -8,7 +8,7 @@ namespace Artemis.Core;
/// <summary>
/// Represents a kind of node inside a <see cref="INodeScript" />
/// </summary>
public interface INode : INotifyPropertyChanged, IBreakableModel
public interface INode : INotifyPropertyChanged, IBreakableModel, IPluginFeatureDependent
{
/// <summary>
/// Gets or sets the ID of the node.

View File

@ -8,7 +8,7 @@ namespace Artemis.Core;
/// <summary>
/// Represents a node script
/// </summary>
public interface INodeScript : INotifyPropertyChanged, IDisposable, IStorageModel
public interface INodeScript : INotifyPropertyChanged, IDisposable, IStorageModel, IPluginFeatureDependent
{
/// <summary>
/// Gets the name of the node script.

View File

@ -401,6 +401,16 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
}
#endregion
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public IEnumerable<PluginFeature> GetFeatureDependencies()
{
return Nodes.SelectMany(n => n.GetFeatureDependencies());
}
#endregion
}
/// <summary>

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.Events;
using DryIoc;
namespace Artemis.Core;
@ -404,4 +403,14 @@ public abstract class Node : BreakableModel, INode
}
#endregion
#region Implementation of IPluginFeatureDependent
/// <inheritdoc />
public virtual IEnumerable<PluginFeature> GetFeatureDependencies()
{
return NodeData == null ? [] : [NodeData.Provider];
}
#endregion
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using Artemis.Core;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Layout;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Plugin;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile;
@ -37,7 +38,7 @@ public class SubmissionWizardState : IDisposable
public List<ImageUploadRequest> Images { get; set; } = new();
public IEntrySource? EntrySource { get; set; }
public void ChangeScreen<TSubmissionViewModel>() where TSubmissionViewModel : SubmissionViewModel
{
try

View File

@ -65,10 +65,10 @@ public partial class ProfileSelectionStepViewModel : SubmissionViewModel
private void ExecuteContinue()
{
if (SelectedProfile == null)
if (SelectedProfile?.Profile == null)
return;
State.EntrySource = new ProfileEntrySource(SelectedProfile);
State.EntrySource = new ProfileEntrySource(SelectedProfile, SelectedProfile.GetFeatureDependencies().Distinct().ToList());
State.Name = SelectedProfile.Name;
State.Icon = SelectedProfile.Icon.GetIconStream();

View File

@ -4,10 +4,12 @@ namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
public class ProfileEntrySource : IEntrySource
{
public ProfileEntrySource(ProfileConfiguration profileConfiguration)
public ProfileEntrySource(ProfileConfiguration profileConfiguration, List<PluginFeature> dependencies)
{
ProfileConfiguration = profileConfiguration;
Dependencies = dependencies;
}
public ProfileConfiguration ProfileConfiguration { get; set; }
public ProfileConfiguration ProfileConfiguration { get; }
public List<PluginFeature> Dependencies { get; }
}

View File

@ -31,6 +31,7 @@ public class ProfileEntryUploadHandler : IEntryUploadHandler
MultipartFormDataContent content = new();
StreamContent streamContent = new(archiveStream);
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
content.Add(JsonContent.Create(source.Dependencies.Select(d => new {PluginId = d.Plugin.Guid, FeatureId = d.Id}).ToList()), "ReleaseDependencies");
content.Add(streamContent, "file", "file.zip");
// Submit