Feature: Implement modals (#2087)
* Implement Modals (#428) * Socket Modal Support * fix shareded client support * Properly use `HasResponded` instead of `_hasResponded` * `ModalBuilder` and `TextInputBuilder` validation. * make orginisation more consistant. * Rest Modals. * Docs + add missing methods * fix message signatures and missing abstract members * modal changes * um????? * update modal docs * update docs - again for some reason * cleanup * fix message signatures * add modal commands support to interaction service * Fix _hasResponded * update to new unsupported standard. * Sending modals with Interaction service. * fix spelling in ComponentBuilder * sending IModals when responding to interactions * interaction service modals * fix rest modals * spelling and minor improvements. * improve interaction service modal proformance * use precompiled lambda for interaction service modals * respect user compiled lambda choice * changes to modals in the interaction service (more) * support compiled lambdas in modal properties. * modal interactions tweaks * fix inline doc * more modal docs * configure responce to faild modal component * init * solve runtime errors * solve build errors * add default value parsing * make modal info caching static * make ModalUtils static * add inline docs * fix build errors * code cleanup * Introduce Required and Label properties as seperate attributes. * replace internal dictionary of ModalInfo with a list * change input building logic of modals * update RespondWithModalAsync method * add initial value parameter back to ModalTextInput and fix optional modal field * add missing inline docs * dispose the reference modal instance after building * code cleanup on modalcommandbuilder * Update docs/guides/int_basics/message-components/text-input.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/message-components/text-input.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/modals/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/modals/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/modals/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/modals/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/modals/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/modals/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_basics/modals/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_framework/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_framework/intro.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/guides/int_framework/samples/intro/modal.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteractionData.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/MessageComponents/TextInputComponent.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/Modals/IModalInteraction.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Core/Entities/Interactions/Modals/ModalBuilder.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Interactions/Attributes/Commands/ModalInteractionAttribute.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Interactions/Attributes/Modals/RequiredInputAttribute.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.Interactions/InteractionServiceConfig.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponentData.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.WebSocket/Entities/Interaction/Modals/SocketModalData.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * update interaction service modal docs * implements ExitOnMissingmModalField config option and adds Type field to modal info * Add WithValue to text input builders * Fix rare NRE on component enumeration * Fix RequestOptions being required in some methods * Use 'OfType' instead of 'Where' * Remove android unsported warning * Change publicity of properties in IInputComponeontBuilder.cs Co-authored-by: Cenk Ergen <57065323+Cenngo@users.noreply.github.com> Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Remove complex parameter ref Co-authored-by: CottageDwellingCat <80918250+CottageDwellingCat@users.noreply.github.com> Co-authored-by: Cenk Ergen <57065323+Cenngo@users.noreply.github.com> Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com>
This commit is contained in:
BIN
docs/guides/int_basics/modals/images/image1.png
Normal file
BIN
docs/guides/int_basics/modals/images/image1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/guides/int_basics/modals/images/image2.png
Normal file
BIN
docs/guides/int_basics/modals/images/image2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/guides/int_basics/modals/images/image3.png
Normal file
BIN
docs/guides/int_basics/modals/images/image3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/guides/int_basics/modals/images/image4.png
Normal file
BIN
docs/guides/int_basics/modals/images/image4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
135
docs/guides/int_basics/modals/intro.md
Normal file
135
docs/guides/int_basics/modals/intro.md
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
uid: Guides.Modals.Intro
|
||||
title: Getting Started with Modals
|
||||
---
|
||||
# Modals
|
||||
|
||||
## Getting started with modals
|
||||
This guide will show you how to use modals and give a few examples of
|
||||
valid use cases. If your question is not covered by this guide ask in the
|
||||
[Discord.Net Discord Server](https://discord.gg/dnet).
|
||||
|
||||
### What is a modal?
|
||||
Modals are forms bots can send when responding to interactions. Modals
|
||||
are sent to Discord as an array of message components and converted
|
||||
into the form layout by user's clients. Modals are required to have a
|
||||
custom id, title, and at least one component.
|
||||
|
||||

|
||||
|
||||
When users submit modals, your client fires the ModalSubmitted event.
|
||||
You can get the components of the modal from the `Data.Components` property
|
||||
on the SocketModal:
|
||||
|
||||

|
||||
|
||||
### Using modals
|
||||
|
||||
Lets create a simple modal with an entry field for users to
|
||||
tell us their favorite food. We can start by creating a slash
|
||||
command that will respond with the modal.
|
||||
```cs
|
||||
[SlashCommand("food", "Tell us about your favorite food!")]
|
||||
public async Task FoodPreference()
|
||||
{
|
||||
// send a modal
|
||||
}
|
||||
```
|
||||
|
||||
Now that we have our command set up, we need to build a modal.
|
||||
We can use the aptly named `ModalBuilder` for that:
|
||||
|
||||
| Method | Description |
|
||||
| --------------- | ----------------------------------------- |
|
||||
| `WithTitle` | Sets the modal's title. |
|
||||
| `WithCustomId` | Sets the modal's custom id. |
|
||||
| `AddTextInput` | Adds a `TextInputBuilder` to the modal. |
|
||||
| `AddComponents` | Adds multiple components to the modal. |
|
||||
| `Build` | Builds the `ModalBuilder` into a `Modal`. |
|
||||
|
||||
We know we need to add a text input to the modal, so let's look at that
|
||||
method's parameters.
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ------------------------------------------ |
|
||||
| `label` | Sets the input's label. |
|
||||
| `customId` | Sets the input's custom id. |
|
||||
| `style` | Sets the input's style. |
|
||||
| `placeholder` | Sets the input's placeholder. |
|
||||
| `minLength` | Sets the minimum input length. |
|
||||
| `maxLength` | Sets the maximum input length. |
|
||||
| `required` | Sets whether or not the modal is required. |
|
||||
| `value` | Sets the input's default value. |
|
||||
|
||||
To make a basic text input we would only need to set the `label` and
|
||||
`customId`, but in this example we will also use the `placeholder`
|
||||
parameter. Next we can build our modal:
|
||||
|
||||
```cs
|
||||
var mb = new ModalBuilder()
|
||||
.WithTitle("Fav Food")
|
||||
.WithCustomId("food_menu")
|
||||
.AddTextInput("What??", "food_name", placeholder:"Pizza")
|
||||
.AddTextInput("Why??", "food_reason", TextInputStyle.Paragraph,
|
||||
"Kus it's so tasty");
|
||||
```
|
||||
|
||||
Now that we have a ModalBuilder we can update our command to respond
|
||||
with the modal.
|
||||
|
||||
```cs
|
||||
[SlashCommand("food", "Tell us about your favorite food!")]
|
||||
public async Task FoodPreference()
|
||||
{
|
||||
var mb = new ModalBuilder()
|
||||
.WithTitle("Fav Food")
|
||||
.WithCustomId("food_menu")
|
||||
.AddTextInput("What??", "food_name", placeholder:"Pizza")
|
||||
.AddTextInput("Why??", "food_reason", TextInputStyle.Paragraph,
|
||||
"Kus it's so tasty");
|
||||
|
||||
await Context.Interaction.RespondWithModalAsync(mb.Build());
|
||||
}
|
||||
```
|
||||
|
||||
When we run the command, our modal should pop up:
|
||||
|
||||

|
||||
|
||||
### Respond to modals
|
||||
|
||||
> [!WARNING]
|
||||
> Modals can not be sent when respoding to a modal.
|
||||
|
||||
Once a user has submitted the modal, we need to let everyone know what
|
||||
their favorite food is. We can start by hooking a task to the client's
|
||||
`ModalSubmitted` event.
|
||||
```cs
|
||||
_client.ModalSubmitted += async modal =>
|
||||
{
|
||||
// Get the values of components.
|
||||
List<SocketMessageComponentData> components =
|
||||
modal.Data.Components.ToList();
|
||||
string food = components
|
||||
.Where(x => x.CustomId == "food_name").First().Value;
|
||||
string reason = components
|
||||
.Where(x => x.CustomId == "food_reason").First().Value;
|
||||
|
||||
// Build the message to send.
|
||||
string message = "hey @everyone; I just learned " +
|
||||
$"{modal.User.Mention}'s favorite food is " +
|
||||
$"{food} because {reason}.";
|
||||
|
||||
// Specify the AllowedMentions so we don't actually ping everyone.
|
||||
AllowedMentions mentions = new AllowedMentions();
|
||||
mentions.AllowedTypes = AllowedMentionTypes.Users;
|
||||
|
||||
// Respond to the modal.
|
||||
await modal.RespondAsync(message, allowedMentions:mentions);
|
||||
}
|
||||
```
|
||||
|
||||
Now responding to the modal should inform everyone of our tasty
|
||||
choices.
|
||||
|
||||

|
||||
Reference in New Issue
Block a user