Skip to content

Instantly share code, notes, and snippets.

@Soheab
Last active July 15, 2024 05:33
Show Gist options
  • Save Soheab/cfd769870b7b6eaf00a7aebf5293a622 to your computer and use it in GitHub Desktop.
Save Soheab/cfd769870b7b6eaf00a7aebf5293a622 to your computer and use it in GitHub Desktop.
from typing import Any, TYPE_CHECKING, List
import asyncio
from discord import ui, Interaction
class GlobalView(ui.View):
def __init__(
self,
author_id: int,
*,
absolute_timeout: bool = False,
timeout: float = 180.0
) -> None:
self.author_id: int = author_id
# call the original __init__
# original handles the items and timeout
# so we don't need to do that ourselves.
# we are setting the timeout to None if absolute_timeout is True
# since we handle the timeout in that case.
super().__init__(timeout=timeout if not absolute_timeout else None)
# author_id is a custom thing
# so we need to handle that, which we did above.
# absolute_timeout is also a custom thing.
# it's for stopping the view exactly at the timeout you set
# since the timeout resets on interaction.
# we handle that here.
# first check if there is even a timeout
# if not, we do nothing.
if timeout is not None and absolute_timeout:
loop = asyncio.get_event_loop()
# here we tell asyncio call to call View.stop and on_timeout after <timeout>
def call_later_callback():
# stop the view
self.stop()
# call on_timeout
loop.create_task(self.on_timeout())
loop.call_later(timeout, call_later_callback)
# method that disables all items
# you still need to edit the message.
def disable_all_items(self):
for item in self.children:
if hasattr(item, "disabled"):
item.disabled = True
# global view timeout handler
async def on_timeout(self):
# defining a list of label: custom_id
# so we can know which items timed out
formatted_items: List[str] = [
f"{item.label}: {getattr(item, 'custom_id', None)}"
for item in self.children
]
print(
f "A timeout occurred in the following view: {self.__class__!r}\n",
f"Timed out with items: {', '.join(formatted_items)}"
)
# global view error handler
async def on_error(
self,
interaction: Interaction,
error: Exception,
item: ui.Item
) -> Any:
print(
f"An error occurred in the following view: {self.__class__!r}\n",
f"With item: {item!r}"
)
# do original implementation
await super().on_error(interaction, error, item)
# global interaction (view) check
async def interaction_check(self, interaction: Interaction) -> bool:
# send a message if the id of the interaction user
# and view owner don't match
if interaction.user.id != self.author_id:
await interaction.response.send_message("This is not your view!")
# return False so that the lib doesn't invoke the item callback.
return False
# else return True, we handled it above.
return True

How do I use that class?

Simple! Copy the contents from above and paste it in a file like /utils/views/base.py and import it whenever you create a view.

Something like the following:

/base.py:

# copypasted content

/something.py

from base import GlobalView

class Something(GlobalView):
    ...

# sending
v = Something(123) # 123 = user id
await ...send(view=v)

Features

  • Built-in user id check
  • Error handler
  • Timeout handler
  • disable_all_items method
  • Absolute view timeout
@tookender
Copy link

thank you soheab

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment