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

2 months ago
# -*- 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([])