(interactions): Basic select menu support.
This commit is contained in:
@@ -4,41 +4,12 @@ import uuid
|
|||||||
from .enums import ButtonStyle, InteractionType
|
from .enums import ButtonStyle, InteractionType
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
Notes:
|
|
||||||
When interaction is sent, add message info
|
|
||||||
Add wait_for to Button and SelectMenu
|
|
||||||
wait_for_interaction for generic
|
|
||||||
listen=True for the listenables, register with a listener
|
|
||||||
Need a deregister then as well
|
|
||||||
|
|
||||||
send(..., components=[ActionRow(Button(...))])
|
|
||||||
|
|
||||||
Automatically ack interaction? DEFERRED_UPDATE_MESSAGE
|
|
||||||
|
|
||||||
async def Button.wait_for(timeout=None, ack=False)
|
|
||||||
Blocks until the button is pressed. Returns a ButtonPress (Interaction).
|
|
||||||
def MessageComponent.add_callback(timeout)
|
|
||||||
Adds an async callback function to the Component.
|
|
||||||
|
|
||||||
Construct the response independent of the original component.
|
|
||||||
Original component has a convenience wait_for that runs wait_for_interaction(custom_id=self.custom_id)...
|
|
||||||
The callback? Just add a wait_for
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class MessageComponent:
|
class MessageComponent:
|
||||||
_type = None
|
_type = None
|
||||||
|
|
||||||
def __init_(self, *args, **kwargs):
|
def __init_(self, *args, **kwargs):
|
||||||
self.message = None
|
self.message = None
|
||||||
|
|
||||||
def listen(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class ActionRow(MessageComponent):
|
class ActionRow(MessageComponent):
|
||||||
_type = 1
|
_type = 1
|
||||||
@@ -54,7 +25,37 @@ class ActionRow(MessageComponent):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class Button(MessageComponent):
|
class AwaitableComponent:
|
||||||
|
async def wait_for(self, timeout=None, check=None):
|
||||||
|
from meta import client
|
||||||
|
|
||||||
|
def _check(interaction):
|
||||||
|
valid = True
|
||||||
|
print(interaction.custom_id)
|
||||||
|
valid = valid and interaction.interaction_type == InteractionType.MESSAGE_COMPONENT
|
||||||
|
valid = valid and interaction.custom_id == self.custom_id
|
||||||
|
valid = valid and (check is None or check(interaction))
|
||||||
|
return valid
|
||||||
|
|
||||||
|
return await client.wait_for('interaction_create', timeout=timeout, check=_check)
|
||||||
|
|
||||||
|
def add_callback(self, timeout=None, repeat=True, pass_args=(), pass_kwargs={}):
|
||||||
|
def wrapper(func):
|
||||||
|
async def wrapped():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
button_press = await self.wait_for(timeout=timeout)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
break
|
||||||
|
asyncio.create_task(func(button_press, *pass_args, **pass_kwargs))
|
||||||
|
if not repeat:
|
||||||
|
break
|
||||||
|
future = asyncio.create_task(wrapped())
|
||||||
|
return future
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class Button(MessageComponent, AwaitableComponent):
|
||||||
_type = 2
|
_type = 2
|
||||||
|
|
||||||
def __init__(self, label, style=ButtonStyle.PRIMARY, custom_id=None, url=None, emoji=None, disabled=False):
|
def __init__(self, label, style=ButtonStyle.PRIMARY, custom_id=None, url=None, emoji=None, disabled=False):
|
||||||
@@ -63,7 +64,7 @@ class Button(MessageComponent):
|
|||||||
raise ValueError("Link buttons must have a url")
|
raise ValueError("Link buttons must have a url")
|
||||||
custom_id = None
|
custom_id = None
|
||||||
elif custom_id is None:
|
elif custom_id is None:
|
||||||
custom_id = uuid.uuid4()
|
custom_id = str(uuid.uuid4())
|
||||||
|
|
||||||
self.label = label
|
self.label = label
|
||||||
self.style = style
|
self.style = style
|
||||||
@@ -88,38 +89,52 @@ class Button(MessageComponent):
|
|||||||
data['emoji'] = self.emoji.to_dict()
|
data['emoji'] = self.emoji.to_dict()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def wait_for_press(self, timeout=None, check=None):
|
|
||||||
from meta import client
|
|
||||||
|
|
||||||
def _check(interaction):
|
class SelectOption:
|
||||||
valid = True
|
def __init__(self, label, value, description, emoji=None, default=False):
|
||||||
print(interaction.custom_id)
|
self.label = label
|
||||||
valid = valid and interaction.interaction_type == InteractionType.MESSAGE_COMPONENT
|
self.value = value
|
||||||
valid = valid and interaction.custom_id == self.custom_id
|
self.description = description
|
||||||
valid = valid and (check is None or check(interaction))
|
self.emoji = emoji
|
||||||
return valid
|
self.default = default
|
||||||
|
|
||||||
return await client.wait_for('interaction_create', timeout=timeout, check=_check)
|
def to_dict(self):
|
||||||
|
data = {
|
||||||
|
"label": self.label,
|
||||||
|
"value": self.value,
|
||||||
|
"description": self.description,
|
||||||
|
}
|
||||||
|
if self.emoji:
|
||||||
|
data['emoji'] = self.emoji.to_dict()
|
||||||
|
if self.default:
|
||||||
|
data['default'] = self.default
|
||||||
|
|
||||||
def on_press(self, timeout=None, repeat=True, pass_args=(), pass_kwargs={}):
|
return data
|
||||||
def wrapper(func):
|
|
||||||
async def wrapped():
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
button_press = await self.wait_for_press(timeout=timeout)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
break
|
|
||||||
asyncio.create_task(func(button_press, *pass_args, **pass_kwargs))
|
|
||||||
if not repeat:
|
|
||||||
break
|
|
||||||
future = asyncio.create_task(wrapped())
|
|
||||||
return future
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
class SelectMenu(MessageComponent):
|
class SelectMenu(MessageComponent, AwaitableComponent):
|
||||||
_type = 3
|
_type = 3
|
||||||
|
|
||||||
|
def __init__(self, *options, custom_id=None, placeholder=None, min_values=None, max_values=None, disabled=False):
|
||||||
|
self.options = options
|
||||||
|
self.custom_id = custom_id or str(uuid.uuid4())
|
||||||
|
self.placeholder = placeholder
|
||||||
|
self.min_values = min_values
|
||||||
|
self.max_values = max_values
|
||||||
|
self.disabled = disabled
|
||||||
|
|
||||||
# MessageComponent listener
|
def to_dict(self):
|
||||||
live_components = {}
|
data = {
|
||||||
|
"type": self._type,
|
||||||
|
'custom_id': self.custom_id,
|
||||||
|
'options': [option.to_dict() for option in self.options],
|
||||||
|
}
|
||||||
|
if self.placeholder:
|
||||||
|
data['placeholder'] = self.placeholder
|
||||||
|
if self.min_values:
|
||||||
|
data['min_values'] = self.min_values
|
||||||
|
if self.max_values:
|
||||||
|
data['max_values'] = self.max_values
|
||||||
|
if self.disabled:
|
||||||
|
data['disabled'] = self.disabled
|
||||||
|
return data
|
||||||
|
|||||||
@@ -43,10 +43,20 @@ class ButtonPress(ComponentInteraction):
|
|||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
|
||||||
|
class Selection(ComponentInteraction):
|
||||||
|
__slots__ = ('values',)
|
||||||
|
|
||||||
|
def _from_data(self, data):
|
||||||
|
super()._from_data(data)
|
||||||
|
self.values = data['data']['values']
|
||||||
|
|
||||||
|
|
||||||
def _component_interaction_factory(data):
|
def _component_interaction_factory(data):
|
||||||
component_type = data['data']['component_type']
|
component_type = data['data']['component_type']
|
||||||
|
|
||||||
if component_type == ComponentType.BUTTON:
|
if component_type == ComponentType.BUTTON:
|
||||||
return ButtonPress
|
return ButtonPress
|
||||||
|
elif component_type == ComponentType.SELECTMENU:
|
||||||
|
return Selection
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user