didier/data/menus/paginated_leaderboard.py

128 lines
3.8 KiB
Python
Raw Normal View History

2022-02-05 19:36:25 +01:00
from typing import Callable
import discord
from discord import ApplicationContext
from discord.ext import menus, pages
from dataclasses import dataclass
from discord.ext.commands import Context
from functions.utils import get_display_name
@dataclass
class Leaderboard:
ctx: Context
title: str
data: list
highlight: str = None
format_f: Callable = None
per_page: int = 10
colour: discord.Colour = discord.Colour.blue()
fetch_names: bool = False
def __post_init__(self):
if self.format_f is None:
self.format_f = self._format
def _should_highlight(self, data) -> bool:
"""Check if an entry should be highlighted"""
if self.fetch_names:
return data == self.ctx.author.id
return data == self.highlight
def _format(self, index: int, data: tuple) -> str:
name = data[0]
if self.fetch_names:
name = get_display_name(self.ctx, int(data[0]))
s = f"{index + 1}: {name} ({data[1]})"
return s
def _get_page_count(self) -> int:
"""Get the amount of pages required to represent this data"""
count = len(self.data) // self.per_page
if len(self.data) % self.per_page != 0:
count += 1
return count
def _create_embed(self, description: str) -> discord.Embed:
embed = discord.Embed(colour=self.colour)
embed.set_author(name=self.title)
embed.description = description
return embed
def create_pages(self) -> list[discord.Embed]:
# Amount of entries added to this page
added = 0
page_list = []
description = ""
for i, v in enumerate(self.data):
s = self.format_f(i, v)
if self._should_highlight(v[0]):
s = f"**{s}**"
description += s + "\n"
added += 1
# Page full, create an embed & change counters
if added == self.per_page:
embed = self._create_embed(description)
description = ""
added = 0
page_list.append(embed)
# Add final embed
if added != 0:
embed = self._create_embed(description)
page_list.append(embed)
return page_list
def create_paginator(self) -> pages.Paginator:
return pages.Paginator(pages=self.create_pages(), show_disabled=False, disable_on_timeout=True, timeout=30)
async def respond(self, ctx: ApplicationContext, **kwargs) -> discord.Message:
paginator = self.create_paginator()
return await paginator.respond(ctx.interaction, **kwargs)
async def send(self, ctx: Context, **kwargs) -> discord.Message:
paginator = self.create_paginator()
return await paginator.send(ctx, **kwargs)
class Source(menus.ListPageSource):
def __init__(self, data, name, colour=discord.Colour.blue()):
super().__init__(data, per_page=10)
self.name = name
self.colour = colour
async def format_page(self, menu: menus.MenuPages, entries):
offset = menu.current_page * self.per_page
description = ""
for i, v in enumerate(entries, start=offset):
# Check if the person's name has to be highlighted
if v.startswith("**") and v.endswith("**"):
description += "**"
v = v[2:]
description += "{}: {}\n".format(i + 1, v)
embed = discord.Embed(colour=self.colour)
embed.set_author(name=self.name)
embed.description = description
embed.set_footer(text="{}/{}".format(menu.current_page + 1, self.get_max_pages()))
return embed
class Pages(menus.MenuPages):
def __init__(self, source, clear_reactions_after, timeout=30.0):
super().__init__(source, timeout=timeout, delete_message_after=True, clear_reactions_after=clear_reactions_after)