diff --git a/didier/cogs/discord.py b/didier/cogs/discord.py index 23c7c35..be6fa90 100644 --- a/didier/cogs/discord.py +++ b/didier/cogs/discord.py @@ -8,6 +8,9 @@ from database.crud import birthdays, bookmarks from database.exceptions import DuplicateInsertException, ForbiddenNameException from didier import Didier from didier.exceptions import expect +from didier.menus.bookmarks import BookmarkSource +from didier.menus.common import Menu +from didier.utils.discord.assets import get_author_avatar from didier.utils.types.datetime import str_to_date from didier.utils.types.string import leading from didier.views.modals import CreateBookmark @@ -107,6 +110,19 @@ class Discord(commands.Cog): @bookmark.command(name="Search", aliases=["List", "Ls"]) async def bookmark_search(self, ctx: commands.Context, *, query: Optional[str] = None): """Search through the list of bookmarks""" + async with self.client.postgres_session as session: + results = await bookmarks.get_bookmarks(session, ctx.author.id, query=query) + + if not results: + embed = discord.Embed(title="Bookmarks", colour=discord.Colour.red()) + avatar_url = get_author_avatar(ctx).url + embed.set_author(name=ctx.author.display_name, icon_url=avatar_url) + embed.description = "You haven't created any bookmarks yet." + return await ctx.reply(embed=embed, mention_author=False) + + source = BookmarkSource(ctx, results) + menu = Menu(source) + await menu.start(ctx) async def _bookmark_ctx(self, interaction: discord.Interaction, message: discord.Message): """Create a bookmark out of this message""" diff --git a/didier/utils/discord/menus/__init__.py b/didier/menus/__init__.py similarity index 100% rename from didier/utils/discord/menus/__init__.py rename to didier/menus/__init__.py diff --git a/didier/menus/bookmarks.py b/didier/menus/bookmarks.py new file mode 100644 index 0000000..101cd6e --- /dev/null +++ b/didier/menus/bookmarks.py @@ -0,0 +1,29 @@ +import discord +from discord.ext import commands +from overrides import overrides + +from database.schemas import Bookmark +from didier.menus.common import PageSource + +__all__ = ["BookmarkSource"] + +from didier.utils.discord.assets import get_author_avatar + + +class BookmarkSource(PageSource[Bookmark]): + """PageSource for the Bookmark commands""" + + @overrides + def create_embeds(self, ctx: commands.Context): + for page in range(self.page_count): + embed = discord.Embed(title="Bookmarks", colour=discord.Colour.blue()) + avatar_url = get_author_avatar(ctx).url + embed.set_author(name=ctx.author.display_name, icon_url=avatar_url) + + description = "" + + for bookmark in self.dataset[page : page + self.per_page]: + description += f"`#{bookmark.bookmark_id}`: [{bookmark.label}]({bookmark.jump_url})\n" + + embed.description = description.strip() + self.embeds.append(embed) diff --git a/didier/utils/discord/menus/common.py b/didier/menus/common.py similarity index 94% rename from didier/utils/discord/menus/common.py rename to didier/menus/common.py index 983723d..763d976 100644 --- a/didier/utils/discord/menus/common.py +++ b/didier/menus/common.py @@ -21,11 +21,11 @@ class PageSource(ABC, Generic[T]): page_count: int per_page: int - def __init__(self, dataset: list[T], *, per_page: int = 10): + def __init__(self, ctx: commands.Context, dataset: list[T], *, per_page: int = 10): self.dataset = dataset self.per_page = per_page self.page_count = self._get_page_count() - self.create_embeds() + self.create_embeds(ctx) self._add_embed_page_footers() def _get_page_count(self) -> int: @@ -47,7 +47,7 @@ class PageSource(ABC, Generic[T]): embed.set_footer(text=f"{i + 1}/{self.page_count}") @abstractmethod - def create_embeds(self): + def create_embeds(self, ctx: commands.Context): """Method that builds the list of embeds from the input data""" raise NotImplementedError @@ -68,6 +68,10 @@ class Menu(discord.ui.View): def do_button_disabling(self): """Disable buttons depending on the current page""" + # No items to disable + if not self.children: + return + first_page = cast(discord.ui.Button, self.children[0]) first_page.disabled = self.current_page == 0 @@ -87,8 +91,6 @@ class Menu(discord.ui.View): """ self.do_button_disabling() - print(self.current_page, self.source[self.current_page].footer.text) - # Send the initial message if there is none yet, else edit the existing one if self.message is None: self.message = await self.ctx.reply( @@ -100,6 +102,10 @@ class Menu(discord.ui.View): async def start(self, ctx: commands.Context): """Send the initial message with this menu""" self.ctx = ctx + + if len(self.source) == 1: + self.clear_items() + await self.display_current_state() async def stop_view(self, interaction: Optional[discord.Interaction] = None): diff --git a/didier/utils/discord/assets.py b/didier/utils/discord/assets.py new file mode 100644 index 0000000..90473a6 --- /dev/null +++ b/didier/utils/discord/assets.py @@ -0,0 +1,12 @@ +from typing import Union + +import discord +from discord.ext import commands + +__all__ = ["get_author_avatar"] + + +def get_author_avatar(ctx: Union[commands.Context, discord.Interaction]) -> discord.Asset: + """Get a user's avatar asset""" + author = ctx.author if isinstance(ctx, commands.Context) else ctx.user + return author.avatar or author.default_avatar