diff --git a/src/tdlib/client.rs b/src/tdlib/client.rs index 36a0014..939f69c 100644 --- a/src/tdlib/client.rs +++ b/src/tdlib/client.rs @@ -870,22 +870,43 @@ impl TdClient { // Извлекаем реакции let reactions = self.extract_reactions(message); - MessageInfo::new( - message_id, - sender_name, - message.is_outgoing, - content, - entities, - message.date, - message.edit_date, - is_read, - message.can_be_edited, - message.can_be_deleted_only_for_self, - message.can_be_deleted_for_all_users, - reply_to, - forward_from, - reactions, - ) + // Используем MessageBuilder для более читабельного создания + let mut builder = crate::tdlib::MessageBuilder::new(message_id) + .sender_name(sender_name) + .text(content) + .entities(entities) + .date(message.date) + .edit_date(message.edit_date); + + // Применяем флаги + if message.is_outgoing { + builder = builder.outgoing(); + } + if is_read { + builder = builder.read(); + } + if message.can_be_edited { + builder = builder.editable(); + } + if message.can_be_deleted_only_for_self { + builder = builder.deletable_for_self(); + } + if message.can_be_deleted_for_all_users { + builder = builder.deletable_for_all(); + } + + // Добавляем опциональные данные + if let Some(reply) = reply_to { + builder = builder.reply_to(reply); + } + if let Some(forward) = forward_from { + builder = builder.forward_from(forward); + } + if !reactions.is_empty() { + builder = builder.reactions(reactions); + } + + builder.build() } /// Извлекает информацию о reply из сообщения diff --git a/src/tdlib/mod.rs b/src/tdlib/mod.rs index cb394d3..2802eb1 100644 --- a/src/tdlib/mod.rs +++ b/src/tdlib/mod.rs @@ -11,8 +11,8 @@ pub mod users; pub use auth::AuthState; pub use client::TdClient; pub use types::{ - ChatInfo, FolderInfo, ForwardInfo, MessageInfo, NetworkState, ProfileInfo, ReactionInfo, - ReplyInfo, UserOnlineStatus, + ChatInfo, FolderInfo, ForwardInfo, MessageBuilder, MessageInfo, NetworkState, ProfileInfo, + ReactionInfo, ReplyInfo, UserOnlineStatus, }; // Re-export ChatAction для удобства diff --git a/src/tdlib/types.rs b/src/tdlib/types.rs index 90c3952..b716b88 100644 --- a/src/tdlib/types.rs +++ b/src/tdlib/types.rs @@ -213,6 +213,290 @@ impl MessageInfo { } } +/// Builder для удобного создания MessageInfo с fluent API +/// +/// # Примеры +/// +/// ``` +/// use tele_tui::tdlib::MessageBuilder; +/// use tele_tui::types::MessageId; +/// +/// let message = MessageBuilder::new(MessageId::new(123)) +/// .sender_name("Alice") +/// .text("Hello, world!") +/// .outgoing() +/// .date(1640000000) +/// .build(); +/// ``` +pub struct MessageBuilder { + id: MessageId, + sender_name: String, + is_outgoing: bool, + text: String, + entities: Vec, + date: i32, + edit_date: i32, + is_read: bool, + can_be_edited: bool, + can_be_deleted_only_for_self: bool, + can_be_deleted_for_all_users: bool, + reply_to: Option, + forward_from: Option, + reactions: Vec, +} + +impl MessageBuilder { + /// Создать новый builder с обязательным ID сообщения + pub fn new(id: MessageId) -> Self { + Self { + id, + sender_name: String::new(), + is_outgoing: false, + text: String::new(), + entities: Vec::new(), + date: 0, + edit_date: 0, + is_read: false, + can_be_edited: false, + can_be_deleted_only_for_self: true, + can_be_deleted_for_all_users: false, + reply_to: None, + forward_from: None, + reactions: Vec::new(), + } + } + + /// Установить имя отправителя + pub fn sender_name(mut self, name: impl Into) -> Self { + self.sender_name = name.into(); + self + } + + /// Пометить сообщение как исходящее + pub fn outgoing(mut self) -> Self { + self.is_outgoing = true; + self.can_be_edited = true; + self.can_be_deleted_for_all_users = true; + self + } + + /// Пометить сообщение как входящее + pub fn incoming(mut self) -> Self { + self.is_outgoing = false; + self.can_be_edited = false; + self.can_be_deleted_for_all_users = false; + self + } + + /// Установить текст сообщения + pub fn text(mut self, text: impl Into) -> Self { + self.text = text.into(); + self + } + + /// Установить entities для форматирования + pub fn entities(mut self, entities: Vec) -> Self { + self.entities = entities; + self + } + + /// Установить дату сообщения (unix timestamp) + pub fn date(mut self, date: i32) -> Self { + self.date = date; + self + } + + /// Установить дату редактирования (unix timestamp) + pub fn edit_date(mut self, edit_date: i32) -> Self { + self.edit_date = edit_date; + self + } + + /// Пометить сообщение как отредактированное (edit_date = date + 60) + pub fn edited(mut self) -> Self { + self.edit_date = self.date + 60; + self + } + + /// Пометить сообщение как прочитанное + pub fn read(mut self) -> Self { + self.is_read = true; + self + } + + /// Пометить сообщение как непрочитанное + pub fn unread(mut self) -> Self { + self.is_read = false; + self + } + + /// Разрешить редактирование + pub fn editable(mut self) -> Self { + self.can_be_edited = true; + self + } + + /// Разрешить удаление только для себя + pub fn deletable_for_self(mut self) -> Self { + self.can_be_deleted_only_for_self = true; + self + } + + /// Разрешить удаление для всех + pub fn deletable_for_all(mut self) -> Self { + self.can_be_deleted_for_all_users = true; + self + } + + /// Установить информацию об ответе + pub fn reply_to(mut self, reply: ReplyInfo) -> Self { + self.reply_to = Some(reply); + self + } + + /// Установить информацию о пересылке + pub fn forward_from(mut self, forward: ForwardInfo) -> Self { + self.forward_from = Some(forward); + self + } + + /// Установить реакции + pub fn reactions(mut self, reactions: Vec) -> Self { + self.reactions = reactions; + self + } + + /// Добавить одну реакцию + pub fn add_reaction(mut self, reaction: ReactionInfo) -> Self { + self.reactions.push(reaction); + self + } + + /// Построить MessageInfo из данных builder'а + pub fn build(self) -> MessageInfo { + MessageInfo::new( + self.id, + self.sender_name, + self.is_outgoing, + self.text, + self.entities, + self.date, + self.edit_date, + self.is_read, + self.can_be_edited, + self.can_be_deleted_only_for_self, + self.can_be_deleted_for_all_users, + self.reply_to, + self.forward_from, + self.reactions, + ) + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use crate::types::MessageId; + + #[test] + fn test_message_builder_basic() { + let message = MessageBuilder::new(MessageId::new(123)) + .sender_name("Alice") + .text("Hello, world!") + .date(1640000000) + .build(); + + assert_eq!(message.id(), MessageId::new(123)); + assert_eq!(message.sender_name(), "Alice"); + assert_eq!(message.text(), "Hello, world!"); + assert_eq!(message.date(), 1640000000); + assert!(!message.is_outgoing()); + } + + #[test] + fn test_message_builder_outgoing() { + let message = MessageBuilder::new(MessageId::new(456)) + .sender_name("Me") + .text("Test message") + .outgoing() + .read() + .build(); + + assert!(message.is_outgoing()); + assert!(message.is_read()); + assert!(message.can_be_edited()); + assert!(message.can_be_deleted_for_all_users()); + } + + #[test] + fn test_message_builder_edited() { + let message = MessageBuilder::new(MessageId::new(789)) + .text("Original text") + .date(1640000000) + .edited() + .build(); + + assert!(message.is_edited()); + assert_eq!(message.edit_date(), 1640000060); + } + + #[test] + fn test_message_builder_with_reply() { + let reply = ReplyInfo { + message_id: MessageId::new(100), + sender_name: "Bob".to_string(), + text: "Original message".to_string(), + }; + + let message = MessageBuilder::new(MessageId::new(200)) + .text("Reply text") + .reply_to(reply) + .build(); + + assert!(message.reply_to().is_some()); + assert_eq!(message.reply_to().unwrap().sender_name, "Bob"); + } + + #[test] + fn test_message_builder_with_reactions() { + let reaction = ReactionInfo { + emoji: "👍".to_string(), + count: 5, + is_chosen: true, + }; + + let message = MessageBuilder::new(MessageId::new(300)) + .text("Cool message") + .add_reaction(reaction.clone()) + .build(); + + assert_eq!(message.reactions().len(), 1); + assert_eq!(message.reactions()[0].emoji, "👍"); + assert_eq!(message.reactions()[0].count, 5); + } + + #[test] + fn test_message_builder_fluent_api() { + let message = MessageBuilder::new(MessageId::new(999)) + .sender_name("Charlie") + .text("Complex message") + .date(1640000000) + .outgoing() + .read() + .editable() + .deletable_for_all() + .build(); + + assert_eq!(message.sender_name(), "Charlie"); + assert_eq!(message.text(), "Complex message"); + assert!(message.is_outgoing()); + assert!(message.is_read()); + assert!(message.can_be_edited()); + assert!(message.can_be_deleted_for_all_users()); + } +} + #[derive(Debug, Clone)] pub struct FolderInfo { pub id: i32,