fixes
This commit is contained in:
39
CONTEXT.md
39
CONTEXT.md
@@ -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)
|
||||||
|
|
||||||
## Известные проблемы
|
## Известные проблемы
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
|
|
||||||
## Фаза 3: Улучшение UX [IN PROGRESS]
|
## Фаза 3: Улучшение UX [IN PROGRESS]
|
||||||
|
|
||||||
- [ ] Отправка сообщений
|
- [x] Отправка сообщений
|
||||||
|
- [x] Фильтрация чатов (только Main, без архива)
|
||||||
- [ ] Поиск по чатам (Ctrl+S)
|
- [ ] Поиск по чатам (Ctrl+S)
|
||||||
- [ ] Скролл истории сообщений
|
- [ ] Скролл истории сообщений
|
||||||
- [ ] Загрузка имён пользователей (вместо User_ID)
|
- [ ] Загрузка имён пользователей (вместо User_ID)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user