mirror of
https://github.com/diamondburned/arikawa.git
synced 2024-11-17 12:23:08 +00:00
discord: Modal interaction support (#310)
* Support modal interactions along with the TextInput component * Replace ModalInteraction with Modal to prevent confusion * Fix the required field from not being used correctly * PR Fixes
This commit is contained in:
parent
7727d140a0
commit
d6bc738e50
|
@ -25,6 +25,7 @@ const (
|
||||||
DeferredMessageUpdate
|
DeferredMessageUpdate
|
||||||
UpdateMessage
|
UpdateMessage
|
||||||
AutocompleteResult
|
AutocompleteResult
|
||||||
|
ModalResponse
|
||||||
)
|
)
|
||||||
|
|
||||||
// InteractionResponseFlags implements flags for an
|
// InteractionResponseFlags implements flags for an
|
||||||
|
@ -78,6 +79,11 @@ type InteractionResponseData struct {
|
||||||
//
|
//
|
||||||
// During all other events, this should not be provided.
|
// During all other events, this should not be provided.
|
||||||
Choices *[]AutocompleteChoice `json:"choices"`
|
Choices *[]AutocompleteChoice `json:"choices"`
|
||||||
|
|
||||||
|
// CustomID used with the modal
|
||||||
|
CustomID option.NullableString `json:"custom_id,omitempty"`
|
||||||
|
// Title is the heading of the modal window
|
||||||
|
Title option.NullableString `json:"title,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NeedsMultipart returns true if the InteractionResponseData has files.
|
// NeedsMultipart returns true if the InteractionResponseData has files.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/diamondburned/arikawa/v3/utils/json"
|
"github.com/diamondburned/arikawa/v3/utils/json"
|
||||||
|
"github.com/diamondburned/arikawa/v3/utils/json/option"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ const (
|
||||||
ActionRowComponentType
|
ActionRowComponentType
|
||||||
ButtonComponentType
|
ButtonComponentType
|
||||||
SelectComponentType
|
SelectComponentType
|
||||||
|
TextInputComponentType
|
||||||
)
|
)
|
||||||
|
|
||||||
// String formats Type's name as a string.
|
// String formats Type's name as a string.
|
||||||
|
@ -26,6 +28,8 @@ func (t ComponentType) String() string {
|
||||||
return "Button"
|
return "Button"
|
||||||
case SelectComponentType:
|
case SelectComponentType:
|
||||||
return "Select"
|
return "Select"
|
||||||
|
case TextInputComponentType:
|
||||||
|
return "TextInput"
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("ComponentType(%d)", int(t))
|
return fmt.Sprintf("ComponentType(%d)", int(t))
|
||||||
}
|
}
|
||||||
|
@ -126,6 +130,8 @@ func ParseComponent(b []byte) (Component, error) {
|
||||||
c = &ButtonComponent{}
|
c = &ButtonComponent{}
|
||||||
case SelectComponentType:
|
case SelectComponentType:
|
||||||
c = &SelectComponent{}
|
c = &SelectComponent{}
|
||||||
|
case TextInputComponentType:
|
||||||
|
c = &TextInputComponent{}
|
||||||
default:
|
default:
|
||||||
c = &UnknownComponent{typ: t.Type}
|
c = &UnknownComponent{typ: t.Type}
|
||||||
}
|
}
|
||||||
|
@ -448,6 +454,69 @@ func (s *SelectComponent) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(msg)
|
return json.Marshal(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TextInputStyle uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ TextInputStyle = iota
|
||||||
|
TextInputShortStyle
|
||||||
|
TextInputParagraphStyle
|
||||||
|
)
|
||||||
|
|
||||||
|
// TextInputComponents provide a user-facing text box to be filled out. They can only
|
||||||
|
// be used with modals.
|
||||||
|
type TextInputComponent struct {
|
||||||
|
// CustomID provides a developer-defined ID for the input (max 100 chars)
|
||||||
|
CustomID ComponentID `json:"custom_id"`
|
||||||
|
// Style determines if the component should use the short or paragraph style
|
||||||
|
Style TextInputStyle `json:"style"`
|
||||||
|
// Label is the title of this component, describing its use
|
||||||
|
Label string `json:"label"`
|
||||||
|
// ValueLimits is the minimum and maximum length for the input
|
||||||
|
ValueLimits [2]int `json:"-"`
|
||||||
|
// Required dictates whether or not the user must fill out the component
|
||||||
|
Required bool `json:"required"`
|
||||||
|
// Value is the pre-filled value of this component (max 4000 chars)
|
||||||
|
Value option.NullableString `json:"value,omitempty"`
|
||||||
|
// Placeholder is the text that appears when the input is empty (max 100 chars)
|
||||||
|
Placeholder option.NullableString `json:"placeholder,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TextInputComponent) _cmp() {}
|
||||||
|
func (s *TextInputComponent) _icp() {}
|
||||||
|
|
||||||
|
func (i *TextInputComponent) ID() ComponentID {
|
||||||
|
return i.CustomID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *TextInputComponent) Type() ComponentType {
|
||||||
|
return TextInputComponentType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *TextInputComponent) MarshalJSON() ([]byte, error) {
|
||||||
|
type text TextInputComponent
|
||||||
|
|
||||||
|
type Msg struct {
|
||||||
|
Type ComponentType `json:"type"`
|
||||||
|
*text
|
||||||
|
MinValues *int `json:"max_values,omitempty"`
|
||||||
|
MaxValues *int `json:"min_values,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
m := Msg{
|
||||||
|
Type: i.Type(),
|
||||||
|
text: (*text)(i),
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.ValueLimits != [2]int{0, 0} {
|
||||||
|
m.MinValues = new(int)
|
||||||
|
m.MaxValues = new(int)
|
||||||
|
|
||||||
|
*m.MinValues = i.ValueLimits[0]
|
||||||
|
*m.MaxValues = i.ValueLimits[1]
|
||||||
|
}
|
||||||
|
return json.Marshal(m)
|
||||||
|
}
|
||||||
|
|
||||||
// Unknown is reserved for components with unknown or not yet implemented
|
// Unknown is reserved for components with unknown or not yet implemented
|
||||||
// components types. It can also be used in place of a ComponentInteraction.
|
// components types. It can also be used in place of a ComponentInteraction.
|
||||||
type UnknownComponent struct {
|
type UnknownComponent struct {
|
||||||
|
|
|
@ -86,6 +86,8 @@ func (e *InteractionEvent) UnmarshalJSON(b []byte) error {
|
||||||
return nil
|
return nil
|
||||||
case AutocompleteInteractionType:
|
case AutocompleteInteractionType:
|
||||||
e.Data = &AutocompleteInteraction{}
|
e.Data = &AutocompleteInteraction{}
|
||||||
|
case ModalInteractionType:
|
||||||
|
e.Data = &ModalInteraction{}
|
||||||
default:
|
default:
|
||||||
e.Data = &UnknownInteractionData{
|
e.Data = &UnknownInteractionData{
|
||||||
Raw: target.Data,
|
Raw: target.Data,
|
||||||
|
@ -131,6 +133,7 @@ const (
|
||||||
CommandInteractionType
|
CommandInteractionType
|
||||||
ComponentInteractionType
|
ComponentInteractionType
|
||||||
AutocompleteInteractionType
|
AutocompleteInteractionType
|
||||||
|
ModalInteractionType
|
||||||
)
|
)
|
||||||
|
|
||||||
// InteractionData holds the respose data of an interaction, or more
|
// InteractionData holds the respose data of an interaction, or more
|
||||||
|
@ -365,6 +368,19 @@ func (o CommandInteractionOption) FloatValue() (float64, error) {
|
||||||
return f, err
|
return f, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ModalInteraction is the submitted modal form
|
||||||
|
type ModalInteraction struct {
|
||||||
|
CustomID ComponentID `json:"custom_id"`
|
||||||
|
Components ContainerComponents `json:"components"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InteractionType implements InteractionData.
|
||||||
|
func (m *ModalInteraction) InteractionType() InteractionDataType {
|
||||||
|
return ModalInteractionType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModalInteraction) data() {}
|
||||||
|
|
||||||
// UnknownInteractionData describes an Interaction response with an unknown
|
// UnknownInteractionData describes an Interaction response with an unknown
|
||||||
// type.
|
// type.
|
||||||
type UnknownInteractionData struct {
|
type UnknownInteractionData struct {
|
||||||
|
|
Loading…
Reference in a new issue