"""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)