diff --git a/README.md b/README.md index 804610c4..a90e71b3 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Each window consists of: ```python -from aiogram.filters.state import StatesGroup, State +from aiogram.fsm.state import StatesGroup, State from aiogram_dialog.widgets.text import Format, Const from aiogram_dialog.widgets.kbd import Button from aiogram_dialog import Window @@ -84,7 +84,7 @@ Window( Window itself can do nothing, just prepares message. To use it you need dialog: ```python -from aiogram.filters.state import StatesGroup, State +from aiogram.fsm.state import StatesGroup, State from aiogram_dialog import Dialog, Window @@ -122,7 +122,7 @@ For example in `/start` command handler: async def user_start(message: Message, dialog_manager: DialogManager): await dialog_manager.start(MySG.first, mode=StartMode.RESET_STACK) -dp.message.register(user_start, F.text == "/start") +dp.message.register(user_start, CommandStart()) ``` > **Info:** Always set `mode=StartMode.RESET_STACK` in your top level start command. Otherwise, dialogs are stacked just as they do diff --git a/example/custom_media_url.py b/example/custom_media_url.py index 91792eca..1f169e95 100644 --- a/example/custom_media_url.py +++ b/example/custom_media_url.py @@ -4,12 +4,14 @@ from io import BytesIO from typing import Union + from aiogram import Bot, Dispatcher from aiogram.filters import CommandStart from aiogram.fsm.state import State, StatesGroup from aiogram.types import BufferedInputFile, ContentType, InputFile, Message from PIL import Image, ImageDraw, ImageFont + from aiogram_dialog import ( Dialog, DialogManager, setup_dialogs, StartMode, Window, @@ -20,15 +22,11 @@ from aiogram_dialog.widgets.media import StaticMedia from aiogram_dialog.widgets.text import Const + src_dir = os.path.normpath(os.path.join(__file__, os.path.pardir)) API_TOKEN = os.getenv("BOT_TOKEN") - - -class DialogSG(StatesGroup): - custom = State() - custom2 = State() - normal = State() +CUSTOM_URL_PREFIX = "my://" def draw(text) -> bytes: @@ -50,12 +48,15 @@ def draw(text) -> bytes: return io.read() -CUSTOM_URL_PREFIX = "my://" +class DialogSG(StatesGroup): + custom = State() + custom2 = State() + normal = State() class CustomMessageManager(MessageManager): async def get_media_source( - self, media: MediaAttachment, bot: Bot, + self, media: MediaAttachment, bot: Bot, ) -> Union[InputFile, str]: if media.file_id: return await super().get_media_source(media, bot) diff --git a/example/input_media_group.py b/example/input_media_group.py index e202b889..e54efac5 100644 --- a/example/input_media_group.py +++ b/example/input_media_group.py @@ -24,8 +24,11 @@ class Medias(StatesGroup): start = State() -async def on_input_photo(message: Message, widget: MessageInput, - dialog_manager: DialogManager): +async def on_input_photo( + message: Message, + widget: MessageInput, + dialog_manager: DialogManager, +): dialog_manager.dialog_data.setdefault("photos", []).append( (message.photo[-1].file_id, message.photo[-1].file_unique_id), ) @@ -72,8 +75,13 @@ async def getter(dialog_manager: DialogManager, **kwargs) -> dict: NumberedPager(scroll="pages", when=F["pages"] > 1), width=8, ), - Button(Format("🗑️ Delete photo #{media_number}"), id="del", - on_click=on_delete, when="media_count"), + Button( + Format("🗑️ Delete photo #{media_number}"), + id="del", + on_click=on_delete, + when="media_count", + # Alternative F['media_count'] + ), MessageInput(content_types=[ContentType.PHOTO], func=on_input_photo), getter=getter, state=Medias.start, diff --git a/example/launch_modes.py b/example/launch_modes.py index ced4047b..fb94bff3 100644 --- a/example/launch_modes.py +++ b/example/launch_modes.py @@ -86,9 +86,7 @@ async def main(): storage = MemoryStorage() bot = Bot(token=API_TOKEN) dp = Dispatcher(storage=storage) - dp.include_router(banner) - dp.include_router(product) - dp.include_router(main_menu) + dp.include_routers(banner, product, main_menu) dp.message.register(start, CommandStart()) setup_dialogs(dp) diff --git a/example/list_group.py b/example/list_group.py index cbbe5cef..e791a24b 100644 --- a/example/list_group.py +++ b/example/list_group.py @@ -10,11 +10,13 @@ from aiogram.types import Message from aiogram_dialog import ( - Dialog, DialogManager, LaunchMode, setup_dialogs, StartMode, SubManager, + Dialog, DialogManager, LaunchMode, + setup_dialogs, StartMode, SubManager, Window, ) from aiogram_dialog.widgets.kbd import ( - Checkbox, ListGroup, ManagedCheckbox, Radio, Row, + Checkbox, ListGroup, + ManagedCheckbox, Radio, Row, ) from aiogram_dialog.widgets.text import Const, Format diff --git a/example/loading.py b/example/loading.py index 9c1a6893..fd810716 100644 --- a/example/loading.py +++ b/example/loading.py @@ -9,7 +9,8 @@ from aiogram.types import CallbackQuery, Message from aiogram_dialog import ( - BaseDialogManager, Dialog, DialogManager, setup_dialogs, StartMode, Window, + BaseDialogManager, Dialog, DialogManager, + setup_dialogs, StartMode, Window, ) from aiogram_dialog.widgets.kbd import Button from aiogram_dialog.widgets.text import Const, Multi, Progress @@ -46,8 +47,11 @@ class MainSG(StatesGroup): main = State() -async def start_bg(callback: CallbackQuery, button: Button, - manager: DialogManager): +async def start_bg( + callback: CallbackQuery, + button: Button, + manager: DialogManager, +): await manager.start(Bg.progress) asyncio.create_task(background(callback, manager.bg())) diff --git a/example/mega/bot_dialogs/calendar.py b/example/mega/bot_dialogs/calendar.py index 0b43db1d..5101b89c 100644 --- a/example/mega/bot_dialogs/calendar.py +++ b/example/mega/bot_dialogs/calendar.py @@ -9,7 +9,8 @@ Calendar, CalendarScope, ManagedCalendar, SwitchTo, ) from aiogram_dialog.widgets.kbd.calendar_kbd import ( - CalendarDaysView, CalendarMonthView, CalendarScopeView, CalendarYearsView, + CalendarDaysView, CalendarMonthView, + CalendarScopeView, CalendarYearsView, DATE_TEXT, TODAY_TEXT, ) from aiogram_dialog.widgets.text import Const, Format, Text @@ -77,17 +78,19 @@ def _init_views(self) -> Dict[CalendarScope, CalendarScopeView]: async def on_date_clicked( - callback: ChatEvent, widget: ManagedCalendar, - manager: DialogManager, - selected_date: date, /, + callback: ChatEvent, + widget: ManagedCalendar, + manager: DialogManager, + selected_date: date, /, ): await callback.answer(str(selected_date)) async def on_date_selected( - callback: ChatEvent, widget: ManagedCalendar, - manager: DialogManager, - clicked_date: date, /, + callback: ChatEvent, + widget: ManagedCalendar, + manager: DialogManager, + clicked_date: date, /, ): selected = manager.dialog_data.setdefault(SELECTED_DAYS_KEY, []) serial_date = clicked_date.isoformat() diff --git a/example/mega/bot_dialogs/counter.py b/example/mega/bot_dialogs/counter.py index b4bc19a3..445d8066 100644 --- a/example/mega/bot_dialogs/counter.py +++ b/example/mega/bot_dialogs/counter.py @@ -19,8 +19,9 @@ async def getter(dialog_manager: DialogManager, **kwargs): async def on_text_click( - event: CallbackQuery, widget: ManagedCounter, - dialog_manager: DialogManager, + event: CallbackQuery, + widget: ManagedCounter, + dialog_manager: DialogManager, ) -> None: await event.answer(f"Value: {widget.get_value()}") diff --git a/example/mega/bot_dialogs/mutltiwidget.py b/example/mega/bot_dialogs/mutltiwidget.py index edefff3d..c9f07b03 100644 --- a/example/mega/bot_dialogs/mutltiwidget.py +++ b/example/mega/bot_dialogs/mutltiwidget.py @@ -1,6 +1,4 @@ -from aiogram_dialog import ( - Dialog, Window, -) +from aiogram_dialog import Dialog, Window from aiogram_dialog.widgets.kbd import Checkbox, Counter, Multiselect, Radio from aiogram_dialog.widgets.text import Const, Format from . import states diff --git a/example/mega/bot_dialogs/reply_buttons.py b/example/mega/bot_dialogs/reply_buttons.py index ea03d62d..1d4a341c 100644 --- a/example/mega/bot_dialogs/reply_buttons.py +++ b/example/mega/bot_dialogs/reply_buttons.py @@ -1,8 +1,7 @@ -from aiogram_dialog import ( - Dialog, Window, -) +from aiogram_dialog import Dialog, Window from aiogram_dialog.widgets.kbd import ( - Checkbox, Radio, RequestContact, RequestLocation, Row, + Checkbox, Radio, RequestContact, + RequestLocation, Row, ) from aiogram_dialog.widgets.markup.reply_keyboard import ReplyKeyboardFactory from aiogram_dialog.widgets.text import Const, Format @@ -12,7 +11,6 @@ reply_kbd_dialog = Dialog( Window( Const("Reply keyboard with multiple widgets.\n"), - Row( RequestContact(Const("👤 Send contact")), RequestLocation(Const("📍 Send location")), diff --git a/example/mega/bot_dialogs/scrolls.py b/example/mega/bot_dialogs/scrolls.py index fd9a391b..3e8c264a 100644 --- a/example/mega/bot_dialogs/scrolls.py +++ b/example/mega/bot_dialogs/scrolls.py @@ -1,13 +1,13 @@ import calendar from operator import itemgetter -from aiogram_dialog import ( - Dialog, DialogManager, Window, -) +from aiogram_dialog import Dialog, DialogManager, Window from aiogram_dialog.widgets.common import sync_scroll from aiogram_dialog.widgets.kbd import ( - CurrentPage, FirstPage, LastPage, Multiselect, NextPage, NumberedPager, - PrevPage, Row, ScrollingGroup, StubScroll, SwitchTo, + CurrentPage, FirstPage, LastPage, + Multiselect, NextPage, NumberedPager, + PrevPage, Row, ScrollingGroup, + StubScroll, SwitchTo, ) from aiogram_dialog.widgets.media import StaticMedia from aiogram_dialog.widgets.text import Const, Format, List, ScrollingText @@ -215,9 +215,7 @@ async def paging_getter(dialog_manager: DialogManager, **_kwargs): Format("Day by number is {day}"), StaticMedia(path=Format("media/{current_page}.png")), StubScroll(id=ID_STUB_SCROLL, pages="pages"), - NumberedPager( - scroll=ID_STUB_SCROLL, - ), + NumberedPager(scroll=ID_STUB_SCROLL), SCROLLS_MAIN_MENU_BUTTON, state=states.Scrolls.STUB, getter=paging_getter, diff --git a/example/mega/bot_dialogs/select.py b/example/mega/bot_dialogs/select.py index baf7d525..169e537f 100644 --- a/example/mega/bot_dialogs/select.py +++ b/example/mega/bot_dialogs/select.py @@ -5,7 +5,8 @@ from aiogram_dialog import Dialog, DialogManager, Window from aiogram_dialog.widgets.kbd import ( - Column, Multiselect, Radio, Select, SwitchTo, Toggle, + Column, Multiselect, Radio, + Select, SwitchTo, Toggle, ) from aiogram_dialog.widgets.text import Const, Format, List from . import states @@ -49,10 +50,10 @@ def fruit_id_getter(fruit: Fruit) -> str: async def on_item_selected( - callback: CallbackQuery, - widget: Any, - manager: DialogManager, - selected_item: str, + callback: CallbackQuery, + widget: Any, + manager: DialogManager, + selected_item: str, ): await callback.answer(selected_item) diff --git a/example/mega/bot_dialogs/switch.py b/example/mega/bot_dialogs/switch.py index 9399fcd5..80cbd0a2 100644 --- a/example/mega/bot_dialogs/switch.py +++ b/example/mega/bot_dialogs/switch.py @@ -11,6 +11,15 @@ CHECKBOX_ID = "chk" EMOJI_ID = "emoji" + +async def data_getter( + dialog_manager: DialogManager, **_kwargs, +) -> Dict[str, Any]: + return { + "option": dialog_manager.find(CHECKBOX_ID).is_checked(), + "emoji": dialog_manager.find(EMOJI_ID).get_checked(), + } + main_window = Window( HEADER, Const("Step 1. Press Next"), @@ -18,6 +27,7 @@ MAIN_MENU_BUTTON, state=states.Switch.MAIN, ) + input_window = Window( HEADER, Const("Step 2. Select options"), @@ -38,16 +48,6 @@ state=states.Switch.INPUT, ) - -async def data_getter( - dialog_manager: DialogManager, **_kwargs, -) -> Dict[str, Any]: - return { - "option": dialog_manager.find(CHECKBOX_ID).is_checked(), - "emoji": dialog_manager.find(EMOJI_ID).get_checked(), - } - - last_window = Window( HEADER, Const("Step 3. Your data:"), @@ -64,6 +64,7 @@ async def data_getter( state=states.Switch.LAST, getter=data_getter, ) + switch_dialog = Dialog( main_window, input_window, diff --git a/example/multistack.py b/example/multistack.py index 99acc4a3..4af52ff3 100644 --- a/example/multistack.py +++ b/example/multistack.py @@ -11,7 +11,8 @@ from aiogram.types import CallbackQuery, Message from aiogram_dialog import ( - Dialog, DialogManager, setup_dialogs, StartMode, Window, + Dialog, DialogManager, + setup_dialogs, StartMode, Window, ) from aiogram_dialog.widgets.input import MessageInput from aiogram_dialog.widgets.kbd import Button, Cancel, Multiselect, Start @@ -47,8 +48,11 @@ async def name_handler( await message.answer(f"Nice to meet you, {message.text}") -async def on_click(callback: CallbackQuery, button: Button, - manager: DialogManager): +async def on_click( + callback: CallbackQuery, + button: Button, + manager: DialogManager, +): counter = manager.dialog_data.get("counter", 0) manager.dialog_data["counter"] = counter + 1 @@ -69,8 +73,12 @@ async def on_click(callback: CallbackQuery, button: Button, Format("Last text: {last_text}\n"), Format("{now}"), Button(Const("Click me!"), id="btn1", on_click=on_click), - Start(Const("Start new stack"), id="s1", - mode=StartMode.NEW_STACK, state=DialogSG.greeting), + Start( + Const("Start new stack"), + mode=StartMode.NEW_STACK, + state=DialogSG.greeting, + id="s1", + ), multi, Cancel(), # Inputs work only in default stack diff --git a/example/scrolls.py b/example/scrolls.py index d743d268..437d7250 100644 --- a/example/scrolls.py +++ b/example/scrolls.py @@ -11,11 +11,14 @@ from aiogram.types import Message from aiogram_dialog import ( - Dialog, DialogManager, setup_dialogs, StartMode, Window, + Dialog, DialogManager, + setup_dialogs, StartMode, Window, ) from aiogram_dialog.widgets.kbd import ( - CurrentPage, FirstPage, LastPage, Multiselect, NextPage, NumberedPager, - PrevPage, Row, ScrollingGroup, StubScroll, SwitchTo, + CurrentPage, FirstPage, LastPage, + Multiselect, NextPage, NumberedPager, + PrevPage, Row, ScrollingGroup, + StubScroll, SwitchTo, ) from aiogram_dialog.widgets.text import Const, Format, List, ScrollingText @@ -80,8 +83,11 @@ async def paging_getter(dialog_manager: DialogManager, **_kwargs): dialog = Dialog( Window( Const("Scrolling variant demo. Please, select an option:"), - SwitchTo(Const("Default Pager"), id="default", - state=DialogSG.DEFAULT_PAGER), + SwitchTo( + Const("Default Pager"), + state=DialogSG.DEFAULT_PAGER, + id="default", + ), SwitchTo(Const("Pager options"), id="pagers", state=DialogSG.PAGERS), SwitchTo(Const("Text list scroll"), id="text", state=DialogSG.LIST), SwitchTo(Const("Text scroll"), id="text", state=DialogSG.TEXT), diff --git a/example/simple.py b/example/simple.py index e6096a70..7a939a61 100644 --- a/example/simple.py +++ b/example/simple.py @@ -11,8 +11,9 @@ from redis.asyncio.client import Redis from aiogram_dialog import ( - ChatEvent, Dialog, DialogManager, setup_dialogs, - ShowMode, StartMode, Window, + ChatEvent, Dialog, DialogManager, + setup_dialogs, ShowMode, + StartMode, Window, ) from aiogram_dialog.api.exceptions import UnknownIntent, UnknownState from aiogram_dialog.widgets.input import MessageInput @@ -40,8 +41,11 @@ async def get_data(dialog_manager: DialogManager, **kwargs): } -async def name_handler(message: Message, message_input: MessageInput, - manager: DialogManager): +async def name_handler( + message: Message, + message_input: MessageInput, + manager: DialogManager, +): if manager.is_preview(): await manager.next() return @@ -50,13 +54,19 @@ async def name_handler(message: Message, message_input: MessageInput, await manager.next() -async def other_type_handler(message: Message, message_input: MessageInput, - manager: DialogManager): +async def other_type_handler( + message: Message, + message_input: MessageInput, + manager: DialogManager, +): await message.answer("Text is expected") -async def on_finish(callback: CallbackQuery, button: Button, - manager: DialogManager): +async def on_finish( + callback: CallbackQuery, + button: Button, + manager: DialogManager, +): if manager.is_preview(): await manager.done() return @@ -64,9 +74,12 @@ async def on_finish(callback: CallbackQuery, button: Button, await manager.done() -async def on_age_changed(callback: ChatEvent, select: Any, - manager: DialogManager, - item_id: str): +async def on_age_changed( + callback: ChatEvent, + select: Any, + manager: DialogManager, + item_id: str, +): manager.dialog_data["age"] = item_id await manager.next() diff --git a/example/subdialog.py b/example/subdialog.py index 914fd337..cb1a3102 100644 --- a/example/subdialog.py +++ b/example/subdialog.py @@ -10,12 +10,14 @@ from aiogram.types import CallbackQuery, Message from aiogram_dialog import ( - Data, Dialog, DialogManager, setup_dialogs, StartMode, Window, + Data, Dialog, DialogManager, + setup_dialogs, StartMode, Window, ) from aiogram_dialog.tools import render_preview, render_transitions from aiogram_dialog.widgets.input import MessageInput from aiogram_dialog.widgets.kbd import ( - Back, Button, Cancel, Group, Next, Row, Start, + Back, Button, Cancel, + Group, Next, Row, Start, ) from aiogram_dialog.widgets.text import Const, Format, Multi @@ -29,7 +31,9 @@ class NameSG(StatesGroup): async def name_handler( - message: Message, widget: MessageInput, manager: DialogManager, + message: Message, + widget: MessageInput, + manager: DialogManager, ): manager.dialog_data["name"] = message.text await manager.next() @@ -41,8 +45,11 @@ async def get_name_data(dialog_manager: DialogManager, **kwargs): } -async def on_finish(callback: CallbackQuery, button: Button, - manager: DialogManager): +async def on_finish( + callback: CallbackQuery, + button: Button, + manager: DialogManager, +): await manager.done({"name": manager.dialog_data["name"]}) @@ -73,8 +80,11 @@ class MainSG(StatesGroup): main = State() -async def process_result(start_data: Data, result: Any, - manager: DialogManager): +async def process_result( + start_data: Data, + result: Any, + manager: DialogManager, +): if result: manager.dialog_data["name"] = result["name"] @@ -85,8 +95,11 @@ async def get_main_data(dialog_manager: DialogManager, **kwargs): } -async def on_reset_name(callback: CallbackQuery, button: Button, - manager: DialogManager): +async def on_reset_name( + callback: CallbackQuery, + button: Button, + manager: DialogManager, +): del manager.dialog_data["name"] @@ -98,8 +111,13 @@ async def on_reset_name(callback: CallbackQuery, button: Button, ), Group( Start(Const("Enter name"), id="set", state=NameSG.input), - Button(Const("Reset name"), id="reset", - on_click=on_reset_name, when="name"), + Button( + Const("Reset name"), + id="reset", + on_click=on_reset_name, + when="name", + # Alternative F['name'] + ), ), state=MainSG.main, getter=get_main_data,