This commit is contained in:
Mikhail Kilin
2026-01-20 13:37:02 +03:00
parent b6d9291864
commit 699f50a59c
3 changed files with 90 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
# Текущий контекст проекта # Текущий контекст проекта
## Статус: Базовая интеграция с TDLib работает ## Статус: Фаза 3 — улучшение UX
### Что сделано ### Что сделано
@@ -13,27 +13,46 @@
#### Функциональность #### Функциональность
- Загрузка списка чатов (до 50 штук) - Загрузка списка чатов (до 50 штук)
- **Фильтрация чатов**: показываются только чаты из ChatList::Main (без архива)
- Отображение названия чата и счётчика непрочитанных - Отображение названия чата и счётчика непрочитанных
- Загрузка истории сообщений при открытии чата - Загрузка истории сообщений при открытии чата
- Отображение сообщений с именем отправителя и временем - Отображение сообщений с именем отправителя и временем
- **Отправка текстовых сообщений**
#### Управление #### Управление
- `j/k` или стрелки — навигация по списку чатов - `j/k` или стрелки — навигация по списку чатов
- `д/л` — русская раскладка для j/k - `д/л` — русская раскладка для j/k
- `Enter` — открыть выбранный чат - `Enter` — открыть чат / отправить сообщение
- `Esc` — закрыть открытый чат - `Esc` — закрыть открытый чат
- `Ctrl+k` — перейти к первому чату - `Ctrl+k` — перейти к первому чату
- `Ctrl+R` — обновить список чатов - `Ctrl+R` — обновить список чатов
- `Ctrl+C` — выход - `Ctrl+C` — выход
- Ввод текста в поле сообщения
### Структура проекта ### Структура проекта
``` ```
src/ src/
├── main.rs # Точка входа, UI рендеринг, event loop ├── main.rs # Точка входа, event loop, TDLib инициализация
├── tdlib/ ├── app/
│ ├── mod.rs # Модуль экспорта │ ├── mod.rs # App структура и состояние
│ └── client.rs # TdClient: авторизация, загрузка чатов, сообщений │ └── state.rs # AppScreen enum
├── ui/
│ ├── mod.rs # Роутинг UI по экранам
│ ├── loading.rs # Экран загрузки
│ ├── auth.rs # Экран авторизации
│ ├── main_screen.rs # Главный экран
│ ├── chat_list.rs # Список чатов
│ ├── messages.rs # Область сообщений
│ └── footer.rs # Подвал с командами
├── input/
│ ├── mod.rs # Роутинг ввода
│ ├── auth.rs # Обработка ввода на экране авторизации
│ └── main_input.rs # Обработка ввода на главном экране
├── utils.rs # Утилиты (disable_tdlib_logs, format_timestamp)
└── tdlib/
├── mod.rs # Модуль экспорта
└── client.rs # TdClient: авторизация, загрузка чатов, сообщений, отправка
``` ```
### Ключевые решения ### Ключевые решения
@@ -44,6 +63,10 @@ src/
3. **Синхронизация чатов**: Чаты загружаются асинхронно через updates. Main loop периодически синхронизирует `app.chats` с `td_client.chats`. 3. **Синхронизация чатов**: Чаты загружаются асинхронно через updates. Main loop периодически синхронизирует `app.chats` с `td_client.chats`.
4. **Фильтрация чатов по ChatList::Main**: Показываем только чаты с позицией в Main списке и ненулевым order. Архивные чаты и связанные группы не отображаются.
5. **Сортировка по TDLib order**: Используем `position.order` для сортировки чатов (учитывает pinned и время).
### Зависимости (Cargo.toml) ### Зависимости (Cargo.toml)
```toml ```toml
@@ -65,14 +88,14 @@ API_HASH=your_api_hash
## Что НЕ сделано / TODO ## Что НЕ сделано / TODO
- [ ] Отправка сообщений
- [ ] Поиск по чатам - [ ] Поиск по чатам
- [ ] Папки телеграма (сейчас только "All") - [ ] Папки телеграма (сейчас только "All")
- [ ] Отображение онлайн-статуса пользователя - [ ] Отображение онлайн-статуса пользователя
- [ ] Markdown форматирование в сообщениях - [ ] Markdown форматирование в сообщениях
- [ ] Скролл истории сообщений - [ ] Скролл истории сообщений (больше 50 сообщений)
- [ ] Отметка сообщений как прочитанные - [ ] Отметка сообщений как прочитанные
- [ ] Обновление чатов в реальном времени (новые сообщения) - [ ] Обновление чатов в реальном времени (новые сообщения)
- [ ] Загрузка имён пользователей (сейчас показывается User_ID)
## Известные проблемы ## Известные проблемы

View File

@@ -19,7 +19,8 @@
## Фаза 3: Улучшение UX [IN PROGRESS] ## Фаза 3: Улучшение UX [IN PROGRESS]
- [ ] Отправка сообщений - [x] Отправка сообщений
- [x] Фильтрация чатов (только Main, без архива)
- [ ] Поиск по чатам (Ctrl+S) - [ ] Поиск по чатам (Ctrl+S)
- [ ] Скролл истории сообщений - [ ] Скролл истории сообщений
- [ ] Загрузка имён пользователей (вместо User_ID) - [ ] Загрузка имён пользователей (вместо User_ID)

View File

@@ -124,14 +124,45 @@ impl TdClient {
chat.last_message_date = last_message_date; chat.last_message_date = last_message_date;
} }
// Пересортируем после обновления // Обновляем позиции если они пришли
self.chats.sort_by(|a, b| b.last_message_date.cmp(&a.last_message_date)); for pos in &update.positions {
if matches!(pos.list, ChatList::Main) {
if let Some(chat) = self.chats.iter_mut().find(|c| c.id == chat_id) {
chat.order = pos.order;
chat.is_pinned = pos.is_pinned;
}
}
}
// Пересортируем по order
self.chats.sort_by(|a, b| b.order.cmp(&a.order));
} }
Update::ChatReadInbox(update) => { Update::ChatReadInbox(update) => {
if let Some(chat) = self.chats.iter_mut().find(|c| c.id == update.chat_id) { if let Some(chat) = self.chats.iter_mut().find(|c| c.id == update.chat_id) {
chat.unread_count = update.unread_count; chat.unread_count = update.unread_count;
} }
} }
Update::ChatPosition(update) => {
// Обновляем позицию чата или удаляем его из списка
match &update.position.list {
ChatList::Main => {
if update.position.order == 0 {
// Чат больше не в Main (перемещён в архив и т.д.)
self.chats.retain(|c| c.id != update.chat_id);
} else if let Some(chat) = self.chats.iter_mut().find(|c| c.id == update.chat_id) {
// Обновляем позицию существующего чата
chat.order = update.position.order;
chat.is_pinned = update.position.is_pinned;
}
// Пересортируем по order
self.chats.sort_by(|a, b| b.order.cmp(&a.order));
}
ChatList::Archive | ChatList::Folder(_) => {
// Если чат добавляется в архив или папку, ничего не делаем
// (он уже должен быть удалён из Main)
}
}
}
Update::NewMessage(_new_msg) => { Update::NewMessage(_new_msg) => {
// Новые сообщения обрабатываются при обновлении UI // Новые сообщения обрабатываются при обновлении UI
} }
@@ -152,6 +183,24 @@ impl TdClient {
} }
fn add_or_update_chat(&mut self, td_chat: &TdChat) { fn add_or_update_chat(&mut self, td_chat: &TdChat) {
// Проверяем, есть ли у чата позиция в ChatList::Main
// Если нет - не добавляем (это архивные чаты или связанные группы)
let main_position = td_chat.positions.iter().find(|pos| {
matches!(pos.list, ChatList::Main)
});
// Если чат не в Main списке - удаляем его если был, и выходим
let Some(position) = main_position else {
self.chats.retain(|c| c.id != td_chat.id);
return;
};
// Если order == 0, чат не должен отображаться
if position.order == 0 {
self.chats.retain(|c| c.id != td_chat.id);
return;
}
let (last_message, last_message_date) = td_chat let (last_message, last_message_date) = td_chat
.last_message .last_message
.as_ref() .as_ref()
@@ -164,8 +213,8 @@ impl TdClient {
last_message, last_message,
last_message_date, last_message_date,
unread_count: td_chat.unread_count, unread_count: td_chat.unread_count,
is_pinned: false, is_pinned: position.is_pinned,
order: 0, order: position.order,
}; };
if let Some(existing) = self.chats.iter_mut().find(|c| c.id == td_chat.id) { if let Some(existing) = self.chats.iter_mut().find(|c| c.id == td_chat.id) {
@@ -173,12 +222,14 @@ impl TdClient {
existing.last_message = chat_info.last_message; existing.last_message = chat_info.last_message;
existing.last_message_date = chat_info.last_message_date; existing.last_message_date = chat_info.last_message_date;
existing.unread_count = chat_info.unread_count; existing.unread_count = chat_info.unread_count;
existing.is_pinned = chat_info.is_pinned;
existing.order = chat_info.order;
} else { } else {
self.chats.push(chat_info); self.chats.push(chat_info);
} }
// Сортируем чаты по дате последнего сообщения (новые сверху) // Сортируем чаты по order (TDLib order учитывает pinned и время)
self.chats.sort_by(|a, b| b.last_message_date.cmp(&a.last_message_date)); self.chats.sort_by(|a, b| b.order.cmp(&a.order));
} }
fn convert_message(&self, message: &TdMessage) -> MessageInfo { fn convert_message(&self, message: &TdMessage) -> MessageInfo {