feat: мини-истории, слово дня, меню практики

- Добавлены мини-истории для чтения с выбором жанра и вопросами
- Кнопка показа/скрытия перевода истории
- Количество вопросов берётся из настроек пользователя
- Слово дня генерируется глобально в 00:00 UTC
- Кнопка "Практика" открывает меню выбора режима
- Убран автоматический create_all при запуске (только миграции)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-09 15:05:38 +03:00
parent 69c651c031
commit f38ff2f18e
22 changed files with 3131 additions and 77 deletions

View File

@@ -29,6 +29,40 @@ def get_scenario_name(lang: str, scenario: str) -> str:
return t(lang, f'practice.scenario.{scenario}')
async def show_practice_menu(message: Message, telegram_id: int, edit: bool = False):
"""Показать меню выбора сценария практики"""
async with async_session_maker() as session:
user = await UserService.get_user_by_telegram_id(session, telegram_id)
if not user:
await message.answer(t('ru', 'common.start_first'))
return
lang = get_user_lang(user)
keyboard = []
for scenario_id in SCENARIO_KEYS:
keyboard.append([
InlineKeyboardButton(
text=get_scenario_name(lang, scenario_id),
callback_data=f"scenario_{scenario_id}"
)
])
keyboard.append([
InlineKeyboardButton(
text=t(lang, 'practice.custom_scenario_btn'),
callback_data="scenario_custom"
)
])
reply_markup = InlineKeyboardMarkup(inline_keyboard=keyboard)
if edit:
await message.edit_text(t(lang, 'practice.start_text'), reply_markup=reply_markup)
else:
await message.answer(t(lang, 'practice.start_text'), reply_markup=reply_markup)
@router.message(Command("practice"))
async def cmd_practice(message: Message, state: FSMContext):
"""Обработчик команды /practice"""
@@ -39,31 +73,10 @@ async def cmd_practice(message: Message, state: FSMContext):
await message.answer(t('ru', 'common.start_first'))
return
lang = get_user_lang(user)
# Показываем выбор сценария
keyboard = []
for scenario_id in SCENARIO_KEYS:
keyboard.append([
InlineKeyboardButton(
text=get_scenario_name(lang, scenario_id),
callback_data=f"scenario_{scenario_id}"
)
])
# Кнопка для своего сценария
keyboard.append([
InlineKeyboardButton(
text=t(lang, 'practice.custom_scenario_btn'),
callback_data="scenario_custom"
)
])
reply_markup = InlineKeyboardMarkup(inline_keyboard=keyboard)
await state.update_data(user_id=user.id, level=get_user_level_for_language(user))
await state.set_state(PracticeStates.choosing_scenario)
await message.answer(t(lang, 'practice.start_text'), reply_markup=reply_markup)
await show_practice_menu(message, message.from_user.id, edit=False)
@router.callback_query(F.data == "scenario_custom", PracticeStates.choosing_scenario)