bot rafactor and bugfix

This commit is contained in:
2025-08-19 04:45:16 +09:00
parent 43dda889f8
commit a8d860ed87
31 changed files with 4396 additions and 613 deletions

View File

@@ -1,53 +1,207 @@
from __future__ import annotations
from typing import Iterable, List, Tuple, Optional
from typing import Iterable, List, Optional, Any
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from .messages import MessageType
def template_type_keyboard() -> InlineKeyboardMarkup:
"""Возвращает клавиатуру выбора типа шаблона."""
return KbBuilder.template_type_keyboard()
def get_templates_keyboard(templates: List[Any], page: int = 0) -> InlineKeyboardMarkup:
"""Возвращает клавиатуру со списком шаблонов."""
return KbBuilder.get_templates_keyboard(templates, page)
class KbBuilder:
"""Строитель клавиатур для различных состояний бота."""
PAGE_SIZE = 8
@staticmethod
def channels(channels: Iterable) -> InlineKeyboardMarkup:
rows = [[InlineKeyboardButton(ch.title or str(ch.chat_id), callback_data=f"channel:{ch.id}")]
for ch in channels]
"""Клавиатура выбора канала."""
rows = [
[InlineKeyboardButton(
ch.title or str(ch.chat_id),
callback_data=f"channel:{ch.id}"
)]
for ch in channels
]
return InlineKeyboardMarkup(rows)
@staticmethod
def post_types() -> InlineKeyboardMarkup:
"""Клавиатура выбора типа поста."""
rows = [
[InlineKeyboardButton("Текст", callback_data="type:text"),
InlineKeyboardButton("Фото", callback_data="type:photo")],
[InlineKeyboardButton("Видео", callback_data="type:video"),
InlineKeyboardButton("GIF", callback_data="type:animation")],
[
InlineKeyboardButton("📝 Текст", callback_data=f"type:{MessageType.TEXT.value}"),
InlineKeyboardButton("📷 Фото", callback_data=f"type:{MessageType.PHOTO.value}")
],
[
InlineKeyboardButton("🎥 Видео", callback_data=f"type:{MessageType.VIDEO.value}"),
InlineKeyboardButton("🎬 GIF", callback_data=f"type:{MessageType.ANIMATION.value}")
],
]
return InlineKeyboardMarkup(rows)
@staticmethod
def parse_modes() -> InlineKeyboardMarkup:
rows = [[InlineKeyboardButton("HTML", callback_data="fmt:HTML"),
InlineKeyboardButton("MarkdownV2", callback_data="fmt:MarkdownV2")]]
return InlineKeyboardMarkup(rows)
@staticmethod
def send_confirm() -> InlineKeyboardMarkup:
"""Клавиатура выбора формата текста."""
rows = [
[InlineKeyboardButton("Отправить сейчас", callback_data="send:now")],
[InlineKeyboardButton("Запланировать", callback_data="send:schedule")],
[
InlineKeyboardButton("HTML", callback_data="fmt:HTML"),
InlineKeyboardButton("MarkdownV2", callback_data="fmt:MarkdownV2")
]
]
return InlineKeyboardMarkup(rows)
@staticmethod
def templates_list(items: List, page: int, total: int, page_size: int) -> InlineKeyboardMarkup:
rows: List[List[InlineKeyboardButton]] = []
for t in items:
rows.append([
InlineKeyboardButton((t.title or t.name), callback_data=f"tpluse:{t.name}"),
InlineKeyboardButton("👁 Предпросмотр", callback_data=f"tplprev:{t.name}")
])
def template_type_keyboard() -> InlineKeyboardMarkup:
"""Клавиатура выбора типа шаблона."""
rows = [
[
InlineKeyboardButton("📝 Текст", callback_data=f"tpl_type:{MessageType.TEXT.value}"),
InlineKeyboardButton("📷 Фото", callback_data=f"tpl_type:{MessageType.PHOTO.value}")
],
[
InlineKeyboardButton("🎥 Видео", callback_data=f"tpl_type:{MessageType.VIDEO.value}"),
InlineKeyboardButton("🎬 GIF", callback_data=f"tpl_type:{MessageType.ANIMATION.value}")
]
]
return InlineKeyboardMarkup(rows)
@staticmethod
def get_templates_keyboard(templates: List[Any], page: int = 0) -> InlineKeyboardMarkup:
"""Клавиатура списка шаблонов с пагинацией."""
start_idx = page * KbBuilder.PAGE_SIZE
end_idx = start_idx + KbBuilder.PAGE_SIZE
page_templates = templates[start_idx:end_idx]
rows = []
for template in page_templates:
rows.append([
InlineKeyboardButton(
f"{template.name} ({template.type})",
callback_data=f"template:{template.id}"
)
])
nav_row = []
if page > 0:
nav_row.append(InlineKeyboardButton("◀️ Назад", callback_data=f"page:{page-1}"))
if end_idx < len(templates):
nav_row.append(InlineKeyboardButton("Вперед ▶️", callback_data=f"page:{page+1}"))
if nav_row:
rows.append(nav_row)
return InlineKeyboardMarkup(rows)
@staticmethod
def go_back() -> InlineKeyboardMarkup:
"""Клавиатура с кнопкой назад."""
return InlineKeyboardMarkup([
[InlineKeyboardButton("« Назад", callback_data="back")]
])
@staticmethod
def text_input_options() -> InlineKeyboardMarkup:
"""Клавиатура при вводе текста."""
rows = [
[InlineKeyboardButton("📋 Использовать шаблон", callback_data="tpl:choose")],
[InlineKeyboardButton("⌨️ Добавить клавиатуру", callback_data="kb:add")],
[InlineKeyboardButton("❌ Отмена", callback_data="cancel")]
]
return InlineKeyboardMarkup(rows)
@staticmethod
def send_confirm() -> InlineKeyboardMarkup:
"""Клавиатура подтверждения отправки."""
rows = [
[InlineKeyboardButton("📤 Отправить сейчас", callback_data="send:now")],
[InlineKeyboardButton("⏰ Запланировать", callback_data="send:schedule")],
[InlineKeyboardButton("✏️ Редактировать", callback_data="send:edit")],
[InlineKeyboardButton("❌ Отмена", callback_data="send:cancel")]
]
return InlineKeyboardMarkup(rows)
@staticmethod
def preview_confirm() -> InlineKeyboardMarkup:
"""Клавиатура после предпросмотра."""
rows = [
[InlineKeyboardButton("✅ Использовать", callback_data="pv:use")],
[InlineKeyboardButton("✏️ Изменить переменные", callback_data="pv:edit")],
[InlineKeyboardButton("❌ Отмена", callback_data="tpl:cancel")]
]
return InlineKeyboardMarkup(rows)
@staticmethod
def templates_list(
items: List,
page: int,
total: int,
show_delete: bool = False
) -> InlineKeyboardMarkup:
"""
Клавиатура списка шаблонов с пагинацией.
Args:
items: Список шаблонов на текущей странице
page: Номер текущей страницы
total: Общее количество шаблонов
show_delete: Показывать ли кнопку удаления
"""
rows: List[List[InlineKeyboardButton]] = []
for t in items:
row = [
InlineKeyboardButton(
(t.title or t.name),
callback_data=f"tpluse:{t.name}"
),
InlineKeyboardButton(
"👁 Предпросмотр",
callback_data=f"tplprev:{t.name}"
)
]
if show_delete:
row.append(InlineKeyboardButton(
"🗑",
callback_data=f"tpldel:{t.name}"
))
rows.append(row)
# Навигация
nav: List[InlineKeyboardButton] = []
if page > 0:
nav.append(InlineKeyboardButton("◀️ Назад", callback_data=f"tplpage:{page-1}"))
if (page + 1) * page_size < total:
nav.append(InlineKeyboardButton("Вперёд ▶️", callback_data=f"tplpage:{page+1}"))
nav.append(InlineKeyboardButton(
"◀️ Назад",
callback_data=f"tplpage:{page-1}"
))
if (page + 1) * KbBuilder.PAGE_SIZE < total:
nav.append(InlineKeyboardButton(
"Вперёд ▶️",
callback_data=f"tplpage:{page+1}"
))
if nav:
rows.append(nav)
# Кнопка отмены
rows.append([InlineKeyboardButton("❌ Отмена", callback_data="tpl:cancel")])
return InlineKeyboardMarkup(rows)
@staticmethod
def template_delete_confirm(name: str) -> InlineKeyboardMarkup:
"""Клавиатура подтверждения удаления шаблона."""
rows = [
[
InlineKeyboardButton("✅ Удалить", callback_data=f"tpldelok:{name}"),
InlineKeyboardButton("❌ Отмена", callback_data="tpl:cancel")
]
]
return InlineKeyboardMarkup(rows)
if nav:
rows.append(nav)