fixes
This commit is contained in:
@@ -27,6 +27,8 @@ pub struct ChatInfo {
|
||||
pub unread_count: i32,
|
||||
pub is_pinned: bool,
|
||||
pub order: i64,
|
||||
/// ID последнего прочитанного исходящего сообщения (для галочек)
|
||||
pub last_read_outbox_message_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -46,10 +48,14 @@ pub struct TdClient {
|
||||
client_id: i32,
|
||||
pub chats: Vec<ChatInfo>,
|
||||
pub current_chat_messages: Vec<MessageInfo>,
|
||||
/// ID текущего открытого чата (для получения новых сообщений)
|
||||
pub current_chat_id: Option<i64>,
|
||||
/// Кэш usernames: user_id -> username
|
||||
user_usernames: HashMap<i64, String>,
|
||||
/// Связь chat_id -> user_id для приватных чатов
|
||||
chat_user_ids: HashMap<i64, i64>,
|
||||
/// Очередь сообщений для отметки как прочитанных: (chat_id, message_ids)
|
||||
pub pending_view_messages: Vec<(i64, Vec<i64>)>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -70,8 +76,10 @@ impl TdClient {
|
||||
client_id,
|
||||
chats: Vec::new(),
|
||||
current_chat_messages: Vec::new(),
|
||||
current_chat_id: None,
|
||||
user_usernames: HashMap::new(),
|
||||
chat_user_ids: HashMap::new(),
|
||||
pending_view_messages: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +158,20 @@ impl TdClient {
|
||||
chat.unread_count = update.unread_count;
|
||||
}
|
||||
}
|
||||
Update::ChatReadOutbox(update) => {
|
||||
// Обновляем last_read_outbox_message_id когда собеседник прочитал сообщения
|
||||
if let Some(chat) = self.chats.iter_mut().find(|c| c.id == update.chat_id) {
|
||||
chat.last_read_outbox_message_id = update.last_read_outbox_message_id;
|
||||
}
|
||||
// Если это текущий открытый чат — обновляем is_read у сообщений
|
||||
if Some(update.chat_id) == self.current_chat_id {
|
||||
for msg in &mut self.current_chat_messages {
|
||||
if msg.is_outgoing && msg.id <= update.last_read_outbox_message_id {
|
||||
msg.is_read = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Update::ChatPosition(update) => {
|
||||
// Обновляем позицию чата или удаляем его из списка
|
||||
match &update.position.list {
|
||||
@@ -171,8 +193,22 @@ impl TdClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
Update::NewMessage(_new_msg) => {
|
||||
// Новые сообщения обрабатываются при обновлении UI
|
||||
Update::NewMessage(new_msg) => {
|
||||
// Добавляем новое сообщение если это текущий открытый чат
|
||||
let chat_id = new_msg.message.chat_id;
|
||||
if Some(chat_id) == self.current_chat_id {
|
||||
let msg_info = self.convert_message(&new_msg.message, chat_id);
|
||||
let msg_id = msg_info.id;
|
||||
let is_incoming = !msg_info.is_outgoing;
|
||||
// Проверяем, что сообщение ещё не добавлено (по id)
|
||||
if !self.current_chat_messages.iter().any(|m| m.id == msg_info.id) {
|
||||
self.current_chat_messages.push(msg_info);
|
||||
// Если это входящее сообщение — добавляем в очередь для отметки как прочитанное
|
||||
if is_incoming {
|
||||
self.pending_view_messages.push((chat_id, vec![msg_id]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Update::User(update) => {
|
||||
// Сохраняем username пользователя
|
||||
@@ -243,6 +279,7 @@ impl TdClient {
|
||||
unread_count: td_chat.unread_count,
|
||||
is_pinned,
|
||||
order,
|
||||
last_read_outbox_message_id: td_chat.last_read_outbox_message_id,
|
||||
};
|
||||
|
||||
if let Some(existing) = self.chats.iter_mut().find(|c| c.id == td_chat.id) {
|
||||
@@ -250,6 +287,7 @@ impl TdClient {
|
||||
existing.last_message = chat_info.last_message;
|
||||
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;
|
||||
// Обновляем username если он появился
|
||||
if chat_info.username.is_some() {
|
||||
existing.username = chat_info.username;
|
||||
@@ -267,19 +305,31 @@ impl TdClient {
|
||||
self.chats.sort_by(|a, b| b.order.cmp(&a.order));
|
||||
}
|
||||
|
||||
fn convert_message(&self, message: &TdMessage) -> MessageInfo {
|
||||
fn convert_message(&self, message: &TdMessage, chat_id: i64) -> MessageInfo {
|
||||
let sender_name = match &message.sender_id {
|
||||
tdlib_rs::enums::MessageSender::User(user) => format!("User_{}", user.user_id),
|
||||
tdlib_rs::enums::MessageSender::Chat(chat) => format!("Chat_{}", chat.chat_id),
|
||||
};
|
||||
|
||||
// Определяем, прочитано ли исходящее сообщение
|
||||
let is_read = if message.is_outgoing {
|
||||
// Сообщение прочитано, если его ID <= last_read_outbox_message_id чата
|
||||
self.chats
|
||||
.iter()
|
||||
.find(|c| c.id == chat_id)
|
||||
.map(|c| message.id <= c.last_read_outbox_message_id)
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
true // Входящие сообщения не показывают галочки
|
||||
};
|
||||
|
||||
MessageInfo {
|
||||
id: message.id,
|
||||
sender_name,
|
||||
is_outgoing: message.is_outgoing,
|
||||
content: extract_message_text_static(message),
|
||||
date: message.date,
|
||||
is_read: !message.is_outgoing || message.id <= 0,
|
||||
is_read,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,34 +389,80 @@ impl TdClient {
|
||||
chat_id: i64,
|
||||
limit: i32,
|
||||
) -> Result<Vec<MessageInfo>, String> {
|
||||
// Устанавливаем текущий чат для получения новых сообщений
|
||||
self.current_chat_id = Some(chat_id);
|
||||
let _ = functions::open_chat(chat_id, self.client_id).await;
|
||||
|
||||
// Загружаем историю с сервера (only_local=false)
|
||||
let result = functions::get_chat_history(
|
||||
chat_id,
|
||||
0, // from_message_id (0 = с последнего сообщения)
|
||||
0, // offset
|
||||
limit,
|
||||
false, // only_local - загружаем с сервера!
|
||||
self.client_id,
|
||||
)
|
||||
.await;
|
||||
// Пробуем загрузить несколько раз, так как сообщения могут подгружаться с сервера
|
||||
let mut all_messages: Vec<MessageInfo> = Vec::new();
|
||||
let mut from_message_id: i64 = 0;
|
||||
let mut attempts = 0;
|
||||
const MAX_ATTEMPTS: i32 = 3;
|
||||
|
||||
match result {
|
||||
Ok(tdlib_rs::enums::Messages::Messages(messages)) => {
|
||||
let mut result_messages: Vec<MessageInfo> = messages
|
||||
.messages
|
||||
.into_iter()
|
||||
.filter_map(|m| m.map(|msg| self.convert_message(&msg)))
|
||||
.collect();
|
||||
while attempts < MAX_ATTEMPTS {
|
||||
let result = functions::get_chat_history(
|
||||
chat_id,
|
||||
from_message_id,
|
||||
0, // offset
|
||||
limit,
|
||||
false, // only_local - загружаем с сервера!
|
||||
self.client_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Сообщения приходят от новых к старым, переворачиваем
|
||||
result_messages.reverse();
|
||||
self.current_chat_messages = result_messages.clone();
|
||||
Ok(result_messages)
|
||||
match result {
|
||||
Ok(tdlib_rs::enums::Messages::Messages(messages)) => {
|
||||
let batch: Vec<MessageInfo> = messages
|
||||
.messages
|
||||
.into_iter()
|
||||
.filter_map(|m| m.map(|msg| self.convert_message(&msg, chat_id)))
|
||||
.collect();
|
||||
|
||||
if batch.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Запоминаем ID самого старого сообщения для следующей загрузки
|
||||
if let Some(oldest) = batch.last() {
|
||||
from_message_id = oldest.id;
|
||||
}
|
||||
|
||||
// Добавляем сообщения (они приходят от новых к старым)
|
||||
all_messages.extend(batch);
|
||||
attempts += 1;
|
||||
|
||||
// Если получили достаточно сообщений, выходим
|
||||
if all_messages.len() >= limit as usize {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if all_messages.is_empty() {
|
||||
return Err(format!("Ошибка загрузки сообщений: {:?}", e));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => Err(format!("Ошибка загрузки сообщений: {:?}", e)),
|
||||
}
|
||||
|
||||
// Сообщения приходят от новых к старым, переворачиваем
|
||||
all_messages.reverse();
|
||||
self.current_chat_messages = all_messages.clone();
|
||||
|
||||
// Отмечаем сообщения как прочитанные
|
||||
if !all_messages.is_empty() {
|
||||
let message_ids: Vec<i64> = all_messages.iter().map(|m| m.id).collect();
|
||||
let _ = functions::view_messages(
|
||||
chat_id,
|
||||
message_ids,
|
||||
None, // source
|
||||
true, // force_read
|
||||
self.client_id,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(all_messages)
|
||||
}
|
||||
|
||||
/// Загрузка старых сообщений (для скролла вверх)
|
||||
@@ -391,7 +487,7 @@ impl TdClient {
|
||||
let mut result_messages: Vec<MessageInfo> = messages
|
||||
.messages
|
||||
.into_iter()
|
||||
.filter_map(|m| m.map(|msg| self.convert_message(&msg)))
|
||||
.filter_map(|m| m.map(|msg| self.convert_message(&msg, chat_id)))
|
||||
.collect();
|
||||
|
||||
// Сообщения приходят от новых к старым, переворачиваем
|
||||
@@ -474,6 +570,21 @@ impl TdClient {
|
||||
Err(e) => Err(format!("Ошибка отправки сообщения: {:?}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Обработка очереди сообщений для отметки как прочитанных
|
||||
pub async fn process_pending_view_messages(&mut self) {
|
||||
let pending = std::mem::take(&mut self.pending_view_messages);
|
||||
for (chat_id, message_ids) in pending {
|
||||
let _ = functions::view_messages(
|
||||
chat_id,
|
||||
message_ids,
|
||||
None, // source
|
||||
true, // force_read
|
||||
self.client_id,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Статическая функция для извлечения текста сообщения (без &self)
|
||||
|
||||
Reference in New Issue
Block a user