diff --git a/DSharpPlus.Interactivity/InteractivityExtension.cs b/DSharpPlus.Interactivity/InteractivityExtension.cs index 906eb109ac..edf6f9997d 100644 --- a/DSharpPlus.Interactivity/InteractivityExtension.cs +++ b/DSharpPlus.Interactivity/InteractivityExtension.cs @@ -206,7 +206,7 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(c => c.Type is ComponentType.Button)) + if (!message.FilterComponents().Any()) throw new ArgumentException("Provided message does not contain any button components."); @@ -246,10 +246,12 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(c => c.Type is ComponentType.Button)) + IReadOnlyList buttons = message.FilterComponents(); + + if (!buttons.Any()) throw new ArgumentException("Provided message does not contain any button components."); - var ids = message.Components.SelectMany(m => m.Components).Select(c => c.CustomId); + var ids = buttons.Select(c => c.CustomId); var result = await this @@ -289,7 +291,7 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(c => c.Type is ComponentType.Button)) + if (!message.FilterComponents().Any()) throw new ArgumentException("Provided message does not contain any button components."); var result = await this @@ -330,10 +332,10 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(c => c.Type is ComponentType.Button)) + if (!message.FilterComponents().Any()) throw new ArgumentException("Provided message does not contain any button components."); - if (!message.Components.SelectMany(c => c.Components).OfType().Any(c => c.CustomId == id)) + if (!message.FilterComponents().Any(c => c.CustomId == id)) throw new ArgumentException($"Provided message does not contain button with Id of '{id}'."); var result = await this @@ -367,7 +369,7 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(c => c.Type is ComponentType.Button)) + if (!message.FilterComponents().Any()) throw new ArgumentException("Provided message does not contain any button components."); var result = await this @@ -403,7 +405,7 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(this.IsSelect)) + if (!message.FilterComponents().Any(this.IsSelect)) throw new ArgumentException("Provided message does not contain any select components."); @@ -442,10 +444,10 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(this.IsSelect)) + if (!message.FilterComponents().Any(this.IsSelect)) throw new ArgumentException("Provided message does not contain any select components."); - if (message.Components.SelectMany(c => c.Components).Where(this.IsSelect).All(c => c.CustomId != id)) + if (message.FilterComponents().Where(this.IsSelect).All(c => c.CustomId != id)) throw new ArgumentException($"Provided message does not contain select component with Id of '{id}'."); var result = await this @@ -495,10 +497,10 @@ public async Task> Wait if (!message.Components.Any()) throw new ArgumentException("Provided message does not contain any components."); - if (!message.Components.SelectMany(c => c.Components).Any(this.IsSelect)) + if (!message.FilterComponents().Any(this.IsSelect)) throw new ArgumentException("Provided message does not contain any select components."); - if (message.Components.SelectMany(c => c.Components).Where(this.IsSelect).All(c => c.CustomId != id)) + if (message.FilterComponents().Where(this.IsSelect).All(c => c.CustomId != id)) throw new ArgumentException($"Provided message does not contain button with Id of '{id}'."); var result = await this diff --git a/DSharpPlus.targets b/DSharpPlus.targets index 0e23620ff3..35fc2b2d8a 100644 --- a/DSharpPlus.targets +++ b/DSharpPlus.targets @@ -1,7 +1,7 @@ - 4.4.9 + 4.5.0 1591 9.0 True diff --git a/DSharpPlus/Entities/Channel/Message/DiscordMessage.cs b/DSharpPlus/Entities/Channel/Message/DiscordMessage.cs index a4ffc54c1b..182fc8e330 100644 --- a/DSharpPlus/Entities/Channel/Message/DiscordMessage.cs +++ b/DSharpPlus/Entities/Channel/Message/DiscordMessage.cs @@ -26,6 +26,7 @@ using System.Collections.ObjectModel; using System.Globalization; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Newtonsoft.Json; @@ -102,7 +103,7 @@ public DiscordChannel Channel /// Gets the components this message was sent with. /// [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] - public IReadOnlyCollection Components { get; internal set; } + public IReadOnlyCollection Components { get; internal set; } /// /// Gets the user or member that sent the message. @@ -440,6 +441,35 @@ internal void PopulateMentions() this._mentionedUsers = mentionedUsers.ToList(); } + /// + /// Searches the components on this message for an aggregate of all components of a certain type. + /// + public IReadOnlyList FilterComponents() + where T : DiscordComponent + { + List components = new(); + + foreach (DiscordComponent component in this.Components) + { + if (component is DiscordActionRowComponent actionRowComponent) + { + foreach (DiscordComponent subComponent in actionRowComponent.Components) + { + if (subComponent is T filteredComponent) + { + components.Add(filteredComponent); + } + } + } + else if (component is T filteredComponent) + { + components.Add(filteredComponent); + } + } + + return components; + } + /// /// Edits the message. /// diff --git a/DSharpPlus/Entities/Channel/Message/DiscordMessageBuilder.cs b/DSharpPlus/Entities/Channel/Message/DiscordMessageBuilder.cs index bdf388bb08..44e6a4240e 100644 --- a/DSharpPlus/Entities/Channel/Message/DiscordMessageBuilder.cs +++ b/DSharpPlus/Entities/Channel/Message/DiscordMessageBuilder.cs @@ -115,7 +115,10 @@ public DiscordMessageBuilder(DiscordMessage baseMessage) { this.IsTTS = baseMessage.IsTTS; this.ReplyId = baseMessage.ReferencedMessage?.Id; - this._components = baseMessage.Components.ToList(); // Calling ToList copies the list instead of referencing it + + // calling tolist copies the list, which is good since we inaccurately reflect the message in case of + // unknown components + this._components = baseMessage.Components.OfType().ToList(); this._content = baseMessage.Content; this._embeds = baseMessage.Embeds.ToList(); this._stickers = baseMessage.Stickers.ToList(); diff --git a/DSharpPlus/Entities/Interaction/DiscordInteractionData.cs b/DSharpPlus/Entities/Interaction/DiscordInteractionData.cs index 1767ae3fa4..c63b999c17 100644 --- a/DSharpPlus/Entities/Interaction/DiscordInteractionData.cs +++ b/DSharpPlus/Entities/Interaction/DiscordInteractionData.cs @@ -65,10 +65,10 @@ public sealed class DiscordInteractionData : SnowflakeObject /// /// Components on this interaction. Only applies to modal interactions. /// - public IReadOnlyList Components => this._components; + public IReadOnlyList Components => this._components; [JsonProperty("components", NullValueHandling = NullValueHandling.Ignore)] - internal List _components; + internal List _components; /// /// The Id of the target. Applicable for context menus. diff --git a/DSharpPlus/EventArgs/Interaction/ModalSubmitEventArgs.cs b/DSharpPlus/EventArgs/Interaction/ModalSubmitEventArgs.cs index f3bd769b45..4adfbf466b 100644 --- a/DSharpPlus/EventArgs/Interaction/ModalSubmitEventArgs.cs +++ b/DSharpPlus/EventArgs/Interaction/ModalSubmitEventArgs.cs @@ -46,7 +46,7 @@ internal ModalSubmitEventArgs(DiscordInteraction interaction) var dict = new Dictionary(); foreach (var component in interaction.Data._components) - if (component.Components.First() is TextInputComponent input) + if ((component as DiscordActionRowComponent)?.Components.First() is TextInputComponent input) dict.Add(input.CustomId, input.Value); this.Values = dict;