from typing import TYPE_CHECKING from aiogram import Router, F from aiogram.types import Message, CallbackQuery, InlineKeyboardButton from aiogram.fsm.context import FSMContext from ..context import ContextData, CallbackCommand from ....model.settings import Settings from ....utils.main import get_send_message, clear_state from ....model.descriptors import CommandCallbackContext from ..navigation import ( save_navigation_context, get_navigation_context, pop_navigation_context, ) if TYPE_CHECKING: from ....main import QBotApp router = Router() @router.message(F.text.startswith("/")) async def command_text(message: Message, **kwargs): str_command = message.text.lstrip("/") callback_data = ContextData( command=CallbackCommand.USER_COMMAND, user_command=str_command ) await command_handler(message=message, callback_data=callback_data, **kwargs) @router.callback_query(ContextData.filter(F.command == CallbackCommand.USER_COMMAND)) async def command_callback(message: CallbackQuery, **kwargs): await command_handler(message=message, **kwargs) async def command_handler(message: Message | CallbackQuery, **kwargs): callback_data: ContextData = kwargs.pop("callback_data") str_command = callback_data.user_command app: "QBotApp" = kwargs.pop("app") command = app.bot_commands.get(str_command) if not command: return state: FSMContext = kwargs.pop("state") state_data = await state.get_data() if command.register_navigation: clear_state(state_data=state_data) if command.clear_navigation: state_data.pop("navigation_stack", None) state_data.pop("navigation_context", None) if command.register_navigation: stack = save_navigation_context( callback_data=callback_data, state_data=state_data ) callback_context = CommandCallbackContext[app.user_class]( message=message, callback_data=callback_data, db_session=kwargs.pop("db_session"), user=kwargs.pop("user"), app=app, state_data=state_data, state=state, i18n=kwargs.pop("i18n"), kwargs=kwargs, ) await command.handler(callback_context) await state.set_data(state_data) if command.register_navigation: stack, navigation_context = get_navigation_context(state_data=state_data) back_callback_data = pop_navigation_context(stack=stack) if back_callback_data: callback_context.keyboard_builder.row( InlineKeyboardButton( text=(await Settings.get(Settings.APP_STRINGS_BACK_BTN)), callback_data=back_callback_data.pack(), ) ) send_message = get_send_message(message) if isinstance(message, CallbackCommand): message = message.message if callback_context.message_text: await send_message( text=callback_context.message_text, reply_markup=callback_context.keyboard_builder.as_markup(), ) else: await message.edit_reply_markup( reply_markup=callback_context.keyboard_builder.as_markup() )