Overview

Concept

Aiogram-dialog is a GUI framework for telegram bot. It is inspired by ideas of Android SDK and React.js

Main ideas are:

  1. Split data retrieving and message rendering

  2. Unite rendering buttons and processing clicks

  3. Better states routing

  4. Widgets

The main building block of your UI is Window. Each window represents a message sent to user and processing of a user reaction on it.

Each window consists of Widgets and callback functions. Widgets can represent message text and keyboard. Callbacks are used to retrieve required data or process user input.

You combine windows into Dialog. This allows you to switch between windows creating different scenarios of communication with user.

In more complex cases you can create more than one dialog. Then you can start new dialogs without closing previous one and automatically return back when it is closed. You can pass data between dialogs keeping they state isolated at the same time.

Quickstart

Install library:

pip install aiogram_dialog

Create states group for your dialog:

from aiogram.dispatcher.filters.state import StatesGroup, State

class MySG(StatesGroup):
    main = State()

Create at least one window with buttons or text:

from aiogram.dispatcher.filters.state import StatesGroup, State

from aiogram_dialog import Window
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const


class MySG(StatesGroup):
    main = State()


main_window = Window(
    Const("Hello, unknown person"),  # just a constant text
    Button(Const("Useless button"), id="nothing"),  # button with text and id
    state=MySG.main,  # state is used to identify window between dialogs
)

Create dialog with your windows:

from aiogram_dialog import Dialog

dialog = Dialog(main_window)

Let’s assume that you have created your aiogram bot with dispatcher and states storage as you normally do. It is important you have a storage because aiogram_dialog uses FSMContext internally to store it state:

from aiogram import Bot, Dispatcher, executor
from aiogram.contrib.fsm_storage.memory import MemoryStorage

storage = MemoryStorage()
bot = Bot(token='BOT TOKEN HERE')
dp = Dispatcher(bot, storage=storage)

To start using your dialog you need to register it. Also library needs some additional registrations for its internals. To do it we will create DialogRegistry and use it to register our dialog

from aiogram_dialog import DialogRegistry

registry = DialogRegistry(dp)  # this is required to use `aiogram_dialog`
registry.register(dialog)  # register a dialog

At this point we have configured everything. But dialog won’t start itself. We will create simple command handler to deal with it. To start dialog we need DialogManager which is automatically injected by library. Also mind the reset_stack argument. The library can start multiple dialogs stacking one above other. Currently we do not want this feature, so we will reset stack on each start:

from aiogram.types import Message
from aiogram_dialog import DialogManager, StartMode

@dp.message_handler(commands=["start"])
async def start(m: Message, dialog_manager: DialogManager):
    # Important: always set `mode=StartMode.RESET_STACK` you don't want to stack dialogs
    await dialog_manager.start(MySG.main, mode=StartMode.RESET_STACK)

Last step, you need to start your bot as usual:

from aiogram import executor

if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

Summary:

from aiogram import Bot, Dispatcher, executor
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.types import Message

from aiogram_dialog import Window, Dialog, DialogRegistry, DialogManager, StartMode
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const

storage = MemoryStorage()
bot = Bot(token='BOT TOKEN HERE')
dp = Dispatcher(bot, storage=storage)
registry = DialogRegistry(dp)


class MySG(StatesGroup):
    main = State()


main_window = Window(
    Const("Hello, unknown person"),
    Button(Const("Useless button"), id="nothing"),
    state=MySG.main,
)
dialog = Dialog(main_window)
registry.register(dialog)


@dp.message_handler(commands=["start"])
async def start(m: Message, dialog_manager: DialogManager):
    await dialog_manager.start(MySG.main, mode=StartMode.RESET_STACK)


if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

The result will look like:

_images/quickstart.png