Command Buttons
Interaction Acknowledging
If your button does something other than editing the message, you'll need to ack the request via ButtonClickContext#ack()
.
If all of your buttons do nothing with the message it's a pretty safe bet to put the entire button handler in the ack queue callback.
Command buttons are a default part of JDA and Discord's featureset, and this library lets you use them. However, the implementation is a bit weird, so let's dive in.
Buttons are defined in the constructor, even though they're realistically only needed when the command is actually called.
To get around this, the library stores a lazy button function that's called passing the SlashCommandContext
as a parameter and returning a HashSet<Button>
.
But you don't need to worry about that, because making buttons is rather simple:
Example Button Usage
init {
buttons { ctx ->
val id = newComponentId()
.user(ctx.user().id)
.action("delete")
danger(id, "Delete")
}
}
Note the above usage of newComponentId()
. Normally, in JDA, Component IDs are stored in Strings. However, in this library, to provide a somewhat consistent button component ID format, there's a class named ButtonComponentId
.
Component IDs should follow the format commandName:user:action:value
.
commandName |
The name of the command that created the button. This must match the command name otherwise the command library will not call the button click handler. |
user |
The user who pressed the button, to prevent spoofing. |
action |
The action to perform, to discern between buttons programmatically. |
value |
A possible value needed when the button is pressed, such as a numerical value for messages to delete in a purge command. |
To handle the button, you can assume every call of your handler to be of a button for that specific command. You'll need to handle ID checking, and action/value reading.
Example Button Handler Implementation
override fun handleButtonClick(ctx: ButtonClickContext) {
val id = ctx.parsedComponent() // ButtonComponentId
if (id.user() != ctx.user().id) return
when (id.action()) {
"delete" -> //delete the message
/etc
}
}
In order to utilize the buttons that are generated by the function set in your primary constructor, you'll want to call actionRowsFrom(SlashCommandContext)
on any ReplyAction
, which will call the button generator function and add all of the buttons to the message.
A Functional Example
class DestructOnDemand : SlashCommand("destruct", "Dummy message with a button allowing you to delete it at will.") {
init {
buttons { ctx ->
val id = newComponentId()
.user(ctx.user().id)
.action("delete")
danger(id, "Delete")
}
}
override fun handleSlashCommand(ctx: SlashCommandContext) {
ctx.reply("lmao")
.actionRowsFrom(ctx)
.queue()
}
override fun handleButtonClick(ctx: ButtonClickContext) {
val id = ctx.parsedComponent()
if (id.user() != ctx.user().id) return
when (id.action()) {
"delete" -> ctx.ack().queue { ctx.message?.delete()?.queue() }
}
}
}