From 68fb0e9c62c53602267e684d8f5919c28f678d1c Mon Sep 17 00:00:00 2001 From: Conatum Date: Mon, 5 Jun 2023 12:09:24 +0300 Subject: [PATCH] rewrite: help command and ui. --- config/emojis.conf | 2 + src/core/cog.py | 2 +- src/modules/__init__.py | 1 + src/modules/meta/__init__.py | 9 ++ src/modules/meta/cog.py | 36 ++++++++ src/modules/meta/help.txt | 57 ++++++++++++ src/modules/meta/help_sections.py | 143 ++++++++++++++++++++++++++++++ src/modules/meta/helpui.py | 99 +++++++++++++++++++++ 8 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 src/modules/meta/__init__.py create mode 100644 src/modules/meta/cog.py create mode 100644 src/modules/meta/help.txt create mode 100644 src/modules/meta/help_sections.py create mode 100644 src/modules/meta/helpui.py diff --git a/config/emojis.conf b/config/emojis.conf index 2cda4f8d..7cb37a00 100644 --- a/config/emojis.conf +++ b/config/emojis.conf @@ -48,6 +48,8 @@ tick = :✅: clock = :⏱️: warning = :⚠️: config = :⚙️: +stats = :📊: +utility = :⏱️: coin = <:coin:975880967485022239> diff --git a/src/core/cog.py b/src/core/cog.py index 3bd09bec..2050732a 100644 --- a/src/core/cog.py +++ b/src/core/cog.py @@ -92,7 +92,7 @@ class CoreCog(LionCog): if name in self.mention_cache: mention = self.mention_cache[name] else: - mention = f"" return mention async def cog_unload(self): diff --git a/src/modules/__init__.py b/src/modules/__init__.py index f7a2d6b9..d0db8273 100644 --- a/src/modules/__init__.py +++ b/src/modules/__init__.py @@ -12,6 +12,7 @@ active = [ '.statistics', '.pomodoro', '.rooms', + '.meta', '.test', ] diff --git a/src/modules/meta/__init__.py b/src/modules/meta/__init__.py new file mode 100644 index 00000000..53cd76ef --- /dev/null +++ b/src/modules/meta/__init__.py @@ -0,0 +1,9 @@ +from babel.translator import LocalBabel + +babel = LocalBabel('meta') + + +async def setup(bot): + from .cog import MetaCog + + await bot.add_cog(MetaCog(bot)) diff --git a/src/modules/meta/cog.py b/src/modules/meta/cog.py new file mode 100644 index 00000000..c31e3535 --- /dev/null +++ b/src/modules/meta/cog.py @@ -0,0 +1,36 @@ +from typing import Optional +import asyncio + +import discord +from discord.ext import commands as cmds +from discord import app_commands as appcmds + +from wards import low_management +from meta import LionBot, LionCog, LionContext +from utils.ui import AButton, AsComponents + +from . import babel +from .helpui import HelpUI + +_p = babel._p + + +class MetaCog(LionCog): + def __init__(self, bot: LionBot): + self.bot = bot + + @cmds.hybrid_command( + name=_p('cmd:help', "help"), + description=_p( + 'cmd:help|desc', + "See a brief summary of my commands and features." + ) + ) + async def help_cmd(self, ctx: LionContext): + ui = HelpUI( + ctx.bot, + ctx.author, + ctx.guild, + show_admin=await low_management(ctx), + ) + await ui.run(ctx.interaction) diff --git a/src/modules/meta/help.txt b/src/modules/meta/help.txt new file mode 100644 index 00000000..cae12db8 --- /dev/null +++ b/src/modules/meta/help.txt @@ -0,0 +1,57 @@ +Member View / Admin View / SuperAdmin View +Compact / Full + +Compact Member: +---------------------------- +# Personal Configuration +View or adjust personal settings with the {/my} command. +{/my timezone}: ... +{/my language}: ... + +# Economy +Earn coins through studying/chatting/voice activity +then spend them in the {/shop} or {/send} them to others. +You could also {/room rent} a private room! +{/send}: ... +{/shop}: ... +{/room}: ... + +# Statistics +... +{/ranks}: ... +{/me}: ... +{/stats}: ... +{/leaderboard}: ... + +# Utilities +... +{/reminders}: ... +{/tasklist}: ... +{/pomodoro}: ... +{/schedule}: ... +---------------------------- + +Compact Admin +---------------------------- +# General server configuration +{/dashboard}: +{/configure general}: +{/configure language}: + +# Economy +{/configure economy}: +{/editshop} + +# Statistics +{/ranks}: +{/configure ranks}: +{/configure statistics}: +{/configure voice_rewards}: +{/configure message_exp}: + +# Utilities +{/configure pomodoro}: +{/configure rooms}: +{/configure tasklist} +{/timer admin} +---------------------------- diff --git a/src/modules/meta/help_sections.py b/src/modules/meta/help_sections.py new file mode 100644 index 00000000..279d6426 --- /dev/null +++ b/src/modules/meta/help_sections.py @@ -0,0 +1,143 @@ +from typing import Optional + +import discord + +from meta import LionBot, conf + +from . import babel + +_p = babel._p + + +cmd_map = { + "cmd_my": "my", + "cmd_my_timezone": "my timezone", + "cmd_my_language": "my language", + "cmd_ranks": "ranks", + "cmd_leaderboard": "leaderboard", + "cmd_me": "me", + "cmd_stats": "stats", + "cmd_send": "send", + "cmd_shop": "shop open", + "cmd_room": "room rent", + "cmd_reminders": "remindme in", + "cmd_tasklist": "tasklist open", + "cmd_timers": "timers list", + "cmd_schedule": "schedule book", + "cmd_dashboard": "dashboard" +} + +emojis = { + 'config_emoji': conf.emojis.config, + 'stats_emoji': conf.emojis.stats, + 'coin': conf.emojis.coin, + 'utility_emoji': conf.emojis.utility +} + + +member_study = _p( + 'helptext|level:member|mode:study', + """ + {config_emoji} Personal Configuration + *View or adjust personal settings with the {cmd_my} command.* + {cmd_my_timezone}: Timezone used to display your stats and set reminders. + {cmd_my_language}: Your preferred language for commands and interactions. + + + {stats_emoji} Statistics + *Study in voice channels to earn activity ranks and compete on the leaderboard!* + {cmd_me}: View your personal study profile and set your profile tags. + {cmd_stats}: View study statistics for the current and past weeks or months. + {cmd_ranks}: See the list of activity ranks. + {cmd_leaderboard}: Compete with other members on the server leaderboards. + + + {coin} Economy + *Earn coins through studying, then spend them on some well deserved rewards!* + {cmd_send}: Send your {coin} to another member. + {cmd_shop}: Purchase server roles with your {coin}. + {cmd_room}: Rent a private voice channel for you and your friends. + + + {utility_emoji} Utilities + *Some other utilities to help you stay productive while studying!* + {cmd_reminders}: Ask me to remind you about that important task! + {cmd_tasklist}: Create tasks and feel the satisfaction of checking them off. + {cmd_timers}: Stay productive using the classic *pomodoro technique*! + {cmd_schedule}: Schedule a shared study session and keep yourself accountable! + """ +) + +admin_extra = _p( + 'helptext|page:admin', + """ + Use {cmd_dashboard} to see an overview of the server configuration, \ + and quickly jump to the feature configuration panels to modify settings. + + Configuration panels are also accessible directly through the `/configure` commands \ + and most settings can be set with these commands. + + Other relevant commands for guild configuration below: + `/editshop`: Add/Edit/Remove colour roles from the {coin} shop. + `/ranks`: Add/Edit/Remove activity ranks. + `/timer admin`: Add/Edit/Remove Pomodoro timers in voice channels. + """ +) + + +async def make_member_page(bot: LionBot, user: discord.User, guild: Optional[discord.Guild]) -> discord.Embed: + """ + Create the member-oriented help section, with user and optional guild context. + + Takes into account the guild mode, if provided. + """ + t = bot.translator.t + + mention_cmd = bot.core.mention_cmd + cmd_mentions = { + key: mention_cmd(name) for key, name in cmd_map.items() + } + format_args = {**emojis, **cmd_mentions} + + # TODO: Take into account lguild mode + text = t(member_study).format(**format_args) + sections = text.split('\n\n\n') + + embed = discord.Embed( + colour=discord.Colour.orange(), + title=t(_p( + 'helptext|level:member|title', + "Command Summary (for members)" + )) + ) + for section in sections: + title, _, body = section.strip().partition('\n') + embed.add_field(name=title, value=body, inline=False) + + return embed + + +async def make_admin_page(bot: LionBot, user: discord.User, guild: Optional[discord.Guild]) -> discord.Embed: + """ + Create the admin-oriented help section, with user or member context. + """ + t = bot.translator.t + + mention_cmd = bot.core.mention_cmd + cmd_mentions = { + key: mention_cmd(name) for key, name in cmd_map.items() + } + format_args = {**emojis, **cmd_mentions} + + text = t(admin_extra).format(**format_args) + + embed = discord.Embed( + colour=discord.Colour.orange(), + title=t(_p( + 'helptext|level:admin|title', + "Command Summary (for server admins)" + )) + ) + embed.description = text + + return embed diff --git a/src/modules/meta/helpui.py b/src/modules/meta/helpui.py new file mode 100644 index 00000000..1aca6e0f --- /dev/null +++ b/src/modules/meta/helpui.py @@ -0,0 +1,99 @@ +from typing import Optional +import asyncio + +import discord +from discord.ui.button import button, Button, ButtonStyle + +from meta import LionBot, conf +from utils.ui import MessageUI +from utils.lib import MessageArgs + +from .help_sections import make_admin_page, make_member_page +from . import babel + +_p = babel._p + + +class HelpUI(MessageUI): + def __init__(self, + bot: LionBot, + caller: discord.User | discord.Member, guild: Optional[discord.Guild], + show_admin: bool = False, + **kwargs): + self.bot = bot + self.caller = caller + self.guild = guild + self.show_admin = show_admin + + kwargs.setdefault('callerid', caller.id) + super().__init__(**kwargs) + + self.member_page = None + self.admin_page = None + + # 0: Member page, 1: Admin page, 2: Super Admin page + self.page = 0 + + # ----- UI Components ----- + @button(label='MEMBER_PAGE_PLACEHOLDER', style=ButtonStyle.blurple) + async def member_page_button(self, press: discord.Interaction, pressed: Button): + await press.response.defer() + self.page = 0 + await self.redraw() + + async def member_page_button_refresh(self): + self.member_page_button.label = self.bot.translator.t(_p( + 'ui:help|button:member_page|label', + "Member Page" + )) + + @button(label='ADMIN_PAGE_PLACEHOLDER', style=ButtonStyle.blurple) + async def admin_page_button(self, press: discord.Interaction, pressed: Button): + await press.response.defer() + self.page = 1 + await self.redraw() + + async def admin_page_button_refresh(self): + self.admin_page_button.label = self.bot.translator.t(_p( + 'ui:help|button:admin_page|label', + "Admin Page" + )) + + @button(emoji=conf.emojis.cancel, style=ButtonStyle.red) + async def close_button(self, press: discord.Interaction, pressed: Button): + await press.response.defer() + await self.quit() + + async def close_button_refresh(self): + pass + + # ----- UI Flow ----- + async def make_message(self) -> MessageArgs: + if self.page == 0: + message = MessageArgs(embed=self.member_page) + elif self.page == 1: + message = MessageArgs(embed=self.admin_page) + else: + message = MessageArgs(embed=self.member_page) + return message + + async def refresh_layout(self): + if self.show_admin: + await asyncio.gather( + self.close_button_refresh(), + self.member_page_button_refresh(), + self.admin_page_button_refresh(), + ) + switcher = self.member_page_button if self.page else self.admin_page_button + self.set_layout( + (switcher, self.close_button) + ) + else: + self.set_layout() + + async def reload(self): + self.member_page = await make_member_page(self.bot, self.caller, self.guild) + if self.show_admin: + self.admin_page = await make_admin_page(self.bot, self.caller, self.guild) + else: + self.admin_page = None