@@ -1,7 +1,7 @@ | |||||
using Discord.Utils; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
using Discord.Utils; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
@@ -278,9 +278,7 @@ namespace Discord | |||||
{ | { | ||||
if (_actionRows?.SelectMany(x => x.Components)?.Any(x => x.Type == ComponentType.TextInput) ?? false) | if (_actionRows?.SelectMany(x => x.Components)?.Any(x => x.Type == ComponentType.TextInput) ?? false) | ||||
throw new ArgumentException("TextInputComponents are not allowed in messages.", nameof(ActionRows)); | throw new ArgumentException("TextInputComponents are not allowed in messages.", nameof(ActionRows)); | ||||
if (_actionRows?.SelectMany(x => x.Components)?.Any(x => x.Type == ComponentType.ModalSubmit) ?? false) | |||||
throw new ArgumentException("ModalSubmit components are not allowed in messages.", nameof(ActionRows)); | |||||
return _actionRows != null | return _actionRows != null | ||||
? new MessageComponent(_actionRows.Select(x => x.Build()).ToList()) | ? new MessageComponent(_actionRows.Select(x => x.Build()).ToList()) | ||||
: MessageComponent.Empty; | : MessageComponent.Empty; | ||||
@@ -357,7 +355,7 @@ namespace Discord | |||||
/// <param name="minValues">The min values of the placeholder.</param> | /// <param name="minValues">The min values of the placeholder.</param> | ||||
/// <param name="maxValues">The max values of the placeholder.</param> | /// <param name="maxValues">The max values of the placeholder.</param> | ||||
/// <param name="disabled">Whether or not the menu is disabled.</param> | /// <param name="disabled">Whether or not the menu is disabled.</param> | ||||
/// <returns>The current builder.</returns> | |||||
/// <returns>The current builder.</returns> | |||||
public ActionRowBuilder WithSelectMenu(string customId, List<SelectMenuOptionBuilder> options, | public ActionRowBuilder WithSelectMenu(string customId, List<SelectMenuOptionBuilder> options, | ||||
string placeholder = null, int minValues = 1, int maxValues = 1, bool disabled = false) | string placeholder = null, int minValues = 1, int maxValues = 1, bool disabled = false) | ||||
{ | { | ||||
@@ -431,10 +429,10 @@ namespace Discord | |||||
{ | { | ||||
var builtButton = button.Build(); | var builtButton = button.Build(); | ||||
if(Components.Count >= 5) | |||||
if (Components.Count >= 5) | |||||
throw new InvalidOperationException($"Components count reached {MaxChildCount}"); | throw new InvalidOperationException($"Components count reached {MaxChildCount}"); | ||||
if (Components.Any(x => x.Type == ComponentType.SelectMenu)) | |||||
if (Components.Any(x => x.Type.IsSelectType())) | |||||
throw new InvalidOperationException($"A button cannot be added to a row with a SelectMenu"); | throw new InvalidOperationException($"A button cannot be added to a row with a SelectMenu"); | ||||
AddComponent(builtButton); | AddComponent(builtButton); | ||||
@@ -458,11 +456,15 @@ namespace Discord | |||||
case ComponentType.ActionRow: | case ComponentType.ActionRow: | ||||
return false; | return false; | ||||
case ComponentType.Button: | case ComponentType.Button: | ||||
if (Components.Any(x => x.Type == ComponentType.SelectMenu)) | |||||
if (Components.Any(x => x.Type.IsSelectType())) | |||||
return false; | return false; | ||||
else | else | ||||
return Components.Count < 5; | return Components.Count < 5; | ||||
case ComponentType.SelectMenu: | case ComponentType.SelectMenu: | ||||
case ComponentType.ChannelSelect: | |||||
case ComponentType.MentionableSelect: | |||||
case ComponentType.RoleSelect: | |||||
case ComponentType.UserSelect: | |||||
return Components.Count == 0; | return Components.Count == 0; | ||||
default: | default: | ||||
return false; | return false; | ||||
@@ -759,6 +761,18 @@ namespace Discord | |||||
}; | }; | ||||
} | } | ||||
/// <summary> | |||||
/// Gets or sets the type of the current select menu. | |||||
/// </summary> | |||||
/// <exception cref="ArgumentException">Type must be a select menu type.</exception> | |||||
public ComponentType Type | |||||
{ | |||||
get => _type; | |||||
set => _type = value.IsSelectType() | |||||
? value | |||||
: throw new ArgumentException("Type must be a select menu type.", nameof(value)); | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the placeholder text of the current select menu. | /// Gets or sets the placeholder text of the current select menu. | ||||
/// </summary> | /// </summary> | ||||
@@ -827,11 +841,17 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public bool IsDisabled { get; set; } | public bool IsDisabled { get; set; } | ||||
/// <summary> | |||||
/// Gets or sets the menu's channel types (only valid on <see cref="ComponentType.ChannelSelect"/>s). | |||||
/// </summary> | |||||
public List<ChannelType> ChannelTypes { get; set; } | |||||
private List<SelectMenuOptionBuilder> _options = new List<SelectMenuOptionBuilder>(); | private List<SelectMenuOptionBuilder> _options = new List<SelectMenuOptionBuilder>(); | ||||
private int _minValues = 1; | private int _minValues = 1; | ||||
private int _maxValues = 1; | private int _maxValues = 1; | ||||
private string _placeholder; | private string _placeholder; | ||||
private string _customId; | private string _customId; | ||||
private ComponentType _type = ComponentType.SelectMenu; | |||||
/// <summary> | /// <summary> | ||||
/// Creates a new instance of a <see cref="SelectMenuBuilder"/>. | /// Creates a new instance of a <see cref="SelectMenuBuilder"/>. | ||||
@@ -862,7 +882,9 @@ namespace Discord | |||||
/// <param name="maxValues">The max values of this select menu.</param> | /// <param name="maxValues">The max values of this select menu.</param> | ||||
/// <param name="minValues">The min values of this select menu.</param> | /// <param name="minValues">The min values of this select menu.</param> | ||||
/// <param name="isDisabled">Disabled this select menu or not.</param> | /// <param name="isDisabled">Disabled this select menu or not.</param> | ||||
public SelectMenuBuilder(string customId, List<SelectMenuOptionBuilder> options, string placeholder = null, int maxValues = 1, int minValues = 1, bool isDisabled = false) | |||||
/// <param name="type">The <see cref="ComponentType"/> of this select menu.</param> | |||||
/// <param name="channelTypes">The types of channels this menu can select (only valid on <see cref="ComponentType.ChannelSelect"/>s)</param> | |||||
public SelectMenuBuilder(string customId, List<SelectMenuOptionBuilder> options = null, string placeholder = null, int maxValues = 1, int minValues = 1, bool isDisabled = false, ComponentType type = ComponentType.SelectMenu, List<ChannelType> channelTypes = null) | |||||
{ | { | ||||
CustomId = customId; | CustomId = customId; | ||||
Options = options; | Options = options; | ||||
@@ -870,6 +892,8 @@ namespace Discord | |||||
IsDisabled = isDisabled; | IsDisabled = isDisabled; | ||||
MaxValues = maxValues; | MaxValues = maxValues; | ||||
MinValues = minValues; | MinValues = minValues; | ||||
Type = type; | |||||
ChannelTypes = channelTypes ?? new(); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -990,6 +1014,45 @@ namespace Discord | |||||
return this; | return this; | ||||
} | } | ||||
/// <summary> | |||||
/// Sets the menu's current type. | |||||
/// </summary> | |||||
/// <param name="type">The type of the menu.</param> | |||||
/// <returns> | |||||
/// The current builder. | |||||
/// </returns> | |||||
public SelectMenuBuilder WithType(ComponentType type) | |||||
{ | |||||
Type = type; | |||||
return this; | |||||
} | |||||
/// <summary> | |||||
/// Sets the menus valid channel types (only for <see cref="ComponentType.ChannelSelect"/>s). | |||||
/// </summary> | |||||
/// <param name="channelTypes">The valid channel types of the menu.</param> | |||||
/// <returns> | |||||
/// The current builder. | |||||
/// </returns> | |||||
public SelectMenuBuilder WithChannelTypes(List<ChannelType> channelTypes) | |||||
{ | |||||
ChannelTypes = channelTypes; | |||||
return this; | |||||
} | |||||
/// <summary> | |||||
/// Sets the menus valid channel types (only for <see cref="ComponentType.ChannelSelect"/>s). | |||||
/// </summary> | |||||
/// <param name="channelTypes">The valid channel types of the menu.</param> | |||||
/// <returns> | |||||
/// The current builder. | |||||
/// </returns> | |||||
public SelectMenuBuilder WithChannelTypes(params ChannelType[] channelTypes) | |||||
{ | |||||
ChannelTypes = channelTypes.ToList(); | |||||
return this; | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Builds a <see cref="SelectMenuComponent"/> | /// Builds a <see cref="SelectMenuComponent"/> | ||||
/// </summary> | /// </summary> | ||||
@@ -998,7 +1061,7 @@ namespace Discord | |||||
{ | { | ||||
var options = Options?.Select(x => x.Build()).ToList(); | var options = Options?.Select(x => x.Build()).ToList(); | ||||
return new SelectMenuComponent(CustomId, options, Placeholder, MinValues, MaxValues, IsDisabled); | |||||
return new SelectMenuComponent(CustomId, options, Placeholder, MinValues, MaxValues, IsDisabled, Type, ChannelTypes); | |||||
} | } | ||||
} | } | ||||
@@ -26,8 +26,23 @@ namespace Discord | |||||
TextInput = 4, | TextInput = 4, | ||||
/// <summary> | /// <summary> | ||||
/// An interaction sent when a model is submitted. | |||||
/// A select menu for picking from users. | |||||
/// </summary> | /// </summary> | ||||
ModalSubmit = 5, | |||||
UserSelect = 5, | |||||
/// <summary> | |||||
/// A select menu for picking from roles. | |||||
/// </summary> | |||||
RoleSelect = 6, | |||||
/// <summary> | |||||
/// A select menu for picking from roles and users. | |||||
/// </summary> | |||||
MentionableSelect = 7, | |||||
/// <summary> | |||||
/// A select menu for picking from channels. | |||||
/// </summary> | |||||
ChannelSelect = 8, | |||||
} | } | ||||
} | } |
@@ -18,12 +18,27 @@ namespace Discord | |||||
ComponentType Type { get; } | ComponentType Type { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the value(s) of a <see cref="SelectMenuComponent"/> interaction response. | |||||
/// Gets the value(s) of a <see cref="ComponentType.SelectMenu"/> interaction response. | |||||
/// </summary> | /// </summary> | ||||
IReadOnlyCollection<string> Values { get; } | IReadOnlyCollection<string> Values { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the value of a <see cref="TextInputComponent"/> interaction response. | |||||
/// Gets the channels(s) of a <see cref="ComponentType.ChannelSelect"/> interaction response. | |||||
/// </summary> | |||||
IReadOnlyCollection<IChannel> Channels { get; } | |||||
/// <summary> | |||||
/// Gets the user(s) of a <see cref="ComponentType.UserSelect"/> or <see cref="ComponentType.MentionableSelect"/> interaction response. | |||||
/// </summary> | |||||
IReadOnlyCollection<IUser> Users { get; } | |||||
/// <summary> | |||||
/// Gets the roles(s) of a <see cref="ComponentType.RoleSelect"/> or <see cref="ComponentType.MentionableSelect"/> interaction response. | |||||
/// </summary> | |||||
IReadOnlyCollection<IRole> Roles { get; } | |||||
/// <summary> | |||||
/// Gets the value of a <see cref="ComponentType.TextInput"/> interaction response. | |||||
/// </summary> | /// </summary> | ||||
public string Value { get; } | public string Value { get; } | ||||
} | } | ||||
@@ -1,3 +1,4 @@ | |||||
using System; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
@@ -9,7 +10,7 @@ namespace Discord | |||||
public class SelectMenuComponent : IMessageComponent | public class SelectMenuComponent : IMessageComponent | ||||
{ | { | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public ComponentType Type => ComponentType.SelectMenu; | |||||
public ComponentType Type { get; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string CustomId { get; } | public string CustomId { get; } | ||||
@@ -39,6 +40,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public bool IsDisabled { get; } | public bool IsDisabled { get; } | ||||
/// <summary> | |||||
/// Gets the allowed channel types for this modal | |||||
/// </summary> | |||||
public IReadOnlyCollection<ChannelType> ChannelTypes { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Turns this select menu into a builder. | /// Turns this select menu into a builder. | ||||
/// </summary> | /// </summary> | ||||
@@ -52,9 +58,9 @@ namespace Discord | |||||
Placeholder, | Placeholder, | ||||
MaxValues, | MaxValues, | ||||
MinValues, | MinValues, | ||||
IsDisabled); | |||||
IsDisabled, Type, ChannelTypes.ToList()); | |||||
internal SelectMenuComponent(string customId, List<SelectMenuOption> options, string placeholder, int minValues, int maxValues, bool disabled) | |||||
internal SelectMenuComponent(string customId, List<SelectMenuOption> options, string placeholder, int minValues, int maxValues, bool disabled, ComponentType type, IEnumerable<ChannelType> channelTypes = null) | |||||
{ | { | ||||
CustomId = customId; | CustomId = customId; | ||||
Options = options; | Options = options; | ||||
@@ -62,6 +68,8 @@ namespace Discord | |||||
MinValues = minValues; | MinValues = minValues; | ||||
MaxValues = maxValues; | MaxValues = maxValues; | ||||
IsDisabled = disabled; | IsDisabled = disabled; | ||||
Type = type; | |||||
ChannelTypes = channelTypes?.ToArray() ?? Array.Empty<ChannelType>(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -7,12 +7,12 @@ using System.Threading.Tasks; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Represents a modal interaction. | |||||
/// Represents a modal interaction. | |||||
/// </summary> | /// </summary> | ||||
public class Modal : IMessageComponent | public class Modal : IMessageComponent | ||||
{ | { | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public ComponentType Type => ComponentType.ModalSubmit; | |||||
public ComponentType Type => throw new NotSupportedException("Modals do not have a component type."); | |||||
/// <summary> | /// <summary> | ||||
/// Gets the title of the modal. | /// Gets the title of the modal. | ||||
@@ -0,0 +1,8 @@ | |||||
namespace Discord.Utils; | |||||
public static class ComponentTypeUtils | |||||
{ | |||||
public static bool IsSelectType(this ComponentType type) => type is ComponentType.ChannelSelect | |||||
or ComponentType.SelectMenu or ComponentType.RoleSelect or ComponentType.UserSelect | |||||
or ComponentType.MentionableSelect; | |||||
} |
@@ -21,6 +21,10 @@ namespace Discord.API | |||||
{ | { | ||||
ComponentType.Button => new ButtonComponent(x as Discord.ButtonComponent), | ComponentType.Button => new ButtonComponent(x as Discord.ButtonComponent), | ||||
ComponentType.SelectMenu => new SelectMenuComponent(x as Discord.SelectMenuComponent), | ComponentType.SelectMenu => new SelectMenuComponent(x as Discord.SelectMenuComponent), | ||||
ComponentType.ChannelSelect => new SelectMenuComponent(x as Discord.SelectMenuComponent), | |||||
ComponentType.UserSelect => new SelectMenuComponent(x as Discord.SelectMenuComponent), | |||||
ComponentType.RoleSelect => new SelectMenuComponent(x as Discord.SelectMenuComponent), | |||||
ComponentType.MentionableSelect => new SelectMenuComponent(x as Discord.SelectMenuComponent), | |||||
ComponentType.TextInput => new TextInputComponent(x as Discord.TextInputComponent), | ComponentType.TextInput => new TextInputComponent(x as Discord.TextInputComponent), | ||||
_ => null | _ => null | ||||
}; | }; | ||||
@@ -1,4 +1,5 @@ | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System.Collections.Generic; | |||||
namespace Discord.API | namespace Discord.API | ||||
{ | { | ||||
@@ -15,5 +16,8 @@ namespace Discord.API | |||||
[JsonProperty("value")] | [JsonProperty("value")] | ||||
public Optional<string> Value { get; set; } | public Optional<string> Value { get; set; } | ||||
[JsonProperty("resolved")] | |||||
public Optional<MessageComponentInteractionDataResolved> Resolved { get; set; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,19 @@ | |||||
using Newtonsoft.Json; | |||||
using System.Collections.Generic; | |||||
namespace Discord.API; | |||||
internal class MessageComponentInteractionDataResolved | |||||
{ | |||||
[JsonProperty("users")] | |||||
public Optional<Dictionary<string, User>> Users { get; set; } | |||||
[JsonProperty("members")] | |||||
public Optional<Dictionary<string, GuildMember>> Members { get; set; } | |||||
[JsonProperty("channels")] | |||||
public Optional<Dictionary<string, Channel>> Channels { get; set; } | |||||
[JsonProperty("roles")] | |||||
public Optional<Dictionary<string, Role>> Roles { get; set; } | |||||
} |
@@ -26,6 +26,12 @@ namespace Discord.API | |||||
[JsonProperty("disabled")] | [JsonProperty("disabled")] | ||||
public bool Disabled { get; set; } | public bool Disabled { get; set; } | ||||
[JsonProperty("channel_types")] | |||||
public Optional<ChannelType[]> ChannelTypes { get; set; } | |||||
[JsonProperty("resolved")] | |||||
public Optional<MessageComponentInteractionDataResolved> Resolved { get; set; } | |||||
[JsonProperty("values")] | [JsonProperty("values")] | ||||
public Optional<string[]> Values { get; set; } | public Optional<string[]> Values { get; set; } | ||||
public SelectMenuComponent() { } | public SelectMenuComponent() { } | ||||
@@ -39,6 +45,7 @@ namespace Discord.API | |||||
MinValues = component.MinValues; | MinValues = component.MinValues; | ||||
MaxValues = component.MaxValues; | MaxValues = component.MaxValues; | ||||
Disabled = component.IsDisabled; | Disabled = component.IsDisabled; | ||||
ChannelTypes = component.ChannelTypes.ToArray(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -21,6 +21,26 @@ namespace Discord.Rest | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public IReadOnlyCollection<string> Values { get; } | public IReadOnlyCollection<string> Values { get; } | ||||
/// <inheritdoc cref="IComponentInteractionData.Channels"/>/> | |||||
public IReadOnlyCollection<RestChannel> Channels { get; } | |||||
/// <inheritdoc cref="IComponentInteractionData.Users"/>/> | |||||
public IReadOnlyCollection<RestUser> Users { get; } | |||||
/// <inheritdoc cref="IComponentInteractionData.Roles"/>/> | |||||
public IReadOnlyCollection<RestRole> Roles { get; } | |||||
#region IComponentInteractionData | |||||
/// <inheritdoc/> | |||||
IReadOnlyCollection<IChannel> IComponentInteractionData.Channels => Channels; | |||||
/// <inheritdoc/> | |||||
IReadOnlyCollection<IUser> IComponentInteractionData.Users => Users; | |||||
/// <inheritdoc/> | |||||
IReadOnlyCollection<IRole> IComponentInteractionData.Roles => Roles; | |||||
#endregion | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string Value { get; } | public string Value { get; } | ||||
@@ -21,12 +21,24 @@ namespace Discord.Rest | |||||
public IReadOnlyCollection<RestMessageComponentData> Components { get; } | public IReadOnlyCollection<RestMessageComponentData> Components { get; } | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public ComponentType Type => ComponentType.ModalSubmit; | |||||
public ComponentType Type => throw new NotSupportedException("Modals do not have a component type."); | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public IReadOnlyCollection<string> Values | public IReadOnlyCollection<string> Values | ||||
=> throw new NotSupportedException("Modal interactions do not have values!"); | => throw new NotSupportedException("Modal interactions do not have values!"); | ||||
/// <inheritdoc/> | |||||
public IReadOnlyCollection<IChannel> Channels | |||||
=> throw new NotSupportedException("Modal interactions do not have channels!"); | |||||
/// <inheritdoc/> | |||||
public IReadOnlyCollection<IUser> Users | |||||
=> throw new NotSupportedException("Modal interactions do not have users!"); | |||||
/// <inheritdoc/> | |||||
public IReadOnlyCollection<IRole> Roles | |||||
=> throw new NotSupportedException("Modal interactions do not have roles!"); | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public string Value | public string Value | ||||
=> throw new NotSupportedException("Modal interactions do not have value!"); | => throw new NotSupportedException("Modal interactions do not have value!"); | ||||
@@ -170,26 +170,28 @@ namespace Discord.Rest | |||||
parsed.Url.GetValueOrDefault(), | parsed.Url.GetValueOrDefault(), | ||||
parsed.Disabled.GetValueOrDefault()); | parsed.Disabled.GetValueOrDefault()); | ||||
} | } | ||||
case ComponentType.SelectMenu: | |||||
case ComponentType.SelectMenu or ComponentType.ChannelSelect or ComponentType.RoleSelect or ComponentType.MentionableSelect or ComponentType.UserSelect: | |||||
{ | { | ||||
var parsed = (API.SelectMenuComponent)y; | var parsed = (API.SelectMenuComponent)y; | ||||
return new SelectMenuComponent( | return new SelectMenuComponent( | ||||
parsed.CustomId, | parsed.CustomId, | ||||
parsed.Options.Select(z => new SelectMenuOption( | |||||
parsed.Options?.Select(z => new SelectMenuOption( | |||||
z.Label, | z.Label, | ||||
z.Value, | z.Value, | ||||
z.Description.GetValueOrDefault(), | z.Description.GetValueOrDefault(), | ||||
z.Emoji.IsSpecified | z.Emoji.IsSpecified | ||||
? z.Emoji.Value.Id.HasValue | |||||
? new Emote(z.Emoji.Value.Id.Value, z.Emoji.Value.Name, z.Emoji.Value.Animated.GetValueOrDefault()) | |||||
: new Emoji(z.Emoji.Value.Name) | |||||
: null, | |||||
? z.Emoji.Value.Id.HasValue | |||||
? new Emote(z.Emoji.Value.Id.Value, z.Emoji.Value.Name, z.Emoji.Value.Animated.GetValueOrDefault()) | |||||
: new Emoji(z.Emoji.Value.Name) | |||||
: null, | |||||
z.Default.ToNullable())).ToList(), | z.Default.ToNullable())).ToList(), | ||||
parsed.Placeholder.GetValueOrDefault(), | parsed.Placeholder.GetValueOrDefault(), | ||||
parsed.MinValues, | parsed.MinValues, | ||||
parsed.MaxValues, | parsed.MaxValues, | ||||
parsed.Disabled | |||||
); | |||||
parsed.Disabled, | |||||
parsed.Type, | |||||
parsed.ChannelTypes.GetValueOrDefault() | |||||
); | |||||
} | } | ||||
default: | default: | ||||
return null; | return null; | ||||
@@ -30,6 +30,10 @@ namespace Discord.Net.Converters | |||||
messageComponent = new API.ButtonComponent(); | messageComponent = new API.ButtonComponent(); | ||||
break; | break; | ||||
case ComponentType.SelectMenu: | case ComponentType.SelectMenu: | ||||
case ComponentType.ChannelSelect: | |||||
case ComponentType.MentionableSelect: | |||||
case ComponentType.RoleSelect: | |||||
case ComponentType.UserSelect: | |||||
messageComponent = new API.SelectMenuComponent(); | messageComponent = new API.SelectMenuComponent(); | ||||
break; | break; | ||||
case ComponentType.TextInput: | case ComponentType.TextInput: | ||||
@@ -1,3 +1,5 @@ | |||||
#define DEBUG_PACKETS | |||||
using Discord.API.Gateway; | using Discord.API.Gateway; | ||||
using Discord.Net.Queue; | using Discord.Net.Queue; | ||||
using Discord.Net.Rest; | using Discord.Net.Rest; | ||||
@@ -5,6 +5,7 @@ using Discord.Net.Converters; | |||||
using Discord.Net.Udp; | using Discord.Net.Udp; | ||||
using Discord.Net.WebSockets; | using Discord.Net.WebSockets; | ||||
using Discord.Rest; | using Discord.Rest; | ||||
using Discord.Utils; | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using Newtonsoft.Json.Linq; | using Newtonsoft.Json.Linq; | ||||
using System; | using System; | ||||
@@ -2364,7 +2365,7 @@ namespace Discord.WebSocket | |||||
await TimedInvokeAsync(_slashCommandExecuted, nameof(SlashCommandExecuted), slashCommand).ConfigureAwait(false); | await TimedInvokeAsync(_slashCommandExecuted, nameof(SlashCommandExecuted), slashCommand).ConfigureAwait(false); | ||||
break; | break; | ||||
case SocketMessageComponent messageComponent: | case SocketMessageComponent messageComponent: | ||||
if (messageComponent.Data.Type == ComponentType.SelectMenu) | |||||
if (messageComponent.Data.Type.IsSelectType()) | |||||
await TimedInvokeAsync(_selectMenuExecuted, nameof(SelectMenuExecuted), messageComponent).ConfigureAwait(false); | await TimedInvokeAsync(_selectMenuExecuted, nameof(SelectMenuExecuted), messageComponent).ConfigureAwait(false); | ||||
if (messageComponent.Data.Type == ComponentType.Button) | if (messageComponent.Data.Type == ComponentType.Button) | ||||
await TimedInvokeAsync(_buttonExecuted, nameof(ButtonExecuted), messageComponent).ConfigureAwait(false); | await TimedInvokeAsync(_buttonExecuted, nameof(ButtonExecuted), messageComponent).ConfigureAwait(false); | ||||
@@ -1,3 +1,5 @@ | |||||
using Discord.Utils; | |||||
using System.Linq; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using Model = Discord.API.MessageComponentInteractionData; | using Model = Discord.API.MessageComponentInteractionData; | ||||
@@ -8,24 +10,25 @@ namespace Discord.WebSocket | |||||
/// </summary> | /// </summary> | ||||
public class SocketMessageComponentData : IComponentInteractionData | public class SocketMessageComponentData : IComponentInteractionData | ||||
{ | { | ||||
/// <summary> | |||||
/// Gets the components Custom Id that was clicked. | |||||
/// </summary> | |||||
/// <inheritdoc /> | |||||
public string CustomId { get; } | public string CustomId { get; } | ||||
/// <summary> | |||||
/// Gets the type of the component clicked. | |||||
/// </summary> | |||||
/// <inheritdoc /> | |||||
public ComponentType Type { get; } | public ComponentType Type { get; } | ||||
/// <summary> | |||||
/// Gets the value(s) of a <see cref="SelectMenuComponent"/> interaction response. | |||||
/// </summary> | |||||
/// <inheritdoc /> | |||||
public IReadOnlyCollection<string> Values { get; } | public IReadOnlyCollection<string> Values { get; } | ||||
/// <summary> | |||||
/// Gets the value of a <see cref="TextInputComponent"/> interaction response. | |||||
/// </summary> | |||||
/// <inheritdoc /> | |||||
public IReadOnlyCollection<IChannel> Channels { get; } | |||||
/// <inheritdoc /> | |||||
public IReadOnlyCollection<IUser> Users { get; } | |||||
/// <inheritdoc /> | |||||
public IReadOnlyCollection<IRole> Roles { get; } | |||||
/// <inheritdoc /> | |||||
public string Value { get; } | public string Value { get; } | ||||
internal SocketMessageComponentData(Model model) | internal SocketMessageComponentData(Model model) | ||||
@@ -45,7 +48,7 @@ namespace Discord.WebSocket | |||||
? (component as API.TextInputComponent).Value.Value | ? (component as API.TextInputComponent).Value.Value | ||||
: null; | : null; | ||||
Values = component.Type == ComponentType.SelectMenu | |||||
Values = component.Type.IsSelectType() | |||||
? (component as API.SelectMenuComponent).Values.Value | ? (component as API.SelectMenuComponent).Values.Value | ||||
: null; | : null; | ||||
} | } | ||||
@@ -118,7 +118,7 @@ namespace Discord.WebSocket | |||||
/// <returns> | /// <returns> | ||||
/// Collection of WebSocket-based users. | /// Collection of WebSocket-based users. | ||||
/// </returns> | /// </returns> | ||||
public IReadOnlyCollection<SocketUser> MentionedUsers => _userMentions; | |||||
public IReadOnlyCollection<SocketUser> MentionedUsers => _userMentions; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); | public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); | ||||
@@ -226,7 +226,9 @@ namespace Discord.WebSocket | |||||
parsed.Placeholder.GetValueOrDefault(), | parsed.Placeholder.GetValueOrDefault(), | ||||
parsed.MinValues, | parsed.MinValues, | ||||
parsed.MaxValues, | parsed.MaxValues, | ||||
parsed.Disabled | |||||
parsed.Disabled, | |||||
parsed.Type, | |||||
parsed.ChannelTypes.GetValueOrDefault() | |||||
); | ); | ||||
} | } | ||||
default: | default: | ||||