Source code for spotted.utils.keyboard_util

"""Creates the inlinekeyboard sent by the bot in its messages.
Callback_data format: <callback_family>_<callback_name>,[arg]"""

from itertools import islice, zip_longest

from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup

from spotted.data import Config, PendingPost
from spotted.utils.constants import APPROVED_KB, REJECTED_KB


[docs] def get_confirm_kb() -> InlineKeyboardMarkup: """Generates the InlineKeyboard to confirm the creation of the post Returns: new inline keyboard """ return InlineKeyboardMarkup( [ [ InlineKeyboardButton(text="Si", callback_data="post_confirm,submit"), InlineKeyboardButton(text="No", callback_data="post_confirm,cancel"), ] ] )
[docs] def get_preview_kb() -> InlineKeyboardMarkup: """Generates the InlineKeyboard to choose if the post should be previewed or not Returns: new inline keyboard """ return InlineKeyboardMarkup( [ [ InlineKeyboardButton(text="Si", callback_data="post_preview,accept"), InlineKeyboardButton(text="No", callback_data="post_preview,reject"), ] ] )
[docs] def get_settings_kb() -> InlineKeyboardMarkup: """Generates the InlineKeyboard to edit the settings Returns: new inline keyboard """ return InlineKeyboardMarkup( [ [ InlineKeyboardButton(" Anonimo ", callback_data="settings,anonimo"), InlineKeyboardButton(" Con credit ", callback_data="settings,credit"), ] ] )
[docs] def get_approve_kb(pending_post: PendingPost = None, approve: int = -1, reject: int = -1) -> InlineKeyboardMarkup: """Generates the InlineKeyboard for the pending post. If the pending post is None, the keyboard will be generated with 0 votes. Otherwise, the keyboard will be generated with the correct number of votes. To avoid unnecessary queries, the number of votes can be passed as an argument and will be assumed to be correct. Args: pending_post: existing pending post to which the keyboard is attached approve: number of approve votes known in advance reject: number of reject votes known in advance Returns: new inline keyboard """ if pending_post is None: # the post has just been created n_approve = 0 n_reject = 0 else: n_approve = pending_post.get_votes(vote=True) if approve < 0 else approve n_reject = pending_post.get_votes(vote=False) if reject < 0 else reject return InlineKeyboardMarkup( [ [ InlineKeyboardButton(f"🟢 {n_approve}", callback_data="approve_yes"), InlineKeyboardButton(f"🔴 {n_reject}", callback_data="approve_no"), ], [InlineKeyboardButton("⏹ Stop", callback_data="approve_status,pause,0")], ] )
[docs] def get_autoreply_kb(page: int, items_per_page: int) -> list[list[InlineKeyboardButton]]: """Generates the keyboard for the autoreplies Args: page: page of the autoreplies items_per_page: number of items per page Returns: new part of keyboard """ keyboard = [] autoreplies = islice(Config.autoreplies_get("autoreplies"), page * items_per_page, (page + 1) * items_per_page) for row in zip_longest(*[iter(autoreplies)] * 2, fillvalue=None): new_row = [] for autoreply in row: if autoreply is not None: new_row.append(InlineKeyboardButton(autoreply, callback_data=f"autoreply,{autoreply}")) keyboard.append(new_row) return keyboard
[docs] def get_paused_kb(page: int, items_per_page: int) -> InlineKeyboardMarkup: """Generates the InlineKeyboard for the paused post Args: page: page of the autoreplies Returns: autoreplies keyboard append with resume button """ keyboard = get_autoreply_kb(page, items_per_page) # navigation buttons navigation_row = [] # to keep the same number of buttons in the row none_button = InlineKeyboardButton(" ", callback_data="none") if page > 0: navigation_row.append(InlineKeyboardButton("⏮ Previous", callback_data=f"approve_status,pause,{page - 1}")) else: navigation_row.append(none_button) navigation_row.append(InlineKeyboardButton("▶️ Resume", callback_data="approve_status,play")) if len(Config.autoreplies_get("autoreplies")) > (page + 1) * items_per_page: navigation_row.append(InlineKeyboardButton("⏭ Next", callback_data=f"approve_status,pause,{page + 1}")) else: navigation_row.append(none_button) keyboard.append(navigation_row) return InlineKeyboardMarkup(keyboard)
[docs] def get_published_post_kb() -> InlineKeyboardMarkup | None: """Generates the InlineKeyboard for the published post adding the report button if needed Returns: new inline keyboard """ keyboard: list[InlineKeyboardButton] = [] # the last button in the last row will be the report button report_button = InlineKeyboardButton("🚩 Report", callback_data="report_spot") follow_button = InlineKeyboardButton("👁 Follow", callback_data="follow_spot") if Config.post_get("report"): if len(keyboard) > 0: keyboard[-1].append(report_button) else: keyboard.append([report_button]) keyboard.append([follow_button]) return InlineKeyboardMarkup(keyboard) if keyboard else None
[docs] async def get_post_outcome_kb( bot: Bot, votes: list[tuple[int, bool]], reason: str | None = None ) -> InlineKeyboardMarkup: """Generates the InlineKeyboard for the outcome of a post Args: bot: bot instance votes: list of votes reason: reason for the rejection, currently used on autoreplies Returns: new inline keyboard """ keyboard = [] approved_by = [vote[0] for vote in votes if vote[1]] rejected_by = [vote[0] for vote in votes if not vote[1]] # keyboard with 2 columns: one for the approve votes and one for the reject votes for approve, reject in zip_longest(approved_by, rejected_by, fillvalue=False): keyboard.append( [ InlineKeyboardButton( f"🟢 {(await bot.get_chat(approve)).username}" if approve else "", callback_data="none" ), InlineKeyboardButton( f"🔴 {(await bot.get_chat(reject)).username}" if reject else "", callback_data="none" ), ] ) is_approved = len(approved_by) > len(rejected_by) and reason is None outcome_text = APPROVED_KB if is_approved else REJECTED_KB if reason is not None and not is_approved: outcome_text += f" [{reason}]" keyboard.append( [ InlineKeyboardButton(outcome_text, callback_data="none"), ] ) return InlineKeyboardMarkup(keyboard)