188 lines
6.7 KiB
Python
188 lines
6.7 KiB
Python
"""
|
|
Discord confirmation and interaction UI components.
|
|
|
|
Contains Question, Confirm, and ButtonOptions classes for user interactions.
|
|
"""
|
|
import asyncio
|
|
import discord
|
|
from typing import Literal
|
|
|
|
|
|
class Question:
|
|
def __init__(self, bot, channel, prompt, qtype, timeout, embed=None):
|
|
"""
|
|
Version 0.4
|
|
|
|
:param bot, discord bot object
|
|
:param channel, discord Channel object
|
|
:param prompt, string, prompt message to post
|
|
:param qtype, string, 'yesno', 'int', 'float', 'text', or 'url'
|
|
:param timeout, float, time to wait for a response
|
|
"""
|
|
if not prompt and not embed:
|
|
raise TypeError('prompt and embed may not both be None')
|
|
|
|
self.bot = bot
|
|
self.channel = channel
|
|
self.prompt = prompt
|
|
self.qtype = qtype
|
|
self.timeout = timeout
|
|
self.embed = embed
|
|
|
|
async def ask(self, responders: list):
|
|
"""
|
|
Params: responder, list of discord User objects
|
|
Returns: True/False if confirm question; full response otherwise
|
|
"""
|
|
yes = ['yes', 'y', 'ye', 'yee', 'yerp', 'yep', 'yeet', 'yip', 'yup', 'yarp', 'si']
|
|
no = ['no', 'n', 'nope', 'nah', 'nyet', 'nein']
|
|
|
|
if type(responders) is not list:
|
|
raise TypeError('Responders must be a list of Members')
|
|
|
|
def yesno(mes):
|
|
return mes.channel == self.channel and mes.author in responders and mes.content.lower() in yes + no
|
|
|
|
def text(mes):
|
|
return mes.channel == self.channel and mes.author in responders
|
|
|
|
await self.channel.send(content=self.prompt, embed=self.embed)
|
|
|
|
try:
|
|
resp = await self.bot.wait_for(
|
|
'message',
|
|
timeout=self.timeout,
|
|
check=yesno if self.qtype == 'yesno' else text
|
|
)
|
|
except asyncio.TimeoutError:
|
|
return None
|
|
except Exception as e:
|
|
await self.channel.send(f'Yuck, do you know what this means?\n\n{e}')
|
|
return None
|
|
|
|
if self.qtype == 'yesno':
|
|
if resp.content.lower() in yes:
|
|
return True
|
|
else:
|
|
return False
|
|
elif self.qtype == 'int':
|
|
return int(resp.content)
|
|
elif self.qtype == 'float':
|
|
return float(resp.content)
|
|
elif self.qtype == 'url':
|
|
if resp.content[:7] == 'http://' or resp.content[:8] == 'https://':
|
|
return resp.content
|
|
else:
|
|
return False
|
|
else:
|
|
return resp.content
|
|
|
|
|
|
class Confirm(discord.ui.View):
|
|
def __init__(self, responders: list, timeout: float = 300.0, label_type: Literal['yes', 'confirm'] = None):
|
|
super().__init__(timeout=timeout)
|
|
if not isinstance(responders, list):
|
|
raise TypeError('responders must be a list')
|
|
self.value = None
|
|
self.responders = responders
|
|
if label_type == 'yes':
|
|
self.confirm.label = 'Yes'
|
|
self.cancel.label = 'No'
|
|
|
|
# When the confirm button is pressed, set the inner value to `True` and
|
|
# stop the View from listening to more input.
|
|
# We also send the user an ephemeral message that we're confirming their choice.
|
|
@discord.ui.button(label='Confirm', style=discord.ButtonStyle.green)
|
|
async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|
if interaction.user not in self.responders:
|
|
return
|
|
|
|
self.value = True
|
|
self.clear_items()
|
|
self.stop()
|
|
|
|
# This one is similar to the confirmation button except sets the inner value to `False`
|
|
@discord.ui.button(label='Cancel', style=discord.ButtonStyle.grey)
|
|
async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|
if interaction.user not in self.responders:
|
|
return
|
|
|
|
self.value = False
|
|
self.clear_items()
|
|
self.stop()
|
|
|
|
|
|
class ButtonOptions(discord.ui.View):
|
|
def __init__(self, responders: list, timeout: float = 300.0, labels=None):
|
|
super().__init__(timeout=timeout)
|
|
if not isinstance(responders, list):
|
|
raise TypeError('responders must be a list')
|
|
self.value = None
|
|
self.responders = responders
|
|
self.options = labels
|
|
for count, x in enumerate(labels):
|
|
if count == 0:
|
|
self.option1.label = x
|
|
if x is None or x.lower() == 'na' or x == 'N/A':
|
|
self.remove_item(self.option1)
|
|
if count == 1:
|
|
self.option2.label = x
|
|
if x is None or x.lower() == 'na' or x == 'N/A':
|
|
self.remove_item(self.option2)
|
|
if count == 2:
|
|
self.option3.label = x
|
|
if x is None or x.lower() == 'na' or x == 'N/A':
|
|
self.remove_item(self.option3)
|
|
if count == 3:
|
|
self.option4.label = x
|
|
if x is None or x.lower() == 'na' or x == 'N/A':
|
|
self.remove_item(self.option4)
|
|
if count == 4:
|
|
self.option5.label = x
|
|
if x is None or x.lower() == 'na' or x == 'N/A':
|
|
self.remove_item(self.option5)
|
|
|
|
@discord.ui.button(label='Option 1', style=discord.ButtonStyle.primary)
|
|
async def option1(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|
if interaction.user not in self.responders:
|
|
return
|
|
|
|
self.value = self.options[0]
|
|
self.clear_items()
|
|
self.stop()
|
|
|
|
@discord.ui.button(label='Option 2', style=discord.ButtonStyle.primary)
|
|
async def option2(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|
if interaction.user not in self.responders:
|
|
return
|
|
|
|
self.value = self.options[1]
|
|
self.clear_items()
|
|
self.stop()
|
|
|
|
@discord.ui.button(label='Option 3', style=discord.ButtonStyle.primary)
|
|
async def option3(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|
if interaction.user not in self.responders:
|
|
return
|
|
|
|
self.value = self.options[2]
|
|
self.clear_items()
|
|
self.stop()
|
|
|
|
@discord.ui.button(label='Option 4', style=discord.ButtonStyle.primary)
|
|
async def option4(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|
if interaction.user not in self.responders:
|
|
return
|
|
|
|
self.value = self.options[3]
|
|
self.clear_items()
|
|
self.stop()
|
|
|
|
@discord.ui.button(label='Option 5', style=discord.ButtonStyle.primary)
|
|
async def option5(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|
if interaction.user not in self.responders:
|
|
return
|
|
|
|
self.value = self.options[4]
|
|
self.clear_items()
|
|
self.stop() |