Last active
June 7, 2019 07:43
-
-
Save setazer/4b19575615cd85559dee748cb2816022 to your computer and use it in GitHub Desktop.
Telebot paginator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from math import ceil | |
from random import randint | |
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton | |
from telebot.apihelper import ApiException | |
class InlinePaginator(): | |
def __init__(self, msg, data, items_per_row=5, max_rows=5): | |
self.data = data | |
self.current_page = 1 | |
self.items_per_row = items_per_row | |
self.items_per_page = self.items_per_row * max_rows | |
self.max_pages = ceil(len(self.data) / self.items_per_page) | |
self.navigation_process = None | |
self.selector = None | |
self.finisher = None | |
self.msg = msg | |
self.bot = None | |
def __del__(self): | |
pass | |
def add_data_item(self, button_data, button_text): | |
self.data.append((button_data, button_text)) | |
self.refresh() | |
def delete_data_item(self, button_data=None, button_text=None): | |
if not any([button_data, button_text]): | |
return | |
else: | |
found_buttons = [item for item in self.data if ( | |
(item[0] == button_data and item[1] == button_text) if all([button_data, button_text]) else ( | |
item[0] == button_data or item[1] == button_text))] | |
if found_buttons: | |
for item in found_buttons: | |
self.data.remove(item) | |
self.refresh() | |
return | |
else: | |
raise ValueError("Items not found") | |
def refresh(self): | |
self.max_pages = ceil(len(self.data) / self.items_per_page) | |
if self.current_page > self.max_pages: | |
self.current_page = self.max_pages | |
self.show_current_page() | |
def show_current_page(self): | |
markup = InlineKeyboardMarkup() | |
markup.row_width = self.items_per_row | |
buttons = [] | |
for value, text in self.data[(self.current_page - 1) * self.items_per_page: | |
self.current_page * self.items_per_page]: | |
buttons.append(InlineKeyboardButton(text=text, callback_data=f'pag_item{value}')) | |
markup.add(*buttons) | |
nav_buttons = [] | |
if self.current_page > 1: | |
nav_buttons.append(InlineKeyboardButton(text="⏪" + emojize_number(1), callback_data='pag_switch1')) | |
nav_buttons.append(InlineKeyboardButton(text="◀️" + emojize_number(self.current_page - 1), | |
callback_data=f'pag_switch{self.current_page - 1}')) | |
else: | |
nav_buttons += [InlineKeyboardButton(text="⏺", callback_data='pag_cur')] * 2 | |
nav_buttons.append(InlineKeyboardButton(text=emojize_number(self.current_page), | |
# callback_data с произвольным числом чтобы телега не ругалась, | |
# что сообщение не изменилось, когда происходит перерисовка при удалении элемента | |
callback_data=f'pag_cur{randint(0,1000000000)}')) | |
if self.current_page < self.max_pages: | |
nav_buttons.append(InlineKeyboardButton(text="▶️" + emojize_number(self.current_page + 1), | |
callback_data=f'pag_switch{self.current_page + 1}')) | |
nav_buttons.append(InlineKeyboardButton(text="️⏩" + emojize_number(self.max_pages), | |
callback_data=f'pag_switch{self.max_pages}')) | |
else: | |
nav_buttons += [InlineKeyboardButton(text="⏺", callback_data='pag_cur')] * 2 | |
markup.row(*nav_buttons) | |
markup.row(InlineKeyboardButton(text="✅ Завершить", callback_data='pag_finish')) | |
if self.bot: | |
try: | |
self.bot.edit_message_reply_markup(self.msg.chat.id, self.msg.message_id, reply_markup=markup) | |
except ApiException: | |
pass | |
def _navigation_process(self, call): | |
if 'pag_cur' in call.data: | |
self.refresh() | |
return | |
if 'pag_item' in call.data: | |
if self.selector: | |
self.selector(call, call.data[len('pag_item'):]) | |
elif 'pag_finish' in call.data: | |
if self.bot: | |
# находим и удалям хендлер нажатий кнопок пагинатора (он ведь больше не нужен) | |
for index, callback_handler in enumerate(self.bot.callback_query_handlers): | |
if callback_handler['function'] == self._navigation_process: | |
del self.bot.callback_query_handlers[index] | |
break | |
self.bot.delete_message(call.message.chat.id, call.message.message_id) | |
self.finisher(call) | |
elif 'pag_switch' in call.data: | |
new_page = int(call.data.replace('pag_switch', '')) | |
if self.current_page != new_page: | |
self.current_page = new_page | |
self.show_current_page() | |
def hook_telebot(self, bot, func_item_selected, finisher=lambda f: None): | |
self.bot = bot | |
self.selector = func_item_selected | |
self.finisher = finisher | |
self.navigation_process = bot.callback_query_handler(func=lambda | |
call: 'pag_' in call.data and call.message.chat.id == self.msg.chat.id and call.message.message_id == self.msg.message_id)( | |
self._navigation_process) # регистрация нажатия на кнопки в пагинаторе с привязкой к конкретной мессаге, | |
# чтобы 2 пагинатора не влияли друг на друга | |
self.show_current_page() | |
def emojize_number(num): | |
digits = {'0':'0️⃣','1':'1️⃣','2':'2️⃣','3':'3️⃣','4':'4️⃣','5':'5️⃣','6':'6️⃣','7':'7️⃣','8':'8️⃣','9':'9️⃣'} | |
result = '' | |
for char in str(num): | |
result+=digits[char] | |
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import telebot | |
from paginator import InlinePaginator | |
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton | |
TELEGRAM_PROXY = { | |
"http": "proxy.antizapret.prostovpn.org:3128", | |
"https": "proxy.antizapret.prostovpn.org:3128" | |
} | |
OWNER_ROOM_ID = '' | |
TELEGRAM_TOKEN = '' | |
telebot.apihelper.proxy=TELEGRAM_PROXY | |
bot = telebot.TeleBot(TELEGRAM_TOKEN) | |
paginators={} | |
buttons = [(str(item),str(item*1000)) for item in range(140)] # тестовый массив с данными вида [('1','1000'),('2','2000'),...] | |
def selected(data,call): # функция для обработки выбранного элемента | |
bot.send_message(call.message.chat.id,data) | |
def dead_paginator(call): # удаляем ненужный пагинатор | |
del paginators[(call.message.chat.id, call.message.message_id)] | |
sel=bot.send_message('@pyTelegramBotAPI_talks_ru',"Select item:") # мессага для подцепления | |
paginators[(sel.chat.id, sel.message_id)] = InlinePaginator(sel,buttons) # создаём навигацию, прицепляя её к мессаге и передавая массив с данными | |
paginators[(sel.chat.id, sel.message_id)].hook_telebot(bot,selected,dead_paginator) # подцепляем бота, функцию которая будет обрабатывать выбранный элемент | |
# и функцию которая будет выполнена при нажатии "Завершить" | |
# подцепление так же включает внутреннюю обработку нажатия на кнопки навигации | |
bot.polling() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment