diff --git a/src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs index 963d4523..c534e9f3 100644 --- a/src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs @@ -1,43 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Discord { + /// + /// Represents a builder for creating a . + /// public class ModalBuilder { - /// - /// Gets or sets the components of the current modal. - /// - public ModalComponentBuilder Components { get; set; } = new(); - - /// - /// Gets or sets the title of the current modal. - /// - public string Title { get; set; } - - /// - /// Gets or sets the custom id of the current modal. - /// - public string CustomId - { - get => _customId; - set => _customId = value?.Length switch - { - > ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom Id length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), - 0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom Id length must be at least 1."), - _ => value - }; - } - private string _customId; public ModalBuilder() { } /// - /// Creates a new instance of a + /// Creates a new instance of the . /// /// The modal's title. /// The modal's customId. @@ -50,6 +27,30 @@ namespace Discord Components = components ?? new(); } + /// + /// Gets or sets the title of the current modal. + /// + public string Title { get; set; } + + /// + /// Gets or sets the custom ID of the current modal. + /// + public string CustomId + { + get => _customId; + set => _customId = value?.Length switch + { + > ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom ID length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom ID length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the components of the current modal. + /// + public ModalComponentBuilder Components { get; set; } = new(); + /// /// Sets the title of the current modal. /// @@ -76,10 +77,11 @@ namespace Discord /// Adds a component to the current builder. /// /// The component to add. + /// The row to add the text input. /// The current builder. - public ModalBuilder AddTextInput(TextInputBuilder component) + public ModalBuilder AddTextInput(TextInputBuilder component, int row = 0) { - Components.WithTextInput(component); + Components.WithTextInput(component, row); return this; } @@ -108,21 +110,111 @@ namespace Discord return this; } + /// + /// Gets a by the specified . + /// + /// The type of the component to get. + /// The of the component to get. + /// + /// The component of type that was found, otherwise. + /// + public TMessageComponent GetComponent(string customId) + where TMessageComponent : class, IMessageComponent + { + Preconditions.NotNull(customId, nameof(customId)); + + return Components.ActionRows + ?.SelectMany(r => r.Components.OfType()) + .FirstOrDefault(c => c?.CustomId == customId); + } + + /// + /// Updates a by the specified . + /// + /// The of the input to update. + /// An action that configures the updated text input. + /// The current builder. + /// + /// Thrown when the to be updated was not found. + /// + public ModalBuilder UpdateTextInput(string customId, Action updateTextInput) + { + Preconditions.NotNull(customId, nameof(customId)); + + var component = GetComponent(customId) ?? throw new ArgumentException($"There is no component of type {nameof(TextInputComponent)} with the specified custom ID in this modal builder.", nameof(customId)); + var row = Components.ActionRows.First(r => r.Components.Contains(component)); + + var builder = new TextInputBuilder + { + Label = component.Label, + CustomId = component.CustomId, + Style = component.Style, + Placeholder = component.Placeholder, + MinLength = component.MinLength, + MaxLength = component.MaxLength, + Required = component.Required, + Value = component.Value + }; + + updateTextInput(builder); + + row.Components.Remove(component); + row.AddComponent(builder.Build()); + + return this; + } + + /// + /// Updates the value of a by the specified . + /// + /// The of the input to update. + /// The new value to put. + /// The current builder. + public ModalBuilder UpdateTextInput(string customId, object value) + { + UpdateTextInput(customId, x => x.Value = value?.ToString()); + return this; + } + + /// + /// Removes a component from this builder by the specified . + /// + /// The of the component to remove. + /// The current builder. + public ModalBuilder RemoveComponent(string customId) + { + Preconditions.NotNull(customId, nameof(customId)); + + Components.ActionRows?.ForEach(r => r.Components.RemoveAll(c => c.CustomId == customId)); + return this; + } + + /// + /// Removes all components of the given from this builder. + /// + /// The to remove. + /// The current builder. + public ModalBuilder RemoveComponentsOfType(ComponentType type) + { + Components.ActionRows?.ForEach(r => r.Components.RemoveAll(c => c.Type == type)); + return this; + } + /// /// Builds this builder into a . /// /// A with the same values as this builder. - /// Only TextInputComponents are allowed. - /// Modals must have a custom id. + /// Modals must have a custom ID. /// Modals must have a title. + /// Only components of type are allowed. public Modal Build() { if (string.IsNullOrEmpty(CustomId)) - throw new ArgumentException("Modals must have a custom id.", nameof(CustomId)); + throw new ArgumentException("Modals must have a custom ID.", nameof(CustomId)); if (string.IsNullOrWhiteSpace(Title)) throw new ArgumentException("Modals must have a title.", nameof(Title)); - if (Components.ActionRows?.SelectMany(x => x.Components).Any(x => x.Type != ComponentType.TextInput) ?? false) - throw new ArgumentException($"Only TextInputComponents are allowed.", nameof(Components)); + if (Components.ActionRows?.SelectMany(r => r.Components).Any(c => c.Type != ComponentType.TextInput) ?? false) + throw new ArgumentException($"Only components of type {nameof(TextInputComponent)} are allowed.", nameof(Components)); return new(Title, CustomId, Components.Build()); }