refactor: add MessageBuilder with fluent API (P2.7)
Добавлен MessageBuilder для удобного создания MessageInfo с помощью
fluent API вместо вызова конструктора с 14 параметрами.
Изменения:
- Создан MessageBuilder в tdlib/types.rs с fluent API
- Реализованы методы:
* new(id) - создание builder с обязательным ID
* sender_name(), text(), entities(), date(), edit_date()
* outgoing(), incoming(), read(), unread(), edited()
* editable(), deletable_for_self(), deletable_for_all()
* reply_to(), forward_from(), reactions(), add_reaction()
* build() - финальное создание MessageInfo
- Обновлён convert_message() для использования builder
- Добавлен экспорт MessageBuilder в tdlib/mod.rs
- Добавлены 6 unit тестов демонстрирующих fluent API
Преимущества:
- Более читабельный код создания сообщений
- Самодокументирующийся API
- Гибкость в установке опциональных полей
- Легче добавлять новые поля в будущем
Пример использования:
```rust
let message = MessageBuilder::new(MessageId::new(123))
.sender_name("Alice")
.text("Hello, world!")
.outgoing()
.read()
.build();
```
Статус: Priority 2 ЗАВЕРШЁН 100% (5/5 задач)! 🎉
- ✅ Error enum
- ✅ Config validation
- ✅ Newtype для ID
- ✅ MessageInfo реструктуризация
- ✅ MessageBuilder pattern
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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<TextEntity>,
|
||||
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<ReplyInfo>,
|
||||
forward_from: Option<ForwardInfo>,
|
||||
reactions: Vec<ReactionInfo>,
|
||||
}
|
||||
|
||||
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<String>) -> 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<String>) -> Self {
|
||||
self.text = text.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Установить entities для форматирования
|
||||
pub fn entities(mut self, entities: Vec<TextEntity>) -> 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<ReactionInfo>) -> 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,
|
||||
|
||||
Reference in New Issue
Block a user