fix: mark incoming messages as read when opening chat and load all history

Fixes two critical bugs:
1. Unread badge not clearing when opening chat - incoming messages weren't marked as viewed
2. Only last 2-3 messages loaded instead of full history due to incorrect break condition

Changes:
- Add incoming message IDs to pending_view_messages queue on chat open
- Remove premature break in get_chat_history() that stopped after 2 messages
- Add FakeTdClient.pending_view_messages field for testing
- Implement process_pending_view_messages() in FakeTdClient

Tests added:
- test_incoming_message_shows_unread_badge: verify "(1)" appears for unread
- test_opening_chat_clears_unread_badge: verify badge clears after opening
- test_opening_chat_loads_many_messages: verify all 50 messages load, not just last few

All 28 chat_list tests pass.
This commit is contained in:
Mikhail Kilin
2026-02-04 02:07:47 +03:00
parent 5ac10ea24c
commit dec60ea74e
5 changed files with 193 additions and 6 deletions

View File

@@ -46,6 +46,7 @@ pub struct FakeTdClient {
pub searched_queries: Arc<Mutex<Vec<SearchQuery>>>,
pub viewed_messages: Arc<Mutex<Vec<(i64, Vec<i64>)>>>, // (chat_id, message_ids)
pub chat_actions: Arc<Mutex<Vec<(i64, String)>>>, // (chat_id, action)
pub pending_view_messages: Arc<Mutex<Vec<(ChatId, Vec<MessageId>)>>>, // Очередь для отметки как прочитанные
// Update channel для симуляции событий
pub update_tx: Arc<Mutex<Option<mpsc::UnboundedSender<TdUpdate>>>>,
@@ -119,6 +120,7 @@ impl Clone for FakeTdClient {
searched_queries: Arc::clone(&self.searched_queries),
viewed_messages: Arc::clone(&self.viewed_messages),
chat_actions: Arc::clone(&self.chat_actions),
pending_view_messages: Arc::clone(&self.pending_view_messages),
update_tx: Arc::clone(&self.update_tx),
simulate_delays: self.simulate_delays,
fail_next_operation: Arc::clone(&self.fail_next_operation),
@@ -151,6 +153,7 @@ impl FakeTdClient {
searched_queries: Arc::new(Mutex::new(vec![])),
viewed_messages: Arc::new(Mutex::new(vec![])),
chat_actions: Arc::new(Mutex::new(vec![])),
pending_view_messages: Arc::new(Mutex::new(vec![])),
update_tx: Arc::new(Mutex::new(None)),
simulate_delays: false,
fail_next_operation: Arc::new(Mutex::new(false)),

View File

@@ -125,7 +125,12 @@ impl TdClientTrait for FakeTdClient {
}
async fn process_pending_view_messages(&mut self) {
// Not used in fake client
// Перемещаем pending в viewed для проверки в тестах
let mut pending = self.pending_view_messages.lock().unwrap();
for (chat_id, message_ids) in pending.drain(..) {
let ids: Vec<i64> = message_ids.iter().map(|id| id.as_i64()).collect();
self.viewed_messages.lock().unwrap().push((chat_id.as_i64(), ids));
}
}
// ============ User methods ============
@@ -276,7 +281,10 @@ impl TdClientTrait for FakeTdClient {
}
fn pending_view_messages_mut(&mut self) -> &mut Vec<(ChatId, Vec<MessageId>)> {
panic!("pending_view_messages_mut not supported for FakeTdClient")
// WORKAROUND: Возвращаем мутабельную ссылку через leak
// Это безопасно так как мы единственные владельцы &mut self
let guard = self.pending_view_messages.lock().unwrap();
unsafe { &mut *(guard.as_ptr() as *mut Vec<(ChatId, Vec<MessageId>)>) }
}
fn pending_user_ids_mut(&mut self) -> &mut Vec<UserId> {