This commit is contained in:
Mikhail Kilin
2026-01-21 21:20:18 +03:00
parent 0a9ae8b448
commit 1ef341d907
9 changed files with 326 additions and 95 deletions

View File

@@ -1,6 +1,6 @@
use std::env;
use std::collections::HashMap;
use tdlib_rs::enums::{AuthorizationState, ChatList, ChatType, MessageContent, Update, User};
use tdlib_rs::enums::{AuthorizationState, ChatList, ChatType, MessageContent, Update, User, UserStatus};
use tdlib_rs::functions;
use tdlib_rs::types::{Chat as TdChat, Message as TdMessage};
@@ -29,6 +29,8 @@ pub struct ChatInfo {
pub order: i64,
/// ID последнего прочитанного исходящего сообщения (для галочек)
pub last_read_outbox_message_id: i64,
/// ID папок, в которых находится чат
pub folder_ids: Vec<i32>,
}
#[derive(Debug, Clone)]
@@ -41,6 +43,29 @@ pub struct MessageInfo {
pub is_read: bool,
}
#[derive(Debug, Clone)]
pub struct FolderInfo {
pub id: i32,
pub name: String,
}
/// Онлайн-статус пользователя
#[derive(Debug, Clone, PartialEq)]
pub enum UserOnlineStatus {
/// Онлайн
Online,
/// Был недавно (менее часа назад)
Recently,
/// Был на этой неделе
LastWeek,
/// Был в этом месяце
LastMonth,
/// Давно не был
LongTimeAgo,
/// Оффлайн с указанием времени (unix timestamp)
Offline(i32),
}
pub struct TdClient {
pub auth_state: AuthState,
pub api_id: i32,
@@ -60,6 +85,12 @@ pub struct TdClient {
pub pending_view_messages: Vec<(i64, Vec<i64>)>,
/// Очередь user_id для загрузки имён
pub pending_user_ids: Vec<i64>,
/// Папки чатов
pub folders: Vec<FolderInfo>,
/// Позиция основного списка среди папок
pub main_chat_list_position: i32,
/// Онлайн-статусы пользователей: user_id -> status
user_statuses: HashMap<i64, UserOnlineStatus>,
}
#[allow(dead_code)]
@@ -86,6 +117,9 @@ impl TdClient {
chat_user_ids: HashMap::new(),
pending_view_messages: Vec::new(),
pending_user_ids: Vec::new(),
folders: Vec::new(),
main_chat_list_position: 0,
user_statuses: HashMap::new(),
}
}
@@ -97,6 +131,13 @@ impl TdClient {
self.client_id
}
/// Получение онлайн-статуса пользователя по chat_id (для приватных чатов)
pub fn get_user_status_by_chat_id(&self, chat_id: i64) -> Option<&UserOnlineStatus> {
self.chat_user_ids
.get(&chat_id)
.and_then(|user_id| self.user_statuses.get(user_id))
}
/// Инициализация TDLib с параметрами
pub async fn init(&mut self) -> Result<(), String> {
let result = functions::set_tdlib_parameters(
@@ -193,9 +234,22 @@ impl TdClient {
// Пересортируем по order
self.chats.sort_by(|a, b| b.order.cmp(&a.order));
}
ChatList::Archive | ChatList::Folder(_) => {
// Если чат добавляется в архив или папку, ничего не делаем
// (он уже должен быть удалён из Main)
ChatList::Folder(folder) => {
// Обновляем folder_ids для чата
if let Some(chat) = self.chats.iter_mut().find(|c| c.id == update.chat_id) {
if update.position.order == 0 {
// Чат удалён из папки
chat.folder_ids.retain(|&id| id != folder.chat_folder_id);
} else {
// Чат добавлен в папку
if !chat.folder_ids.contains(&folder.chat_folder_id) {
chat.folder_ids.push(folder.chat_folder_id);
}
}
}
}
ChatList::Archive => {
// Архив пока не обрабатываем
}
}
}
@@ -220,6 +274,16 @@ impl TdClient {
// Сохраняем имя и username пользователя
let user = update.user;
// Пропускаем удалённые аккаунты (пустое имя)
if user.first_name.is_empty() && user.last_name.is_empty() {
// Удаляем чаты с этим пользователем из списка
let user_id = user.id;
self.chats.retain(|c| {
self.chat_user_ids.get(&c.id) != Some(&user_id)
});
return;
}
// Сохраняем display name (first_name + last_name)
let display_name = if user.last_name.is_empty() {
user.first_name.clone()
@@ -243,6 +307,30 @@ impl TdClient {
}
}
}
Update::ChatFolders(update) => {
// Обновляем список папок
self.folders = update
.chat_folders
.into_iter()
.map(|f| FolderInfo {
id: f.id,
name: f.title,
})
.collect();
self.main_chat_list_position = update.main_chat_list_position;
}
Update::UserStatus(update) => {
// Обновляем онлайн-статус пользователя
let status = match update.status {
UserStatus::Online(_) => UserOnlineStatus::Online,
UserStatus::Offline(offline) => UserOnlineStatus::Offline(offline.was_online),
UserStatus::Recently(_) => UserOnlineStatus::Recently,
UserStatus::LastWeek(_) => UserOnlineStatus::LastWeek,
UserStatus::LastMonth(_) => UserOnlineStatus::LastMonth,
UserStatus::Empty => UserOnlineStatus::LongTimeAgo,
};
self.user_statuses.insert(update.user_id, status);
}
_ => {}
}
}
@@ -260,6 +348,13 @@ impl TdClient {
}
fn add_or_update_chat(&mut self, td_chat: &TdChat) {
// Пропускаем удалённые аккаунты
if td_chat.title == "Deleted Account" || td_chat.title.is_empty() {
// Удаляем из списка если уже был добавлен
self.chats.retain(|c| c.id != td_chat.id);
return;
}
// Ищем позицию в Main списке (если есть)
let main_position = td_chat.positions.iter().find(|pos| {
matches!(pos.list, ChatList::Main)
@@ -286,6 +381,19 @@ impl TdClient {
_ => None,
};
// Извлекаем ID папок из позиций
let folder_ids: Vec<i32> = td_chat
.positions
.iter()
.filter_map(|pos| {
if let ChatList::Folder(folder) = &pos.list {
Some(folder.chat_folder_id)
} else {
None
}
})
.collect();
let chat_info = ChatInfo {
id: td_chat.id,
title: td_chat.title.clone(),
@@ -296,6 +404,7 @@ impl TdClient {
is_pinned,
order,
last_read_outbox_message_id: td_chat.last_read_outbox_message_id,
folder_ids,
};
if let Some(existing) = self.chats.iter_mut().find(|c| c.id == td_chat.id) {
@@ -304,6 +413,7 @@ impl TdClient {
existing.last_message_date = chat_info.last_message_date;
existing.unread_count = chat_info.unread_count;
existing.last_read_outbox_message_id = chat_info.last_read_outbox_message_id;
existing.folder_ids = chat_info.folder_ids;
// Обновляем username если он появился
if chat_info.username.is_some() {
existing.username = chat_info.username;
@@ -417,6 +527,25 @@ impl TdClient {
}
}
/// Загрузка чатов для конкретной папки
pub async fn load_folder_chats(&mut self, folder_id: i32, limit: i32) -> Result<(), String> {
let chat_list = ChatList::Folder(tdlib_rs::types::ChatListFolder {
chat_folder_id: folder_id,
});
let result = functions::load_chats(
Some(chat_list),
limit,
self.client_id,
)
.await;
match result {
Ok(_) => Ok(()),
Err(e) => Err(format!("Ошибка загрузки чатов папки: {:?}", e)),
}
}
/// Загрузка истории сообщений чата
pub async fn get_chat_history(
&mut self,