You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

304 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- coding: utf-8 -*-
"""
:authors: python273, Helow19274, prostomarkeloff
:license: Apache License, Version 2.0, see LICENSE file
:copyright: (c) 2019 python273
"""
from enum import Enum
from .utils import sjson_dumps
MAX_BUTTONS_ON_LINE = 5
MAX_DEFAULT_LINES = 10
MAX_INLINE_LINES = 6
class VkKeyboardColor(Enum):
""" Возможные цвета кнопок """
#: Синяя
PRIMARY = 'primary'
#: Белая
SECONDARY = 'secondary'
#: Красная
NEGATIVE = 'negative'
#: Зелёная
POSITIVE = 'positive'
class VkKeyboardButton(Enum):
""" Возможные типы кнопки """
#: Кнопка с текстом
TEXT = "text"
#: Кнопка с местоположением
LOCATION = "location"
#: Кнопка с оплатой через VKPay
VKPAY = "vkpay"
#: Кнопка с приложением VK Apps
VKAPPS = "open_app"
#: Кнопка с ссылкой
OPENLINK = "open_link"
#: Callback-кнопка
CALLBACK = "callback"
class VkKeyboard(object):
""" Класс для создания клавиатуры для бота (https://vk.com/dev/bots_docs_3)
:param one_time: Если True, клавиатура исчезнет после нажатия на кнопку
:type one_time: bool
"""
__slots__ = ('one_time', 'lines', 'keyboard', 'inline')
def __init__(self, one_time=False, inline=False):
self.one_time = one_time
self.inline = inline
self.lines = [[]]
self.keyboard = {
'one_time': self.one_time,
'inline': self.inline,
'buttons': self.lines
}
def get_keyboard(self):
""" Получить json клавиатуры """
return sjson_dumps(self.keyboard)
@classmethod
def get_empty_keyboard(cls):
""" Получить json пустой клавиатуры.
Если отправить пустую клавиатуру, текущая у пользователя исчезнет.
"""
keyboard = cls()
keyboard.keyboard['buttons'] = []
return keyboard.get_keyboard()
def add_button(self, label, color=VkKeyboardColor.SECONDARY, payload=None):
""" Добавить кнопку с текстом.
Максимальное количество кнопок на строке - MAX_BUTTONS_ON_LINE
:param label: Надпись на кнопке и текст, отправляющийся при её нажатии.
:type label: str
:param color: цвет кнопки.
:type color: VkKeyboardColor or str
:param payload: Параметр для callback api
:type payload: str or list or dict
"""
current_line = self.lines[-1]
if len(current_line) >= MAX_BUTTONS_ON_LINE:
raise ValueError(f'Max {MAX_BUTTONS_ON_LINE} buttons on a line')
color_value = color
if isinstance(color, VkKeyboardColor):
color_value = color_value.value
if payload is not None and not isinstance(payload, str):
payload = sjson_dumps(payload)
button_type = VkKeyboardButton.TEXT.value
current_line.append({
'color': color_value,
'action': {
'type': button_type,
'payload': payload,
'label': label,
}
})
def add_callback_button(self, label, color=VkKeyboardColor.SECONDARY, payload=None):
""" Добавить callback-кнопку с текстом.
Максимальное количество кнопок на строке - MAX_BUTTONS_ON_LINE
:param label: Надпись на кнопке и текст, отправляющийся при её нажатии.
:type label: str
:param color: цвет кнопки.
:type color: VkKeyboardColor or str
:param payload: Параметр для callback api
:type payload: str or list or dict
"""
current_line = self.lines[-1]
if len(current_line) >= MAX_BUTTONS_ON_LINE:
raise ValueError(f'Max {MAX_BUTTONS_ON_LINE} buttons on a line')
color_value = color
if isinstance(color, VkKeyboardColor):
color_value = color_value.value
if payload is not None and not isinstance(payload, str):
payload = sjson_dumps(payload)
button_type = VkKeyboardButton.CALLBACK.value
current_line.append({
'color': color_value,
'action': {
'type': button_type,
'payload': payload,
'label': label,
}
})
def add_location_button(self, payload=None):
""" Добавить кнопку с местоположением.
Всегда занимает всю ширину линии.
:param payload: Параметр для callback api
:type payload: str or list or dict
"""
current_line = self.lines[-1]
if len(current_line) != 0:
raise ValueError(
'This type of button takes the entire width of the line'
)
if payload is not None and not isinstance(payload, str):
payload = sjson_dumps(payload)
button_type = VkKeyboardButton.LOCATION.value
current_line.append({
'action': {
'type': button_type,
'payload': payload
}
})
def add_vkpay_button(self, hash, payload=None):
""" Добавить кнопку с оплатой с помощью VKPay.
Всегда занимает всю ширину линии.
:param hash: Параметры платежа VKPay и ID приложения
(в поле aid) разделённые &
:type hash: str
:param payload: Параметр для совместимости со старыми клиентами
:type payload: str or list or dict
"""
current_line = self.lines[-1]
if len(current_line) != 0:
raise ValueError(
'This type of button takes the entire width of the line'
)
if payload is not None and not isinstance(payload, str):
payload = sjson_dumps(payload)
button_type = VkKeyboardButton.VKPAY.value
current_line.append({
'action': {
'type': button_type,
'payload': payload,
'hash': hash
}
})
def add_vkapps_button(self, app_id, owner_id, label, hash, payload=None):
""" Добавить кнопку с приложением VK Apps.
Всегда занимает всю ширину линии.
:param app_id: Идентификатор вызываемого приложения с типом VK Apps
:type app_id: int
:param owner_id: Идентификатор сообщества, в котором установлено
приложение, если требуется открыть в контексте сообщества
:type owner_id: int
:param label: Название приложения, указанное на кнопке
:type label: str
:param hash: хэш для навигации в приложении, будет передан в строке
параметров запуска после символа #
:type hash: str
:param payload: Параметр для совместимости со старыми клиентами
:type payload: str or list or dict
"""
current_line = self.lines[-1]
if len(current_line) != 0:
raise ValueError(
'This type of button takes the entire width of the line'
)
if payload is not None and not isinstance(payload, str):
payload = sjson_dumps(payload)
button_type = VkKeyboardButton.VKAPPS.value
current_line.append({
'action': {
'type': button_type,
'app_id': app_id,
'owner_id': owner_id,
'label': label,
'payload': payload,
'hash': hash
}
})
def add_openlink_button(self, label, link, payload=None):
""" Добавить кнопку с ссылкой
Максимальное количество кнопок на строке - MAX_BUTTONS_ON_LINE
:param label: Надпись на кнопке
:type label: str
:param link: ссылка, которую необходимо открыть по нажатию на кнопку
:type link: str
:param payload: Параметр для callback api
:type payload: str or list or dict
"""
current_line = self.lines[-1]
if len(current_line) >= MAX_BUTTONS_ON_LINE:
raise ValueError(f'Max {MAX_BUTTONS_ON_LINE} buttons on a line')
if payload is not None and not isinstance(payload, str):
payload = sjson_dumps(payload)
button_type = VkKeyboardButton.OPENLINK.value
current_line.append({
'action': {
'type': button_type,
'link': link,
'label': label,
'payload': payload
}
})
def add_line(self):
""" Создаёт новую строку, на которой можно размещать кнопки.
Максимальное количество строк:
Стандартное отображение - MAX_DEFAULT_LINES;
Inline-отображение - MAX_INLINE_LINES.
"""
if self.inline:
if len(self.lines) >= MAX_INLINE_LINES:
raise ValueError(f'Max {MAX_INLINE_LINES} lines for inline keyboard')
else:
if len(self.lines) >= MAX_DEFAULT_LINES:
raise ValueError(f'Max {MAX_DEFAULT_LINES} lines for default keyboard')
self.lines.append([])