Перейти к содержанию

UI

Keyboard

Keyboard

Keyboard(*buttons, one_time=True, inline=False)

Bases: UIBuilder

Генерирует клавиатуру на основе переданных кнопок. Чтобы добавить новый ряд, передайте Ellipsis (три точки) вместо кнопки. Клавиатуру можно создать и в другом стиле: вызывая .add() для каждой новой кнопки и .new_line() для перехода на следующий ряд

Настройки one_time и inline передаются при самой инициализации

Объект можно напрямую передать в поле keyboard при отправке сообщения

Source code in vkflow\ui\keyboard.py
def __init__(
    self, *buttons: InitializedButton | EllipsisType, one_time: bool = True, inline: bool = False
) -> None:
    self.scheme = {"inline": inline, "buttons": [[]]}

    if not inline:
        self.scheme.update(one_time=one_time)

    self._build(*buttons)

empty staticmethod

empty()

Returns:

Type Description
str

Пустую клавиатуру. Используйте, чтобы удалить текущую

Source code in vkflow\ui\keyboard.py
@staticmethod
def empty() -> str:
    """
    Returns:
        Пустую клавиатуру. Используйте, чтобы удалить текущую
    """
    return '{"buttons":[],"one_time":true}'

add

add(button)

Добавляет в клавиатуру кнопку

Parameters:

Name Type Description Default
button InitializedButton

Кнопка, которую надо добавить

required

Returns:

Type Description
Keyboard

Текущая клавиатура

Source code in vkflow\ui\keyboard.py
def add(self, button: InitializedButton) -> Keyboard:
    """
    Добавляет в клавиатуру кнопку

    Arguments:
        button: Кнопка, которую надо добавить

    Returns:
        Текущая клавиатура
    """
    self.scheme["buttons"][-1].append(button.scheme)
    return self

new_line

new_line()

Добавляет новый ряд клавиатуре

Source code in vkflow\ui\keyboard.py
def new_line(self) -> Keyboard:
    """
    Добавляет новый ряд клавиатуре
    """
    if not self.scheme["buttons"][-1]:
        raise ValueError(
            "Cannot add a new line: the last line is empty. "
            "Add at least one button before creating a new line."
        )

    self.scheme["buttons"].append([])
    return self

add_button

add_button(
    text=None,
    color="secondary",
    *,
    in_row=True,
    button=None,
    **kwargs
)

Добавляет кнопку в клавиатуру

Parameters:

Name Type Description Default
text str | None

Текст кнопки (для text кнопок)

None
color str

Цвет кнопки (positive, negative, primary, secondary)

'secondary'
in_row bool

Находится ли в строке с другими кнопками или занимает всю строку

True
button InitializedButton | None

Готовая кнопка (если передана, text и color игнорируются)

None
**kwargs Any

Дополнительные параметры для кнопки (payload и т.п.)

{}

Returns:

Type Description
Keyboard

Текущая клавиатура

Source code in vkflow\ui\keyboard.py
def add_button(
    self,
    text: str | None = None,
    color: str = "secondary",
    *,
    in_row: bool = True,
    button: InitializedButton | None = None,
    **kwargs: typing.Any,
) -> Keyboard:
    """
    Добавляет кнопку в клавиатуру

    Arguments:
        text: Текст кнопки (для text кнопок)
        color: Цвет кнопки (positive, negative, primary, secondary)
        in_row: Находится ли в строке с другими кнопками или занимает всю строку
        button: Готовая кнопка (если передана, text и color игнорируются)
        **kwargs: Дополнительные параметры для кнопки (payload и т.п.)

    Returns:
        Текущая клавиатура
    """
    from vkflow.ui.button import Button

    if button is None:
        if text is None:
            raise ValueError("Either 'text' or 'button' must be provided")

        button = Button.text(text, **kwargs)

        if hasattr(button, color):
            button = getattr(button, color)()

    if not in_row and self.scheme["buttons"][-1]:
        self.new_line()

    self.add(button)

    if not in_row:
        self.new_line()

    return self

View

View

View(*, timeout=180, inline=True)

Interactive view with callback buttons.

Supports optional FSM integration via fsm_storage class attribute. When set, button callbacks can receive an 'fsm' parameter that will be automatically injected with FSMContext.

Examples:

Basic view (no FSM)

class MyView(View): @button(label="Click me") async def click(self, ctx): await ctx.show_snackbar("Clicked!")

View with FSM

class OrderView(View): fsm_storage = my_storage # Set FSM storage

@button(label="Confirm")
async def confirm(self, ctx, fsm):
    data = await fsm.finish()
    await ctx.show_snackbar(f"Order: {data}")
Source code in vkflow\ui\view.py
def __init__(self, *, timeout: float | None = 180, inline: bool = True):
    self.id = str(uuid.uuid4())
    self.timeout = timeout
    self.inline = inline
    self.message: SentMessage | None = None
    self._buttons: dict[str, ViewButton] = {}
    self._finished = False
    self._dispatching = False
    self._timeout_task: asyncio.Task | None = None
    self._wait_future: asyncio.Future | None = None
    self._store: ViewStore | None = None

    for name in dir(self):
        attr = getattr(type(self), name, None)

        if isinstance(attr, ViewButton):
            self._buttons[attr.custom_id] = attr

get_fsm

get_fsm(interaction)

Get FSMContext for an interaction.

Parameters:

Name Type Description Default
interaction CallbackButtonPressed

The callback button interaction

required

Returns:

Type Description
Any

FSMContext instance

Raises:

Type Description
ValueError

If fsm_storage is not configured

Source code in vkflow\ui\view.py
def get_fsm(self, interaction: CallbackButtonPressed) -> typing.Any:
    """
    Get FSMContext for an interaction.

    Args:
        interaction: The callback button interaction

    Returns:
        FSMContext instance

    Raises:
        ValueError: If fsm_storage is not configured
    """
    if self.fsm_storage is None:
        raise ValueError("fsm_storage not configured on View. Set it as a class attribute.")

    from vkflow.app.fsm import Context as FSMContext

    return FSMContext.from_message(
        self.fsm_storage,
        interaction,
        strategy=self.fsm_strategy,
    )

Button

Button

InteractiveButton

InteractiveButton

InteractiveButton(
    label,
    *,
    color="secondary",
    payload=None,
    custom_id=None
)

Bases: InitializedButton

Source code in vkflow\ui\interactive_button.py
def __init__(
    self,
    label: str,
    *,
    color: str = "secondary",
    payload: dict | str | None = None,
    custom_id: str | None = None,
):
    self.custom_id = custom_id or self.__class__.__name__

    self._label = label
    self._color = color

    self._base_payload = payload or {}

    if isinstance(self._base_payload, dict):
        callback_payload = {
            **self._base_payload,
            "__button_class": self.__class__.__name__,
            "__button_id": self.custom_id,
        }
    else:
        callback_payload = self._base_payload

    super().__init__(
        label=label,
        type="callback",
        payload=callback_payload,
    )

    self.scheme["color"] = color

Carousel

Carousel(gen)

Bases: UIBuilder

Source code in vkflow\ui\carousel.py
def __init__(self, gen: typing.Callable[..., typing.Iterator[Element]]) -> None:
    self._gen = gen
    self.scheme = {
        "type": "carousel",
        "elements": [elem.scheme for elem in self._gen()],
    }

Element

Element

Element(
    *, buttons, title=None, description=None, photo_id=None
)

Bases: UIBuilder

Source code in vkflow\ui\carousel.py
def __init__(
    self,
    *,
    buttons: list[InitializedButton],
    title: str | None = None,
    description: str | None = None,
    photo_id: str | Photo | None = None,
) -> None:
    self.scheme = {"buttons": [but.scheme for but in buttons]}
    if title is not None:
        self.scheme.update(title=title)

    if description is not None:
        self.scheme.update(description=description)

    if photo_id is not None:
        if isinstance(photo_id, Photo):
            photo_id = photo_id.represent_as_api_param()
        self.scheme.update(photo_id=photo_id)

ButtonColor

ButtonColor

Bases: StrEnum

ButtonType

ButtonType

Bases: StrEnum