diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index d240e322..9a4efc8c 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -555,6 +555,7 @@ def get_title_list(s: str) -> list: Bot keyboards ReplyKeyboardMarkup KeyboardButton + KeyboardButtonStyle ReplyKeyboardRemove InlineKeyboardMarkup InlineKeyboardButton diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 57883ee1..bd4ed922 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -1,6 +1,6 @@ from __future__ import annotations -__version__ = "v0.2.224.2" +__version__ = "v0.2.224.3" __license__ = "MIT License" from concurrent.futures.thread import ThreadPoolExecutor diff --git a/pyrogram/types/bots_and_keyboards/__init__.py b/pyrogram/types/bots_and_keyboards/__init__.py index a939d97e..90078fda 100644 --- a/pyrogram/types/bots_and_keyboards/__init__.py +++ b/pyrogram/types/bots_and_keyboards/__init__.py @@ -30,6 +30,7 @@ from .inline_keyboard_button_buy import InlineKeyboardButtonBuy from .inline_keyboard_markup import InlineKeyboardMarkup from .keyboard_button import KeyboardButton +from .keyboard_button_style import KeyboardButtonStyle from .login_url import LoginUrl from .menu_button import MenuButton from .menu_button_commands import MenuButtonCommands @@ -69,6 +70,7 @@ "InlineKeyboardButtonBuy", "InlineKeyboardMarkup", "KeyboardButton", + "KeyboardButtonStyle", "LoginUrl", "MenuButton", "MenuButtonCommands", diff --git a/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py b/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py index 24e6f28a..f65e19e2 100644 --- a/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py @@ -56,6 +56,9 @@ class InlineKeyboardButton(Object): copy_text (``str``, *optional*): A button that copies the text to the clipboard. + + style (:obj:`~pyrogram.types.KeyboardButtonStyle`, *optional*): + Button style. """ def __init__( @@ -71,6 +74,7 @@ def __init__( callback_game: types.CallbackGame | None = None, requires_password: bool | None = None, copy_text: str | None = None, + style: types.KeyboardButtonStyle | None = None, ) -> None: super().__init__() @@ -85,9 +89,12 @@ def __init__( self.callback_game = callback_game self.requires_password = requires_password self.copy_text = copy_text + self.style = style @staticmethod def read(b: raw.base.KeyboardButton): + style = types.KeyboardButtonStyle.read(getattr(b, "style", None)) + if isinstance(b, raw.types.KeyboardButtonCallback): # Try decode data to keep it as string, but if fails, fallback to bytes so we don't lose any information, # instead of decoding by ignoring/replacing errors. @@ -100,48 +107,63 @@ def read(b: raw.base.KeyboardButton): text=b.text, callback_data=data, requires_password=getattr(b, "requires_password", None), + style=style, ) if isinstance(b, raw.types.KeyboardButtonUrl): - return InlineKeyboardButton(text=b.text, url=b.url) + return InlineKeyboardButton(text=b.text, url=b.url, style=style) if isinstance(b, raw.types.KeyboardButtonUrlAuth): return InlineKeyboardButton( text=b.text, login_url=types.LoginUrl.read(b), + style=style, ) if isinstance(b, raw.types.KeyboardButtonUserProfile): - return InlineKeyboardButton(text=b.text, user_id=b.user_id) + return InlineKeyboardButton(text=b.text, user_id=b.user_id, style=style) if isinstance(b, raw.types.KeyboardButtonSwitchInline): if b.same_peer: return InlineKeyboardButton( text=b.text, switch_inline_query_current_chat=b.query, + style=style, ) - return InlineKeyboardButton(text=b.text, switch_inline_query=b.query) + return InlineKeyboardButton( + text=b.text, + switch_inline_query=b.query, + style=style, + ) if isinstance(b, raw.types.KeyboardButtonGame): return InlineKeyboardButton( text=b.text, callback_game=types.CallbackGame(), + style=style, ) if isinstance(b, raw.types.KeyboardButtonWebView): return InlineKeyboardButton( text=b.text, web_app=types.WebAppInfo(url=b.url), + style=style, ) if isinstance(b, raw.types.KeyboardButtonCopy): - return types.InlineKeyboardButton(text=b.text, copy_text=b.copy_text) + return types.InlineKeyboardButton( + text=b.text, + copy_text=b.copy_text, + style=style, + ) if isinstance(b, raw.types.KeyboardButtonBuy): return types.InlineKeyboardButtonBuy.read(b) return None async def write(self, client: pyrogram.Client): + style = self.style.write() if self.style else None + if self.callback_data is not None: # Telegram only wants bytes, but we are allowed to pass strings too, for convenience. data = ( @@ -154,27 +176,35 @@ async def write(self, client: pyrogram.Client): text=self.text, data=data, requires_password=self.requires_password, + style=style, ) if self.url is not None: - return raw.types.KeyboardButtonUrl(text=self.text, url=self.url) + return raw.types.KeyboardButtonUrl( + text=self.text, + url=self.url, + style=style, + ) if self.login_url is not None: return self.login_url.write( text=self.text, bot=await client.resolve_peer(self.login_url.bot_username or "self"), + style=style, ) if self.user_id is not None: return raw.types.InputKeyboardButtonUserProfile( text=self.text, user_id=await client.resolve_peer(self.user_id), + style=style, ) if self.switch_inline_query is not None: return raw.types.KeyboardButtonSwitchInline( text=self.text, query=self.switch_inline_query, + style=style, ) if self.switch_inline_query_current_chat is not None: @@ -182,19 +212,22 @@ async def write(self, client: pyrogram.Client): text=self.text, query=self.switch_inline_query_current_chat, same_peer=True, + style=style, ) if self.callback_game is not None: - return raw.types.KeyboardButtonGame(text=self.text) + return raw.types.KeyboardButtonGame(text=self.text, style=style) if self.web_app is not None: return raw.types.KeyboardButtonWebView( text=self.text, url=self.web_app.url, + style=style, ) if self.copy_text is not None: return raw.types.KeyboardButtonCopy( text=self.text, copy_text=self.copy_text, + style=style, ) return None diff --git a/pyrogram/types/bots_and_keyboards/inline_keyboard_button_buy.py b/pyrogram/types/bots_and_keyboards/inline_keyboard_button_buy.py index 7cb3b1bd..72603dd1 100644 --- a/pyrogram/types/bots_and_keyboards/inline_keyboard_button_buy.py +++ b/pyrogram/types/bots_and_keyboards/inline_keyboard_button_buy.py @@ -1,7 +1,7 @@ from __future__ import annotations import pyrogram -from pyrogram import raw +from pyrogram import raw, types from pyrogram.types.object import Object @@ -13,16 +13,30 @@ class InlineKeyboardButtonBuy(Object): text (``str``): Text of the button. If none of the optional fields are used, it will be sent as a message when the button is pressed. + + style (:obj:`~pyrogram.types.KeyboardButtonStyle`, *optional*): + Button style. """ - def __init__(self, text: str) -> None: + def __init__( + self, + text: str, + style: types.KeyboardButtonStyle | None = None, + ) -> None: super().__init__() self.text = str(text) + self.style = style @staticmethod def read(b): - return InlineKeyboardButtonBuy(text=b.text) + return InlineKeyboardButtonBuy( + text=b.text, + style=types.KeyboardButtonStyle.read(getattr(b, "style", None)), + ) async def write(self, _: pyrogram.Client): - return raw.types.KeyboardButtonBuy(text=self.text) + return raw.types.KeyboardButtonBuy( + text=self.text, + style=self.style.write() if self.style else None, + ) diff --git a/pyrogram/types/bots_and_keyboards/keyboard_button.py b/pyrogram/types/bots_and_keyboards/keyboard_button.py index 8cdf3b78..6d8ea4b8 100644 --- a/pyrogram/types/bots_and_keyboards/keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/keyboard_button.py @@ -35,6 +35,8 @@ class KeyboardButton(Object): button is pressed. The Web App will be able to send a “web_app_data” service message. Available in private chats only. + style (:obj:`~pyrogram.types.KeyboardButtonStyle`, *optional*): + Button style. """ def __init__( @@ -46,6 +48,7 @@ def __init__( | types.RequestPeerTypeChannel = None, request_user: types.RequestPeerTypeUser = None, web_app: types.WebAppInfo = None, + style: types.KeyboardButtonStyle = None, ) -> None: super().__init__() @@ -55,20 +58,27 @@ def __init__( self.request_chat = request_chat self.request_user = request_user self.web_app = web_app + self.style = style @staticmethod def read(b): + style = types.KeyboardButtonStyle.read(getattr(b, "style", None)) + if isinstance(b, raw.types.KeyboardButton): - return b.text + return KeyboardButton(text=b.text, style=style) if style else b.text if isinstance(b, raw.types.KeyboardButtonRequestPhone): - return KeyboardButton(text=b.text, request_contact=True) + return KeyboardButton(text=b.text, request_contact=True, style=style) if isinstance(b, raw.types.KeyboardButtonRequestGeoLocation): - return KeyboardButton(text=b.text, request_location=True) + return KeyboardButton(text=b.text, request_location=True, style=style) if isinstance(b, raw.types.KeyboardButtonSimpleWebView): - return KeyboardButton(text=b.text, web_app=types.WebAppInfo(url=b.url)) + return KeyboardButton( + text=b.text, + web_app=types.WebAppInfo(url=b.url), + style=style, + ) if isinstance(b, raw.types.KeyboardButtonRequestPeer): if isinstance(b.peer_type, raw.types.RequestPeerTypeBroadcast): @@ -79,6 +89,7 @@ def read(b): is_username=b.peer_type.has_username, max=b.max_quantity, ), + style=style, ) if isinstance(b.peer_type, raw.types.RequestPeerTypeChat): return KeyboardButton( @@ -90,6 +101,7 @@ def read(b): is_forum=b.peer_type.forum, max=b.max_quantity, ), + style=style, ) if isinstance(b.peer_type, raw.types.RequestPeerTypeUser): @@ -100,17 +112,24 @@ def read(b): is_premium=b.peer_type.premium, max=b.max_quantity, ), + style=style, ) return None return None def write(self): + style = self.style.write() if self.style else None + if self.request_contact: - return raw.types.KeyboardButtonRequestPhone(text=self.text) + return raw.types.KeyboardButtonRequestPhone(text=self.text, style=style) if self.request_location: - return raw.types.KeyboardButtonRequestGeoLocation(text=self.text) + return raw.types.KeyboardButtonRequestGeoLocation( + text=self.text, + style=style, + ) if self.request_chat: if isinstance(self.request_chat, types.RequestPeerTypeChannel): + # Note: InputKeyboardButtonRequestPeer doesn't have style in schema return raw.types.InputKeyboardButtonRequestPeer( text=self.text, button_id=self.request_chat.button_id, @@ -154,5 +173,6 @@ def write(self): return raw.types.KeyboardButtonSimpleWebView( text=self.text, url=self.web_app.url, + style=style, ) - return raw.types.KeyboardButton(text=self.text) + return raw.types.KeyboardButton(text=self.text, style=style) diff --git a/pyrogram/types/bots_and_keyboards/keyboard_button_style.py b/pyrogram/types/bots_and_keyboards/keyboard_button_style.py new file mode 100644 index 00000000..abc25d85 --- /dev/null +++ b/pyrogram/types/bots_and_keyboards/keyboard_button_style.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from pyrogram import raw +from pyrogram.types.object import Object + + +class KeyboardButtonStyle(Object): + """Button style. + + Parameters: + bg_primary (``bool``, *optional*): + Whether the button should be primary. + + bg_danger (``bool``, *optional*): + Whether the button should be danger. + + bg_success (``bool``, *optional*): + Whether the button should be success. + + icon (``int``, *optional*): + Custom icon for the button. + """ + + def __init__( + self, + *, + bg_primary: bool | None = None, + bg_danger: bool | None = None, + bg_success: bool | None = None, + icon: int | None = None, + ) -> None: + super().__init__() + + self.bg_primary = bg_primary + self.bg_danger = bg_danger + self.bg_success = bg_success + self.icon = icon + + @staticmethod + def read(b: raw.types.KeyboardButtonStyle) -> KeyboardButtonStyle | None: + if not b: + return None + + return KeyboardButtonStyle( + bg_primary=b.bg_primary, + bg_danger=b.bg_danger, + bg_success=b.bg_success, + icon=b.icon, + ) + + def write(self) -> raw.types.KeyboardButtonStyle: + return raw.types.KeyboardButtonStyle( + bg_primary=self.bg_primary, + bg_danger=self.bg_danger, + bg_success=self.bg_success, + icon=self.icon, + ) diff --git a/pyrogram/types/bots_and_keyboards/login_url.py b/pyrogram/types/bots_and_keyboards/login_url.py index 16619421..42f9eba5 100644 --- a/pyrogram/types/bots_and_keyboards/login_url.py +++ b/pyrogram/types/bots_and_keyboards/login_url.py @@ -60,11 +60,17 @@ def __init__( def read(b: raw.types.KeyboardButtonUrlAuth) -> LoginUrl: return LoginUrl(url=b.url, forward_text=b.fwd_text, button_id=b.button_id) - def write(self, text: str, bot: raw.types.InputUser): + def write( + self, + text: str, + bot: raw.types.InputUser, + style: raw.types.KeyboardButtonStyle | None = None, + ): return raw.types.InputKeyboardButtonUrlAuth( text=text, url=self.url, bot=bot, fwd_text=self.forward_text, request_write_access=self.request_write_access, + style=style, )