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:
Split data retrieving and message rendering
Unite rendering buttons and processing clicks
Better states routing
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.filters.state import StatesGroup, State
class MySG(StatesGroup):
main = State()
Create at least one window with buttons or text:
from aiogram.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
from aiogram.fsm.storage.memory import MemoryStorage
storage = MemoryStorage()
bot = Bot(token='BOT TOKEN HERE')
dp = Dispatcher(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(commands=["start"])
async def start(message: 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:
if __name__ == '__main__':
dp.run_polling(bot, skip_updates=True)
Summary:
from aiogram import Bot, Dispatcher
from aiogram.filters.state import StatesGroup, State
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import Message
from aiogram_dialog import (
Dialog, DialogManager, DialogRegistry, StartMode, Window,
)
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const
storage = MemoryStorage()
bot = Bot(token='BOT TOKEN HERE')
dp = Dispatcher(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(commands=["start"])
async def start(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(MySG.main, mode=StartMode.RESET_STACK)
if __name__ == '__main__':
dp.run_polling(bot, skip_updates=True)
The result will look like: