|
# Importing everything we need... |
|
# https://gist.github.com/Soheab/f46fee27498aad4a8962d59b6f0415c6 |
|
|
|
from __future__ import annotations |
|
from typing import Any, Callable, Coroutine, Optional, Union, TYPE_CHECKING |
|
|
|
|
|
from discord import Interaction, TextStyle |
|
from discord.ui import Modal, TextInput |
|
from discord.utils import maybe_coroutine |
|
|
|
if TYPE_CHECKING: |
|
from typing_extensions import Self |
|
|
|
|
|
# Defining a class named SimpleModalWaitFor and subclassing Modal |
|
class SimpleModalWaitFor(Modal): |
|
# Overriding the __init__ method. |
|
# This way we can set the title of the modal more easily |
|
# to a custom value or "Waiting For Input" by default. |
|
# Same goes for the timeout, it defaults to no timeout |
|
# but we are setting it to 30 seconds. |
|
|
|
# We are also adding an Optional check kwarg to the constructor |
|
# which will be used to easily define a check for the modal |
|
# that will be called in Modal.interaction_check. |
|
# It's called before on_submit by the library. |
|
# The check will take a function with two parameters, |
|
# the class and interaction and optional async. |
|
|
|
# We also added 6 keyword arguments to make it easier to set the text input field's values. |
|
|
|
# - input_label: The label of the text input field. Defaults to "Input text". |
|
# This is the label of the text input field, appears above the text input. |
|
|
|
# - input_placeholder: The placeholder of the text input field. Defaults to nothing. |
|
# This is the text that appears in the text input field when it is empty. |
|
|
|
# - input_default: The default value of the text input field. Defaults to nothing. |
|
# This is the value that will be set to the text input field when the modal is opened. |
|
# the user can change it ofc. |
|
|
|
# - input_max_lengte: The max length of the text input field. Defaults to 100. |
|
# This limits how many characters the user can enter, discord will error if they try to enter more than this. |
|
|
|
# - input_min_length: The min length of the text input field. Defaults to 5. |
|
# This is how many characters the user must enter before they can submit the modal. |
|
|
|
# - input_style: The style of the text input field, defaulting to TextStyle.short |
|
# TextStyle.short = small text bar |
|
# TextStyle.long = big text bar |
|
def __init__( |
|
self, |
|
title: str = "Waiting For Input", |
|
*, |
|
# Adding the check attribute to the modal |
|
# and typing as a optional async function that takes two parameters, the class and interaction |
|
# and returns a boolean. |
|
check: Optional[Callable[[Self, Interaction], Union[Coroutine[Any, Any, bool], bool]]] = None, |
|
# timeout is an original kwarg that we are adding because we want to set a default value. |
|
# and want to able set it from the constructor. |
|
timeout: float = 30.0, |
|
# Adding the text input modifiers. |
|
input_label: str = "Input text", |
|
input_max_length: int = 100, |
|
input_min_length: int = 5, |
|
input_style: TextStyle = TextStyle.short, |
|
input_placeholder: Optional[str] = None, |
|
input_default: Optional[str] = None, |
|
): |
|
# Passing our custom title or "Waiting For Input" if not provided and the timeout. |
|
# custom_id is a unique identifier for discord, nothing important (it's not required). |
|
super().__init__(title=title, timeout=timeout, custom_id="wait_for_modal") |
|
# Set an attribute for the check function. |
|
# So we can access it in our interaction_check method. |
|
self._check: Optional[Callable[[Self, Interaction], Union[Coroutine[Any, Any, bool], bool]]] = check |
|
|
|
# Set an attribute on the class to store the value of the text input field, |
|
# we will set this to None by default |
|
# because we don't know what the user will enter yet. |
|
# We will set this to a string value when the user submits the modal in on_submit. |
|
self.value: Optional[str] = None |
|
|
|
# Set an attribute on the class to store the interaction from on_submit. |
|
# This is so we can send a message to the user submitted the modal. |
|
self.interaction: Optional[Interaction] = None |
|
|
|
# Define our input field. |
|
self.answer = TextInput( |
|
label=input_label, |
|
placeholder=input_placeholder, |
|
max_length=input_max_length, |
|
min_length=input_min_length, |
|
style=input_style, |
|
default=input_default, |
|
# custom_id is a unique identifier for discord, nothing important (it's not required). |
|
# we are using the modal's custom_id as a prefix and adding "_input_field" to it. |
|
custom_id=self.custom_id + "_input_field", |
|
) |
|
# Add the input field to the modal. |
|
self.add_item(self.answer) |
|
|
|
# Define our interaction_check method. |
|
# This method will be called when the modal is submitted. |
|
async def interaction_check(self, interaction: Interaction) -> bool: |
|
# If we have a check function, call it. |
|
if self._check: |
|
# Since the check can be optional async |
|
# we need to use maybe_coroutine to make await it if it's a coroutine |
|
# else just call it as a normal function. |
|
allow = await maybe_coroutine(self._check, self, interaction) |
|
return allow |
|
|
|
# If we don't have a check function, return True (default). |
|
return True |
|
|
|
# Define our on_submit method. |
|
# This is where we will get the value of the text input field. |
|
async def on_submit(self, interaction: Interaction) -> None: |
|
# Set our value attrbute to the value of the text input field. |
|
self.value = self.answer.value |
|
# Set our interaction attribute to the interaction. |
|
self.interaction = interaction |
|
# Stop the modal. |
|
# This will allow us to get the value of the text input field |
|
# in our command. |
|
self.stop() |
man fuck this shit, imma make nothing instead