1use serde::{Deserialize, Serialize};
2
3use crate::message::WebAppInfo;
4
5#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7pub struct InlineKeyboardMarkup {
8 pub inline_keyboard: Vec<Vec<InlineKeyboardButton>>,
11}
12
13impl InlineKeyboardMarkup {
14 #[must_use]
16 pub fn new() -> Self {
17 Self::default()
18 }
19
20 #[must_use]
22 pub fn row(mut self, row: Vec<InlineKeyboardButton>) -> Self {
23 self.inline_keyboard.push(row);
24 self
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct InlineKeyboardButton {
31 pub text: String,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub icon_custom_emoji_id: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub style: Option<ButtonStyle>,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub url: Option<String>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub callback_data: Option<String>,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub web_app: Option<WebAppInfo>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub login_url: Option<LoginUrl>,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub switch_inline_query: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub switch_inline_query_current_chat: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub switch_inline_query_chosen_chat: Option<SwitchInlineQueryChosenChat>,
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub copy_text: Option<CopyTextButton>,
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub callback_game: Option<serde_json::Value>,
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub pay: Option<bool>,
69}
70
71impl InlineKeyboardButton {
72 #[must_use]
74 pub fn callback(text: impl Into<String>, data: impl Into<String>) -> Self {
75 Self {
76 text: text.into(),
77 callback_data: Some(data.into()),
78 icon_custom_emoji_id: None,
79 style: None,
80 url: None,
81 web_app: None,
82 login_url: None,
83 switch_inline_query: None,
84 switch_inline_query_current_chat: None,
85 switch_inline_query_chosen_chat: None,
86 copy_text: None,
87 callback_game: None,
88 pay: None,
89 }
90 }
91
92 #[must_use]
94 pub fn url(text: impl Into<String>, url: impl Into<String>) -> Self {
95 Self {
96 text: text.into(),
97 url: Some(url.into()),
98 icon_custom_emoji_id: None,
99 style: None,
100 callback_data: None,
101 web_app: None,
102 login_url: None,
103 switch_inline_query: None,
104 switch_inline_query_current_chat: None,
105 switch_inline_query_chosen_chat: None,
106 copy_text: None,
107 callback_game: None,
108 pay: None,
109 }
110 }
111
112 #[must_use]
114 pub fn web_app(text: impl Into<String>, url: impl Into<String>) -> Self {
115 Self {
116 text: text.into(),
117 web_app: Some(WebAppInfo { url: url.into() }),
118 icon_custom_emoji_id: None,
119 style: None,
120 url: None,
121 callback_data: None,
122 login_url: None,
123 switch_inline_query: None,
124 switch_inline_query_current_chat: None,
125 switch_inline_query_chosen_chat: None,
126 copy_text: None,
127 callback_game: None,
128 pay: None,
129 }
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
135#[serde(rename_all = "snake_case")]
136pub enum ButtonStyle {
137 Danger,
139 Success,
141 Primary,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct LoginUrl {
148 pub url: String,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub forward_text: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub bot_username: Option<String>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub request_write_access: Option<bool>,
159}
160
161#[derive(Debug, Clone, Default, Serialize, Deserialize)]
163pub struct SwitchInlineQueryChosenChat {
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub query: Option<String>,
167 #[serde(skip_serializing_if = "Option::is_none")]
169 pub allow_user_chats: Option<bool>,
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub allow_bot_chats: Option<bool>,
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub allow_group_chats: Option<bool>,
176 #[serde(skip_serializing_if = "Option::is_none")]
178 pub allow_channel_chats: Option<bool>,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct CopyTextButton {
184 pub text: String,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct ReplyKeyboardMarkup {
191 pub keyboard: Vec<Vec<KeyboardButton>>,
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub is_persistent: Option<bool>,
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub resize_keyboard: Option<bool>,
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub one_time_keyboard: Option<bool>,
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub input_field_placeholder: Option<String>,
205 #[serde(skip_serializing_if = "Option::is_none")]
207 pub selective: Option<bool>,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct KeyboardButton {
213 pub text: String,
215 #[serde(skip_serializing_if = "Option::is_none")]
217 pub icon_custom_emoji_id: Option<String>,
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub style: Option<ButtonStyle>,
221 #[serde(skip_serializing_if = "Option::is_none")]
223 pub request_users: Option<KeyboardButtonRequestUsers>,
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub request_chat: Option<KeyboardButtonRequestChat>,
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub request_managed_bot: Option<KeyboardButtonRequestManagedBot>,
230 #[serde(skip_serializing_if = "Option::is_none")]
232 pub request_contact: Option<bool>,
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub request_location: Option<bool>,
236 #[serde(skip_serializing_if = "Option::is_none")]
238 pub request_poll: Option<KeyboardButtonPollType>,
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub web_app: Option<WebAppInfo>,
242}
243
244impl KeyboardButton {
245 #[must_use]
247 pub fn text(label: impl Into<String>) -> Self {
248 Self {
249 text: label.into(),
250 icon_custom_emoji_id: None,
251 style: None,
252 request_users: None,
253 request_chat: None,
254 request_managed_bot: None,
255 request_contact: None,
256 request_location: None,
257 request_poll: None,
258 web_app: None,
259 }
260 }
261
262 #[must_use]
264 pub fn request_contact(label: impl Into<String>) -> Self {
265 Self {
266 request_contact: Some(true),
267 ..Self::text(label)
268 }
269 }
270
271 #[must_use]
273 pub fn request_location(label: impl Into<String>) -> Self {
274 Self {
275 request_location: Some(true),
276 ..Self::text(label)
277 }
278 }
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct KeyboardButtonRequestUsers {
284 pub request_id: i32,
286 #[serde(skip_serializing_if = "Option::is_none")]
288 pub user_is_bot: Option<bool>,
289 #[serde(skip_serializing_if = "Option::is_none")]
291 pub user_is_premium: Option<bool>,
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub max_quantity: Option<u8>,
295 #[serde(skip_serializing_if = "Option::is_none")]
297 pub request_name: Option<bool>,
298 #[serde(skip_serializing_if = "Option::is_none")]
300 pub request_username: Option<bool>,
301 #[serde(skip_serializing_if = "Option::is_none")]
303 pub request_photo: Option<bool>,
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct KeyboardButtonRequestChat {
309 pub request_id: i32,
311 pub chat_is_channel: bool,
313 #[serde(skip_serializing_if = "Option::is_none")]
315 pub chat_is_forum: Option<bool>,
316 #[serde(skip_serializing_if = "Option::is_none")]
318 pub chat_has_username: Option<bool>,
319 #[serde(skip_serializing_if = "Option::is_none")]
321 pub chat_is_created: Option<bool>,
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub user_administrator_rights: Option<serde_json::Value>,
325 #[serde(skip_serializing_if = "Option::is_none")]
327 pub bot_administrator_rights: Option<serde_json::Value>,
328 #[serde(skip_serializing_if = "Option::is_none")]
330 pub bot_is_member: Option<bool>,
331 #[serde(skip_serializing_if = "Option::is_none")]
333 pub request_title: Option<bool>,
334 #[serde(skip_serializing_if = "Option::is_none")]
336 pub request_username: Option<bool>,
337 #[serde(skip_serializing_if = "Option::is_none")]
339 pub request_photo: Option<bool>,
340}
341
342#[derive(Debug, Clone, Default, Serialize, Deserialize)]
346pub struct KeyboardButtonRequestManagedBot {
347 pub request_id: i32,
349 #[serde(skip_serializing_if = "Option::is_none")]
351 pub suggested_name: Option<String>,
352 #[serde(skip_serializing_if = "Option::is_none")]
354 pub suggested_username: Option<String>,
355}
356
357#[derive(Debug, Clone, Serialize, Deserialize)]
359pub struct KeyboardButtonPollType {
360 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
362 pub kind: Option<String>,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct ReplyKeyboardRemove {
368 pub remove_keyboard: bool,
370 #[serde(skip_serializing_if = "Option::is_none")]
372 pub selective: Option<bool>,
373}
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct ForceReply {
378 pub force_reply: bool,
380 #[serde(skip_serializing_if = "Option::is_none")]
382 pub input_field_placeholder: Option<String>,
383 #[serde(skip_serializing_if = "Option::is_none")]
385 pub selective: Option<bool>,
386}
387
388#[derive(Debug, Clone, Serialize, Deserialize)]
390#[serde(untagged)]
391pub enum ReplyMarkup {
392 InlineKeyboard(InlineKeyboardMarkup),
394 ReplyKeyboard(ReplyKeyboardMarkup),
396 Remove(ReplyKeyboardRemove),
398 ForceReply(ForceReply),
400}
401
402#[derive(Debug, Clone, Serialize, Deserialize)]
404#[serde(tag = "type", rename_all = "snake_case")]
405pub enum MenuButton {
406 Commands,
408 WebApp {
410 text: String,
412 web_app: WebAppInfo,
414 },
415 Default,
417}