mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-10 19:46:36 +03:00
Create a custom.Button class and support send_message(buttons=...)
This commit is contained in:
parent
a50d013ee6
commit
8c28be04bc
|
@ -45,3 +45,11 @@ telethon\.tl\.custom\.forward module
|
|||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
telethon\.tl\.custom\.button module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: telethon.tl.custom.button
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
|
@ -13,10 +13,11 @@ from .telegrambaseclient import TelegramBaseClient
|
|||
from .users import UserMethods # Required for everything
|
||||
from .messageparse import MessageParseMethods # Required for messages
|
||||
from .uploads import UploadMethods # Required for messages to send files
|
||||
from .updates import UpdateMethods # Required for buttons (register callbacks)
|
||||
from .buttons import ButtonMethods # Required for messages to use buttons
|
||||
from .messages import MessageMethods
|
||||
from .chats import ChatMethods
|
||||
from .dialogs import DialogMethods
|
||||
from .downloads import DownloadMethods
|
||||
from .auth import AuthMethods
|
||||
from .updates import UpdateMethods
|
||||
from .telegramclient import TelegramClient
|
||||
|
|
48
telethon/client/buttons.py
Normal file
48
telethon/client/buttons.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
from .updates import UpdateMethods
|
||||
from ..tl import types, custom
|
||||
from .. import utils
|
||||
|
||||
|
||||
class ButtonMethods(UpdateMethods):
|
||||
def _build_reply_markup(self, buttons):
|
||||
if buttons is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
if buttons.SUBCLASS_OF_ID == 0xe2e10ef2:
|
||||
return buttons # crc32(b'ReplyMarkup'):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if not utils.is_list_like(buttons):
|
||||
buttons = [[buttons]]
|
||||
elif not utils.is_list_like(buttons[0]):
|
||||
buttons = [buttons]
|
||||
|
||||
is_inline = False
|
||||
is_normal = False
|
||||
|
||||
rows = []
|
||||
for row in buttons:
|
||||
current = []
|
||||
for button in row:
|
||||
inline = custom.Button._is_inline(button)
|
||||
is_inline |= inline
|
||||
is_normal |= not inline
|
||||
if isinstance(button, custom.Button):
|
||||
# TODO actually register callbacks
|
||||
button = button.button
|
||||
|
||||
if button.SUBCLASS_OF_ID == 0xbad74a3:
|
||||
# 0xbad74a3 == crc32(b'KeyboardButton')
|
||||
current.append(button)
|
||||
|
||||
if current:
|
||||
rows.append(types.KeyboardButtonRow(current))
|
||||
|
||||
if is_inline == is_normal and is_normal:
|
||||
raise ValueError('You cannot mix inline with normal buttons')
|
||||
elif is_inline:
|
||||
return types.ReplyInlineMarkup(rows)
|
||||
elif is_normal:
|
||||
return types.ReplyKeyboardMarkup(rows)
|
|
@ -8,13 +8,14 @@ from async_generator import async_generator, yield_
|
|||
|
||||
from .messageparse import MessageParseMethods
|
||||
from .uploads import UploadMethods
|
||||
from .buttons import ButtonMethods
|
||||
from .. import utils
|
||||
from ..tl import types, functions, custom
|
||||
|
||||
__log__ = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MessageMethods(UploadMethods, MessageParseMethods):
|
||||
class MessageMethods(ButtonMethods, UploadMethods, MessageParseMethods):
|
||||
|
||||
# region Public methods
|
||||
|
||||
|
@ -333,7 +334,7 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
async def send_message(
|
||||
self, entity, message='', *, reply_to=None,
|
||||
parse_mode=utils.Default, link_preview=True, file=None,
|
||||
force_document=False, clear_draft=False):
|
||||
force_document=False, clear_draft=False, buttons=None):
|
||||
"""
|
||||
Sends the given message to the specified entity (user/chat/channel).
|
||||
|
||||
|
@ -382,8 +383,15 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
Whether the existing draft should be cleared or not.
|
||||
Has no effect when sending a file.
|
||||
|
||||
buttons (`list`, `custom.Button <telethon.tl.custom.button.Button>`,
|
||||
:tl:`KeyboardButton`):
|
||||
The matrix (list of lists), row list or button to be shown
|
||||
after sending the message. This parameter will only work if
|
||||
you have signed in as a bot. You can also pass your own
|
||||
:tl:`ReplyMarkup` here.
|
||||
|
||||
Returns:
|
||||
The sent `telethon.tl.custom.message.Message`.
|
||||
The sent `custom.Message <telethon.tl.custom.message.Message>`.
|
||||
"""
|
||||
if file is not None:
|
||||
return await self.send_file(
|
||||
|
@ -417,12 +425,17 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
else:
|
||||
reply_id = None
|
||||
|
||||
if buttons is None:
|
||||
markup = message.reply_markup
|
||||
else:
|
||||
markup = self._build_reply_markup(buttons)
|
||||
|
||||
request = functions.messages.SendMessageRequest(
|
||||
peer=entity,
|
||||
message=message.message or '',
|
||||
silent=message.silent,
|
||||
reply_to_msg_id=reply_id,
|
||||
reply_markup=message.reply_markup,
|
||||
reply_markup=markup,
|
||||
entities=message.entities,
|
||||
clear_draft=clear_draft,
|
||||
no_webpage=not isinstance(
|
||||
|
@ -438,7 +451,8 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
entities=msg_ent,
|
||||
no_webpage=not link_preview,
|
||||
reply_to_msg_id=utils.get_message_id(reply_to),
|
||||
clear_draft=clear_draft
|
||||
clear_draft=clear_draft,
|
||||
reply_markup=self._build_reply_markup(buttons)
|
||||
)
|
||||
|
||||
result = await self(request)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
from . import (
|
||||
UpdateMethods, AuthMethods, DownloadMethods, DialogMethods,
|
||||
ChatMethods, MessageMethods, UploadMethods, MessageParseMethods,
|
||||
UserMethods
|
||||
AuthMethods, DownloadMethods, DialogMethods, ChatMethods,
|
||||
MessageMethods, ButtonMethods, UpdateMethods, UploadMethods,
|
||||
MessageParseMethods, UserMethods
|
||||
)
|
||||
|
||||
|
||||
class TelegramClient(
|
||||
UpdateMethods, AuthMethods, DownloadMethods, DialogMethods,
|
||||
ChatMethods, MessageMethods, UploadMethods, MessageParseMethods,
|
||||
UserMethods
|
||||
AuthMethods, DownloadMethods, DialogMethods, ChatMethods,
|
||||
MessageMethods, ButtonMethods, UpdateMethods, UploadMethods,
|
||||
MessageParseMethods, UserMethods
|
||||
):
|
||||
pass
|
||||
|
|
|
@ -4,3 +4,4 @@ from .input_sized_file import InputSizedFile
|
|||
from .messagebutton import MessageButton
|
||||
from .forward import Forward
|
||||
from .message import Message
|
||||
from .button import Button
|
||||
|
|
129
telethon/tl/custom/button.py
Normal file
129
telethon/tl/custom/button.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
from .. import types
|
||||
|
||||
|
||||
class Button:
|
||||
"""
|
||||
Helper class to allow defining ``reply_markup`` when
|
||||
sending a message with inline or keyboard buttons.
|
||||
|
||||
You should make use of the defined class methods to create button
|
||||
instances instead making them yourself (i.e. don't do ``Button(...)``
|
||||
but instead use methods line `Button.inline(...) <inline>` etc.)
|
||||
|
||||
You can use `inline`, `switch_inline` and `url`
|
||||
together to create inline buttons (under the message).
|
||||
|
||||
You can use `text`, `request_location` and `request_phone`
|
||||
together to create a reply markup (replaces the user keyboard).
|
||||
|
||||
You **cannot** mix the two type of buttons together,
|
||||
and it will error if you try to do so.
|
||||
|
||||
The text for all buttons may be at most 142 characters.
|
||||
If more characters are given, Telegram will cut the text
|
||||
to 128 characters and add the ellipsis (…) character as
|
||||
the 129.
|
||||
"""
|
||||
def __init__(self, button, callback=None):
|
||||
self.button = button
|
||||
self.callback = callback
|
||||
self.is_inline = self._is_inline(button)
|
||||
|
||||
@classmethod
|
||||
def _is_inline(cls, button):
|
||||
"""
|
||||
Returns ``True`` if the button belongs to an inline keyboard.
|
||||
"""
|
||||
if isinstance(button, cls):
|
||||
return button.is_inline
|
||||
else:
|
||||
return isinstance(button, (
|
||||
types.KeyboardButtonCallback,
|
||||
types.KeyboardButtonSwitchInline,
|
||||
types.KeyboardButtonUrl
|
||||
))
|
||||
|
||||
@classmethod
|
||||
def inline(cls, text, callback=None, data=None):
|
||||
"""
|
||||
Creates a new inline button.
|
||||
|
||||
The `callback` parameter should be a function callback accepting
|
||||
a single parameter (the triggered event on click) if specified.
|
||||
Otherwise, you should register the event manually.
|
||||
|
||||
If `data` is omitted, the given `text` will be used as `data`.
|
||||
In any case `data` should be either ``bytes`` or ``str``.
|
||||
|
||||
Note that the given `data` must be less or equal to 64 bytes.
|
||||
If more than 64 bytes are passed as data, ``ValueError`` is raised.
|
||||
"""
|
||||
if not data:
|
||||
data = text.encode('utf-8')
|
||||
|
||||
if len(data) > 64:
|
||||
raise ValueError('Too many bytes for the data')
|
||||
|
||||
return cls(types.KeyboardButtonCallback(text, data), callback)
|
||||
|
||||
@classmethod
|
||||
def switch_inline(cls, text, query='', same_peer=False):
|
||||
"""
|
||||
Creates a new button to switch to inline query.
|
||||
|
||||
If `query` is given, it will be the default text to be used
|
||||
when making the inline query.
|
||||
|
||||
If ``same_peer is True`` the inline query will directly be
|
||||
set under the currently opened chat. Otherwise, the user will
|
||||
have to select a different dialog to make the query.
|
||||
"""
|
||||
return cls(types.KeyboardButtonSwitchInline(text, query, same_peer))
|
||||
|
||||
@classmethod
|
||||
def url(cls, text, url=None):
|
||||
"""
|
||||
Creates a new button to open the desired URL upon clicking it.
|
||||
|
||||
If no `url` is given, the `text` will be used as said URL instead.
|
||||
"""
|
||||
return cls(types.KeyboardButtonUrl(text, url or text))
|
||||
|
||||
@classmethod
|
||||
def text(cls, text):
|
||||
"""
|
||||
Creates a new button with the given text.
|
||||
"""
|
||||
return cls(types.KeyboardButton(text))
|
||||
|
||||
@classmethod
|
||||
def request_location(cls, text):
|
||||
"""
|
||||
Creates a new button that will request
|
||||
the user's location upon being clicked.
|
||||
"""
|
||||
return cls(types.KeyboardButtonRequestGeoLocation(text))
|
||||
|
||||
@classmethod
|
||||
def request_phone(cls, text):
|
||||
"""
|
||||
Creates a new button that will request
|
||||
the user's phone number upon being clicked.
|
||||
"""
|
||||
return cls(types.KeyboardButtonRequestPhone(text))
|
||||
|
||||
@classmethod
|
||||
def clear(cls):
|
||||
"""
|
||||
Clears all the buttons. When used, no other
|
||||
button should be present or it will be ignored.
|
||||
"""
|
||||
return types.ReplyKeyboardHide()
|
||||
|
||||
@classmethod
|
||||
def force_reply(cls):
|
||||
"""
|
||||
Forces a reply. If used, no other button
|
||||
should be present or it will be ignored.
|
||||
"""
|
||||
return types.ReplyKeyboardForceReply()
|
Loading…
Reference in New Issue
Block a user