Skip to content

Commit

Permalink
feat: Improving the help menu (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
AustinH-adl authored Oct 22, 2024
1 parent f1b8b28 commit 3e56db8
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 26 deletions.
209 changes: 209 additions & 0 deletions src/commands/help_menu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import os

from discord import (
Object,
Embed,
ui,
Color,
app_commands,
SelectOption,
ButtonStyle,
Interaction,
)

GUILD_ID = int(os.environ["GUILD_ID"])


class HelpMenu(ui.View):
currentpage: int = 0
commands = []
maxpages: int

def __init__(self, client):
super().__init__()
self.value = None
self.commands = list(
client.tree.get_commands(guild=Object(GUILD_ID))
) # Gets commands on class creation

# Separate group commands and misc commands
self.group_commands = []
self.misc_commands = []
self.maxpages = 1
self.organise_commands()

def organise_commands(self):
"""Organise commands into groups and misc categories."""
for command in self.commands:
if isinstance(command, app_commands.Group):
self.group_commands.append(command)
self.maxpages += 1
else:
self.misc_commands.append(command)

def create_help_embed(self, page: int):
"""Create and return new embed for given page"""

# Adjust current page index based on boundaries
if page < 0:
self.currentpage = 0
elif page > self.maxpages:
self.currentpage = self.maxpages - 1
else:
self.currentpage = page

# Disable buttons in invalid states (using or does not work)
for item in self.children:
if isinstance(item, ui.Button):
if item.label == "Next":
item.disabled = self.currentpage >= self.maxpages
if item.label == "End":
item.disabled = self.currentpage >= self.maxpages
if item.label == "Back":
item.disabled = self.currentpage == 0
if item.label == "Start":
item.disabled = self.currentpage == 0

# Define embed
embed = Embed(
title="Invalid embed",
description="Something went wrong!",
color=Color.yellow(),
)

if (
self.currentpage == 0
): # Main help menu for displaying different groups with limited detail
embed = Embed(
title="__DuckBot__",
description="DuckBot is the CS Club's Discord bot, created by the CS Club Open Source Team.",
color=Color.yellow(),
)
# Adding group names
for command in self.group_commands:
embed.add_field(
name=f"{self.capfirst(command.name)}",
value=f"{command.description}",
inline=False,
)
# Misc command
embed.add_field(
name="__**Misc**__", value="Miscellaneous commands", inline=False
)
for command in self.misc_commands:
embed.add_field(
name=f"{self.capfirst(command.name)}",
value=f"{command.description}",
inline=False,
)

elif (
self.currentpage > 0 and self.currentpage < self.maxpages
): # Menu for different groups
command = self.group_commands[self.currentpage - 1]
# Adding fields for groups
embed = Embed(
title=f"{self.capfirst(command.name)} Commands",
description=f"{command.description}",
color=Color.yellow(),
)
for subcommand in command.commands:
if isinstance(subcommand, app_commands.Group):
for subsubcommand in subcommand.commands:
embed.add_field(
name=f"/{command.name} {subcommand.name} {subsubcommand.name}",
value=subsubcommand.description,
inline=True,
)
else:
embed.add_field(
name=f"/{command.name} {subcommand.name}",
value=subcommand.description,
inline=True,
)
elif self.currentpage == self.maxpages:
embed = Embed(
title="Miscellaneous Commands",
description="These are commands that are not part of any group.",
color=Color.yellow(),
)
for command in self.misc_commands:
embed.add_field(
name=f"/{command.name}",
value=f"{command.description}",
inline=False,
)
return embed

def total_pages(self):
"""Calculate total pages: 1 for grouped commands, 1 for misc commands, and 1 for each group."""
return 2 + len(self.group_commands)

def update_select_options(self):
"""Update options in the select menu"""
options = []
for i, command in enumerate(self.group_commands):
label = f"{command.name}"
options.append(
SelectOption(label=label, value=str(i), description=command.description)
)
options.append(
SelectOption(
label="Miscellaneous Commands",
value=self.maxpages,
description="These are commands that are not part of any group.",
)
)
for item in self.children:
if isinstance(item, ui.Select):
item.options = options

def capfirst(self, string):
"""Capitalize the first letter of string argument"""
newstring = string[0].upper() + string[1:].lower()
return newstring

# Buttons change currentpage to corresponding value

@ui.button(label="Start", style=ButtonStyle.primary)
async def menu_start(self, interaction: Interaction, button: ui.Button):
"""Start menu button"""
self.currentpage = 0
embed = self.create_help_embed(self.currentpage)
await interaction.response.edit_message(embed=embed, view=self)

@ui.button(label="Back", style=ButtonStyle.primary)
async def menu_back(self, interaction: Interaction, button: ui.Button):
"""Back button"""
self.currentpage -= 1
embed = self.create_help_embed(self.currentpage)
await interaction.response.edit_message(embed=embed, view=self)

@ui.button(label="Next", style=ButtonStyle.primary)
async def menu_next(self, interaction: Interaction, button: ui.Button):
"""Next button"""
self.currentpage += 1
embed = self.create_help_embed(self.currentpage)
await interaction.response.edit_message(embed=embed, view=self)

@ui.button(label="End", style=ButtonStyle.primary)
async def menu_end(self, interaction: Interaction, button: ui.Button):
"""End menu button"""
self.currentpage = self.maxpages
embed = self.create_help_embed(self.currentpage)
await interaction.response.edit_message(embed=embed, view=self)

# Select menu changes menu to selected
@ui.select(
placeholder="Select a command or group...",
min_values=1,
max_values=1,
options=[],
)
async def help_select_callback(self, interaction: Interaction, select: ui.Select):
"""Get the selected index and update the current page"""
selected_index = int(select.values[0])
self.currentpage = selected_index

embed = self.create_help_embed(selected_index)
await interaction.response.edit_message(embed=embed, view=self)
32 changes: 6 additions & 26 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@
Object,
Interaction,
Embed,
Color,
Message,
RawReactionActionEvent,
Attachment,
)

from discord.errors import NotFound
from discord.ext import commands
from dotenv import load_dotenv

from constants.colours import LIGHT_YELLOW
from commands import gemini, skullboard
from commands import gemini, skullboard, help_menu
from utils import time

# Load environment variables from .env file
Expand Down Expand Up @@ -172,30 +172,10 @@ async def chat(interaction: Interaction, query: str | None, file: Attachment | N
guild=Object(GUILD_ID),
)
async def help(interaction: Interaction):
commands = list(client.tree.get_commands(guild=Object(GUILD_ID)))
embed = Embed(
title="DuckBot",
description="DuckBot is the CS Club's Discord bot, created by the CS Club Open Source Team.",
color=Color.yellow(),
)
for command in commands:
if isinstance(command, app_commands.Group):
# Add the group name
embed.add_field(
name=f"/{command.name}", value=f"{command.description}", inline=False
)
# Add each subcommand in the group
for subcommand in command.commands:
embed.add_field(
name=f"/{command.name} {subcommand.name}",
value=subcommand.description,
inline=True,
)
else:
embed.add_field(
name=f"/{command.name}", value=command.description, inline=False
)
await interaction.response.send_message(embed=embed)
Help_Menu_View = help_menu.HelpMenu(client) # Creating the view for buttons
Help_Menu_View.update_select_options() # Creating options for select menu
embed = Help_Menu_View.create_help_embed(0)
await interaction.response.send_message(embed=embed, view=Help_Menu_View)


# Ignore non-slash commands
Expand Down

0 comments on commit 3e56db8

Please sign in to comment.