Files
telegram-tui/src/tdlib/types.rs
Mikhail Kilin 644e36597d fixes
2026-01-31 03:48:50 +03:00

553 lines
16 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use tdlib_rs::types::TextEntity;
use crate::types::{ChatId, MessageId};
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct ChatInfo {
pub id: ChatId,
pub title: String,
pub username: Option<String>,
pub last_message: String,
pub last_message_date: i32,
pub unread_count: i32,
/// Количество непрочитанных упоминаний (@)
pub unread_mention_count: i32,
pub is_pinned: bool,
pub order: i64,
/// ID последнего прочитанного исходящего сообщения (для галочек)
pub last_read_outbox_message_id: MessageId,
/// ID папок, в которых находится чат
pub folder_ids: Vec<i32>,
/// Чат замьючен (уведомления отключены)
pub is_muted: bool,
/// Черновик сообщения
pub draft_text: Option<String>,
}
/// Информация о сообщении, на которое отвечают
#[derive(Debug, Clone)]
pub struct ReplyInfo {
/// ID сообщения, на которое отвечают
pub message_id: MessageId,
/// Имя отправителя оригинального сообщения
pub sender_name: String,
/// Текст оригинального сообщения (превью)
pub text: String,
}
/// Информация о пересланном сообщении
#[derive(Debug, Clone)]
pub struct ForwardInfo {
/// Имя оригинального отправителя
pub sender_name: String,
/// Дата оригинального сообщения (для будущего использования)
#[allow(dead_code)]
pub date: i32,
}
/// Информация о реакции на сообщение
#[derive(Debug, Clone)]
pub struct ReactionInfo {
/// Эмодзи реакции (например, "👍")
pub emoji: String,
/// Количество людей, поставивших эту реакцию
pub count: i32,
/// Поставил ли текущий пользователь эту реакцию
pub is_chosen: bool,
}
/// Метаданные сообщения (ID, отправитель, время)
#[derive(Debug, Clone)]
pub struct MessageMetadata {
pub id: MessageId,
pub sender_name: String,
pub date: i32,
/// Дата редактирования (0 если не редактировалось)
pub edit_date: i32,
}
/// Контент сообщения (текст и форматирование)
#[derive(Debug, Clone, PartialEq)]
pub struct MessageContent {
pub text: String,
/// Сущности форматирования (bold, italic, code и т.д.)
pub entities: Vec<TextEntity>,
}
/// Состояние и права доступа к сообщению
#[derive(Debug, Clone)]
pub struct MessageState {
pub is_outgoing: bool,
pub is_read: bool,
/// Можно ли редактировать сообщение
pub can_be_edited: bool,
/// Можно ли удалить только для себя
pub can_be_deleted_only_for_self: bool,
/// Можно ли удалить для всех
pub can_be_deleted_for_all_users: bool,
}
/// Взаимодействия с сообщением (reply, forward, reactions)
#[derive(Debug, Clone)]
pub struct MessageInteractions {
/// Информация о reply (если это ответ на сообщение)
pub reply_to: Option<ReplyInfo>,
/// Информация о forward (если сообщение переслано)
pub forward_from: Option<ForwardInfo>,
/// Реакции на сообщение
pub reactions: Vec<ReactionInfo>,
}
#[derive(Debug, Clone)]
pub struct MessageInfo {
pub metadata: MessageMetadata,
pub content: MessageContent,
pub state: MessageState,
pub interactions: MessageInteractions,
}
impl MessageInfo {
/// Создать новое сообщение
pub fn new(
id: MessageId,
sender_name: String,
is_outgoing: bool,
content: 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>,
) -> Self {
Self {
metadata: MessageMetadata {
id,
sender_name,
date,
edit_date,
},
content: MessageContent {
text: content,
entities,
},
state: MessageState {
is_outgoing,
is_read,
can_be_edited,
can_be_deleted_only_for_self,
can_be_deleted_for_all_users,
},
interactions: MessageInteractions {
reply_to,
forward_from,
reactions,
},
}
}
// Удобные getter'ы для частых операций
pub fn id(&self) -> MessageId {
self.metadata.id
}
pub fn sender_name(&self) -> &str {
&self.metadata.sender_name
}
pub fn date(&self) -> i32 {
self.metadata.date
}
pub fn edit_date(&self) -> i32 {
self.metadata.edit_date
}
pub fn is_edited(&self) -> bool {
self.metadata.edit_date > 0
}
pub fn text(&self) -> &str {
&self.content.text
}
pub fn entities(&self) -> &[TextEntity] {
&self.content.entities
}
pub fn is_outgoing(&self) -> bool {
self.state.is_outgoing
}
pub fn is_read(&self) -> bool {
self.state.is_read
}
pub fn can_be_edited(&self) -> bool {
self.state.can_be_edited
}
pub fn can_be_deleted_only_for_self(&self) -> bool {
self.state.can_be_deleted_only_for_self
}
pub fn can_be_deleted_for_all_users(&self) -> bool {
self.state.can_be_deleted_for_all_users
}
pub fn reply_to(&self) -> Option<&ReplyInfo> {
self.interactions.reply_to.as_ref()
}
pub fn forward_from(&self) -> Option<&ForwardInfo> {
self.interactions.forward_from.as_ref()
}
pub fn reactions(&self) -> &[ReactionInfo] {
&self.interactions.reactions
}
}
/// 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,
pub name: String,
}
/// Информация о профиле чата/пользователя
#[derive(Debug, Clone)]
pub struct ProfileInfo {
pub chat_id: ChatId,
pub title: String,
pub username: Option<String>,
pub bio: Option<String>,
pub phone_number: Option<String>,
pub chat_type: String, // "Личный чат", "Группа", "Канал"
pub member_count: Option<i32>,
pub description: Option<String>,
pub invite_link: Option<String>,
pub is_group: bool,
pub online_status: Option<String>,
}
/// Состояние сетевого соединения
#[derive(Debug, Clone, PartialEq)]
pub enum NetworkState {
/// Ожидание подключения к сети
WaitingForNetwork,
/// Подключение к прокси
ConnectingToProxy,
/// Подключение к серверам Telegram
Connecting,
/// Обновление данных
Updating,
/// Подключено
Ready,
}
/// Онлайн-статус пользователя
#[derive(Debug, Clone, PartialEq)]
pub enum UserOnlineStatus {
/// Онлайн
Online,
/// Был недавно (менее часа назад)
Recently,
/// Был на этой неделе
LastWeek,
/// Был в этом месяце
LastMonth,
/// Давно не был
LongTimeAgo,
/// Оффлайн с указанием времени (unix timestamp)
Offline(i32),
}