From b2aecf11da4e9d52fd5a462970db50b6ff24cfb5 Mon Sep 17 00:00:00 2001 From: Mikhail Kilin Date: Sun, 18 Jan 2026 21:34:54 +0300 Subject: [PATCH] fixes --- .env | 2 - src/main.rs | 160 ++++++++++++++++++++++++++++++-------------- src/tdlib/client.rs | 18 +++-- 3 files changed, 124 insertions(+), 56 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 9829081..0000000 --- a/.env +++ /dev/null @@ -1,2 +0,0 @@ -API_ID=36457397 -API_HASH=f74f670f33f3fa30a89b46c58dac2ff7 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4e18047..98a6019 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,6 +65,7 @@ struct App { chat_list_state: ListState, selected_chat: Option, current_messages: Vec, + message_input: String, // Input for new message folders: Vec, selected_folder: usize, is_loading: bool, @@ -87,6 +88,7 @@ impl App { chat_list_state: state, selected_chat: None, current_messages: Vec::new(), + message_input: String::new(), folders: vec!["All".to_string()], selected_folder: 0, is_loading: true, @@ -138,6 +140,7 @@ impl App { fn close_chat(&mut self) { self.selected_chat = None; self.current_messages.clear(); + self.message_input.clear(); } fn select_first_chat(&mut self) { @@ -372,61 +375,94 @@ async fn handle_main_input(app: &mut App, key: event::KeyEvent) { let has_super = key.modifiers.contains(KeyModifiers::SUPER); let has_ctrl = key.modifiers.contains(KeyModifiers::CONTROL); - match key.code { - // Navigate down: j, Down, д (Russian) - KeyCode::Char('j') | KeyCode::Char('д') | KeyCode::Down if !has_super && !has_ctrl => { - app.next_chat(); + // Если чат открыт - режим ввода сообщения + if app.selected_chat.is_some() { + match key.code { + KeyCode::Esc => { + app.close_chat(); + } + KeyCode::Char('r') if has_ctrl => { + // Обновить список чатов работает и в режиме чата + app.status_message = Some("Обновление чатов...".to_string()); + if let Err(e) = app.td_client.load_chats(50).await { + app.error_message = Some(e); + } + app.status_message = None; + } + KeyCode::Backspace => { + app.message_input.pop(); + } + KeyCode::Enter => { + // TODO: отправка сообщения + // Пока просто очищаем инпут + if !app.message_input.is_empty() { + app.message_input.clear(); + } + } + KeyCode::Char(c) => { + // Вводим символы в инпут сообщения + app.message_input.push(c); + } + _ => {} } - // Navigate up: k, Up, л (Russian) - KeyCode::Char('k') | KeyCode::Char('л') | KeyCode::Up if !has_super && !has_ctrl => { - app.previous_chat(); - } - // Jump to first chat: Cmd+Up or Ctrl+k/л - KeyCode::Up if has_super => { - app.select_first_chat(); - } - KeyCode::Char('k') | KeyCode::Char('л') if has_ctrl => { - app.select_first_chat(); - } - KeyCode::Enter => { - let prev_selected = app.selected_chat; - app.select_current_chat(); + } else { + // Режим навигации по списку чатов + match key.code { + // Navigate down: j, Down, д (Russian) + KeyCode::Char('j') | KeyCode::Char('д') | KeyCode::Down if !has_super && !has_ctrl => { + app.next_chat(); + } + // Navigate up: k, Up, л (Russian) + KeyCode::Char('k') | KeyCode::Char('л') | KeyCode::Up if !has_super && !has_ctrl => { + app.previous_chat(); + } + // Jump to first chat: Cmd+Up or Ctrl+k/л + KeyCode::Up if has_super => { + app.select_first_chat(); + } + KeyCode::Char('k') | KeyCode::Char('л') if has_ctrl => { + app.select_first_chat(); + } + KeyCode::Enter => { + let prev_selected = app.selected_chat; + app.select_current_chat(); - // Если выбрали новый чат, загружаем историю - if app.selected_chat != prev_selected { - if let Some(chat_id) = app.get_selected_chat_id() { - app.status_message = Some("Загрузка сообщений...".to_string()); - match app.td_client.get_chat_history(chat_id, 30).await { - Ok(messages) => { - app.current_messages = messages; - app.status_message = None; - } - Err(e) => { - app.error_message = Some(e); - app.status_message = None; + // Если выбрали новый чат, загружаем историю + if app.selected_chat != prev_selected { + if let Some(chat_id) = app.get_selected_chat_id() { + app.status_message = Some("Загрузка сообщений...".to_string()); + match app.td_client.get_chat_history(chat_id, 30).await { + Ok(messages) => { + app.current_messages = messages; + app.status_message = None; + } + Err(e) => { + app.error_message = Some(e); + app.status_message = None; + } } } } } - } - KeyCode::Esc => { - app.close_chat(); - } - KeyCode::Char('r') if has_ctrl => { - // Обновить список чатов - app.status_message = Some("Обновление чатов...".to_string()); - if let Err(e) = app.td_client.load_chats(50).await { - app.error_message = Some(e); + KeyCode::Esc => { + // Ничего не делаем, чат и так не открыт } - app.status_message = None; - } - KeyCode::Char(c) if c >= '1' && c <= '9' => { - let folder_idx = (c as usize) - ('1' as usize); - if folder_idx < app.folders.len() { - app.selected_folder = folder_idx; + KeyCode::Char('r') if has_ctrl => { + // Обновить список чатов + app.status_message = Some("Обновление чатов...".to_string()); + if let Err(e) = app.td_client.load_chats(50).await { + app.error_message = Some(e); + } + app.status_message = None; } + KeyCode::Char(c) if c >= '1' && c <= '9' => { + let folder_idx = (c as usize) - ('1' as usize); + if folder_idx < app.folders.len() { + app.selected_folder = folder_idx; + } + } + _ => {} } - _ => {} } } @@ -773,14 +809,34 @@ fn render_messages(f: &mut Frame, area: Rect, app: &App) { ))); } - let messages_widget = - Paragraph::new(lines).block(Block::default().borders(Borders::ALL)); + // Вычисляем скролл, чтобы показать последние сообщения + let visible_height = message_chunks[1].height.saturating_sub(2) as usize; // -2 для borders + let total_lines = lines.len(); + let scroll_offset = if total_lines > visible_height { + (total_lines - visible_height) as u16 + } else { + 0 + }; + + let messages_widget = Paragraph::new(lines) + .block(Block::default().borders(Borders::ALL)) + .scroll((scroll_offset, 0)); f.render_widget(messages_widget, message_chunks[1]); // Input box - let input = Paragraph::new("> ...") + let input_text = if app.message_input.is_empty() { + "> Введите сообщение...".to_string() + } else { + format!("> {}", app.message_input) + }; + let input_style = if app.message_input.is_empty() { + Style::default().fg(Color::DarkGray) + } else { + Style::default().fg(Color::Yellow) + }; + let input = Paragraph::new(input_text) .block(Block::default().borders(Borders::ALL)) - .style(Style::default().fg(Color::Yellow)); + .style(input_style); f.render_widget(input, message_chunks[2]); } } else { @@ -796,7 +852,11 @@ fn render_footer(f: &mut Frame, area: Rect, app: &App) { format!(" {} ", msg) } else if let Some(err) = &app.error_message { format!(" Error: {} ", err) + } else if app.selected_chat.is_some() { + // Режим ввода сообщения + " Enter: Send | Esc: Close chat | Ctrl+R: Refresh | Ctrl+C: Quit ".to_string() } else { + // Режим навигации " j/k: Navigate | Ctrl+k: First | Enter: Open | Esc: Close | Ctrl+R: Refresh | Ctrl+C: Quit ".to_string() }; diff --git a/src/tdlib/client.rs b/src/tdlib/client.rs index f826847..857c3d1 100644 --- a/src/tdlib/client.rs +++ b/src/tdlib/client.rs @@ -19,6 +19,7 @@ pub struct ChatInfo { pub id: i64, pub title: String, pub last_message: String, + pub last_message_date: i32, pub unread_count: i32, pub is_pinned: bool, pub order: i64, @@ -105,15 +106,19 @@ impl TdClient { } Update::ChatLastMessage(update) => { let chat_id = update.chat_id; - let last_message_text = update + let (last_message_text, last_message_date) = update .last_message .as_ref() - .map(|msg| extract_message_text_static(msg)) + .map(|msg| (extract_message_text_static(msg), msg.date)) .unwrap_or_default(); if let Some(chat) = self.chats.iter_mut().find(|c| c.id == chat_id) { chat.last_message = last_message_text; + chat.last_message_date = last_message_date; } + + // Пересортируем после обновления + self.chats.sort_by(|a, b| b.last_message_date.cmp(&a.last_message_date)); } Update::ChatReadInbox(update) => { if let Some(chat) = self.chats.iter_mut().find(|c| c.id == update.chat_id) { @@ -140,16 +145,17 @@ impl TdClient { } fn add_or_update_chat(&mut self, td_chat: &TdChat) { - let last_message = td_chat + let (last_message, last_message_date) = td_chat .last_message .as_ref() - .map(|m| extract_message_text_static(m)) + .map(|m| (extract_message_text_static(m), m.date)) .unwrap_or_default(); let chat_info = ChatInfo { id: td_chat.id, title: td_chat.title.clone(), last_message, + last_message_date, unread_count: td_chat.unread_count, is_pinned: false, order: 0, @@ -158,10 +164,14 @@ impl TdClient { if let Some(existing) = self.chats.iter_mut().find(|c| c.id == td_chat.id) { existing.title = chat_info.title; existing.last_message = chat_info.last_message; + existing.last_message_date = chat_info.last_message_date; existing.unread_count = chat_info.unread_count; } else { self.chats.push(chat_info); } + + // Сортируем чаты по дате последнего сообщения (новые сверху) + self.chats.sort_by(|a, b| b.last_message_date.cmp(&a.last_message_date)); } fn convert_message(&self, message: &TdMessage) -> MessageInfo {