pythontelegram-botaiogram

How to add a "back" button to a Telegram bot?


I can’t figure out how to implement a “Back” button that would return to the previous menu. I've tried using a stack to keep track of previous states, but it's inefficient and doesn't always work. Is there a way to implement such a feature? So, let's say the "Back-2" button would take me back to the menu with the "Source Channel Settings" button, and the "Back-1" button would take me back to the "Bot Settings". I would be grateful for any ideas.

@dp.message(Command('start'))
async def bot_settings(message: Message):
    keyboard = ReplyKeyboardMarkup(keyboard=[
        [KeyboardButton(text="Bot Settings")],
    ])
    await message.answer("Choose an action:", reply_markup=keyboard)


@dp.message(lambda message: message.text == "Bot Settings")
async def bot_settings_menu(message: Message):
    keyboard = ReplyKeyboardMarkup(keyboard=[
        [KeyboardButton(text="Source Channel Settings")],
        [KeyboardButton(text="Back-1")]
    ])
    await message.answer(text="Choose an action:", reply_markup=keyboard)


@dp.message(lambda message: message.text == "Source Channels Setup")
async def configure_source_channels(message: Message):
    keyboard = ReplyKeyboardMarkup(keyboard=[
        [KeyboardButton(text="Add channel", request_chat=KeyboardButtonRequestChat(
            request_id=1,
            user_is_bot=False,
            chat_is_channel=True,
            chat_is_forum=False
        ))],
        [KeyboardButton(text="Channel list")],
        [KeyboardButton(text="Back-2")]
    ])
    await message.answer(text="Choose an action:", reply_markup=keyboard)

Solution

  • from aiogram import types
    
    # Define states
    MAIN_MENU = 'main_menu'
    BOT_SETTINGS = 'bot_settings'
    SOURCE_CHANNEL_SETTINGS = 'source_channel_settings'
    
    # State storage
    user_states = {}
    
    def get_user_state(user_id):
        return user_states.get(user_id, MAIN_MENU)
    
    def update_user_state(user_id, state):
        user_states[user_id] = state
    
    # Entry point to bot settings, sets the user's state to BOT_SETTINGS
    @dpp.message(Command('start'))
    async def bot_settings(message: Message):
        update_user_state(message.from_user.id, BOT_SETTINGS)
        keyboard = ReplyKeyboardMarkup(keyboard=[
            [KeyboardButton(text="Bot Settings")],
            [KeyboardButton(text="Back")],
        ])
        await message.answer("Choose an action:", reply_markup=keyboard)
    
    # Handles the Bot Settings menu
    @dpp.message(lambda message: message.text == "Bot Settings")
    async def bot_settings_menu(message: Message):
        update_user_state(message.from_user.id, SOURCE_CHANNEL_SETTINGS)
        keyboard = ReplyKeyboardMarkup(keyboard=[
            [KeyboardButton(text="Source Channel Settings")],
            [KeyboardButton(text="Back")],
        ])
        await message.answer("Choose an action:", reply_markup=keyboard)
    
    # Handles the Source Channels Setup menu
    @dpp.message(lambda message: message.text == "Source Channels Setup")
    async def configure_source_channels(message: Message):
        # Your source channel configuration code goes here
        pass
    
    # A generic back button handler
    @dpp.message(lambda message: message.text == "Back")
    async def handle_back(message: Message):
        user_id = message.from_user.id
        current_state = get_user_state(user_id)
    
        if current_state == SOURCE_CHANNEL_SETTINGS:
            # Go back to BOT_SETTINGS
            await bot_settings(message)
        elif current_state == BOT_SETTINGS:
            # Go back to MAIN_MENU or whatever the initial state is
            await start(message)
        else:
            # Default action or error message
            await message.answer("Not sure where to go back from here.")
    
    # Your 'start' handler or main menu function
    async def start(message: Message):
        # Code to handle the main menu
        pass