From 8591de7119b150db26eccc302b1a9bf7c61bf184 Mon Sep 17 00:00:00 2001
From: zobweyt <98274273+zobweyt@users.noreply.github.com>
Date: Sat, 2 Sep 2023 21:03:54 +0300
Subject: [PATCH] [Feature] Add useful utility methods to `ModalBuilder`
(#2773)
* Add method to get a component of type
* Add methods to update a component
* Add methods to remove a component(s)
* Add missing `row` parameter to wrapper
* Update XML documentation
* Reorder properties to follow coding style
* Remove unnecessary usings to follow coding style
* Fix build usings
* Fix XML documentation
* Add `null` checks to remove methods
* Fix empty constructor
* Fix `CustomId` setter
* Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs
Co-authored-by: Misha133 <61027276+Misha-133@users.noreply.github.com>
* Fix `GetComponent` to return null
* Fix XML documentation
* Add `null` checks
* Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs
* Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs
* Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs
Co-authored-by: Misha133 <61027276+Misha-133@users.noreply.github.com>
---------
Co-authored-by: Misha133 <61027276+Misha-133@users.noreply.github.com>
---
.../Interactions/Modals/ModalBuilder.cs | 160 ++++++++++++++----
1 file changed, 126 insertions(+), 34 deletions(-)
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());
}