mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 13:28:33 +00:00
Merge branch 'development'
This commit is contained in:
commit
9fcd20d762
2
.github/workflows/docfx.yml
vendored
2
.github/workflows/docfx.yml
vendored
@ -26,7 +26,7 @@ jobs:
|
||||
- name: Build DocFX
|
||||
run: docfx docfx/docfx_project/docfx.json
|
||||
- name: Upload to FTP
|
||||
uses: SamKirkland/FTP-Deploy-Action@4.3.4
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
||||
with:
|
||||
server: www360.your-server.de
|
||||
protocol: ftps
|
||||
|
||||
@ -61,6 +61,9 @@ public abstract class BreakableModel : CorePropertyChanged, IBreakableModel
|
||||
/// <inheritdoc />
|
||||
public void SetBrokenState(string state, Exception? exception = null)
|
||||
{
|
||||
if (state == BrokenState && BrokenStateException?.StackTrace == exception?.StackTrace)
|
||||
return;
|
||||
|
||||
BrokenState = state ?? throw new ArgumentNullException(nameof(state));
|
||||
BrokenStateException = exception;
|
||||
OnBrokenStateChanged();
|
||||
|
||||
15
src/Artemis.Core/Models/IPluginFeatureDependent.cs
Normal file
15
src/Artemis.Core/Models/IPluginFeatureDependent.cs
Normal 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();
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -243,4 +243,14 @@ public class DataBinding<TLayerProperty> : IDataBinding
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IPluginFeatureDependent
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PluginFeature> GetFeatureDependencies()
|
||||
{
|
||||
return Script.GetFeatureDependencies();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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 />
|
||||
|
||||
@ -160,10 +160,12 @@ public sealed class Layer : RenderProfileElement
|
||||
public LayerAdapter Adapter { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool ShouldBeEnabled => !Suspended && DisplayConditionMet;
|
||||
public override bool ShouldBeEnabled => !Suspended && DisplayConditionMet && HasBounds;
|
||||
|
||||
internal override RenderElementEntity RenderElementEntity => LayerEntity;
|
||||
|
||||
private bool HasBounds => Bounds.Width > 0 && Bounds.Height > 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<ILayerProperty> GetAllLayerProperties()
|
||||
{
|
||||
@ -187,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>
|
||||
@ -383,7 +395,7 @@ public sealed class Layer : RenderProfileElement
|
||||
|
||||
if (ShouldBeEnabled)
|
||||
Enable();
|
||||
else if (Suspended || (Timeline.IsFinished && !_renderCopies.Any()))
|
||||
else if (Suspended || !HasBounds || (Timeline.IsFinished && !_renderCopies.Any()))
|
||||
Disable();
|
||||
|
||||
if (!Enabled || Timeline.Delta == TimeSpan.Zero)
|
||||
@ -766,7 +778,7 @@ public sealed class Layer : RenderProfileElement
|
||||
|
||||
if (!_leds.Remove(led))
|
||||
return;
|
||||
|
||||
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
@ -14,12 +15,13 @@ public readonly struct FloatRange
|
||||
/// </summary>
|
||||
/// <param name="start">The start value of the range</param>
|
||||
/// <param name="end">The end value of the range</param>
|
||||
[JsonConstructor]
|
||||
public FloatRange(float start, float end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
|
||||
_rand = new Random();
|
||||
_rand = Random.Shared;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
@ -14,12 +15,13 @@ public readonly struct IntRange
|
||||
/// </summary>
|
||||
/// <param name="start">The start value of the range</param>
|
||||
/// <param name="end">The end value of the range</param>
|
||||
[JsonConstructor]
|
||||
public IntRange(int start, int end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
|
||||
_rand = new Random();
|
||||
_rand = Random.Shared;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -162,7 +162,7 @@ public partial class ProfileConfigurationEditViewModel : DialogViewModelBase<Pro
|
||||
// Preselect the icon or fall back to a random one
|
||||
SelectedMaterialIcon = !IsNew && Enum.TryParse(_profileConfiguration.Icon.IconName, out MaterialIconKind enumValue)
|
||||
? icons.FirstOrDefault(m => m.Icon == enumValue)
|
||||
: icons.ElementAt(new Random().Next(0, icons.Count - 1));
|
||||
: icons.ElementAt(Random.Shared.Next(0, icons.Count - 1));
|
||||
}
|
||||
|
||||
private async Task SaveIcon()
|
||||
|
||||
@ -10,10 +10,10 @@ namespace Artemis.UI.Screens.Workshop.Entries.Details;
|
||||
public class EntryInfoViewModel : ViewModelBase
|
||||
{
|
||||
private readonly INotificationService _notificationService;
|
||||
public IGetEntryById_Entry Entry { get; }
|
||||
public IEntryDetails Entry { get; }
|
||||
public DateTimeOffset? UpdatedAt { get; }
|
||||
|
||||
public EntryInfoViewModel(IGetEntryById_Entry entry, INotificationService notificationService)
|
||||
public EntryInfoViewModel(IEntryDetails entry, INotificationService notificationService)
|
||||
{
|
||||
_notificationService = notificationService;
|
||||
Entry = entry;
|
||||
|
||||
@ -20,7 +20,7 @@ public class EntryReleasesViewModel : ViewModelBase
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly INotificationService _notificationService;
|
||||
|
||||
public EntryReleasesViewModel(IGetEntryById_Entry entry, EntryInstallationHandlerFactory factory, IWindowService windowService, INotificationService notificationService)
|
||||
public EntryReleasesViewModel(IEntryDetails entry, EntryInstallationHandlerFactory factory, IWindowService windowService, INotificationService notificationService)
|
||||
{
|
||||
_factory = factory;
|
||||
_windowService = windowService;
|
||||
@ -31,7 +31,7 @@ public class EntryReleasesViewModel : ViewModelBase
|
||||
OnInstallationStarted = Confirm;
|
||||
}
|
||||
|
||||
public IGetEntryById_Entry Entry { get; }
|
||||
public IEntryDetails Entry { get; }
|
||||
public ReactiveCommand<Unit, Unit> DownloadLatestRelease { get; }
|
||||
|
||||
public Func<IEntryDetails, Task<bool>> OnInstallationStarted { get; set; }
|
||||
|
||||
@ -21,9 +21,11 @@
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Command="{CompiledBinding NavigateToEntry}"
|
||||
IsVisible="{CompiledBinding Entry, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="*, Auto">
|
||||
<!-- Icon -->
|
||||
<Border Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
CornerRadius="6"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 10 0"
|
||||
@ -34,7 +36,7 @@
|
||||
</Border>
|
||||
|
||||
<!-- Body -->
|
||||
<Grid Grid.Column="1" VerticalAlignment="Stretch" RowDefinitions="Auto,*,Auto">
|
||||
<Grid Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Stretch" RowDefinitions="Auto,*,Auto">
|
||||
<TextBlock Grid.Row="0" Margin="0 0 0 5" TextTrimming="CharacterEllipsis">
|
||||
<Run Classes="h5" Text="{CompiledBinding Entry.Name, FallbackValue=Title}" />
|
||||
<Run Classes="subtitle">by</Run>
|
||||
@ -65,7 +67,7 @@
|
||||
</Grid>
|
||||
|
||||
<!-- Info -->
|
||||
<StackPanel Grid.Column="2" Margin="0 0 4 0">
|
||||
<StackPanel Grid.Column="2" Grid.Row="0" Margin="0 0 4 0" HorizontalAlignment="Right">
|
||||
<TextBlock TextAlignment="Right" Text="{CompiledBinding Entry.CreatedAt, FallbackValue=01-01-1337, Converter={StaticResource DateTimeConverter}}" />
|
||||
<TextBlock TextAlignment="Right">
|
||||
<avalonia:MaterialIcon Kind="Downloads" />
|
||||
@ -73,6 +75,18 @@
|
||||
<Run>downloads</Run>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Install state -->
|
||||
<StackPanel Grid.Column="2" Grid.Row="1" Margin="0 0 4 0" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsVisible="{CompiledBinding IsInstalled}">
|
||||
<TextBlock TextAlignment="Right" IsVisible="{CompiledBinding !UpdateAvailable}">
|
||||
<avalonia:MaterialIcon Kind="CheckCircle" Foreground="{DynamicResource SystemAccentColorLight1}"/>
|
||||
<Run>installed</Run>
|
||||
</TextBlock>
|
||||
<TextBlock TextAlignment="Right" IsVisible="{CompiledBinding UpdateAvailable}">
|
||||
<avalonia:MaterialIcon Kind="Update" Foreground="{DynamicResource SystemAccentColorLight1}"/>
|
||||
<Run>update available</Run>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Button>
|
||||
</UserControl>
|
||||
@ -1,26 +1,39 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Artemis.WebClient.Workshop;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Workshop.Entries.List;
|
||||
|
||||
public class EntryListItemViewModel : ActivatableViewModelBase
|
||||
public partial class EntryListItemViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly IRouter _router;
|
||||
[Notify] private bool _isInstalled;
|
||||
[Notify] private bool _updateAvailable;
|
||||
|
||||
public EntryListItemViewModel(IGetEntries_Entries_Items entry, IRouter router)
|
||||
public EntryListItemViewModel(IEntrySummary entry, IRouter router, IWorkshopService workshopService)
|
||||
{
|
||||
_router = router;
|
||||
|
||||
Entry = entry;
|
||||
NavigateToEntry = ReactiveCommand.CreateFromTask(ExecuteNavigateToEntry);
|
||||
|
||||
this.WhenActivated((CompositeDisposable _) =>
|
||||
{
|
||||
InstalledEntry? installedEntry = workshopService.GetInstalledEntry(entry.Id);
|
||||
IsInstalled = installedEntry != null;
|
||||
UpdateAvailable = installedEntry != null && installedEntry.ReleaseId != entry.LatestReleaseId;
|
||||
});
|
||||
}
|
||||
|
||||
public IGetEntries_Entries_Items Entry { get; }
|
||||
public IEntrySummary Entry { get; }
|
||||
public ReactiveCommand<Unit, Unit> NavigateToEntry { get; }
|
||||
|
||||
private async Task ExecuteNavigateToEntry()
|
||||
|
||||
@ -21,7 +21,7 @@ namespace Artemis.UI.Screens.Workshop.Entries.List;
|
||||
|
||||
public abstract partial class EntryListViewModel : RoutableScreen<WorkshopListParameters>
|
||||
{
|
||||
private readonly SourceList<IGetEntries_Entries_Items> _entries = new();
|
||||
private readonly SourceList<IEntrySummary> _entries = new();
|
||||
private readonly ObservableAsPropertyHelper<bool> _isLoading;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly string _route;
|
||||
@ -37,13 +37,13 @@ public abstract partial class EntryListViewModel : RoutableScreen<WorkshopListPa
|
||||
CategoriesViewModel categoriesViewModel,
|
||||
EntryListInputViewModel entryListInputViewModel,
|
||||
INotificationService notificationService,
|
||||
Func<IGetEntries_Entries_Items, EntryListItemViewModel> getEntryListViewModel)
|
||||
Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||
{
|
||||
_route = route;
|
||||
_workshopClient = workshopClient;
|
||||
_notificationService = notificationService;
|
||||
_showPagination = this.WhenAnyValue<EntryListViewModel, int>(vm => vm.TotalPages).Select(t => t > 1).ToProperty(this, vm => vm.ShowPagination);
|
||||
_isLoading = this.WhenAnyValue<EntryListViewModel, bool, int, int>(vm => vm.Page, vm => vm.LoadedPage, (p, c) => p != c).ToProperty(this, vm => vm.IsLoading);
|
||||
_showPagination = this.WhenAnyValue(vm => vm.TotalPages).Select(t => t > 1).ToProperty(this, vm => vm.ShowPagination);
|
||||
_isLoading = this.WhenAnyValue(vm => vm.Page, vm => vm.LoadedPage, (p, c) => p != c).ToProperty(this, vm => vm.IsLoading);
|
||||
|
||||
CategoriesViewModel = categoriesViewModel;
|
||||
InputViewModel = entryListInputViewModel;
|
||||
|
||||
@ -14,7 +14,7 @@ public class LayoutListViewModel : List.EntryListViewModel
|
||||
CategoriesViewModel categoriesViewModel,
|
||||
EntryListInputViewModel entryListInputViewModel,
|
||||
INotificationService notificationService,
|
||||
Func<IGetEntries_Entries_Items, EntryListItemViewModel> getEntryListViewModel)
|
||||
Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||
: base("workshop/entries/layouts", workshopClient, router, categoriesViewModel, entryListInputViewModel, notificationService, getEntryListViewModel)
|
||||
{
|
||||
entryListInputViewModel.SearchWatermark = "Search layouts";
|
||||
|
||||
@ -14,7 +14,7 @@ public class PluginListViewModel : EntryListViewModel
|
||||
CategoriesViewModel categoriesViewModel,
|
||||
EntryListInputViewModel entryListInputViewModel,
|
||||
INotificationService notificationService,
|
||||
Func<IGetEntries_Entries_Items, EntryListItemViewModel> getEntryListViewModel)
|
||||
Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||
: base("workshop/entries/plugins", workshopClient, router, categoriesViewModel, entryListInputViewModel, notificationService, getEntryListViewModel)
|
||||
{
|
||||
entryListInputViewModel.SearchWatermark = "Search plugins";
|
||||
|
||||
@ -14,7 +14,7 @@ public class ProfileListViewModel : List.EntryListViewModel
|
||||
CategoriesViewModel categoriesViewModel,
|
||||
EntryListInputViewModel entryListInputViewModel,
|
||||
INotificationService notificationService,
|
||||
Func<IGetEntries_Entries_Items, EntryListItemViewModel> getEntryListViewModel)
|
||||
Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||
: base("workshop/entries/profiles", workshopClient, router, categoriesViewModel, entryListInputViewModel, notificationService, getEntryListViewModel)
|
||||
{
|
||||
entryListInputViewModel.SearchWatermark = "Search profiles";
|
||||
|
||||
@ -17,13 +17,17 @@
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<Border Classes="card" Grid.Row="1" Grid.Column="1" Margin="10 0">
|
||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||
<mdxaml:MarkdownScrollViewer.Styles>
|
||||
<StyleInclude Source="/Styles/Markdown.axaml" />
|
||||
</mdxaml:MarkdownScrollViewer.Styles>
|
||||
</mdxaml:MarkdownScrollViewer>
|
||||
</Border>
|
||||
<ScrollViewer Grid.Row="1" Grid.Column="1">
|
||||
<StackPanel Margin="10 0" Spacing="10">
|
||||
<Border Classes="card">
|
||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||
<mdxaml:MarkdownScrollViewer.Styles>
|
||||
<StyleInclude Source="/Styles/Markdown.axaml" />
|
||||
</mdxaml:MarkdownScrollViewer.Styles>
|
||||
</mdxaml:MarkdownScrollViewer>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count}" Content="{CompiledBinding EntryImagesViewModel}" />
|
||||
</Grid>
|
||||
|
||||
@ -24,10 +24,10 @@ public partial class LayoutDetailsViewModel : RoutableScreen<WorkshopDetailParam
|
||||
private readonly IWorkshopClient _client;
|
||||
private readonly IDeviceService _deviceService;
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly Func<IGetEntryById_Entry, EntryInfoViewModel> _getEntryInfoViewModel;
|
||||
private readonly Func<IGetEntryById_Entry, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||
private readonly Func<IGetEntryById_Entry, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||
[Notify] private IGetEntryById_Entry? _entry;
|
||||
private readonly Func<IEntryDetails, EntryInfoViewModel> _getEntryInfoViewModel;
|
||||
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||
[Notify] private IEntryDetails? _entry;
|
||||
[Notify] private EntryInfoViewModel? _entryInfoViewModel;
|
||||
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
||||
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
||||
@ -35,9 +35,9 @@ public partial class LayoutDetailsViewModel : RoutableScreen<WorkshopDetailParam
|
||||
public LayoutDetailsViewModel(IWorkshopClient client,
|
||||
IDeviceService deviceService,
|
||||
IWindowService windowService,
|
||||
Func<IGetEntryById_Entry, EntryInfoViewModel> getEntryInfoViewModel,
|
||||
Func<IGetEntryById_Entry, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||
Func<IGetEntryById_Entry, EntryImagesViewModel> getEntryImagesViewModel)
|
||||
Func<IEntryDetails, EntryInfoViewModel> getEntryInfoViewModel,
|
||||
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
|
||||
{
|
||||
_client = client;
|
||||
_deviceService = deviceService;
|
||||
@ -59,19 +59,12 @@ public partial class LayoutDetailsViewModel : RoutableScreen<WorkshopDetailParam
|
||||
return;
|
||||
|
||||
Entry = result.Data?.Entry;
|
||||
if (Entry == null)
|
||||
{
|
||||
EntryInfoViewModel = null;
|
||||
EntryReleasesViewModel = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntryInfoViewModel = _getEntryInfoViewModel(Entry);
|
||||
EntryReleasesViewModel = _getEntryReleasesViewModel(Entry);
|
||||
EntryImagesViewModel = _getEntryImagesViewModel(Entry);
|
||||
EntryInfoViewModel = Entry != null ? _getEntryInfoViewModel(Entry) : null;
|
||||
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||
|
||||
if (EntryReleasesViewModel != null)
|
||||
EntryReleasesViewModel.OnInstallationFinished = OnInstallationFinished;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnInstallationFinished(InstalledEntry installedEntry)
|
||||
|
||||
@ -17,13 +17,27 @@
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<Border Classes="card" Grid.Row="1" Grid.Column="1" Margin="10 0">
|
||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||
<mdxaml:MarkdownScrollViewer.Styles>
|
||||
<StyleInclude Source="/Styles/Markdown.axaml" />
|
||||
</mdxaml:MarkdownScrollViewer.Styles>
|
||||
</mdxaml:MarkdownScrollViewer>
|
||||
</Border>
|
||||
<ScrollViewer Grid.Row="1" Grid.Column="1">
|
||||
<StackPanel Margin="10 0" Spacing="10">
|
||||
<Border Classes="card">
|
||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||
<mdxaml:MarkdownScrollViewer.Styles>
|
||||
<StyleInclude Source="/Styles/Markdown.axaml" />
|
||||
</mdxaml:MarkdownScrollViewer.Styles>
|
||||
</mdxaml:MarkdownScrollViewer>
|
||||
</Border>
|
||||
|
||||
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Dependants, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<StackPanel>
|
||||
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Used by these profiles</TextBlock>
|
||||
<Border Classes="card-separator" />
|
||||
<ScrollViewer>
|
||||
<ItemsControl ItemsSource="{CompiledBinding Dependants}"></ItemsControl>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count}" Content="{CompiledBinding EntryImagesViewModel}" />
|
||||
</Grid>
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Screens.Workshop.Entries.Details;
|
||||
using Artemis.UI.Screens.Workshop.Entries.List;
|
||||
using Artemis.UI.Screens.Workshop.Parameters;
|
||||
using Artemis.UI.Screens.Workshop.Plugins.Dialogs;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
@ -21,20 +24,23 @@ public partial class PluginDetailsViewModel : RoutableScreen<WorkshopDetailParam
|
||||
private readonly IWorkshopClient _client;
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly Func<IGetEntryById_Entry, EntryInfoViewModel> _getEntryInfoViewModel;
|
||||
private readonly Func<IGetEntryById_Entry, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||
private readonly Func<IGetEntryById_Entry, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||
[Notify] private IGetEntryById_Entry? _entry;
|
||||
private readonly Func<IEntryDetails, EntryInfoViewModel> _getEntryInfoViewModel;
|
||||
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||
private readonly Func<IEntrySummary, EntryListItemViewModel> _getEntryListViewModel;
|
||||
[Notify] private IEntryDetails? _entry;
|
||||
[Notify] private EntryInfoViewModel? _entryInfoViewModel;
|
||||
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
||||
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
||||
|
||||
[Notify] private ReadOnlyObservableCollection<EntryListItemViewModel>? _dependants;
|
||||
|
||||
public PluginDetailsViewModel(IWorkshopClient client,
|
||||
IWindowService windowService,
|
||||
IPluginManagementService pluginManagementService,
|
||||
Func<IGetEntryById_Entry, EntryInfoViewModel> getEntryInfoViewModel,
|
||||
Func<IGetEntryById_Entry, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||
Func<IGetEntryById_Entry, EntryImagesViewModel> getEntryImagesViewModel)
|
||||
Func<IEntryDetails, EntryInfoViewModel> getEntryInfoViewModel,
|
||||
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel,
|
||||
Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||
{
|
||||
_client = client;
|
||||
_windowService = windowService;
|
||||
@ -42,6 +48,7 @@ public partial class PluginDetailsViewModel : RoutableScreen<WorkshopDetailParam
|
||||
_getEntryInfoViewModel = getEntryInfoViewModel;
|
||||
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
||||
_getEntryImagesViewModel = getEntryImagesViewModel;
|
||||
_getEntryListViewModel = getEntryListViewModel;
|
||||
}
|
||||
|
||||
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||
@ -56,20 +63,20 @@ public partial class PluginDetailsViewModel : RoutableScreen<WorkshopDetailParam
|
||||
return;
|
||||
|
||||
Entry = result.Data?.Entry;
|
||||
if (Entry == null)
|
||||
{
|
||||
EntryInfoViewModel = null;
|
||||
EntryReleasesViewModel = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntryInfoViewModel = _getEntryInfoViewModel(Entry);
|
||||
EntryReleasesViewModel = _getEntryReleasesViewModel(Entry);
|
||||
EntryImagesViewModel = _getEntryImagesViewModel(Entry);
|
||||
EntryInfoViewModel = Entry != null ? _getEntryInfoViewModel(Entry) : null;
|
||||
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||
|
||||
if (EntryReleasesViewModel != null)
|
||||
{
|
||||
EntryReleasesViewModel.OnInstallationStarted = OnInstallationStarted;
|
||||
EntryReleasesViewModel.OnInstallationFinished = OnInstallationFinished;
|
||||
}
|
||||
|
||||
IReadOnlyList<IEntrySummary>? dependants = (await _client.GetDependantEntries.ExecuteAsync(entryId, 0, 25, cancellationToken)).Data?.Entries?.Items;
|
||||
Dependants = dependants != null && dependants.Any()
|
||||
? new ReadOnlyObservableCollection<EntryListItemViewModel>(new ObservableCollection<EntryListItemViewModel>(dependants.Select(_getEntryListViewModel)))
|
||||
: null;
|
||||
}
|
||||
|
||||
private async Task<bool> OnInstallationStarted(IEntryDetails entryDetails)
|
||||
|
||||
@ -17,13 +17,28 @@
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<Border Classes="card" Grid.Row="1" Grid.Column="1" Margin="10 0">
|
||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||
<mdxaml:MarkdownScrollViewer.Styles>
|
||||
<StyleInclude Source="/Styles/Markdown.axaml" />
|
||||
</mdxaml:MarkdownScrollViewer.Styles>
|
||||
</mdxaml:MarkdownScrollViewer>
|
||||
</Border>
|
||||
<ScrollViewer Grid.Row="1" Grid.Column="1">
|
||||
<StackPanel Margin="10 0" Spacing="10">
|
||||
<Border Classes="card">
|
||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||
<mdxaml:MarkdownScrollViewer.Styles>
|
||||
<StyleInclude Source="/Styles/Markdown.axaml" />
|
||||
</mdxaml:MarkdownScrollViewer.Styles>
|
||||
</mdxaml:MarkdownScrollViewer>
|
||||
</Border>
|
||||
|
||||
<Border Classes="card" VerticalAlignment="Top" IsVisible="{CompiledBinding Dependencies, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<StackPanel>
|
||||
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Required plugins</TextBlock>
|
||||
<Border Classes="card-separator" />
|
||||
<ScrollViewer>
|
||||
<ItemsControl ItemsSource="{CompiledBinding Dependencies}"></ItemsControl>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
|
||||
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count}" Content="{CompiledBinding EntryImagesViewModel}" />
|
||||
</Grid>
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.UI.Screens.Workshop.Entries.Details;
|
||||
using Artemis.UI.Screens.Workshop.Entries.List;
|
||||
using Artemis.UI.Screens.Workshop.Parameters;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Artemis.WebClient.Workshop;
|
||||
@ -13,23 +17,28 @@ namespace Artemis.UI.Screens.Workshop.Profile;
|
||||
public partial class ProfileDetailsViewModel : RoutableScreen<WorkshopDetailParameters>
|
||||
{
|
||||
private readonly IWorkshopClient _client;
|
||||
private readonly Func<IGetEntryById_Entry, EntryInfoViewModel> _getEntryInfoViewModel;
|
||||
private readonly Func<IGetEntryById_Entry, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||
private readonly Func<IGetEntryById_Entry, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||
[Notify] private IGetEntryById_Entry? _entry;
|
||||
private readonly Func<IEntryDetails, EntryInfoViewModel> _getEntryInfoViewModel;
|
||||
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
|
||||
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
|
||||
private readonly Func<IEntrySummary, EntryListItemViewModel> _getEntryListViewModel;
|
||||
|
||||
[Notify] private IEntryDetails? _entry;
|
||||
[Notify] private EntryInfoViewModel? _entryInfoViewModel;
|
||||
[Notify] private EntryReleasesViewModel? _entryReleasesViewModel;
|
||||
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
|
||||
[Notify] private ReadOnlyObservableCollection<EntryListItemViewModel>? _dependencies;
|
||||
|
||||
public ProfileDetailsViewModel(IWorkshopClient client,
|
||||
Func<IGetEntryById_Entry, EntryInfoViewModel> getEntryInfoViewModel,
|
||||
Func<IGetEntryById_Entry, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||
Func<IGetEntryById_Entry, EntryImagesViewModel> getEntryImagesViewModel)
|
||||
Func<IEntryDetails, EntryInfoViewModel> getEntryInfoViewModel,
|
||||
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
|
||||
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel,
|
||||
Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||
{
|
||||
_client = client;
|
||||
_getEntryInfoViewModel = getEntryInfoViewModel;
|
||||
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
||||
_getEntryImagesViewModel = getEntryImagesViewModel;
|
||||
_getEntryListViewModel = getEntryListViewModel;
|
||||
}
|
||||
|
||||
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||
@ -44,16 +53,13 @@ public partial class ProfileDetailsViewModel : RoutableScreen<WorkshopDetailPara
|
||||
return;
|
||||
|
||||
Entry = result.Data?.Entry;
|
||||
if (Entry == null)
|
||||
{
|
||||
EntryInfoViewModel = null;
|
||||
EntryReleasesViewModel = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntryInfoViewModel = _getEntryInfoViewModel(Entry);
|
||||
EntryReleasesViewModel = _getEntryReleasesViewModel(Entry);
|
||||
EntryImagesViewModel = _getEntryImagesViewModel(Entry);
|
||||
}
|
||||
EntryInfoViewModel = Entry != null ? _getEntryInfoViewModel(Entry) : null;
|
||||
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||
|
||||
IReadOnlyList<IEntrySummary>? dependencies = (await _client.GetLatestDependencies.ExecuteAsync(entryId, cancellationToken)).Data?.Entry?.LatestRelease?.Dependencies;
|
||||
Dependencies = dependencies != null && dependencies.Any()
|
||||
? new ReadOnlyObservableCollection<EntryListItemViewModel>(new ObservableCollection<EntryListItemViewModel>(dependencies.Select(_getEntryListViewModel)))
|
||||
: null;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ public class LayoutEntryInstallationHandler : IEntryInstallationHandler
|
||||
}
|
||||
|
||||
// Ensure there is an installed entry
|
||||
InstalledEntry installedEntry = _workshopService.GetInstalledEntry(entry) ?? new InstalledEntry(entry, release);
|
||||
InstalledEntry installedEntry = _workshopService.GetInstalledEntry(entry.Id) ?? new InstalledEntry(entry, release);
|
||||
DirectoryInfo releaseDirectory = installedEntry.GetReleaseDirectory(release);
|
||||
|
||||
// If the folder already exists, remove it so that if the layout now contains less files, old things dont stick around
|
||||
|
||||
@ -25,7 +25,7 @@ public class PluginEntryInstallationHandler : IEntryInstallationHandler
|
||||
public async Task<EntryInstallResult> InstallAsync(IEntryDetails entry, IRelease release, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
// Ensure there is an installed entry
|
||||
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry);
|
||||
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry.Id);
|
||||
if (installedEntry != null)
|
||||
{
|
||||
// If the folder already exists, we're not going to reinstall the plugin since files may be in use, consider our job done
|
||||
|
||||
@ -36,7 +36,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
||||
}
|
||||
|
||||
// Find existing installation to potentially replace the profile
|
||||
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry);
|
||||
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry.Id);
|
||||
if (installedEntry != null && installedEntry.TryGetMetadata("ProfileId", out Guid profileId))
|
||||
{
|
||||
ProfileConfiguration? existing = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == profileId);
|
||||
|
||||
@ -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; }
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -12,14 +12,16 @@ internal class AuthenticationToken
|
||||
if (tokenResponse.RefreshToken == null)
|
||||
throw new ArtemisWebClientException("Token response contains no refresh token");
|
||||
|
||||
IdentityToken = tokenResponse.IdentityToken;
|
||||
AccessToken = tokenResponse.AccessToken;
|
||||
RefreshToken = tokenResponse.RefreshToken;
|
||||
ExpiresAt = DateTimeOffset.UtcNow.AddSeconds(tokenResponse.ExpiresIn);
|
||||
}
|
||||
|
||||
|
||||
public DateTimeOffset ExpiresAt { get; private set; }
|
||||
public bool Expired => DateTimeOffset.UtcNow.AddSeconds(5) >= ExpiresAt;
|
||||
|
||||
public string? IdentityToken { get; private set; }
|
||||
public string AccessToken { get; private set; }
|
||||
public string RefreshToken { get; private set; }
|
||||
}
|
||||
@ -28,6 +28,20 @@ fragment submittedEntry on Entry {
|
||||
createdAt
|
||||
}
|
||||
|
||||
fragment entrySummary on Entry {
|
||||
id
|
||||
author
|
||||
name
|
||||
summary
|
||||
entryType
|
||||
downloads
|
||||
createdAt
|
||||
latestReleaseId
|
||||
categories {
|
||||
...category
|
||||
}
|
||||
}
|
||||
|
||||
fragment entryDetails on Entry {
|
||||
id
|
||||
author
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
query GetDependantEntries($entryId: Long! $skip: Int $take: Int) {
|
||||
entries(
|
||||
where: {
|
||||
latestRelease: { dependencies: { some: { id: { eq: $entryId } } } }
|
||||
}
|
||||
skip: $skip
|
||||
take: $take
|
||||
order: { createdAt: DESC }
|
||||
) {
|
||||
totalCount
|
||||
items {
|
||||
...entrySummary
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,16 +2,7 @@ query GetEntries($search: String $filter: EntryFilterInput $skip: Int $take: Int
|
||||
entries(search: $search where: $filter skip: $skip take: $take, order: $order) {
|
||||
totalCount
|
||||
items {
|
||||
id
|
||||
author
|
||||
name
|
||||
summary
|
||||
entryType
|
||||
downloads
|
||||
createdAt
|
||||
categories {
|
||||
...category
|
||||
}
|
||||
...entrySummary
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
query GetLatestDependencies($id: Long!) {
|
||||
entry(id: $id) {
|
||||
latestRelease {
|
||||
dependencies {
|
||||
...entrySummary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,12 +258,21 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Logout()
|
||||
public async Task Logout()
|
||||
{
|
||||
DiscoveryDocumentResponse disco = await GetDiscovery();
|
||||
|
||||
// Open the web browser for the user to log out
|
||||
if (disco.EndSessionEndpoint != null)
|
||||
{
|
||||
RequestUrl authRequestUrl = new(disco.EndSessionEndpoint);
|
||||
string url = authRequestUrl.CreateEndSessionUrl(_token?.IdentityToken);
|
||||
Utilities.OpenUrl(url);
|
||||
}
|
||||
|
||||
_token = null;
|
||||
_claims.Clear();
|
||||
SetStoredRefreshToken(null);
|
||||
|
||||
_isLoggedInSubject.OnNext(false);
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,6 @@ public interface IAuthenticationService : IProtectedArtemisService
|
||||
Task<string?> GetBearer();
|
||||
Task<bool> AutoLogin(bool force = false);
|
||||
Task Login(CancellationToken cancellationToken);
|
||||
void Logout();
|
||||
Task Logout();
|
||||
bool GetIsEmailVerified();
|
||||
}
|
||||
@ -14,7 +14,7 @@ public interface IWorkshopService
|
||||
Task NavigateToEntry(long entryId, EntryType entryType);
|
||||
|
||||
List<InstalledEntry> GetInstalledEntries();
|
||||
InstalledEntry? GetInstalledEntry(IEntryDetails entry);
|
||||
InstalledEntry? GetInstalledEntry(long entryId);
|
||||
void RemoveInstalledEntry(InstalledEntry installedEntry);
|
||||
void SaveInstalledEntry(InstalledEntry entry);
|
||||
void Initialize();
|
||||
|
||||
@ -152,9 +152,9 @@ public class WorkshopService : IWorkshopService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public InstalledEntry? GetInstalledEntry(IEntryDetails entry)
|
||||
public InstalledEntry? GetInstalledEntry(long entryId)
|
||||
{
|
||||
EntryEntity? entity = _entryRepository.GetByEntryId(entry.Id);
|
||||
EntryEntity? entity = _entryRepository.GetByEntryId(entryId);
|
||||
if (entity == null)
|
||||
return null;
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ schema: schema.graphql
|
||||
extensions:
|
||||
endpoints:
|
||||
Default GraphQL Endpoint:
|
||||
url: https://localhost:7281/graphql
|
||||
url: https://workshop.artemis-rgb.com/graphql
|
||||
headers:
|
||||
user-agent: JS GraphQL
|
||||
introspect: true
|
||||
|
||||
@ -5,8 +5,6 @@ schema {
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
directive @tag(name: String!) on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
||||
|
||||
type Category {
|
||||
icon: String!
|
||||
id: Long!
|
||||
@ -35,6 +33,7 @@ type Entry {
|
||||
authorId: UUID!
|
||||
categories: [Category!]!
|
||||
createdAt: DateTime!
|
||||
dependantReleases: [Release!]!
|
||||
description: String!
|
||||
downloads: Long!
|
||||
entryType: EntryType!
|
||||
@ -46,6 +45,7 @@ type Entry {
|
||||
latestReleaseId: Long
|
||||
layoutInfo: [LayoutInfo!]!
|
||||
name: String!
|
||||
pluginInfo: PluginInfo
|
||||
releases: [Release!]!
|
||||
summary: String!
|
||||
tags: [Tag!]!
|
||||
@ -84,10 +84,33 @@ type Mutation {
|
||||
updateEntryImage(input: UpdateEntryImageInput!): Image
|
||||
}
|
||||
|
||||
type PluginInfo {
|
||||
api: Int
|
||||
entry: Entry!
|
||||
entryId: Long!
|
||||
helpPage: String
|
||||
platforms: PluginPlatform
|
||||
pluginGuid: UUID!
|
||||
repository: String
|
||||
requiresAdmin: Boolean!
|
||||
website: String
|
||||
}
|
||||
|
||||
"A segment of a collection."
|
||||
type PluginInfosCollectionSegment {
|
||||
"A flattened list of the items."
|
||||
items: [PluginInfo!]
|
||||
"Information to aid in pagination."
|
||||
pageInfo: CollectionSegmentInfo!
|
||||
totalCount: Int!
|
||||
}
|
||||
|
||||
type Query {
|
||||
categories(order: [CategorySortInput!], where: CategoryFilterInput): [Category!]!
|
||||
entries(order: [EntrySortInput!], search: String, skip: Int, take: Int, where: EntryFilterInput): EntriesCollectionSegment
|
||||
entry(id: Long!): Entry
|
||||
pluginInfo(pluginGuid: UUID!): PluginInfo
|
||||
pluginInfos(order: [PluginInfoSortInput!], skip: Int, take: Int, where: PluginInfoFilterInput): PluginInfosCollectionSegment
|
||||
searchEntries(input: String!, order: [EntrySortInput!], type: EntryType, where: EntryFilterInput): [Entry!]!
|
||||
searchKeyboardLayout(deviceProvider: UUID!, logicalLayout: String, model: String!, physicalLayout: KeyboardLayoutType!, vendor: String!): LayoutInfo
|
||||
searchLayout(deviceProvider: UUID!, deviceType: RGBDeviceType!, model: String!, vendor: String!): LayoutInfo
|
||||
@ -96,6 +119,7 @@ type Query {
|
||||
|
||||
type Release {
|
||||
createdAt: DateTime!
|
||||
dependencies: [Entry!]!
|
||||
downloadSize: Long!
|
||||
downloads: Long!
|
||||
entry: Entry!
|
||||
@ -131,11 +155,18 @@ enum KeyboardLayoutType {
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
enum PluginPlatform {
|
||||
LINUX
|
||||
OSX
|
||||
WINDOWS
|
||||
}
|
||||
|
||||
enum RGBDeviceType {
|
||||
ALL
|
||||
COOLER
|
||||
DRAM
|
||||
FAN
|
||||
GAME_CONTROLLER
|
||||
GRAPHICS_CARD
|
||||
HEADSET
|
||||
HEADSET_STAND
|
||||
@ -166,6 +197,11 @@ scalar Long
|
||||
|
||||
scalar UUID
|
||||
|
||||
input BooleanOperationFilterInput {
|
||||
eq: Boolean
|
||||
neq: Boolean
|
||||
}
|
||||
|
||||
input CategoryFilterInput {
|
||||
and: [CategoryFilterInput!]
|
||||
icon: StringOperationFilterInput
|
||||
@ -220,6 +256,7 @@ input EntryFilterInput {
|
||||
authorId: UuidOperationFilterInput
|
||||
categories: ListFilterInputTypeOfCategoryFilterInput
|
||||
createdAt: DateTimeOperationFilterInput
|
||||
dependantReleases: ListFilterInputTypeOfReleaseFilterInput
|
||||
description: StringOperationFilterInput
|
||||
downloads: LongOperationFilterInput
|
||||
entryType: EntryTypeOperationFilterInput
|
||||
@ -232,6 +269,7 @@ input EntryFilterInput {
|
||||
layoutInfo: ListFilterInputTypeOfLayoutInfoFilterInput
|
||||
name: StringOperationFilterInput
|
||||
or: [EntryFilterInput!]
|
||||
pluginInfo: PluginInfoFilterInput
|
||||
releases: ListFilterInputTypeOfReleaseFilterInput
|
||||
summary: StringOperationFilterInput
|
||||
tags: ListFilterInputTypeOfTagFilterInput
|
||||
@ -250,6 +288,7 @@ input EntrySortInput {
|
||||
latestRelease: ReleaseSortInput
|
||||
latestReleaseId: SortEnumType
|
||||
name: SortEnumType
|
||||
pluginInfo: PluginInfoSortInput
|
||||
summary: SortEnumType
|
||||
}
|
||||
|
||||
@ -322,6 +361,13 @@ input ListFilterInputTypeOfCategoryFilterInput {
|
||||
some: CategoryFilterInput
|
||||
}
|
||||
|
||||
input ListFilterInputTypeOfEntryFilterInput {
|
||||
all: EntryFilterInput
|
||||
any: Boolean
|
||||
none: EntryFilterInput
|
||||
some: EntryFilterInput
|
||||
}
|
||||
|
||||
input ListFilterInputTypeOfImageFilterInput {
|
||||
all: ImageFilterInput
|
||||
any: Boolean
|
||||
@ -372,6 +418,39 @@ input NullableOfKeyboardLayoutTypeOperationFilterInput {
|
||||
nin: [KeyboardLayoutType]
|
||||
}
|
||||
|
||||
input NullableOfPluginPlatformOperationFilterInput {
|
||||
eq: PluginPlatform
|
||||
in: [PluginPlatform]
|
||||
neq: PluginPlatform
|
||||
nin: [PluginPlatform]
|
||||
}
|
||||
|
||||
input PluginInfoFilterInput {
|
||||
and: [PluginInfoFilterInput!]
|
||||
api: IntOperationFilterInput
|
||||
entry: EntryFilterInput
|
||||
entryId: LongOperationFilterInput
|
||||
helpPage: StringOperationFilterInput
|
||||
or: [PluginInfoFilterInput!]
|
||||
platforms: NullableOfPluginPlatformOperationFilterInput
|
||||
pluginGuid: UuidOperationFilterInput
|
||||
repository: StringOperationFilterInput
|
||||
requiresAdmin: BooleanOperationFilterInput
|
||||
website: StringOperationFilterInput
|
||||
}
|
||||
|
||||
input PluginInfoSortInput {
|
||||
api: SortEnumType
|
||||
entry: EntrySortInput
|
||||
entryId: SortEnumType
|
||||
helpPage: SortEnumType
|
||||
platforms: SortEnumType
|
||||
pluginGuid: SortEnumType
|
||||
repository: SortEnumType
|
||||
requiresAdmin: SortEnumType
|
||||
website: SortEnumType
|
||||
}
|
||||
|
||||
input RGBDeviceTypeOperationFilterInput {
|
||||
eq: RGBDeviceType
|
||||
in: [RGBDeviceType!]
|
||||
@ -382,6 +461,7 @@ input RGBDeviceTypeOperationFilterInput {
|
||||
input ReleaseFilterInput {
|
||||
and: [ReleaseFilterInput!]
|
||||
createdAt: DateTimeOperationFilterInput
|
||||
dependencies: ListFilterInputTypeOfEntryFilterInput
|
||||
downloadSize: LongOperationFilterInput
|
||||
downloads: LongOperationFilterInput
|
||||
entry: EntryFilterInput
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user