tgbot/types/definitions/rich/message.rs
1use serde::{Deserialize, Serialize};
2
3use super::block::RichBlock;
4use crate::{
5 api::{Method, Payload},
6 types::{ChatId, Integer, Message, ReplyMarkup, ReplyParameters, SuggestedPostParameters},
7};
8
9/// Rich formatted message.
10#[serde_with::skip_serializing_none]
11#[derive(Clone, Debug, Deserialize, Serialize)]
12pub struct RichMessage {
13 /// Content of the message.
14 pub blocks: Vec<RichBlock>,
15 /// Whether the message must be show right-to-left.
16 pub is_rtl: Option<bool>,
17}
18
19impl<A, B> From<A> for RichMessage
20where
21 A: IntoIterator<Item = B>,
22 B: Into<RichBlock>,
23{
24 fn from(value: A) -> Self {
25 Self::from_iter(value)
26 }
27}
28
29impl<I> FromIterator<I> for RichMessage
30where
31 I: Into<RichBlock>,
32{
33 fn from_iter<T>(value: T) -> Self
34 where
35 T: IntoIterator<Item = I>,
36 {
37 Self {
38 blocks: value.into_iter().map(Into::into).collect(),
39 is_rtl: None,
40 }
41 }
42}
43
44impl RichMessage {
45 /// Sets a new value for the `is_rtl` flag.
46 ///
47 /// # Arguments
48 ///
49 /// * `value` - Whether the message must be shown right-to-left.
50 pub fn with_is_rtl(mut self, value: bool) -> Self {
51 self.is_rtl = Some(value);
52 self
53 }
54}
55
56/// Describes a rich message to be sent.
57#[serde_with::skip_serializing_none]
58#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
59pub struct InputRichMessage {
60 html: Option<String>,
61 markdown: Option<String>,
62 is_rtl: Option<bool>,
63 skip_entity_detection: Option<bool>,
64}
65
66impl InputRichMessage {
67 /// Creates a new `InputRichMessage`.
68 ///
69 /// # Arguments
70 ///
71 /// * `value` - Content of the rich message to send described using Markdown formatting.
72 pub fn markdown<T>(value: T) -> Self
73 where
74 T: Into<String>,
75 {
76 Self {
77 html: None,
78 markdown: Some(value.into()),
79 is_rtl: None,
80 skip_entity_detection: None,
81 }
82 }
83
84 /// Creates a new `InputRichMessage`.
85 ///
86 /// # Arguments
87 ///
88 /// * `value` - Content of the rich message to send described using HTML formatting.
89 pub fn html<T>(value: T) -> Self
90 where
91 T: Into<String>,
92 {
93 Self {
94 html: Some(value.into()),
95 markdown: None,
96 is_rtl: None,
97 skip_entity_detection: None,
98 }
99 }
100
101 /// Sets a new value for the `is_rtl` flag.
102 ///
103 /// # Arguments
104 ///
105 /// * `value` - Whether the rich message must be shown right-to-left.
106 pub fn with_is_rtl(mut self, value: bool) -> Self {
107 self.is_rtl = Some(value);
108 self
109 }
110
111 /// Sets a new value for the `skip_entity_detection` flag.
112 ///
113 /// # Arguments
114 ///
115 /// * `value` - Whethert to skip automatic detection of entities in the text.
116 pub fn with_skip_entity_detection(mut self, value: bool) -> Self {
117 self.skip_entity_detection = Some(value);
118 self
119 }
120}
121
122/// Sends rich messages.
123///
124/// If the message contains a block with a media element,
125/// then the bot must have the right to send the media to the chat.
126#[serde_with::skip_serializing_none]
127#[derive(Clone, Debug, Serialize)]
128pub struct SendRichMessage {
129 chat_id: ChatId,
130 rich_message: InputRichMessage,
131 allow_paid_broadcast: Option<bool>,
132 business_connection_id: Option<String>,
133 direct_messages_topic_id: Option<Integer>,
134 disable_notification: Option<bool>,
135 message_effect_id: Option<String>,
136 message_thread_id: Option<Integer>,
137 protect_content: Option<bool>,
138 reply_markup: Option<ReplyMarkup>,
139 reply_parameters: Option<ReplyParameters>,
140 suggested_post_parameters: Option<SuggestedPostParameters>,
141}
142
143impl SendRichMessage {
144 /// Creates a new `SendRichMessage`.
145 ///
146 /// # Arguments
147 ///
148 /// * `chat_id` - Unique identifier of the target chat.
149 /// * `rich_message` - The message to be sent.
150 pub fn new<T>(chat_id: T, rich_message: InputRichMessage) -> Self
151 where
152 T: Into<ChatId>,
153 {
154 Self {
155 chat_id: chat_id.into(),
156 rich_message,
157 allow_paid_broadcast: None,
158 business_connection_id: None,
159 direct_messages_topic_id: None,
160 disable_notification: None,
161 message_effect_id: None,
162 message_thread_id: None,
163 protect_content: None,
164 reply_markup: None,
165 reply_parameters: None,
166 suggested_post_parameters: None,
167 }
168 }
169
170 /// Sets a new value for the `allow_paid_broadcast` flag.
171 ///
172 /// # Arguments
173 ///
174 /// * `value` - Whether to allow up to 1000 messages per second,
175 /// ignoring broadcasting limits for a fee of 0.1 Telegram Stars per message.
176 ///
177 /// The relevant Stars will be withdrawn from the bot's balance.
178 pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
179 self.allow_paid_broadcast = Some(value);
180 self
181 }
182
183 /// Sets a new business connection ID.
184 ///
185 /// # Arguments
186 ///
187 /// * `value` - Unique identifier of the business connection.
188 pub fn with_business_connection_id<T>(mut self, value: T) -> Self
189 where
190 T: Into<String>,
191 {
192 self.business_connection_id = Some(value.into());
193 self
194 }
195
196 /// Sets a new direct messages topic ID
197 ///
198 /// * `value` - Identifier of the direct messages topic to which the message will be sent.
199 ///
200 /// Required if the message is sent to a direct messages chat.
201 pub fn with_direct_messages_topic_id(mut self, value: Integer) -> Self {
202 self.direct_messages_topic_id = Some(value);
203 self
204 }
205
206 /// Sets a new value for the `disable_notification` flag.
207 ///
208 /// # Arguments
209 ///
210 /// * `value` - Indicates whether to send the message silently or not;
211 /// a user will receive a notification without sound.
212 pub fn with_disable_notification(mut self, value: bool) -> Self {
213 self.disable_notification = Some(value);
214 self
215 }
216
217 /// Sets a new message effect ID.
218 ///
219 /// # Arguments
220 ///
221 /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
222 pub fn with_message_effect_id<T>(mut self, value: T) -> Self
223 where
224 T: Into<String>,
225 {
226 self.message_effect_id = Some(value.into());
227 self
228 }
229
230 /// Sets a new message thread ID.
231 ///
232 /// # Arguments
233 ///
234 /// * `value` - Unique identifier of the target message thread;
235 /// for forum supergroups and private chats of bots with forum topic mode enabled only.
236 pub fn with_message_thread_id(mut self, value: Integer) -> Self {
237 self.message_thread_id = Some(value);
238 self
239 }
240
241 /// Sets a new value for the `protect_content` flag.
242 ///
243 /// # Arguments
244 ///
245 /// * `value` - Indicates whether to protect the contents
246 /// of the sent message from forwarding and saving.
247 pub fn with_protect_content(mut self, value: bool) -> Self {
248 self.protect_content = Some(value);
249 self
250 }
251
252 /// Sets a new reply markup.
253 ///
254 /// # Arguments
255 ///
256 /// * `value` - Reply markup.
257 pub fn with_reply_markup<T>(mut self, value: T) -> Self
258 where
259 T: Into<ReplyMarkup>,
260 {
261 self.reply_markup = Some(value.into());
262 self
263 }
264
265 /// Sets new reply parameters.
266 ///
267 /// # Arguments
268 ///
269 /// * `value` - Description of the message to reply to.
270 pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Self {
271 self.reply_parameters = Some(value);
272 self
273 }
274
275 /// Sets a new suggested post parameters.
276 ///
277 /// # Arguments
278 ///
279 /// * `value` - An object containing the parameters of the suggested post to send.
280 ///
281 /// For direct messages chats only.
282 ///
283 /// If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
284 pub fn with_suggested_post_parameters(mut self, value: SuggestedPostParameters) -> Self {
285 self.suggested_post_parameters = Some(value);
286 self
287 }
288}
289
290impl Method for SendRichMessage {
291 type Response = Message;
292
293 fn into_payload(self) -> Payload {
294 Payload::json("sendRichMessage", self)
295 }
296}
297
298/// Streams a partial rich message to a user while the message is being generated.
299///
300/// Note that streamed draft is ephemeral and acts as a temporary
301/// 30-second preview - once the output is finalized.
302///
303/// You must call [`crate::types::SendRichMessage`] with the complete message
304/// to persist it in the user's chat.
305#[serde_with::skip_serializing_none]
306#[derive(Clone, Debug, Serialize)]
307pub struct SendRichMessageDraft {
308 chat_id: Integer,
309 draft_id: Integer,
310 rich_message: InputRichMessage,
311 message_thread_id: Option<Integer>,
312}
313
314impl SendRichMessageDraft {
315 /// Creates a new `SendRichMessageDraft`.
316 ///
317 /// # Arguments
318 ///
319 /// * `chat_id` - Unique identifier of the target chat.
320 /// * `draft_id` - Unique identifier of the message draft; must be non-zero;
321 /// changes to drafts with the same identifier are animated.
322 /// * `rich_message` - The partial message to be streamed.
323 pub fn new(chat_id: Integer, draft_id: Integer, rich_message: InputRichMessage) -> Self {
324 Self {
325 chat_id,
326 draft_id,
327 rich_message,
328 message_thread_id: None,
329 }
330 }
331
332 /// Sets a new message thread ID.
333 ///
334 /// # Arguments
335 ///
336 /// * `value` - Unique identifier of the target message thread;
337 /// for forum supergroups and private chats of bots with forum topic mode enabled only.
338 pub fn with_message_thread_id(mut self, value: Integer) -> Self {
339 self.message_thread_id = Some(value);
340 self
341 }
342}
343
344impl Method for SendRichMessageDraft {
345 type Response = bool;
346
347 fn into_payload(self) -> Payload {
348 Payload::json("sendRichMessageDraft", self)
349 }
350}