Refactor modal usage and error handling in views

Replaced custom Modal class with BaseModal in embed_builder.py for consistency and maintainability. Updated modal instantiation to use custom_id and improved value handling. Removed redundant on_error methods from help.py, pagination.py, and search.py, and delegated error handling to superclass in controller.py for cleaner error management.
This commit is contained in:
Choco
2025-10-06 15:56:30 +08:00
parent 7f6135801d
commit b503385542
5 changed files with 166 additions and 174 deletions

View File

@@ -484,10 +484,6 @@ class InteractiveController(discord.ui.View):
async def on_error(self, interaction: discord.Interaction, error: Exception, item: discord.ui.Item) -> None:
if isinstance(error, ButtonOnCooldown):
sec = int(error.retry_after)
await interaction.response.send_message(f"You're on cooldown for {sec} second{'' if sec == 1 else 's'}!", ephemeral=True)
return await interaction.response.send_message(f"You're on cooldown for {sec} second{'' if sec == 1 else 's'}!", ephemeral=True)
elif isinstance(error, Exception):
traceback.print_exception(error)
await interaction.response.send_message(error)
return
super().on_error(interaction, error, item)

View File

@@ -24,26 +24,12 @@ SOFTWARE.
import discord
import copy
from typing import List
from discord.ext import commands
from .utils import BaseModal
from ..mongodb import MongoDBHandler
from ..placeholders import PlayerPlaceholder
class Modal(discord.ui.Modal):
def __init__(self, items: List[discord.ui.Item], *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
for item in items:
self.add_item(item)
self.values: dict = {}
async def on_submit(self, interaction: discord.Interaction) -> None:
await interaction.response.defer()
for children in self.children:
self.values[children.label.lower()] = children.value
self.stop()
class Dropdown(discord.ui.Select):
def __init__(self):
@@ -90,42 +76,47 @@ class EmbedBuilderView(discord.ui.View):
@discord.ui.button(label="Edit Content", style=discord.ButtonStyle.blurple)
async def edit_content(self, interaction: discord.Interaction, button: discord.ui.Button):
data = self.data.get(self.embed_type, {})
items = [
discord.ui.TextInput(
label="Title",
placeholder="The title of the embed",
style=discord.TextStyle.paragraph,
max_length=1000,
default=data.get("title", {}).get("name"),
required=False
),
discord.ui.TextInput(
label="Url",
placeholder="The url of the title",
style=discord.TextStyle.short,
max_length=100,
default=data.get("title", {}).get("url"),
required=False
),
discord.ui.TextInput(
label="Color",
placeholder="The color of the embed",
style=discord.TextStyle.short,
max_length=100,
default=data.get("color"),
required=False
),
discord.ui.TextInput(
label="Description",
placeholder="The description of the title",
style=discord.TextStyle.paragraph,
max_length=200,
default=data.get("description"),
required=False
)
]
modal = Modal(items, title="Edit Content")
modal = BaseModal(
title="Edit Content",
custom_id="edit_content",
items=[
discord.ui.TextInput(
label="Title",
placeholder="The title of the embed",
style=discord.TextStyle.paragraph,
custom_id="title",
max_length=1000,
default=data.get("title", {}).get("name"),
required=False
),
discord.ui.TextInput(
label="Url",
placeholder="The url of the title",
style=discord.TextStyle.short,
custom_id="url",
max_length=100,
default=data.get("title", {}).get("url"),
required=False
),
discord.ui.TextInput(
label="Color",
placeholder="The color of the embed",
style=discord.TextStyle.short,
custom_id="color",
max_length=100,
default=data.get("color"),
required=False
),
discord.ui.TextInput(
label="Description",
placeholder="The description of the title",
style=discord.TextStyle.paragraph,
custom_id="description",
max_length=200,
default=data.get("description"),
required=False
)
])
await interaction.response.send_modal(modal)
await modal.wait()
@@ -142,112 +133,120 @@ class EmbedBuilderView(discord.ui.View):
except:
pass
return await interaction.edit_original_response(embed=self.build_embed())
return await self.response.edit(embed=self.build_embed())
@discord.ui.button(label="Edit Author",)
async def edit_author(self, interaction: discord.Interaction, button: discord.ui.Button):
data = self.data.get(self.embed_type, {})
items = [
discord.ui.TextInput(
label="Name",
placeholder="The name of the author",
style=discord.TextStyle.paragraph,
max_length=200,
default=data.get("author", {}).get("name"),
required=False
),
discord.ui.TextInput(
label="Url",
placeholder="The url of the author",
style=discord.TextStyle.short,
max_length=100,
default=data.get("author", {}).get("url"),
required=False
),
discord.ui.TextInput(
label="Icon Url",
placeholder="The icon url of the author",
style=discord.TextStyle.short,
max_length=100,
default=data.get("author", {}).get("icon_url"),
required=False
),
]
modal = Modal(items, title="Edit Author")
modal = BaseModal(
title="Edit Author",
custom_id="edit_author",
items=[
discord.ui.TextInput(
label="Name",
placeholder="The name of the author",
style=discord.TextStyle.paragraph,
custom_id="name",
max_length=200,
default=data.get("author", {}).get("name"),
required=False
),
discord.ui.TextInput(
label="Url",
placeholder="The url of the author",
style=discord.TextStyle.short,
custom_id="url",
max_length=100,
default=data.get("author", {}).get("url"),
required=False
),
discord.ui.TextInput(
label="Icon Url",
placeholder="The icon url of the author",
style=discord.TextStyle.short,
custom_id="icon_url",
max_length=100,
default=data.get("author", {}).get("icon_url"),
required=False
),
])
await interaction.response.send_modal(modal)
await modal.wait()
v = modal.values
if v['name'] != "":
if "author" not in data:
data["author"] = {}
data["author"]["name"] = v['name']
data["author"]["url"] = v['url']
data["author"]["icon_url"] = v['icon url']
data["author"]["icon_url"] = v['icon_url']
else:
del data["author"]
return await interaction.edit_original_response(embed=self.build_embed())
return await self.response.edit(embed=self.build_embed())
@discord.ui.button(label="Edit Image")
async def edit_image(self, interaction: discord.Interaction, button: discord.ui.Button):
data = self.data.get(self.embed_type, {})
items = [
discord.ui.TextInput(
label="Thumbnail",
placeholder="The url of the thumbnail",
style=discord.TextStyle.short,
max_length=200,
default=data.get("thumbnail"),
required=False
),
discord.ui.TextInput(
label="Image",
placeholder="The url of the image",
style=discord.TextStyle.short,
max_length=100,
default=data.get("image"),
required=False
)
]
modal = Modal(items, title="Edit Image")
modal = BaseModal(
title="Edit Image",
custom_id="edit_image",
items=[
discord.ui.TextInput(
label="Thumbnail",
placeholder="The url of the thumbnail",
style=discord.TextStyle.short,
custom_id="thumbnail",
max_length=200,
default=data.get("thumbnail"),
required=False
),
discord.ui.TextInput(
label="Image",
placeholder="The url of the image",
style=discord.TextStyle.short,
custom_id="image",
max_length=100,
default=data.get("image"),
required=False
)
])
await interaction.response.send_modal(modal)
await modal.wait()
v = modal.values
data["thumbnail"] = v['thumbnail']
data["image"] = v['image']
return await interaction.edit_original_response(embed=self.build_embed())
return await self.response.edit(embed=self.build_embed())
@discord.ui.button(label="Edit Footer")
async def edit_footer(self, interaction: discord.Interaction, button: discord.ui.Button):
data = self.data.get(self.embed_type, {})
items = [
discord.ui.TextInput(
label="Text",
placeholder="The text of the footer",
style=discord.TextStyle.paragraph,
max_length=200,
default=data.get("footer", {}).get("text"),
required=False
),
discord.ui.TextInput(
label="Icon Url",
placeholder="The url of the icon",
style=discord.TextStyle.short,
max_length=100,
default=data.get("footer", {}).get("icon_url"),
required=False
)
]
modal = Modal(items, title="Edit Footer")
modal = BaseModal(
title="Edit Footer",
custom_id="edit_footer",
items=[
discord.ui.TextInput(
label="Text",
placeholder="The text of the footer",
style=discord.TextStyle.paragraph,
custom_id="text",
max_length=200,
default=data.get("footer", {}).get("text"),
required=False
),
discord.ui.TextInput(
label="Icon Url",
placeholder="The url of the icon",
style=discord.TextStyle.short,
custom_id="icon_url",
max_length=100,
default=data.get("footer", {}).get("icon_url"),
required=False
)
])
await interaction.response.send_modal(modal)
await modal.wait()
@@ -256,40 +255,44 @@ class EmbedBuilderView(discord.ui.View):
data["footer"] = {}
data["footer"]["text"] = v['text']
data["footer"]["icon_url"] = v['icon url']
data["footer"]["icon_url"] = v['icon_url']
return await interaction.edit_original_response(embed=self.build_embed())
return await self.response.edit(embed=self.build_embed())
@discord.ui.button(label="Add Field", style=discord.ButtonStyle.green, row=1)
async def add_field(self, interaction: discord.Interaction, button: discord.ui.Button):
data = self.data.get(self.embed_type)
items = [
discord.ui.TextInput(
label="Name",
placeholder="The name of the field",
style=discord.TextStyle.paragraph,
max_length=256
),
discord.ui.TextInput(
label="Value",
placeholder="The value of the field",
style=discord.TextStyle.long,
max_length=1024
),
discord.ui.TextInput(
label="Inline",
placeholder="The inline of the field, e.g. True or False",
style=discord.TextStyle.short
)
]
if "fields" not in data:
data["fields"] = []
if len(data["fields"]) >= 25:
return await interaction.response.send_message("You have already reached the maximum of fields!", ephemeral=True)
modal = Modal(items, title="Add Field")
modal = BaseModal(
title="Add Field",
custom_id="add_field",
items=[
discord.ui.TextInput(
label="Name",
placeholder="The name of the field",
style=discord.TextStyle.paragraph,
custom_id="name",
max_length=256
),
discord.ui.TextInput(
label="Value",
placeholder="The value of the field",
style=discord.TextStyle.long,
custom_id="value",
max_length=1024
),
discord.ui.TextInput(
label="Inline",
placeholder="The inline of the field, e.g. True or False",
style=discord.TextStyle.short,
custom_id="inline",
)
])
await interaction.response.send_modal(modal)
await modal.wait()
@@ -300,18 +303,10 @@ class EmbedBuilderView(discord.ui.View):
"inline": True if v["inline"].lower() == "true" else False
})
return await interaction.edit_original_response(embed=self.build_embed())
return await self.response.edit(embed=self.build_embed())
@discord.ui.button(label="Remove Field", style=discord.ButtonStyle.red, row=1)
async def remove_field(self, interaction: discord.Interaction, button: discord.ui.Button):
items = [
discord.ui.TextInput(
label="Index",
placeholder="The number of fields to remove, e.g. 1",
style=discord.TextStyle.short
)
]
data = self.data.get(self.embed_type)
if "fields" not in data:
data["fields"] = []
@@ -319,7 +314,17 @@ class EmbedBuilderView(discord.ui.View):
if len(data["fields"]) == 0:
return await interaction.response.send_message("There are no fields to remove!", ephemeral=True)
modal = Modal(items, title="Remove Field")
modal = BaseModal(
title="Remove Field",
custom_id="remove_field",
items = [
discord.ui.TextInput(
label="Index",
placeholder="The number of fields to remove, e.g. 1",
style=discord.TextStyle.short,
custom_id="index",
)
])
await interaction.response.send_modal(modal)
await modal.wait()
@@ -328,7 +333,7 @@ class EmbedBuilderView(discord.ui.View):
except:
return await interaction.followup.send("Can't found the field", ephemeral=True)
return await interaction.edit_original_response(embed=self.build_embed())
return await self.response.edit(embed=self.build_embed())
@discord.ui.button(label="Apply", style=discord.ButtonStyle.green, row=1)
async def apply(self, interaction: discord.Interaction, button: discord.ui.Button):

View File

@@ -61,9 +61,6 @@ class HelpView(discord.ui.View):
self.add_item(discord.ui.Button(label='Github', emoji=':github:1098265017268322406', url='https://github.com/ChocoMeow/Vocard'))
self.add_item(discord.ui.Button(label='Donate', emoji=':patreon:913397909024800878', url='https://www.patreon.com/Vocard'))
self.add_item(HelpDropdown(self.categories))
async def on_error(self, error, item, interaction) -> None:
return
async def on_timeout(self) -> None:
for child in self.children:

View File

@@ -73,9 +73,6 @@ class PaginationView(discord.ui.View):
child.disabled = state.get("disabled", False)
child.label = state.get("label")
async def on_error(self, error: Exception, item: discord.ui.Item, interaction: discord.Interaction) -> None:
return
async def update_message(self, interaction: discord.Interaction) -> None:
"""Update the view and edit the message."""

View File

@@ -54,9 +54,6 @@ class SearchView(discord.ui.View):
self.values: list[str] = None
self.add_item(SearchDropdown(tracks, texts))
async def on_error(self, error, item, interaction):
return
async def on_timeout(self):
for child in self.children:
child.disabled = True