Skip to content

[Feature] Modal refactoring & select menu support #3172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Discord;
/// </summary>
public class ButtonBuilder : IInteractableComponentBuilder
{
/// <inheritdoc />
public ComponentType Type => ComponentType.Button;

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Immutable;
using System.Linq;

namespace Discord;

public class LabelBuilder : IMessageComponentBuilder
{
/// <inheritdoc cref="IComponentContainer.SupportedComponentTypes"/>
public ImmutableArray<ComponentType> SupportedComponentTypes { get; } =
[
ComponentType.SelectMenu,
ComponentType.TextInput,
];

/// <summary>
/// The maximum length of the label.
/// </summary>
public const int MaxLabelLength = 100;

/// <summary>
/// The maximum length of the description.
/// </summary>
public const int MaxDescriptionLength = 69420; // TODO: set to the real limit

/// <inheritdoc />
public ComponentType Type => ComponentType.Label;

/// <inheritdoc />
public int? Id { get; set; }

/// <summary>
///
/// </summary>
public string Label { get; set; }

/// <summary>
///
/// </summary>
public string Description { get; set; }

public IMessageComponentBuilder Component { get; set; }

/// <summary>
/// Initializes a new <see cref="LabelBuilder"/>.
/// </summary>
public LabelBuilder() { }

/// <summary>
/// Initializes a new <see cref="LabelBuilder"/> with the specified content.
/// </summary>
public LabelBuilder(string label, IMessageComponentBuilder component, string description = null, int? id = null)
{
Id = id;
Label = label;
Component = component;
Description = description;
}

/// <summary>
/// Initializes a new <see cref="LabelBuilder"/> from existing component.
/// </summary>
public LabelBuilder(LabelComponent label)
{
Label = label.Label;
Description = label.Description;
Id = label.Id;
Component = label.Component.ToBuilder();
}

public LabelComponent Build()
{
Preconditions.NotNullOrWhitespace(Label, nameof(Label));
Preconditions.AtMost(Label.Length, MaxLabelLength, nameof(Label));

Preconditions.AtMost(Description?.Length ?? 0, MaxDescriptionLength, nameof(Description));

Preconditions.NotNull(Component, nameof(Component));

if (SupportedComponentTypes.All(x => Component.Type != x))
throw new InvalidOperationException($"Component can only be {nameof(SelectMenuBuilder)} or {nameof(TextInputBuilder)}.");

return new LabelComponent(Id, Label, Description, Component.Build());
}

/// <inheritdoc />
IMessageComponent IMessageComponentBuilder.Build() => Build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class MediaGalleryBuilder : IMessageComponentBuilder
/// <inheritdoc/>
public int? Id { get; set; }

private List<MediaGalleryItemProperties> _items = new();
private List<MediaGalleryItemProperties> _items = [];

/// <summary>
/// Initializes a new instance of the <see cref="MediaGalleryBuilder"/>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,44 @@ public enum ComponentType
/// </summary>
ChannelSelect = 8,

/// <summary>
/// A container to display text alongside an accessory component.
/// </summary>
Section = 9,

/// <summary>
/// A component displaying Markdown text.
/// </summary>
TextDisplay = 10,

/// <summary>
/// A small image that can be used as an accessory.
/// </summary>
Thumbnail = 11,

/// <summary>
/// A component displaying images and other media.
/// </summary>
MediaGallery = 12,

/// <summary>
/// A component displaying an attached file.
/// </summary>
File = 13,

/// <summary>
/// A component to add vertical padding between other components.
/// </summary>
Separator = 14,

/// <summary>
/// A container that visually groups a set of components.
/// </summary>
Container = 17,

/// <summary>
///
/// </summary>
Label = 18,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Discord;

public class LabelComponent : IMessageComponent
{
/// <inheritdoc />
public ComponentType Type => ComponentType.Label;

/// <inheritdoc />
public int? Id { get; private set; }

/// <summary>
///
/// </summary>
public string Label { get; private set; }

/// <summary>
///
/// </summary>
public string Description { get; private set; }

/// <summary>
///
/// </summary>
public IMessageComponent Component { get; private set; }

internal LabelComponent(int? id, string label, string description, IMessageComponent component)
{
Id = id;
Label = label;
Description = description;
Component = component;
}

public IMessageComponentBuilder ToBuilder() => throw new System.NotImplementedException();
}
38 changes: 38 additions & 0 deletions src/Discord.Net.Rest/API/Common/LabelComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Discord.Rest;
using Newtonsoft.Json;

namespace Discord.API;

internal class LabelComponent : IMessageComponent
{
[JsonProperty("type")]
public ComponentType Type { get; set; }

[JsonProperty("id")]
public Optional<int> Id { get; }

[JsonProperty("label")]
public string Label { get; set; }

[JsonProperty("description")]
public string Description { get; set; }

[JsonProperty("component")]
public IMessageComponent Component { get; set; }

public LabelComponent() {}

public LabelComponent(Discord.LabelComponent label)
{
Type = label.Type;
Id = label.Id ?? Optional<int>.Unspecified;
Label = label.Label;
Description = label.Description;
Component = label.Component.ToModel();
}

public IMessageComponentBuilder ToBuilder() => null;

[JsonIgnore]
int? IMessageComponent.Id => Id.ToNullable();
}
9 changes: 9 additions & 0 deletions src/Discord.Net.Rest/Extensions/MessageComponentExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ internal static IMessageComponent ToModel(this IMessageComponent component)

case ContainerComponent container:
return new API.ContainerComponent(container);

case LabelComponent label:
return new API.LabelComponent(label);
}

return null;
Expand Down Expand Up @@ -173,6 +176,12 @@ internal static IMessageComponent ToEntity(this IMessageComponent component)
parsed.Id.ToNullable());
}

case ComponentType.Label:
{
var parsed = (API.LabelComponent)component;
return new LabelComponent(parsed.Id.ToNullable(), parsed.Label, parsed.Description, parsed.Component.ToEntity());
}

default:
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
case ComponentType.Container:
messageComponent = new API.ContainerComponent();
break;
case ComponentType.Label:
messageComponent = new API.LabelComponent();
break;
}
serializer.Populate(jsonObject.CreateReader(), messageComponent);
return messageComponent;
Expand Down