Giter Club home page Giter Club logo

aiogram_dialog's People

Contributors

abrikk avatar bomzheg avatar bondarev avatar bralbral avatar brewbytes-dev avatar chirizxc avatar codwizer avatar darksidecat avatar fregat17 avatar hilorioze avatar hum4noidx avatar ismirnov-aligntech avatar ivankirpichnikov avatar kurokoka551 avatar lamroy95 avatar latand avatar lubaskinc0de avatar myown-del avatar prostmich avatar q-user avatar samwarden avatar searchcore avatar shalmeo avatar t3m8ch avatar tappress avatar tishka17 avatar vladyslav49 avatar vlkorsakov avatar yarqr avatar yuriimotov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aiogram_dialog's Issues

Get items list from dialog manager or state

First of all, thank you @Tishka17 for your great work.

Description
I want to create something like Store Bucket, where user can write manually item that he needs, and this item that he adds will appear in Store Bucket.

  • Items in bucket limited to 5
  • User can interact with each item in the bucket, interaction means showing the item (just write it name e.x.) and removing the item from bucket
  • From scratch, the bucket for each user empty, and after interaction with a bot, the user can add some items and then manage them.

Questions

  1. How I can interact with StateGroup or data_getter for showing user's bucket if it's empty by default and user should add this item manually?
        Select(
            Format("{item}"),
            items=[], # How to get list of items from state like 'ManageItemsSG.show_items'?
            item_id_getter=lambda x: x,
            id="Item",
            on_click=show_item,
        ),
  1. How to save user's progress after he added few items and for example Cancelled interaction with the dialogue window? Are StartMode.NORMAL will help?
async def show_items(m: Message, dialog_manager: DialogManager):
    # Will StartMode.NORMAL save user's items list?
    await dialog_manager.start(ManageItemsSG.show_items, mode=StartMode.NORMAL)

My code:

import asyncio
import logging

from aiogram import Bot, Dispatcher
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 (
    Dialog, DialogManager, DialogRegistry, Window, StartMode, ChatEvent
)
from aiogram_dialog.widgets.input import MessageInput
from aiogram_dialog.widgets.kbd import (
    Button, Back, Cancel, Row, Select
)
from aiogram_dialog.widgets.text import Const, Format

API_TOKEN = "API_TOKEN"

class ManageItemsSG(StatesGroup):
    show_items = State()
    item_manager = State()
    new_item = State()

async def get_item_list(dialog_manager: DialogManager, **kwargs):
    Item = dialog_manager.current_context().dialog_data.get("Item", None)
    return {
        "Item": Item,
    }

async def add_item_request(c: ChatEvent, select: Select, dialog_manager: DialogManager):
    await dialog_manager.start(ManageItemsSG.new_item)


async def add_item(m: Message, dialog: Dialog, dialog_manager: DialogManager):
    dialog_manager.current_context().dialog_data["Item"] = m.text
    await m.answer(f"Your Item '{m.text}' added")
    await dialog_manager.start(ManageItemsSG.show_items, mode=StartMode.NORMAL)


async def show_item(c: ChatEvent, select: Select, dialog_manager: DialogManager, item_id: str):
    dialog_manager.current_context().dialog_data["Item"] = item_id
    await dialog_manager.dialog().next(dialog_manager)

async def show_item_data(c: ChatEvent, select: Select, dialog_manager: DialogManager):
    Item = dialog_manager.current_context().dialog_data.get("Item", "")
    await c.message.answer(f"Show data for: {Item}")
    await dialog_manager.done()

async def remove_item(c: ChatEvent, select: Select, dialog_manager: DialogManager):
    Item = dialog_manager.current_context().dialog_data.get("Item", "")
    await c.message.answer(f"Item {Item} removed")
    await dialog_manager.done()

dial_items_manager = Dialog(
    Window(
        'Your item list',
        Select(
            Format("{item}"),
            items=[], # How to get list of items from state like 'ManageItemsSG.show_items'?
            item_id_getter=lambda x: x,
            id="Item",
            on_click=show_item,
        ),
        Row(
            Button(
                Const('Add item to list'),
                id="add_item",
                on_click=add_item_request,
            )
        ),
        Cancel(),
        state=ManageItemsSG.show_items,
        getter=get_item_list,
    ),
    Window(
        Format("What to do with Item {Item}?"),
        Row(
            Back(),
            Button(Const("Show Item"), on_click=show_item_data, id="show_item_data"),
            Button(Const("Remove Item"), on_click=remove_item, id="remove_item"),
        ),
        state=ManageItemsSG.item_manager,
        getter=get_item_list,
    ),
    Window(
        Const("Write Item which need to add"),
        MessageInput(add_item),
        state=ManageItemsSG.new_item,
        getter=get_item_list,
    ),
)

async def show_items(m: Message, dialog_manager: DialogManager):
    # Will StartMode.NORMAL save user's items list?
    await dialog_manager.start(ManageItemsSG.show_items, mode=StartMode.NORMAL)

async def main():
    # real main
    logging.basicConfig(level=logging.INFO)
    logging.getLogger("aiogram_dialog").setLevel(logging.DEBUG)
    storage = MemoryStorage()
    bot = Bot(token=API_TOKEN)
    dp = Dispatcher(bot, storage=storage)
    registry = DialogRegistry(dp)
    dp.register_message_handler(show_items, text="/show_items", state="*")
    registry.register(dial_items_manager)

    await dp.start_polling()


if __name__ == '__main__':
    asyncio.run(main())

Thanks for any your response.

Dynamic defaults for widgets

We want to see some widgets filled on dialog start.

Probably we can pass defaults through window getter or other way for all current existing statefull widgets

List text widget

Widget to render list of items as text. Format must get same variables as in Select button widget.

Usage example:

List(Format("* [{n}] {item.name}"), item="users", sep="\n")

Prototype to start with:

class List(Text):
    def __init__(self, field: str, when: WhenCondition = None):
        super().__init__(when)
        self.field = field

    async def _render_text(self, data: Dict, manager: DialogManager) -> str:
        return "\n".join(data[self.field])

Need help: How to modify user context variables from external task

Hi, I'm working to integrate aiogram-dialog with IoT project. The basic idea is to read temperature from device and show into Telegram bot (It is a MQTT/Telegram integration).

I would like if someone could give me an example to understand how to change an specific user context variable from a task periodic added by me. In my working example I have did it but using global variables, which is not the best solution.
Also I have readed about middleware class but I didn't understand if it has something to do here.
I will appreciate any kind of help.

import asyncio
import logging
import random

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

from aiogram_dialog import Dialog, DialogManager, Window, DialogRegistry, BaseDialogManager, \
    StartMode
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const, Multi, Progress, Format

API_TOKEN = "YOUR TOKEN"

temperature = 0

# ---------------------------------------------------------------------------------

# States
class MainSG(StatesGroup):
    get_temp = State()

# Getter
async def get_bg_data(dialog_manager: DialogManager, **kwargs):
    return {
        "temp": dialog_manager.current_context().dialog_data.get("temp", 0),
    }

async def refresh_temp(c: CallbackQuery, button: Button, manager: DialogManager):
    await manager.update({
            "temp": temperature ,
        })

main_menu = Dialog(
    Window(
        Const("Clik to obtain temperature"),
        Button(Format("Your temp:  {temp} °C"), id="b1", on_click=refresh_temp ),
        state=MainSG.get_temp,
        getter=get_bg_data
    ),
)

async def start(m: Message, dialog_manager: DialogManager):
    await dialog_manager.start(MainSG.get_temp, mode=StartMode.RESET_STACK)
 
logging.basicConfig(level=logging.INFO)
logging.getLogger("aiogram_dialog").setLevel(logging.DEBUG)
storage = MemoryStorage()
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot, storage=storage)
registry = DialogRegistry(dp)
registry.register(main_menu)
dp.register_message_handler(start, text="/start", state="*")

async def main():
    await dp.start_polling()

# MyTask Function that receive temperature and pass to context variables
async def periodic(sleep_for):
    global temperature
    while True:
        ID = 111111111  # Simulated ID from know user linked to device
        # -----------------------------------
        # Here I thin we must add the magic but at the moment I'm using
        # a global variable
        temperature = random.randint(20,35)   # simulate temperature reading
        # -----------------------------------
        await asyncio.sleep(sleep_for)
   
async def runner():
    await asyncio.gather(main(),periodic(2))

if __name__ == '__main__':
    asyncio.run(runner())

Graph rendering

Example:

from typing import List, Sequence, Tuple

from aiogram.dispatcher.filters.state import State
from graphviz import Digraph

from aiogram_dialog import Dialog
from aiogram_dialog.widgets.kbd import Group, Back, Cancel, Start, SwitchTo, Next


def edge(dot, state1, state2, *args, **kwargs):
    dot.edge(str(id(state1)), str(id(state2)), *args, **kwargs)


def walk_keyboard(dot, dialog, starts: List[Tuple[State, State]], current_state: State, keyboards: Sequence):
    for kbd in keyboards:
        if isinstance(kbd, Group):
            walk_keyboard(dot, dialog, starts, current_state, kbd.buttons)
        elif isinstance(kbd, Start):
            edge(dot, current_state, kbd.state, label="start")
        elif isinstance(kbd, SwitchTo):
            edge(dot, current_state, kbd.state, label="switch")
        elif isinstance(kbd, Next):
            new_state = dialog.states[dialog.states.index(current_state) + 1]
            edge(dot, current_state, new_state, label="next")
        elif isinstance(kbd, Back):
            new_state = dialog.states[dialog.states.index(current_state) - 1]
            edge(dot, current_state, new_state, label="back")
        elif isinstance(kbd, Cancel):
            for from_, to_ in starts:
                if to_.group == current_state.group:
                    edge(dot, current_state, from_, label="cancel")


def find_starts(current_state, keyboards: Sequence):
    for kbd in keyboards:
        if isinstance(kbd, Group):
            yield from find_starts(current_state, kbd.buttons)
        elif isinstance(kbd, Start):
            yield current_state, kbd.state


def render(dialogs: List[Dialog]):
    dot = Digraph(name='AiogramDialog', engine='fdp')
    dot.attr(label='Aiogram Dialog')
    dot.attr(fontname='Ubuntu')
    dot.attr(fontcolor='#000088')
    dot.attr(fontcolor='#000088')
    for dialog in dialogs:
        with dot.subgraph(name=f"cluster_{dialog.states_group_name()}") as subgraph:
            subgraph.attr(label=dialog.states_group_name())
            subgraph.attr(style='filled', color='#f0f0f0')
            for window in dialog.windows.values():
                subgraph.node(str(id(window.get_state())), window.get_state().state)

    starts = []
    for dialog in dialogs:
        for window in dialog.windows.values():
            starts.extend(find_starts(window.get_state(), [window.keyboard]))

    for dialog in dialogs:
        for window in dialog.windows.values():
            walk_keyboard(dot, dialog, starts, window.get_state(), [window.keyboard])
    dot.render("graph")  # filename will be `graph.pdf`


if __name__ == '__main__':
    render([
        # here put you dialogs
    ])

Documentation

  • Help about each widget type
    • Text
      • Const
      • Format
      • Multi
      • Case
      • Jinja
      • Progress
      • List
    • Keyboard
      • Button
      • Url
      • SwitchState
      • Next, Back
      • Start, Cancel
      • Group, Row
      • Checkbox
      • Select
    • Media
      • StaticMedia
      • DynamicMedia
      • MediaSCroll
    • Inputs:
      • MessageInput
      • TextInput
  • Reply keyboards
  • Working with widget data
  • Working with dialog data
  • Inter-dialog communication (start data, result)
  • Compatibility with normal handlers
  • Background tasks
  • Creating custom widgets
  • Best practice and deisgn patterns

Index Error in dialogs.py ! next ! method

    async def next(self, manager: DialogManager):
        if not manager.current_context():
            raise ValueError("No intent")
        print(self.states)
        print(self.states.index(manager.current_context().state))
        print(self.states.index(manager.current_context().state) + 1)
        new_state = self.states[self.states.index(manager.current_context().state) + 1]
        await self.switch_to(new_state, manager)

When I'm pressing scroll arrows -> throwing an index error.
Here is the output with the additional print statements

[<State 'Link[0.0.1:1'>, <State 'Link[0.0.1:2'>]
1
2
Task exception was never retrieved
future: <Task finished name='Task-28' coro=<Dispatcher._process_polling_updates() done, defined at /Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py:409> exception=IndexError('list index out of range')>
Traceback (most recent call last):
  File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 417, in _process_polling_updates
    for responses in itertools.chain.from_iterable(await self.process_updates(updates, fast)):
  File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 238, in process_updates
    return await asyncio.gather(*tasks)
  File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
    response = await handler_obj.handler(*args, **partial_data)
  File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 286, in process_update
    return await self.callback_query_handlers.notify(update.callback_query)
  File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
    response = await handler_obj.handler(*args, **partial_data)
  File "/Users/mac/Documents/PycharmProjects/CustomBot/main.py", line 321, in callback
    await dialog_manager.dialog().next(dialog_manager)
  File "/Users/mac/Library/Caches/pypoetry/virtualenvs/custombot-VvSOzSsp-py3.9/lib/python3.9/site-packages/aiogram_dialog/dialog.py", line 78, in next
    new_state = self.states[self.states.index(manager.current_context().state) + 1]
IndexError: list index out of range

Interactive dialogs preview

It is possible to generate HTML preview for all windows, so user can view it from any place without using telegram.

Requirements for user:

  • user must provide example data for getter
  • user must provide example widget states (depends on widget)
  • user must provide example start data for dialog

Requirements for reuslt:

  • Only one window is visible at moment
  • Any window can be accessed by clicking a separate button
  • All text is rendered with provided example data
  • Bot and window parse_mode is used for correct rendering
  • All buttons that switch state must switch window as well. Other actions are not working.
  • Must be a separate mark if window requires text input

Calendar does not support RedisStorage2

# /app/test.py
from aiogram import Bot, Dispatcher, executor
from aiogram.contrib.fsm_storage.redis import RedisStorage2
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
from datetime import date

from aiogram.types import CallbackQuery

from aiogram_dialog import DialogManager
from aiogram_dialog.widgets.kbd import Calendar


async def on_date_selected(c: CallbackQuery, widget, manager: DialogManager, selected_date: date):
    await c.answer(str(selected_date))


storage = RedisStorage2('redis')
bot = Bot(token='TOKEN')
dp = Dispatcher(bot, storage=storage)
registry = DialogRegistry(dp)


class MySG(StatesGroup):
    main = State()


main_window = Window(
    Const("Hello, unknown person"),
    Calendar(id='calendar', on_click=on_date_selected),
    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)
sid@83cfd5fbfc97:/app$ python test.py 
Updates were skipped successfully.
Task exception was never retrieved
future: <Task finished name='Task-9' coro=<Dispatcher._process_polling_updates() done, defined at /home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py:409> exception=TypeError('Object of type date is not JSON serializable')>
Traceback (most recent call last):
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 417, in _process_polling_updates
    for responses in itertools.chain.from_iterable(await self.process_updates(updates, fast)):
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 238, in process_updates
    return await asyncio.gather(*tasks)
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
    response = await handler_obj.handler(*args, **partial_data)
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/dispatcher.py", line 259, in process_update
    return await self.message_handlers.notify(update.message)
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/handler.py", line 129, in notify
    await self.dispatcher.middleware.trigger(f"post_process_{self.middleware_key}",
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/middlewares.py", line 53, in trigger
    await app.trigger(action, args)
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/dispatcher/middlewares.py", line 106, in trigger
    await handler(*args)
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram_dialog/context/intent_filter.py", line 66, in on_post_process_message
    await proxy.save_context(data.pop(CONTEXT_KEY))
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram_dialog/context/storage.py", line 45, in save_context
    await self.storage.set_data(
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/contrib/fsm_storage/redis.py", line 307, in set_data
    await redis.set(key, json.dumps(data), expire=self._data_ttl)
  File "/home/sid/.local/lib/python3.9/site-packages/aiogram/utils/json.py", line 43, in dumps
    return json.dumps(data, ensure_ascii=False)
  File "/usr/local/lib/python3.9/json/__init__.py", line 234, in dumps
    return cls(
  File "/usr/local/lib/python3.9/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/lib/python3.9/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/lib/python3.9/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type date is not JSON serializable

"loading.py" example brakes when write something

I have started to play around this wondeful library. I have found that "loading.py" example brakes when you write something while the progress bar is working, it duplicate the progress bar as response with different values eachones. What could be the problem? I can not find it.

Thanks!

Add Photo widget

How about to add new widget Photo (to add photo in Window)?
Using like a:

Object data in text widgets

There is not enough widget with the ability to format text with object data. For instance:

Window(
    FormatFromObj('Hello, {obj.from_user.first_name}')  # obj is instance of CallbackQuery or Message
)

unhandled MessageNotModified if user clicks very fast

MessageNotModified appears on quick presses, not depending on min_selected

File "/home/tishka17/src/aiogram_dialog/aiogram_dialog/dialog.py", line 119, in _callback_handler
await self.show(dialog_manager)
File "/home/tishka17/src/aiogram_dialog/aiogram_dialog/dialog.py", line 104, in show
message = await window.show(self, manager)
File "/home/tishka17/src/aiogram_dialog/aiogram_dialog/window.py", line 66, in show
return await event.message.edit_text(
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/types/message.py", line 2526, in edit_text
return await self.bot.edit_message_text(
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/bot.py", line 2216, in edit_message_text
result = await self.request(api.Methods.EDIT_MESSAGE_TEXT, payload)
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/base.py", line 208, in request
return await api.make_request(self.session, self.server, self.__token, method, data, files,
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/api.py", line 140, in make_request
return check_result(method, response.content_type, response.status, await response.text())
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/bot/api.py", line 115, in check_result
exceptions.BadRequest.detect(description)
File "/home/tishka17/src/aiogram_dialog/venv/lib/python3.8/site-packages/aiogram/utils/exceptions.py", line 139, in detect
raise err(cls.text or description)
aiogram.utils.exceptions.MessageNotModified: Message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message

[Bug] Multiselect widget is not clickable if min_selected is not null

Example from docs:

import operator

from aiogram_dialog.widgets.kbd import Multiselect
from aiogram_dialog.widgets.text import Format


# let's assume this is our window data getter
async def get_data(**kwargs):
    fruits = [
        ("Apple", '1'),
        ("Pear", '2'),
        ("Orange", '3'),
        ("Banana", '4'),
    ]
    return {
        "fruits": fruits,
        "count": len(fruits),
    }


fruits_kbd = Multiselect(
    Format("✓ {item[0]}"),  # E.g `✓ Apple`
    Format("{item[0]}"),
    id="m_fruits",
    item_id_getter=operator.itemgetter(1),
    items="fruits",
)

So try to set a min_selected parameter:

fruits_kbd = Multiselect(
    Format("✓ {item[0]}"),  # E.g `✓ Apple`
    Format("{item[0]}"),
    id="m_fruits",
    item_id_getter=operator.itemgetter(1),
    items="fruits",
    min_selected=3
)

Bug: if you click on item it will be marked as selected (✓ Apple), second click on item (to disable them) will thrown an error:

aiogram.utils.exceptions.MessageNotModified: Message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message

Simplify widgets creation

  • str can be automatically converted to Const (or Format?)
  • list/tuple can be converted to Mutli/Group
  • ItemIdGetter in Select probably can be replaced with Format-like text widget

library globally intercepts callback_query_handler, how fix?

i created a couple of forms, through aiogram_dialog everything works great. But I also want to use the custom shapes I created. By creating a handler @ dp.callback_query_handler (lambda call: True) All callbacks are handled by aiogram_dialog.registry or so. My global @ dp.callback_query_handler (lambda call: True) doesn't fire. How to register my custom callback? The goal is to use a callback for the InlineKeyboardButton

@dp.message_handler()
async def echo(message: types.Message):
    inline = [InlineKeyboardButton('Управление', callback_data='control'),
              InlineKeyboardButton('Настройка', callback_data='settings')]

    markup = InlineKeyboardMarkup(inline, one_time_keyboard=True, resize_keyboard=True)

    await message.answer(message.text, reply_markup=markup)


#this block of code is ignored when callback
@dp.callback_query_handler(lambda call: True)
async def process_callback_button(callback_query: types.CallbackQuery):
    await bot.answer_callback_query(callback_query.id)
    await bot.send_message(callback_query.from_user.id, 'Тест калбек!')



async def main():
        storage = MemoryStorage()
        bot = Bot(token=API_TOKEN)
        dp = Dispatcher(bot, storage=storage)
        dp.register_message_handler(pwd_handler, text="/start", state="*")
        registry = DialogRegistry(dp) #
        registry.register(main_window)
        registry.register(pwd_window)
        await dp.start_polling()

. . .

Enhancement of ScrollingGroup 📜

Hey there 👋

Currently, the ScrollingGroup doesn't stop to scroll when it gets to the last page.

So instead of stopping and doing nothing, it scrolls through the same page "in-place". Whenever you want to go back --> you have to click the same amount of times.

Would be nice to have no scrolling as a default

Required inputs

Do not allow clicking "next" until user fills Rasio/Multiselect or other widgets.

More usecases?

Split html and plain text formatting

  1. New method render_html added to render_text
  2. For Const/Format render_html should do autoescaping.
  3. For Const/Format mode=html disables escaping and forbids rendering as simple text
  4. For Jinja only html is supported
  5. Progressbar works like Format
  6. Window check its parse_mode or bot's default and choses which method of renderig it should call
  7. Keyboards always call render_text

Deal with callback.answer

Sometimes we need to show alert on button click.
It is better to do automatically.

Also it can be done when clicking only some buttons in select

Dialog for user in multiuser chat

в диалогах встроить возможность диалог открыть для юзера или для чата. То есть записать user_id в Intent и при обработке сообщений/кликов проверять его

Stateless dialogs

Dialogs, that can work without switching global state.

Idea:

  1. Attach Intent id to callback data
  2. Forbid usage of message_handler
  3. Save dialog state separately. Maybe in dialog context as internal data
  4. Store intent outside of current stack. Probably, have multiple stacks

Dialog launch mode

launch_mod для диалогов, влияющий на стек. Например:

  • SingleInstance - Если в стеке уже есть такой диалог, все вышележащие вместе с ним удаляются и новый кладется поверх
  • SingleTop - если наверху стека такой же диалог как новый, он закрывается перед открытием нового

[BUG] Inline mode.

If in an answer of inline mode(input_message_content), add the inline button (with registered dialogs), then when it is pressed, middleware will give the error.

File "/home/*****/PycharmProjects/*****/venv/lib/python3.9/site-packages/aiogram_dialog/context/intent_filter.py", line 104, in on_pre_process_callback_query
    chat_id=event.message.chat.id,
AttributeError: 'NoneType' object has no attribute 'chat' 

Temporary solution:
In aiogram_dialog/context/intent_filter.py in on_pre_process_callback_query add the following line

chat_id=event.message.chat.id if hasattr(event, "chat") else ""

last_media_id in stack

last_media_id по идеи должен быть типа MediaId а не int, но вот нужно както с циклическим импортом разобратся

Including recurring task into loop question

Hi @Tishka17 ! , first of all cograts for your project, I'm very impressed about it.

I 'm new in programming, but may be you can give me a help.
I'm working in an IOT application where I have to create a task named periodic(sleep_for) in which I read a tuple (Telegram ID user , str message) from a queue every 5 seconds and then message is sent to user id.

In this simplified code I have created a task to do something similar.

How could I implement the task execution working under aiogram_dialog ?

Thank you!!

import logging
import asyncio
import aiogram.utils.markdown as md
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ParseMode
from aiogram.utils import executor

logging.basicConfig(level=logging.INFO)

# ---------------------------------------------------
API_TOKEN = 'Your TOKEN'
YOUR_ID = xxxxxxx36
# ---------------------------------------------------

bot = Bot(token=API_TOKEN)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)

class Form(StatesGroup):
    name = State()  
    looper = State() 

@dp.message_handler(commands='start')
async def cmd_start(message: types.Message):
    #Conversation's entry point
    await Form.name.set()
    await message.reply("Hi there! What's your name?")

@dp.message_handler(state=Form.name)
async def process_name(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        data['name'] = message.text
        await message.reply("Your name is:" + str( data['name'] + "\nWrite anything and I will replay your name"))
        await Form.looper.set()
    
@dp.message_handler(state=Form.looper)
async def process_loop(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        await message.reply("Your name is:" + str( data['name']))
        await Form.looper.set()

async def periodic(sleep_for):
    global YOUR_ID
    counter = 0
    while True:
        msg = "Counter: " + str (counter)
        counter +=1
        await bot.send_message(chat_id=YOUR_ID, text = msg , disable_notification=True)
        await asyncio.sleep(sleep_for)

if __name__ == '__main__':
    loop= asyncio.get_event_loop ()
    loop.create_task (periodic(5))
    executor.start_polling(dp, skip_updates=True)

ContextProcessor

Kinda of middleware, that injects data into result of data getter

can it work in Python 3.7?

Hi, first THX for the library :-)
i try to use python 3.7 and aiogram-dialog 1.0.2
If i use
from aiogram_dialog import Dialog
i get the error
ImportError: cannot import name 'Protocol' from 'typing'
seems that on line 3 in dialog.py
from typing import Protocol
is used
according to my typing.pyi - file, and some other documentation

# Protocol is only present in 3.8 and later, but mypy needs it unconditionally
Protocol: _SpecialForm = ...

Protocol needs at least python 3.8
ist there any older version that support python 3.7?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.