Skip to content

Commit e2e3f40

Browse files
author
Pyrogram-Mod - Dev
committed
Fix type hints and parameters for styled inline keyboards.
- Corrected request_write_access type hint in LoginUrl (str -> bool) - Applied InputKeyboardButtonUserProfile input_user fix - Added style support to all inline button types - Updated documentation with comprehensive examples
1 parent ece8c95 commit e2e3f40

3 files changed

Lines changed: 220 additions & 22 deletions

File tree

docs/source/start/examples/styled_keyboards.rst

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ styled_keyboards
33

44
This example shows how to use the new KeyboardButtonStyle to create styled keyboard buttons with custom colors and icons.
55

6-
Available since Layer 224, keyboard buttons can now have custom styles including background colors (primary, danger, success) and custom emoji icons.
6+
Available since Layer 224, keyboard buttons can now have custom styles including background colors (primary, danger, success) and custom emoji icons. This works for both ReplyKeyboardMarkup (regular keyboards) and InlineKeyboardMarkup (inline buttons).
7+
8+
Reply Keyboard Examples
9+
-----------------------
710

811
.. code-block:: python
912
@@ -110,4 +113,173 @@ Available since Layer 224, keyboard buttons can now have custom styles including
110113
)
111114
112115
116+
app.run(main())
117+
118+
Inline Keyboard Examples
119+
------------------------
120+
121+
.. code-block:: python
122+
123+
from pyrogram import Client
124+
from pyrogram.types import (
125+
InlineKeyboardMarkup,
126+
InlineKeyboardButton,
127+
KeyboardButtonStyle,
128+
WebAppInfo,
129+
LoginUrl
130+
)
131+
132+
# Create a client using your bot token
133+
app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
134+
135+
136+
async def main():
137+
async with app:
138+
# Example 1: Callback button with primary (blue) background
139+
await app.send_message(
140+
"me", # Edit this
141+
"Callback button example:",
142+
reply_markup=InlineKeyboardMarkup(
143+
[[
144+
InlineKeyboardButton(
145+
text="Click Me",
146+
callback_data="clicked",
147+
style=KeyboardButtonStyle(bg_primary=True)
148+
)
149+
]]
150+
)
151+
)
152+
153+
# Example 2: URL button with danger (red) style
154+
await app.send_message(
155+
"me", # Edit this
156+
"URL button example:",
157+
reply_markup=InlineKeyboardMarkup(
158+
[[
159+
InlineKeyboardButton(
160+
text="Open Website",
161+
url="https://example.com",
162+
style=KeyboardButtonStyle(bg_danger=True)
163+
)
164+
]]
165+
)
166+
)
167+
168+
# Example 3: Switch inline query button with success (green) style
169+
await app.send_message(
170+
"me", # Edit this
171+
"Inline query buttons:",
172+
reply_markup=InlineKeyboardMarkup(
173+
[
174+
[
175+
InlineKeyboardButton(
176+
text="Search in other chat",
177+
switch_inline_query="search query",
178+
style=KeyboardButtonStyle(bg_primary=True)
179+
)
180+
],
181+
[
182+
InlineKeyboardButton(
183+
text="Search here",
184+
switch_inline_query_current_chat="search query",
185+
style=KeyboardButtonStyle(bg_success=True)
186+
)
187+
]
188+
]
189+
)
190+
)
191+
192+
# Example 4: User profile button with custom emoji icon
193+
await app.send_message(
194+
"me", # Edit this
195+
"User profile button:",
196+
reply_markup=InlineKeyboardMarkup(
197+
[[
198+
InlineKeyboardButton(
199+
text="View Profile",
200+
user_id=123456789, # Replace with actual user ID
201+
style=KeyboardButtonStyle(
202+
icon=5368324170671202286 # Custom emoji ID
203+
)
204+
)
205+
]]
206+
)
207+
)
208+
209+
# Example 5: WebApp button with primary style
210+
await app.send_message(
211+
"me", # Edit this
212+
"WebApp button:",
213+
reply_markup=InlineKeyboardMarkup(
214+
[[
215+
InlineKeyboardButton(
216+
text="Open WebApp",
217+
web_app=WebAppInfo(url="https://example.com/webapp"),
218+
style=KeyboardButtonStyle(bg_primary=True)
219+
)
220+
]]
221+
)
222+
)
223+
224+
# Example 6: Login URL button with style
225+
await app.send_message(
226+
"me", # Edit this
227+
"Login button:",
228+
reply_markup=InlineKeyboardMarkup(
229+
[[
230+
InlineKeyboardButton(
231+
text="Login with Telegram",
232+
login_url=LoginUrl(
233+
url="https://example.com/login",
234+
forward_text="Login to Example",
235+
request_write_access=True
236+
),
237+
style=KeyboardButtonStyle(bg_success=True)
238+
)
239+
]]
240+
)
241+
)
242+
243+
# Example 7: All button types in one keyboard
244+
await app.send_message(
245+
"me", # Edit this
246+
"Complete keyboard with all styled button types:",
247+
reply_markup=InlineKeyboardMarkup(
248+
[
249+
# Row 1: Callback buttons
250+
[
251+
InlineKeyboardButton(
252+
text="✅ Confirm",
253+
callback_data="confirm",
254+
style=KeyboardButtonStyle(bg_success=True)
255+
),
256+
InlineKeyboardButton(
257+
text="❌ Cancel",
258+
callback_data="cancel",
259+
style=KeyboardButtonStyle(bg_danger=True)
260+
)
261+
],
262+
# Row 2: URL button
263+
[
264+
InlineKeyboardButton(
265+
text="🌐 Visit Website",
266+
url="https://example.com",
267+
style=KeyboardButtonStyle(bg_primary=True)
268+
)
269+
],
270+
# Row 3: Inline query buttons
271+
[
272+
InlineKeyboardButton(
273+
text="🔍 Search",
274+
switch_inline_query_current_chat="",
275+
style=KeyboardButtonStyle(
276+
icon=5368324170671202286 # Search emoji
277+
)
278+
)
279+
]
280+
]
281+
)
282+
)
283+
284+
113285
app.run(main())

pyrogram/types/bots_and_keyboards/inline_keyboard_button.py

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class InlineKeyboardButton(Object):
6969
callback_game (:obj:`~pyrogram.types.CallbackGame`, *optional*):
7070
Description of the game that will be launched when the user presses the button.
7171
**NOTE**: This type of button **must** always be the first button in the first row.
72+
73+
style (:obj:`~pyrogram.types.KeyboardButtonStyle`, *optional*):
74+
Style configuration for the button (background color, icon).
7275
"""
7376

7477
def __init__(
@@ -81,7 +84,8 @@ def __init__(
8184
user_id: int = None,
8285
switch_inline_query: str = None,
8386
switch_inline_query_current_chat: str = None,
84-
callback_game: "types.CallbackGame" = None
87+
callback_game: "types.CallbackGame" = None,
88+
style: "types.KeyboardButtonStyle" = None
8589
):
8690
super().__init__()
8791

@@ -94,10 +98,13 @@ def __init__(
9498
self.switch_inline_query = switch_inline_query
9599
self.switch_inline_query_current_chat = switch_inline_query_current_chat
96100
self.callback_game = callback_game
101+
self.style = style
97102
# self.pay = pay
98103

99104
@staticmethod
100105
def read(b: "raw.base.KeyboardButton"):
106+
style = types.KeyboardButtonStyle.read(getattr(b, "style", None))
107+
101108
if isinstance(b, raw.types.KeyboardButtonCallback):
102109
# Try decode data to keep it as string, but if fails, fallback to bytes so we don't lose any information,
103110
# instead of decoding by ignoring/replacing errors.
@@ -108,101 +115,119 @@ def read(b: "raw.base.KeyboardButton"):
108115

109116
return InlineKeyboardButton(
110117
text=b.text,
111-
callback_data=data
118+
callback_data=data,
119+
style=style
112120
)
113121

114122
if isinstance(b, raw.types.KeyboardButtonUrl):
115123
return InlineKeyboardButton(
116124
text=b.text,
117-
url=b.url
125+
url=b.url,
126+
style=style
118127
)
119128

120129
if isinstance(b, raw.types.KeyboardButtonUrlAuth):
121130
return InlineKeyboardButton(
122131
text=b.text,
123-
login_url=types.LoginUrl.read(b)
132+
login_url=types.LoginUrl.read(b),
133+
style=style
124134
)
125135

126136
if isinstance(b, raw.types.KeyboardButtonUserProfile):
127137
return InlineKeyboardButton(
128138
text=b.text,
129-
user_id=b.user_id
139+
user_id=b.user_id,
140+
style=style
130141
)
131142

132143
if isinstance(b, raw.types.KeyboardButtonSwitchInline):
133144
if b.same_peer:
134145
return InlineKeyboardButton(
135146
text=b.text,
136-
switch_inline_query_current_chat=b.query
147+
switch_inline_query_current_chat=b.query,
148+
style=style
137149
)
138150
else:
139151
return InlineKeyboardButton(
140152
text=b.text,
141-
switch_inline_query=b.query
153+
switch_inline_query=b.query,
154+
style=style
142155
)
143156

144157
if isinstance(b, raw.types.KeyboardButtonGame):
145158
return InlineKeyboardButton(
146159
text=b.text,
147-
callback_game=types.CallbackGame()
160+
callback_game=types.CallbackGame(),
161+
style=style
148162
)
149163

150164
if isinstance(b, raw.types.KeyboardButtonWebView):
151165
return InlineKeyboardButton(
152166
text=b.text,
153167
web_app=types.WebAppInfo(
154168
url=b.url
155-
)
169+
),
170+
style=style
156171
)
157172

158173
async def write(self, client: "pyrogram.Client"):
174+
style = self.style.write() if self.style else None
175+
159176
if self.callback_data is not None:
160177
# Telegram only wants bytes, but we are allowed to pass strings too, for convenience.
161178
data = bytes(self.callback_data, "utf-8") if isinstance(self.callback_data, str) else self.callback_data
162179

163180
return raw.types.KeyboardButtonCallback(
164181
text=self.text,
165-
data=data
182+
data=data,
183+
style=style
166184
)
167185

168186
if self.url is not None:
169187
return raw.types.KeyboardButtonUrl(
170188
text=self.text,
171-
url=self.url
189+
url=self.url,
190+
style=style
172191
)
173192

174193
if self.login_url is not None:
175194
return self.login_url.write(
176195
text=self.text,
177-
bot=await client.resolve_peer(self.login_url.bot_username or "self")
196+
bot=await client.resolve_peer(self.login_url.bot_username or "self"),
197+
style=style
178198
)
179199

180200
if self.user_id is not None:
181201
return raw.types.InputKeyboardButtonUserProfile(
182202
text=self.text,
183-
user_id=await client.resolve_peer(self.user_id)
203+
input_user=await client.resolve_peer(self.user_id),
204+
style=style
184205
)
185206

186207
if self.switch_inline_query is not None:
187208
return raw.types.KeyboardButtonSwitchInline(
188209
text=self.text,
189-
query=self.switch_inline_query
210+
query=self.switch_inline_query,
211+
style=style
190212
)
191213

192214
if self.switch_inline_query_current_chat is not None:
193215
return raw.types.KeyboardButtonSwitchInline(
194216
text=self.text,
195217
query=self.switch_inline_query_current_chat,
196-
same_peer=True
218+
same_peer=True,
219+
style=style
197220
)
198221

199222
if self.callback_game is not None:
200223
return raw.types.KeyboardButtonGame(
201-
text=self.text
224+
text=self.text,
225+
style=style
202226
)
203227

204228
if self.web_app is not None:
205229
return raw.types.KeyboardButtonWebView(
206230
text=self.text,
207-
url=self.web_app.url
231+
url=self.web_app.url,
232+
style=style
208233
)

pyrogram/types/bots_and_keyboards/login_url.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class LoginUrl(Object):
4949
See `Linking your domain to the bot <https://core.telegram.org/widgets/login#linking-your-domain-to-the-bot>`_
5050
for more details.
5151
52-
request_write_access (``str``, *optional*):
52+
request_write_access (``bool``, *optional*):
5353
Pass True to request the permission for your bot to send messages to the user.
5454
5555
button_id (``int``):
@@ -61,7 +61,7 @@ def __init__(
6161
url: str,
6262
forward_text: str = None,
6363
bot_username: str = None,
64-
request_write_access: str = None,
64+
request_write_access: bool = None,
6565
button_id: int = None
6666
):
6767
super().__init__()
@@ -80,11 +80,12 @@ def read(b: "raw.types.KeyboardButtonUrlAuth") -> "LoginUrl":
8080
button_id=b.button_id
8181
)
8282

83-
def write(self, text: str, bot: "raw.types.InputUser"):
83+
def write(self, text: str, bot: "raw.types.InputUser", style: "raw.types.KeyboardButtonStyle" = None):
8484
return raw.types.InputKeyboardButtonUrlAuth(
8585
text=text,
8686
url=self.url,
8787
bot=bot,
8888
fwd_text=self.forward_text,
89-
request_write_access=self.request_write_access
89+
request_write_access=self.request_write_access,
90+
style=style
9091
)

0 commit comments

Comments
 (0)