Skip to content

Instantly share code, notes, and snippets.

@FrostiiWeeb
Last active March 4, 2022 20:43
Show Gist options
  • Save FrostiiWeeb/24fc85964609dfb37f9953cd91d17932 to your computer and use it in GitHub Desktop.
Save FrostiiWeeb/24fc85964609dfb37f9953cd91d17932 to your computer and use it in GitHub Desktop.
A rough example of discord.py modals. The code was improved from the original gist by Jeyy.
from modal import Modal, Style
from discord.ext import commands
import discord
class View(discord.ui.View):
def __init__(self, context: commands.Context):
self.context = context
super().__init__(timeout=180)
@discord.ui.button(label="test")
async def btn(self, button: discord.ui.Button, interaction: discord.Interaction):
modal = Modal(self.context.bot, "Testing Form")
modal.add_input(Style.singleline, "example")
await modal.send(interaction)
res = await modal.get_value()
return await interaction.response.send_message((res.responses[0]).value)
# in a command or something
await ctx.send("An example of modals.", view=View(ctx))
import asyncio
import uuid
import json
from enum import Enum
from typing import *
import discord
from discord.ext import commands
from discord.http import Route
R = TypeVar("R", bound="Response")
V = TypeVar("V", bound="InputValue")
class Response(Generic[R]):
def __init__(self, interaction: discord.Interaction, responses: List[V]) -> None:
self.interaction = interaction
self.responses = responses
class InputValue:
def __init__(self, base, value: str) -> None:
self.input = base
self.value = value
class Style:
singleline = 1
multiline = 2
class Input:
def __init__(self, payload: dict) -> None:
self.type = payload["type"]
self.custom_id = str(uuid.uuid4())
self.style = payload["style"]
self.label = payload["label"]
self.min_length = payload.get("min_length")
self.max_length = payload.get("max_length")
self.required = payload.get("required")
self.value = payload.get("value")
self.placeholder = payload.get("placeholder")
class Modal:
def __init__(self, bot: commands.Bot, title: str) -> None:
self.title = title
self.bot = bot
self.input_fields = []
self.custom_id = str(uuid.uuid4())
self.data = {"type": 9, "title": title, "custom_id": self.custom_id, "components": []}
self.payload = []
self.responded = False
def add_input(
self,
type: Style,
label: str,
min_length=None,
max_length=None,
value: str = None,
placeholder: str = None,
required=False,
):
component = {
"type": 4,
"custom_id": str(uuid.uuid4()),
"style": type,
"label": label,
"required": str(required),
}
if min_length:
component["min_length"] = min_length
if max_length:
component["max_length"] = max_length
if value:
component["value"] = value
if placeholder:
component["placeholder"] = placeholder
self.data["components"].append({"type": 1, "components": [component]})
self.input_fields.append(Input(component))
async def send(self, interaction: discord.Interaction):
self.responded = True
route = Route("POST", f"/interactions/{interaction.id}/{interaction.token}/callback")
await self.bot.http.request(route, headers={"Content-Type": "application/json"}, json=self.data)
@property
def sent(self):
return self.responded
async def get_value(self, timeout: int = 180):
def check(interaction: discord.Interaction):
return interaction.data.get("custom_id") == self.custom_id
try:
msg: str = await self.bot.wait_for("socket_raw_receive", check=check, timeout=timeout)
except asyncio.TimeoutError:
return None, []
msg: Dict[str, Any] = json.loads(msg)
int = discord.Interaction(state=(self.bot._connection), data=msg)
if msg.get("t") == "MODAL_SUMBIT":
data = msg.get("data")
components = data["components"]
result = []
for component in components:
for field in self.input_fields:
if component["components"][0]["custom_id"] == field.custom_id:
field.value = component["components"][0]["value"]
result.append(InputValue(field, field.value))
return Response(int, result)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment