This commit is contained in:
Mihail Gribkov
2025-05-09 18:18:16 +03:00
committed by GitHub
parent c888c84752
commit 4ab96c7721
27 changed files with 264 additions and 236 deletions

View File

@@ -18,10 +18,19 @@ public class ActionRowComponent : IMessageComponent
/// </summary>
public IReadOnlyCollection<IMessageComponent> Components { get; internal set; }
/// <summary>
/// Converts a <see cref="ActionRowComponent"/> to a <see cref="ActionRowBuilder"/>.
/// </summary>
public ActionRowBuilder ToBuilder()
=> new(this);
internal ActionRowComponent() { }
internal ActionRowComponent(IReadOnlyCollection<IMessageComponent> components)
{
Components = components;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -19,98 +19,6 @@ public static class ComponentBuilderExtensions
return builder;
}
/// <summary>
/// Converts a <see cref="IMessageComponent"/> to a builder.
/// </summary>
/// <exception cref="ArgumentException">Unknown component type</exception>
public static IMessageComponentBuilder ToBuilder(this IMessageComponent component)
=> component switch
{
ActionRowComponent actionRow => actionRow.ToBuilder(),
ButtonComponent button => button.ToBuilder(),
SelectMenuComponent select => select.ToBuilder(),
SectionComponent section => section.ToBuilder(),
TextDisplayComponent textDisplay => textDisplay.ToBuilder(),
ThumbnailComponent thumbnail => thumbnail.ToBuilder(),
MediaGalleryComponent mediaGallery => mediaGallery.ToBuilder(),
FileComponent file => file.ToBuilder(),
SeparatorComponent separator => separator.ToBuilder(),
ContainerComponent container => container.ToBuilder(),
_ => throw new ArgumentException("Unknown component type")
};
/// <summary>
/// Converts a <see cref="FileComponent"/> to a <see cref="FileComponentBuilder"/>.
/// </summary>
public static FileComponentBuilder ToBuilder(this FileComponent file)
=> new(file);
/// <summary>
/// Converts a <see cref="SeparatorComponent"/> to a <see cref="SeparatorBuilder"/>.
/// </summary>
public static SeparatorBuilder ToBuilder(this SeparatorComponent separator)
=> new(separator);
/// <summary>
/// Converts a <see cref="MediaGalleryComponent"/> to a <see cref="MediaGalleryBuilder"/>.
/// </summary>
public static MediaGalleryBuilder ToBuilder(this MediaGalleryComponent mediaGallery)
=> new(mediaGallery);
/// <summary>
/// Converts a <see cref="ButtonComponent"/> to a <see cref="ButtonBuilder"/>.
/// </summary>
public static ButtonBuilder ToBuilder(this ButtonComponent button)
=> new(button);
/// <summary>
/// Converts a <see cref="SelectMenuComponent"/> to a <see cref="SelectMenuBuilder"/>.
/// </summary>
public static SelectMenuBuilder ToBuilder(this SelectMenuComponent select)
=> new(select);
/// <summary>
/// Converts a <see cref="ActionRowComponent"/> to a <see cref="ActionRowBuilder"/>.
/// </summary>
public static ActionRowBuilder ToBuilder(this ActionRowComponent actionRow)
=> new(actionRow);
/// <summary>
/// Converts a <see cref="ContainerComponent"/> to a <see cref="ContainerBuilder"/>.
/// </summary>
public static ContainerBuilder ToBuilder(this ContainerComponent container)
=> new(container);
/// <summary>
/// Converts a <see cref="SectionComponent"/> to a <see cref="SectionBuilder"/>.
/// </summary>
public static SectionBuilder ToBuilder(this SectionComponent section)
=> new(section);
/// <summary>
/// Converts a <see cref="ThumbnailComponent"/> to a <see cref="ThumbnailBuilder"/>.
/// </summary>
public static ThumbnailBuilder ToBuilder(this ThumbnailComponent thumbnail)
=> new(thumbnail);
/// <summary>
/// Converts a <see cref="TextDisplayComponent"/> to a <see cref="TextDisplayBuilder"/>.
/// </summary>
public static TextDisplayBuilder ToBuilder(this TextDisplayComponent textDisplay)
=> new (textDisplay);
/// <summary>
/// Converts a <see cref="MediaGalleryItem"/> to a <see cref="MediaGalleryItemProperties"/>.
/// </summary>
public static MediaGalleryItemProperties ToProperties(this MediaGalleryItem item)
=> new(item.Media.ToProperties(), item.Description, item.IsSpoiler);
/// <summary>
/// Converts a <see cref="UnfurledMediaItem"/> to a <see cref="UnfurledMediaItemProperties"/>.
/// </summary>
public static UnfurledMediaItemProperties ToProperties(this UnfurledMediaItem item)
=> new(item.Url);
/// <summary>
/// Converts a collection of <see cref="IMessageComponent"/> to a <see cref="ComponentBuilderV2"/>.
/// </summary>

View File

@@ -169,6 +169,22 @@ public class TextInputBuilder : IInteractableComponentBuilder
}
/// <summary>
/// Creates a new instance of a <see cref="TextInputBuilder"/> from existing component.
/// </summary>
public TextInputBuilder(TextInputComponent textInput)
{
Label = textInput.Label;
Style = textInput.Style;
CustomId = textInput.CustomId;
Placeholder = textInput.Placeholder;
MinLength = textInput.MinLength;
MaxLength = textInput.MaxLength;
Required = textInput.Required;
Value = textInput.Value;
Id = textInput.Id;
}
/// <summary>
/// Sets the label of the current builder.
/// </summary>

View File

@@ -51,13 +51,10 @@ public class ButtonComponent : IInteractableComponent
public ulong? SkuId { get; }
/// <summary>
/// Turns this button into a button builder.
/// Converts a <see cref="ButtonComponent"/> to a <see cref="ButtonBuilder"/>.
/// </summary>
/// <returns>
/// A newly created button builder with the same properties as this button.
/// </returns>
public ButtonBuilder ToBuilder()
=> new (Label, CustomId, Style, Url, Emote, IsDisabled);
=> new(this);
internal ButtonComponent(ButtonStyle style, string label, IEmote emote, string customId, string url, bool isDisabled, ulong? skuId, int? id)
{
@@ -70,4 +67,7 @@ public class ButtonComponent : IInteractableComponent
IsDisabled = isDisabled;
SkuId = skuId;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -28,6 +28,12 @@ public class ContainerComponent : IMessageComponent
/// </summary>
public bool? IsSpoiler { get; }
/// <summary>
/// Converts a <see cref="ContainerComponent"/> to a <see cref="ContainerBuilder"/>.
/// </summary>
public ContainerBuilder ToBuilder()
=> new(this);
internal ContainerComponent(IReadOnlyCollection<IMessageComponent> components, Color? accentColor, bool? isSpoiler, int? id = null)
{
Components = components;
@@ -35,4 +41,7 @@ public class ContainerComponent : IMessageComponent
IsSpoiler = isSpoiler;
Id = id;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -21,10 +21,19 @@ public class FileComponent : IMessageComponent
/// </summary>
public bool? IsSpoiler { get; }
/// <summary>
/// Converts a <see cref="FileComponent"/> to a <see cref="FileComponentBuilder"/>.
/// </summary>
public FileComponentBuilder ToBuilder()
=> new(this);
internal FileComponent(UnfurledMediaItem file, bool? isSpoiler, int? id = null)
{
File = file;
IsSpoiler = isSpoiler;
Id = id;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -10,5 +10,13 @@ public interface IMessageComponent
/// </summary>
ComponentType Type { get; }
/// <summary>
///
/// </summary>
int? Id { get; }
/// <summary>
/// Converts a <see cref="IMessageComponent"/> to a <see cref="IMessageComponentBuilder"/>.
/// </summary>
public IMessageComponentBuilder ToBuilder();
}

View File

@@ -18,9 +18,18 @@ public class MediaGalleryComponent : IMessageComponent
/// </summary>
public IReadOnlyCollection<MediaGalleryItem> Items { get; }
/// <summary>
/// Converts a <see cref="MediaGalleryComponent"/> to a <see cref="MediaGalleryBuilder"/>.
/// </summary>
public MediaGalleryBuilder ToBuilder()
=> new(this);
internal MediaGalleryComponent(IReadOnlyCollection<MediaGalleryItem> items, int? id)
{
Items = items;
Id = id;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -20,6 +20,12 @@ public readonly struct MediaGalleryItem
/// </summary>
public bool IsSpoiler { get; }
/// <summary>
/// Converts a <see cref="MediaGalleryItem"/> to a <see cref="MediaGalleryItemProperties"/>.
/// </summary>
public MediaGalleryItemProperties ToProperties()
=> new(Media.ToProperties(), Description, IsSpoiler);
internal MediaGalleryItem(UnfurledMediaItem media, string description, bool? isSpoiler)
{
Media = media;

View File

@@ -23,10 +23,19 @@ public class SectionComponent : IMessageComponent
/// </summary>
public IMessageComponent Accessory { get; }
/// <summary>
/// Converts a <see cref="SectionComponent"/> to a <see cref="SectionBuilder"/>.
/// </summary>
public SectionBuilder ToBuilder()
=> new(this);
internal SectionComponent(int? id, IReadOnlyCollection<IMessageComponent> components, IMessageComponent accessory)
{
Id = id;
Components = components;
Accessory = accessory;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -1,87 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Discord
namespace Discord;
/// <summary>
/// Represents a select menu component defined at <see href="https://discord.com/developers/docs/interactions/message-components#select-menu-object"/>
/// </summary>
public class SelectMenuComponent : IInteractableComponent
{
/// <inheritdoc/>
public ComponentType Type { get; }
/// <inheritdoc/>
public int? Id { get; }
/// <inheritdoc/>
public string CustomId { get; }
/// <summary>
/// Represents a select menu component defined at <see href="https://discord.com/developers/docs/interactions/message-components#select-menu-object"/>
/// Gets the menus options to select from.
/// </summary>
public class SelectMenuComponent : IInteractableComponent
public IReadOnlyCollection<SelectMenuOption> Options { get; }
/// <summary>
/// Gets the custom placeholder text if nothing is selected.
/// </summary>
public string Placeholder { get; }
/// <summary>
/// Gets the minimum number of items that must be chosen.
/// </summary>
public int MinValues { get; }
/// <summary>
/// Gets the maximum number of items that can be chosen.
/// </summary>
public int MaxValues { get; }
/// <summary>
/// Gets whether this menu is disabled or not.
/// </summary>
public bool IsDisabled { get; }
/// <summary>
/// Gets the allowed channel types for this modal
/// </summary>
public IReadOnlyCollection<ChannelType> ChannelTypes { get; }
/// <summary>
/// Gets default values for auto-populated select menu components.
/// </summary>
public IReadOnlyCollection<SelectMenuDefaultValue> DefaultValues { get; }
/// <summary>
/// Converts a <see cref="SelectMenuComponent"/> to a <see cref="SelectMenuBuilder"/>.
/// </summary>
public SelectMenuBuilder ToBuilder()
=> new(this);
internal SelectMenuComponent(string customId, List<SelectMenuOption> options, string placeholder, int minValues, int maxValues,
bool disabled, ComponentType type, int? id, IEnumerable<ChannelType> channelTypes = null, IEnumerable<SelectMenuDefaultValue> defaultValues = null)
{
/// <inheritdoc/>
public ComponentType Type { get; }
/// <inheritdoc/>
public int? Id { get; }
/// <inheritdoc/>
public string CustomId { get; }
/// <summary>
/// Gets the menus options to select from.
/// </summary>
public IReadOnlyCollection<SelectMenuOption> Options { get; }
/// <summary>
/// Gets the custom placeholder text if nothing is selected.
/// </summary>
public string Placeholder { get; }
/// <summary>
/// Gets the minimum number of items that must be chosen.
/// </summary>
public int MinValues { get; }
/// <summary>
/// Gets the maximum number of items that can be chosen.
/// </summary>
public int MaxValues { get; }
/// <summary>
/// Gets whether this menu is disabled or not.
/// </summary>
public bool IsDisabled { get; }
/// <summary>
/// Gets the allowed channel types for this modal
/// </summary>
public IReadOnlyCollection<ChannelType> ChannelTypes { get; }
/// <summary>
/// Gets default values for auto-populated select menu components.
/// </summary>
public IReadOnlyCollection<SelectMenuDefaultValue> DefaultValues { get; }
/// <summary>
/// Turns this select menu into a builder.
/// </summary>
/// <returns>
/// A newly create builder with the same properties as this select menu.
/// </returns>
public SelectMenuBuilder ToBuilder()
=> new SelectMenuBuilder(
CustomId,
Options.Select(x => new SelectMenuOptionBuilder(x.Label, x.Value, x.Description, x.Emote, x.IsDefault)).ToList(),
Placeholder,
MaxValues,
MinValues,
IsDisabled, Type, ChannelTypes.ToList(),
DefaultValues.ToList());
internal SelectMenuComponent(string customId, List<SelectMenuOption> options, string placeholder, int minValues, int maxValues,
bool disabled, ComponentType type, int? id, IEnumerable<ChannelType> channelTypes = null, IEnumerable<SelectMenuDefaultValue> defaultValues = null)
{
CustomId = customId;
Options = options;
Placeholder = placeholder;
MinValues = minValues;
MaxValues = maxValues;
IsDisabled = disabled;
Type = type;
Id = id;
ChannelTypes = channelTypes?.ToArray() ?? [];
DefaultValues = defaultValues?.ToArray() ?? [];
}
CustomId = customId;
Options = options;
Placeholder = placeholder;
MinValues = minValues;
MaxValues = maxValues;
IsDisabled = disabled;
Type = type;
Id = id;
ChannelTypes = channelTypes?.ToArray() ?? [];
DefaultValues = defaultValues?.ToArray() ?? [];
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -21,10 +21,19 @@ public class SeparatorComponent : IMessageComponent
/// </summary>
public SeparatorSpacingSize? Spacing { get; }
/// <summary>
/// Converts a <see cref="SeparatorComponent"/> to a <see cref="SeparatorBuilder"/>.
/// </summary>
public SeparatorBuilder ToBuilder()
=> new(this);
internal SeparatorComponent(bool? isDivider, SeparatorSpacingSize? spacing, int? id = null)
{
IsDivider = isDivider;
Spacing = spacing;
Id = id;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -16,9 +16,18 @@ public class TextDisplayComponent : IMessageComponent
/// </summary>
public string Content { get; }
/// <summary>
/// Converts a <see cref="TextDisplayComponent"/> to a <see cref="TextDisplayBuilder"/>.
/// </summary>
public TextDisplayBuilder ToBuilder()
=> new(this);
internal TextDisplayComponent(string content, int? id = null)
{
Id = id;
Content = content;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -1,66 +1,75 @@
namespace Discord
namespace Discord;
/// <summary>
/// Represents a <see cref="IMessageComponent"/> text input.
/// </summary>
public class TextInputComponent : IInteractableComponent
{
/// <inheritdoc/>
public ComponentType Type => ComponentType.TextInput;
/// <inheritdoc/>
public string CustomId { get; }
/// <inheritdoc/>
public int? Id { get; }
/// <summary>
/// Represents a <see cref="IMessageComponent"/> text input.
/// Gets the label of the component; this is the text shown above it.
/// </summary>
public class TextInputComponent : IInteractableComponent
public string Label { get; }
/// <summary>
/// Gets the placeholder of the component.
/// </summary>
public string Placeholder { get; }
/// <summary>
/// Gets the minimum length of the inputted text.
/// </summary>
public int? MinLength { get; }
/// <summary>
/// Gets the maximum length of the inputted text.
/// </summary>
public int? MaxLength { get; }
/// <summary>
/// Gets the style of the component.
/// </summary>
public TextInputStyle Style { get; }
/// <summary>
/// Gets whether users are required to input text.
/// </summary>
public bool? Required { get; }
/// <summary>
/// Gets the default value of the component.
/// </summary>
public string Value { get; }
/// <summary>
/// Converts a <see cref="TextInputComponent"/> to a <see cref="TextInputBuilder"/>.
/// </summary>
public TextInputBuilder ToBuilder()
=> new TextInputBuilder(this);
internal TextInputComponent(string customId, string label, string placeholder, int? minLength, int? maxLength,
TextInputStyle style, bool? required, string value, int? id)
{
/// <inheritdoc/>
public ComponentType Type => ComponentType.TextInput;
/// <inheritdoc/>
public string CustomId { get; }
/// <inheritdoc/>
public int? Id { get; }
/// <summary>
/// Gets the label of the component; this is the text shown above it.
/// </summary>
public string Label { get; }
/// <summary>
/// Gets the placeholder of the component.
/// </summary>
public string Placeholder { get; }
/// <summary>
/// Gets the minimum length of the inputted text.
/// </summary>
public int? MinLength { get; }
/// <summary>
/// Gets the maximum length of the inputted text.
/// </summary>
public int? MaxLength { get; }
/// <summary>
/// Gets the style of the component.
/// </summary>
public TextInputStyle Style { get; }
/// <summary>
/// Gets whether users are required to input text.
/// </summary>
public bool? Required { get; }
/// <summary>
/// Gets the default value of the component.
/// </summary>
public string Value { get; }
internal TextInputComponent(string customId, string label, string placeholder, int? minLength, int? maxLength,
TextInputStyle style, bool? required, string value, int? id)
{
CustomId = customId;
Label = label;
Placeholder = placeholder;
MinLength = minLength;
MaxLength = maxLength;
Style = style;
Required = required;
Value = value;
Id = id;
}
CustomId = customId;
Label = label;
Placeholder = placeholder;
MinLength = minLength;
MaxLength = maxLength;
Style = style;
Required = required;
Value = value;
Id = id;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -26,6 +26,12 @@ public class ThumbnailComponent : IMessageComponent
/// </summary>
public bool IsSpoiler { get; }
/// <summary>
/// Converts a <see cref="ThumbnailComponent"/> to a <see cref="ThumbnailBuilder"/>.
/// </summary>
public ThumbnailBuilder ToBuilder()
=> new(this);
internal ThumbnailComponent(int? id, UnfurledMediaItem media, string description, bool? isSpoiler)
{
Id = id;
@@ -33,4 +39,7 @@ public class ThumbnailComponent : IMessageComponent
Description = description;
IsSpoiler = isSpoiler ?? false;
}
/// <inheritdoc />
IMessageComponentBuilder IMessageComponent.ToBuilder() => ToBuilder();
}

View File

@@ -10,6 +10,12 @@ public class UnfurledMediaItem
/// </summary>
public string Url { get; }
/// <summary>
/// Converts a <see cref="UnfurledMediaItem"/> to a <see cref="UnfurledMediaItemProperties"/>.
/// </summary>
public UnfurledMediaItemProperties ToProperties()
=> new(Url);
internal UnfurledMediaItem(string url)
{
Url = url;

View File

@@ -37,5 +37,6 @@ namespace Discord.API
[JsonIgnore]
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}
}

View File

@@ -70,5 +70,7 @@ namespace Discord.API
[JsonIgnore]
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}
}

View File

@@ -33,4 +33,5 @@ internal class ContainerComponent : IMessageComponent
}
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}

View File

@@ -27,4 +27,5 @@ internal class FileComponent : IMessageComponent
}
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}

View File

@@ -30,4 +30,5 @@ internal class MediaGalleryComponent : IMessageComponent
}
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}

View File

@@ -29,4 +29,5 @@ internal class SectionComponent : IMessageComponent
}
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}

View File

@@ -58,5 +58,6 @@ namespace Discord.API
[JsonIgnore]
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}
}

View File

@@ -27,4 +27,5 @@ internal class SeparatorComponent : IMessageComponent
}
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}

View File

@@ -23,4 +23,5 @@ internal class TextDisplayComponent : IMessageComponent
}
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}

View File

@@ -52,5 +52,6 @@ namespace Discord.API
[JsonIgnore]
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}
}

View File

@@ -32,4 +32,5 @@ internal class ThumbnailComponent : IMessageComponent
}
int? IMessageComponent.Id => Id.ToNullable();
IMessageComponentBuilder IMessageComponent.ToBuilder() => null;
}