From be8e6e039405cae445c48e82719319c462e37b6d Mon Sep 17 00:00:00 2001 From: Mihail Gribkov <61027276+Misha-133@users.noreply.github.com> Date: Fri, 9 May 2025 20:54:08 +0300 Subject: [PATCH] Component search fixes & improvements (#3123) --- .../MessageComponents/ActionRowComponent.cs | 2 +- .../Builders/ComponentContainerExtensions.cs | 98 +++++++++++++++++-- .../MessageComponents/ContainerComponent.cs | 2 +- .../MessageComponents/INestedComponent.cs | 14 +++ .../MessageComponents/MessageComponent.cs | 2 +- .../MessageComponents/SectionComponent.cs | 2 +- 6 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/INestedComponent.cs diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs index 6cdb1ffd..c604d535 100644 --- a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs @@ -5,7 +5,7 @@ namespace Discord; /// /// Represents a Row for child components to live in. /// -public class ActionRowComponent : IMessageComponent +public class ActionRowComponent : INestedComponent, IMessageComponent { /// public ComponentType Type => ComponentType.ActionRow; diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ComponentContainerExtensions.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ComponentContainerExtensions.cs index 318367a5..9195a20b 100644 --- a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ComponentContainerExtensions.cs +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ComponentContainerExtensions.cs @@ -341,13 +341,30 @@ public static class ComponentContainerExtensions /// public static ComponentT FindComponentById(this IComponentContainer container, int id) where ComponentT : class, IMessageComponentBuilder - => container.Components - .OfType() - .FirstOrDefault(x => x.Id == id) - ?? container.Components - .OfType() - .Select(x => x.FindComponentById(id)) - .FirstOrDefault(x => x is not null); + { + if (container is ComponentT cmp && cmp.Id == id) + return cmp; + + foreach (var component in container.Components) + { + if (component.Id == id && component is ComponentT target) + return target; + + if (component is SectionBuilder section + && section.Accessory.Id == id + && section.Accessory is ComponentT targetAccessory) + return targetAccessory; + + if (component is IComponentContainer childContainer) + { + var childSearchResult = childContainer.FindComponentById(id); + if (childSearchResult is not null) + return childSearchResult; + } + } + + return null; + } /// /// Gets a IEnumerable containing ids of @@ -360,4 +377,71 @@ public static class ComponentContainerExtensions .Concat(container.Components .OfType() .SelectMany(x => x.GetComponentIds())); + + /// + /// Finds the first in the + /// or any of its child s with matching id. + /// + /// + /// The with matching id, otherwise. + /// + public static IMessageComponent FindComponentById(this INestedComponent container, int id) + => container.FindComponentById(id); + + /// + /// Finds the first ComponentT in the + /// or any of its child s with matching id. + /// + /// + /// The ComponentT with matching id, otherwise. + /// + public static ComponentT FindComponentById(this INestedComponent container, int id) + where ComponentT : class, IMessageComponent + { + if (container is ComponentT cmp && cmp.Id == id) + return cmp; + + return container.Components.FindComponentById(id); + } + + /// + /// Finds the first ComponentT in the + /// or any of its child s with matching id. + /// + /// + /// The ComponentT with matching id, otherwise. + /// + public static ComponentT FindComponentById(this IEnumerable components, int id) + where ComponentT : class, IMessageComponent + { + foreach (var component in components) + { + if (component.Id == id && component is ComponentT target) + return target; + + if (component is SectionComponent section + && section.Accessory.Id == id + && section.Accessory is ComponentT targetAccessory) + return targetAccessory; + + if (component is INestedComponent childContainer) + { + var childSearchResult = childContainer.FindComponentById(id); + if (childSearchResult is not null) + return childSearchResult; + } + } + + return null; + } + + /// + /// Finds the first in the + /// or any of its child s with matching id. + /// + /// + /// The with matching id, otherwise. + /// + public static IMessageComponent FindComponentById(this IEnumerable components, int id) + => components.FindComponentById(id); } diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ContainerComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ContainerComponent.cs index 9e8fe1fa..c01417f7 100644 --- a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ContainerComponent.cs +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ContainerComponent.cs @@ -5,7 +5,7 @@ namespace Discord; /// /// Represents a container component. /// -public class ContainerComponent : IMessageComponent +public class ContainerComponent : INestedComponent, IMessageComponent { /// public ComponentType Type => ComponentType.Container; diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/INestedComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/INestedComponent.cs new file mode 100644 index 00000000..68190fbb --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/INestedComponent.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Discord; + +/// +/// Represents a containing child components. +/// +public interface INestedComponent +{ + /// + /// Gets the child components in this container. + /// + IReadOnlyCollection Components { get; } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs index 18946a73..cf2628f2 100644 --- a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs @@ -5,7 +5,7 @@ namespace Discord; /// /// Represents a component object used to send components with messages. /// -public class MessageComponent +public class MessageComponent : INestedComponent { /// /// Gets the components to be used in a message. diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SectionComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SectionComponent.cs index 30ddcb1a..6d88609d 100644 --- a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SectionComponent.cs +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SectionComponent.cs @@ -5,7 +5,7 @@ namespace Discord; /// /// Represents a section component. /// -public class SectionComponent : IMessageComponent +public class SectionComponent : INestedComponent, IMessageComponent { /// public ComponentType Type => ComponentType.Section;