Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Updating JDA to alpha.9 * Reverting missed <jar> change in pom.xml * Fixing typo * Adding space before casts to match Java formatting guidelines * Modals Initial implementation * Changes based on feedback * Fixed registration order for DiscordModalCommand * Error for Interaction already acknowledged
- Loading branch information
1 parent
8fe9f04
commit dcc8d99
Showing
6 changed files
with
508 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
src/main/java/com/denizenscript/ddiscordbot/commands/DiscordModalCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package com.denizenscript.ddiscordbot.commands; | ||
|
||
import com.denizenscript.ddiscordbot.DenizenDiscordBot; | ||
import com.denizenscript.ddiscordbot.objects.*; | ||
import com.denizenscript.denizencore.objects.ObjectTag; | ||
import com.denizenscript.denizencore.objects.core.ElementTag; | ||
import com.denizenscript.denizencore.scripts.ScriptEntry; | ||
import com.denizenscript.denizencore.scripts.commands.Holdable; | ||
import com.denizenscript.denizencore.utilities.CoreUtilities; | ||
import com.denizenscript.denizencore.utilities.debugging.Debug; | ||
import net.dv8tion.jda.api.interactions.callbacks.IModalCallback; | ||
import net.dv8tion.jda.api.interactions.components.ActionRow; | ||
import net.dv8tion.jda.api.interactions.components.ItemComponent; | ||
import net.dv8tion.jda.api.interactions.components.Modal; | ||
import net.dv8tion.jda.api.requests.restaction.interactions.ModalCallbackAction; | ||
import org.bukkit.Bukkit; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
public class DiscordModalCommand extends AbstractDiscordCommand implements Holdable { | ||
|
||
public DiscordModalCommand() { | ||
setName("discordmodal"); | ||
setSyntax("discordmodal [interaction:<interaction>] [name:<name>] [rows:<rows>] (title:<title>)"); | ||
setRequiredArguments(3, 4); | ||
setPrefixesHandled("interaction", "rows", "title", "name"); | ||
isProcedural = false; | ||
} | ||
|
||
// <--[command] | ||
// @Name discordmodal | ||
// @Syntax discordmodal [interaction:<interaction>] [name:<name>] [rows:<rows>] (title:<title>) | ||
// @Required 3 | ||
// @Maximum 4 | ||
// @Short Manages Discord modals. | ||
// @Plugin dDiscordBot | ||
// @Guide https://guide.denizenscript.com/guides/expanding/ddiscordbot.html | ||
// @Group external | ||
// | ||
// With this command you can respond to an interaction using a modal. | ||
// | ||
// You should usually defer an interaction before using a modal. | ||
// | ||
// The command should usually be ~waited for. See <@link language ~waitable>. | ||
// | ||
// @Usage | ||
// Use to create a modal from text replies. | ||
// - definemap rows: | ||
// 1: | ||
// 1: <discord_text_input.with[name].as[textinput].with[label].as[Type here!].with[style].as[short]> | ||
// - ~discordmodal interaction:<context.interaction> name:example_modal title:Modal! rows:<[rows]> | ||
// | ||
// --> | ||
|
||
@Override | ||
public void execute(ScriptEntry scriptEntry) { | ||
DiscordInteractionTag interaction = scriptEntry.requiredArgForPrefix("interaction", DiscordInteractionTag.class); | ||
ElementTag name = scriptEntry.requiredArgForPrefixAsElement("name"); | ||
ElementTag title = scriptEntry.argForPrefixAsElement("title", ""); | ||
ObjectTag rows = scriptEntry.requiredArgForPrefix("rows", ObjectTag.class); | ||
if (scriptEntry.dbCallShouldDebug()) { | ||
Debug.report(scriptEntry, getName(), interaction, name, rows, title); | ||
} | ||
Runnable runner = () -> { | ||
try { | ||
if (interaction.interaction == null) { | ||
handleError(scriptEntry, "Invalid interaction! Has it expired?"); | ||
return; | ||
} | ||
List<ActionRow> actionRows = createRows(scriptEntry, rows); | ||
if(actionRows == null || actionRows.isEmpty()) { | ||
handleError(scriptEntry, "Invalid action rows!"); | ||
return; | ||
} | ||
if (!interaction.interaction.isAcknowledged()) { | ||
IModalCallback replyTo = (IModalCallback) interaction.interaction; | ||
|
||
Modal modal = Modal.create(name.toString(), title.toString()) | ||
.addActionRows(actionRows) | ||
.build(); | ||
|
||
ModalCallbackAction action = replyTo.replyModal(modal); | ||
action.complete(); | ||
} else { | ||
handleError(scriptEntry, "Interaction already acknowledged!"); | ||
return; | ||
} | ||
} | ||
catch (Exception ex) { | ||
handleError(scriptEntry, ex); | ||
} | ||
}; | ||
Bukkit.getScheduler().runTaskAsynchronously(DenizenDiscordBot.instance, () -> { | ||
runner.run(); | ||
scriptEntry.setFinished(true); | ||
}); | ||
} | ||
|
||
public static List<ActionRow> createRows(ScriptEntry scriptEntry, ObjectTag rowsObj) { | ||
if (rowsObj == null) { | ||
return null; | ||
} | ||
Collection<ObjectTag> rows = CoreUtilities.objectToList(rowsObj, scriptEntry.getContext()); | ||
List<ActionRow> actionRows = new ArrayList<>(); | ||
for (ObjectTag row : rows) { | ||
List<ItemComponent> components = new ArrayList<>(); | ||
for (ObjectTag component : CoreUtilities.objectToList(row, scriptEntry.getContext())) { | ||
if (component.canBeType(DiscordTextInputTag.class)) { | ||
components.add(component.asType(DiscordTextInputTag.class, scriptEntry.getContext()).build()); | ||
} | ||
else { | ||
Debug.echoError("Unsupported modal component list entry '" + component + "'"); | ||
} | ||
} | ||
actionRows.add(ActionRow.of(components)); | ||
} | ||
return actionRows; | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
src/main/java/com/denizenscript/ddiscordbot/events/DiscordModalSubmittedScriptEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package com.denizenscript.ddiscordbot.events; | ||
|
||
import com.denizenscript.ddiscordbot.DiscordScriptEvent; | ||
import com.denizenscript.ddiscordbot.objects.DiscordChannelTag; | ||
import com.denizenscript.ddiscordbot.objects.DiscordGroupTag; | ||
import com.denizenscript.ddiscordbot.objects.DiscordInteractionTag; | ||
import com.denizenscript.ddiscordbot.objects.DiscordSelectionTag; | ||
import com.denizenscript.denizencore.objects.ObjectTag; | ||
import com.denizenscript.denizencore.objects.core.ElementTag; | ||
import com.denizenscript.denizencore.objects.core.MapTag; | ||
import com.denizenscript.denizencore.utilities.text.StringHolder; | ||
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent; | ||
import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent; | ||
|
||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
public class DiscordModalSubmittedScriptEvent extends DiscordScriptEvent { | ||
|
||
// <--[event] | ||
// @Events | ||
// discord modal submitted | ||
// | ||
// @Switch for:<bot> to only process the event for a specified Discord bot. | ||
// @Switch channel:<channel_id> to only process the event when it occurs in a specified Discord channel. | ||
// @Switch group:<group_id> to only process the event for a specified Discord group. | ||
// @Switch name:<modal_name> to only process the event for a specified Discord modal. | ||
// | ||
// @Triggers when a Discord user submits a modal. | ||
// | ||
// @Plugin dDiscordBot | ||
// | ||
// @Group Discord | ||
// | ||
// @Context | ||
// <context.bot> returns the relevant DiscordBotTag. | ||
// <context.channel> returns the DiscordChannelTag. | ||
// <context.group> returns the DiscordGroupTag. | ||
// <context.interaction> returns the DiscordInteractionTag. | ||
// <context.values> returns a MapTag of the values submitted by the user. | ||
// | ||
// --> | ||
|
||
public static DiscordModalSubmittedScriptEvent instance; | ||
|
||
public DiscordModalSubmittedScriptEvent() { | ||
instance = this; | ||
registerCouldMatcher("discord modal submitted"); | ||
registerSwitches("channel", "group", "name"); | ||
} | ||
|
||
public ModalInteractionEvent getEvent() { | ||
return (ModalInteractionEvent) event; | ||
} | ||
|
||
@Override | ||
public boolean matches(ScriptPath path) { | ||
if (!tryChannel(path, getEvent().getChannel())) { | ||
return false; | ||
} | ||
if (!tryGuild(path, getEvent().isFromGuild() ? getEvent().getGuild() : null)) { | ||
return false; | ||
} | ||
if (!runGenericSwitchCheck(path, "name", getEvent().getModalId())) { | ||
return false; | ||
} | ||
return super.matches(path); | ||
} | ||
|
||
@Override | ||
public ObjectTag getContext(String name) { | ||
switch (name) { | ||
case "channel": | ||
return new DiscordChannelTag(botID, getEvent().getChannel()); | ||
case "group": | ||
if (getEvent().isFromGuild()) { | ||
return new DiscordGroupTag(botID, getEvent().getGuild()); | ||
} | ||
break; | ||
case "interaction": | ||
return DiscordInteractionTag.getOrCreate(botID, getEvent().getInteraction()); | ||
case "values": | ||
Map<StringHolder, ObjectTag> map = getEvent().getValues().stream() | ||
.collect(Collectors.toMap(key -> new StringHolder(key.getId()), value -> new ElementTag(value.getAsString(), true))); | ||
return new MapTag(map); | ||
} | ||
return super.getContext(name); | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "DiscordModalSubmitted"; | ||
} | ||
} |
Oops, something went wrong.