feat(start): человекочитаемые кнопки главного меню и обработчики\n\n- Добавлена постоянная клавиатура с удобными подписями (эмодзи)\n- Добавлен /menu для показа клавиатуры в любой момент\n- Реализованы обработчики нажатий по тексту кнопок: /add, /vocabulary, /task, /practice, /import, /stats, /settings\n- Добавлены быстрые темы для тематических слов (inline) и обработчик их выбора
This commit is contained in:
@@ -15,6 +15,16 @@ from services.user_service import UserService
|
|||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
|
# Тексты кнопок главного меню
|
||||||
|
BTN_ADD = "➕ Добавить слово"
|
||||||
|
BTN_VOCAB = "📚 Словарь"
|
||||||
|
BTN_TASK = "🧠 Задание"
|
||||||
|
BTN_PRACTICE = "💬 Практика"
|
||||||
|
BTN_WORDS = "🎯 Тематические слова"
|
||||||
|
BTN_IMPORT = "📖 Импорт из текста"
|
||||||
|
BTN_STATS = "📊 Статистика"
|
||||||
|
BTN_SETTINGS = "⚙️ Настройки"
|
||||||
|
|
||||||
|
|
||||||
def main_menu_keyboard() -> ReplyKeyboardMarkup:
|
def main_menu_keyboard() -> ReplyKeyboardMarkup:
|
||||||
"""Клавиатура с основными командами (кнопки отправляют команды)."""
|
"""Клавиатура с основными командами (кнопки отправляют команды)."""
|
||||||
@@ -22,20 +32,20 @@ def main_menu_keyboard() -> ReplyKeyboardMarkup:
|
|||||||
resize_keyboard=True,
|
resize_keyboard=True,
|
||||||
keyboard=[
|
keyboard=[
|
||||||
[
|
[
|
||||||
KeyboardButton(text="/add"),
|
KeyboardButton(text=BTN_ADD),
|
||||||
KeyboardButton(text="/vocabulary"),
|
KeyboardButton(text=BTN_VOCAB),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
KeyboardButton(text="/task"),
|
KeyboardButton(text=BTN_TASK),
|
||||||
KeyboardButton(text="/practice"),
|
KeyboardButton(text=BTN_PRACTICE),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
KeyboardButton(text="/words travel"),
|
KeyboardButton(text=BTN_WORDS),
|
||||||
KeyboardButton(text="/import"),
|
KeyboardButton(text=BTN_IMPORT),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
KeyboardButton(text="/stats"),
|
KeyboardButton(text=BTN_STATS),
|
||||||
KeyboardButton(text="/settings"),
|
KeyboardButton(text=BTN_SETTINGS),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -114,6 +124,108 @@ async def cmd_menu(message: Message):
|
|||||||
await message.answer("Главное меню доступно ниже ⤵️", reply_markup=main_menu_keyboard())
|
await message.answer("Главное меню доступно ниже ⤵️", reply_markup=main_menu_keyboard())
|
||||||
|
|
||||||
|
|
||||||
|
# Обработчики кнопок главного меню (по тексту)
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_ADD)
|
||||||
|
async def btn_add_pressed(message: Message, state: FSMContext):
|
||||||
|
from bot.handlers.vocabulary import AddWordStates
|
||||||
|
await message.answer(
|
||||||
|
"Отправь слово, которое хочешь добавить:\n"
|
||||||
|
"Например: <code>/add elephant</code>\n\n"
|
||||||
|
"Или просто отправь слово без команды!"
|
||||||
|
)
|
||||||
|
await state.set_state(AddWordStates.waiting_for_word)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_VOCAB)
|
||||||
|
async def btn_vocab_pressed(message: Message):
|
||||||
|
from bot.handlers.vocabulary import cmd_vocabulary
|
||||||
|
await cmd_vocabulary(message)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_TASK)
|
||||||
|
async def btn_task_pressed(message: Message, state: FSMContext):
|
||||||
|
from bot.handlers.tasks import cmd_task
|
||||||
|
await cmd_task(message, state)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_PRACTICE)
|
||||||
|
async def btn_practice_pressed(message: Message, state: FSMContext):
|
||||||
|
from bot.handlers.practice import cmd_practice
|
||||||
|
await cmd_practice(message, state)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_IMPORT)
|
||||||
|
async def btn_import_pressed(message: Message, state: FSMContext):
|
||||||
|
from bot.handlers.import_text import cmd_import
|
||||||
|
await cmd_import(message, state)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_STATS)
|
||||||
|
async def btn_stats_pressed(message: Message):
|
||||||
|
from bot.handlers.tasks import cmd_stats
|
||||||
|
await cmd_stats(message)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_SETTINGS)
|
||||||
|
async def btn_settings_pressed(message: Message):
|
||||||
|
from bot.handlers.settings import cmd_settings
|
||||||
|
await cmd_settings(message)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(F.text == BTN_WORDS)
|
||||||
|
async def btn_words_pressed(message: Message, state: FSMContext):
|
||||||
|
"""Подсказать про тематические слова и показать быстрые темы."""
|
||||||
|
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
|
text = (
|
||||||
|
"📚 <b>Тематические подборки слов</b>\n\n"
|
||||||
|
"Используй: <code>/words [тема]</code>\n\n"
|
||||||
|
"Популярные темы:"
|
||||||
|
)
|
||||||
|
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||||
|
[InlineKeyboardButton(text="✈️ Путешествия", callback_data="menu_theme_travel")],
|
||||||
|
[InlineKeyboardButton(text="🍔 Еда", callback_data="menu_theme_food")],
|
||||||
|
[InlineKeyboardButton(text="💼 Работа", callback_data="menu_theme_work")],
|
||||||
|
[InlineKeyboardButton(text="🌿 Природа", callback_data="menu_theme_nature")],
|
||||||
|
[InlineKeyboardButton(text="💻 Технологии", callback_data="menu_theme_technology")],
|
||||||
|
])
|
||||||
|
await message.answer(text, reply_markup=keyboard)
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(F.data.startswith("menu_theme_"))
|
||||||
|
async def pick_theme_from_menu(callback: CallbackQuery, state: FSMContext):
|
||||||
|
"""Сгенерировать слова по выбранной теме из меню и показать список."""
|
||||||
|
from database.db import async_session_maker
|
||||||
|
from services.user_service import UserService
|
||||||
|
from services.ai_service import ai_service
|
||||||
|
from bot.handlers.words import show_words_list, WordsStates
|
||||||
|
|
||||||
|
theme = callback.data.split("menu_theme_")[-1]
|
||||||
|
|
||||||
|
async with async_session_maker() as session:
|
||||||
|
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
|
||||||
|
if not user:
|
||||||
|
await callback.answer("Сначала /start", show_alert=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
generating = await callback.message.answer(f"🔄 Генерирую подборку слов по теме '{theme}'...")
|
||||||
|
words = await ai_service.generate_thematic_words(theme=theme, level=user.level.value, count=10)
|
||||||
|
await generating.delete()
|
||||||
|
|
||||||
|
if not words:
|
||||||
|
await callback.message.answer("❌ Не удалось сгенерировать подборку. Попробуй позже.")
|
||||||
|
await callback.answer()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Сохраняем в состояние как в /words
|
||||||
|
await state.update_data(theme=theme, words=words, user_id=user.id, level=user.level.name)
|
||||||
|
await state.set_state(WordsStates.viewing_words)
|
||||||
|
|
||||||
|
await show_words_list(callback.message, words, theme)
|
||||||
|
await callback.answer()
|
||||||
|
|
||||||
|
|
||||||
@router.message(Command("help"))
|
@router.message(Command("help"))
|
||||||
async def cmd_help(message: Message):
|
async def cmd_help(message: Message):
|
||||||
"""Обработчик команды /help"""
|
"""Обработчик команды /help"""
|
||||||
|
|||||||
Reference in New Issue
Block a user