1use serde::{Deserialize, Serialize};
2
3use crate::games::CallbackGame;
4use crate::user::ChatAdministratorRights;
5
6use crate::message::WebAppInfo;
7
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10pub struct InlineKeyboardMarkup {
11 pub inline_keyboard: Vec<Vec<InlineKeyboardButton>>,
14}
15
16impl InlineKeyboardMarkup {
17 #[must_use]
19 pub fn new() -> Self {
20 Self::default()
21 }
22
23 #[must_use]
25 pub fn row(mut self, row: Vec<InlineKeyboardButton>) -> Self {
26 self.inline_keyboard.push(row);
27 self
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct InlineKeyboardButton {
34 pub text: String,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub icon_custom_emoji_id: Option<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub style: Option<ButtonStyle>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub url: Option<String>,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub callback_data: Option<String>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub web_app: Option<WebAppInfo>,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub login_url: Option<LoginUrl>,
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub switch_inline_query: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub switch_inline_query_current_chat: Option<String>,
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub switch_inline_query_chosen_chat: Option<SwitchInlineQueryChosenChat>,
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub copy_text: Option<CopyTextButton>,
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub callback_game: Option<CallbackGame>,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub pay: Option<bool>,
72}
73
74impl InlineKeyboardButton {
75 #[must_use]
77 pub fn callback(text: impl Into<String>, data: impl Into<String>) -> Self {
78 Self {
79 text: text.into(),
80 callback_data: Some(data.into()),
81 icon_custom_emoji_id: None,
82 style: None,
83 url: None,
84 web_app: None,
85 login_url: None,
86 switch_inline_query: None,
87 switch_inline_query_current_chat: None,
88 switch_inline_query_chosen_chat: None,
89 copy_text: None,
90 callback_game: None,
91 pay: None,
92 }
93 }
94
95 #[must_use]
97 pub fn url(text: impl Into<String>, url: impl Into<String>) -> Self {
98 Self {
99 text: text.into(),
100 url: Some(url.into()),
101 icon_custom_emoji_id: None,
102 style: None,
103 callback_data: None,
104 web_app: None,
105 login_url: None,
106 switch_inline_query: None,
107 switch_inline_query_current_chat: None,
108 switch_inline_query_chosen_chat: None,
109 copy_text: None,
110 callback_game: None,
111 pay: None,
112 }
113 }
114
115 #[must_use]
117 pub fn web_app(text: impl Into<String>, url: impl Into<String>) -> Self {
118 Self {
119 text: text.into(),
120 web_app: Some(WebAppInfo { url: url.into() }),
121 icon_custom_emoji_id: None,
122 style: None,
123 url: None,
124 callback_data: None,
125 login_url: None,
126 switch_inline_query: None,
127 switch_inline_query_current_chat: None,
128 switch_inline_query_chosen_chat: None,
129 copy_text: None,
130 callback_game: None,
131 pay: None,
132 }
133 }
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138#[serde(rename_all = "snake_case")]
139pub enum ButtonStyle {
140 Danger,
142 Success,
144 Primary,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct LoginUrl {
151 pub url: String,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub forward_text: Option<String>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub bot_username: Option<String>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub request_write_access: Option<bool>,
162}
163
164#[derive(Debug, Clone, Default, Serialize, Deserialize)]
166pub struct SwitchInlineQueryChosenChat {
167 #[serde(skip_serializing_if = "Option::is_none")]
169 pub query: Option<String>,
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub allow_user_chats: Option<bool>,
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub allow_bot_chats: Option<bool>,
176 #[serde(skip_serializing_if = "Option::is_none")]
178 pub allow_group_chats: Option<bool>,
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub allow_channel_chats: Option<bool>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct CopyTextButton {
187 pub text: String,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct ReplyKeyboardMarkup {
194 pub keyboard: Vec<Vec<KeyboardButton>>,
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub is_persistent: Option<bool>,
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub resize_keyboard: Option<bool>,
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub one_time_keyboard: Option<bool>,
205 #[serde(skip_serializing_if = "Option::is_none")]
207 pub input_field_placeholder: Option<String>,
208 #[serde(skip_serializing_if = "Option::is_none")]
210 pub selective: Option<bool>,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct KeyboardButton {
216 pub text: String,
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub icon_custom_emoji_id: Option<String>,
221 #[serde(skip_serializing_if = "Option::is_none")]
223 pub style: Option<ButtonStyle>,
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub request_users: Option<KeyboardButtonRequestUsers>,
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub request_chat: Option<KeyboardButtonRequestChat>,
230 #[serde(skip_serializing_if = "Option::is_none")]
232 pub request_managed_bot: Option<KeyboardButtonRequestManagedBot>,
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub request_contact: Option<bool>,
236 #[serde(skip_serializing_if = "Option::is_none")]
238 pub request_location: Option<bool>,
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub request_poll: Option<KeyboardButtonPollType>,
242 #[serde(skip_serializing_if = "Option::is_none")]
244 pub web_app: Option<WebAppInfo>,
245}
246
247impl KeyboardButton {
248 #[must_use]
250 pub fn text(label: impl Into<String>) -> Self {
251 Self {
252 text: label.into(),
253 icon_custom_emoji_id: None,
254 style: None,
255 request_users: None,
256 request_chat: None,
257 request_managed_bot: None,
258 request_contact: None,
259 request_location: None,
260 request_poll: None,
261 web_app: None,
262 }
263 }
264
265 #[must_use]
267 pub fn request_contact(label: impl Into<String>) -> Self {
268 Self {
269 request_contact: Some(true),
270 ..Self::text(label)
271 }
272 }
273
274 #[must_use]
276 pub fn request_location(label: impl Into<String>) -> Self {
277 Self {
278 request_location: Some(true),
279 ..Self::text(label)
280 }
281 }
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct KeyboardButtonRequestUsers {
287 pub request_id: i32,
289 #[serde(skip_serializing_if = "Option::is_none")]
291 pub user_is_bot: Option<bool>,
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub user_is_premium: Option<bool>,
295 #[serde(skip_serializing_if = "Option::is_none")]
297 pub max_quantity: Option<u8>,
298 #[serde(skip_serializing_if = "Option::is_none")]
300 pub request_name: Option<bool>,
301 #[serde(skip_serializing_if = "Option::is_none")]
303 pub request_username: Option<bool>,
304 #[serde(skip_serializing_if = "Option::is_none")]
306 pub request_photo: Option<bool>,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct KeyboardButtonRequestChat {
312 pub request_id: i32,
314 pub chat_is_channel: bool,
316 #[serde(skip_serializing_if = "Option::is_none")]
318 pub chat_is_forum: Option<bool>,
319 #[serde(skip_serializing_if = "Option::is_none")]
321 pub chat_has_username: Option<bool>,
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub chat_is_created: Option<bool>,
325 #[serde(skip_serializing_if = "Option::is_none")]
327 pub user_administrator_rights: Option<ChatAdministratorRights>,
328 #[serde(skip_serializing_if = "Option::is_none")]
330 pub bot_administrator_rights: Option<ChatAdministratorRights>,
331 #[serde(skip_serializing_if = "Option::is_none")]
333 pub bot_is_member: Option<bool>,
334 #[serde(skip_serializing_if = "Option::is_none")]
336 pub request_title: Option<bool>,
337 #[serde(skip_serializing_if = "Option::is_none")]
339 pub request_username: Option<bool>,
340 #[serde(skip_serializing_if = "Option::is_none")]
342 pub request_photo: Option<bool>,
343}
344
345#[derive(Debug, Clone, Default, Serialize, Deserialize)]
349pub struct KeyboardButtonRequestManagedBot {
350 pub request_id: i32,
352 #[serde(skip_serializing_if = "Option::is_none")]
354 pub suggested_name: Option<String>,
355 #[serde(skip_serializing_if = "Option::is_none")]
357 pub suggested_username: Option<String>,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct KeyboardButtonPollType {
363 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
365 pub kind: Option<String>,
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize)]
370pub struct ReplyKeyboardRemove {
371 pub remove_keyboard: bool,
373 #[serde(skip_serializing_if = "Option::is_none")]
375 pub selective: Option<bool>,
376}
377
378#[derive(Debug, Clone, Serialize, Deserialize)]
380pub struct ForceReply {
381 pub force_reply: bool,
383 #[serde(skip_serializing_if = "Option::is_none")]
385 pub input_field_placeholder: Option<String>,
386 #[serde(skip_serializing_if = "Option::is_none")]
388 pub selective: Option<bool>,
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize)]
393#[serde(untagged)]
394pub enum ReplyMarkup {
395 InlineKeyboard(InlineKeyboardMarkup),
397 ReplyKeyboard(ReplyKeyboardMarkup),
399 Remove(ReplyKeyboardRemove),
401 ForceReply(ForceReply),
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize)]
407#[serde(tag = "type", rename_all = "snake_case")]
408pub enum MenuButton {
409 Commands,
411 WebApp {
413 text: String,
415 web_app: WebAppInfo,
417 },
418 Default,
420}
421
422#[derive(Debug, Clone, Default, Serialize, Deserialize)]
424#[non_exhaustive]
425pub struct PreparedKeyboardButton {
426 pub id: String,
428}