This commit is contained in:
Mikhail Kilin
2026-01-24 02:22:47 +03:00
parent c18f43664e
commit 22c4e17377
9 changed files with 1199 additions and 226 deletions

View File

@@ -3,7 +3,7 @@ mod state;
pub use state::AppScreen;
use ratatui::widgets::ListState;
use crate::tdlib::client::{ChatInfo, MessageInfo};
use crate::tdlib::client::ChatInfo;
use crate::tdlib::TdClient;
pub struct App {
@@ -19,8 +19,9 @@ pub struct App {
pub chats: Vec<ChatInfo>,
pub chat_list_state: ListState,
pub selected_chat_id: Option<i64>,
pub current_messages: Vec<MessageInfo>,
pub message_input: String,
/// Позиция курсора в message_input (в символах)
pub cursor_position: usize,
pub message_scroll_offset: usize,
/// None = All (основной список), Some(id) = папка с id
pub selected_folder_id: Option<i32>,
@@ -30,6 +31,14 @@ pub struct App {
pub search_query: String,
/// Флаг для оптимизации рендеринга - перерисовывать только при изменениях
pub needs_redraw: bool,
// Edit message state
/// ID сообщения, которое редактируется (None = режим отправки нового)
pub editing_message_id: Option<i64>,
/// Индекс выбранного сообщения для навигации (снизу вверх, 0 = последнее)
pub selected_message_index: Option<usize>,
// Delete confirmation
/// ID сообщения для подтверждения удаления (показывает модалку)
pub confirm_delete_message_id: Option<i64>,
}
impl App {
@@ -48,22 +57,20 @@ impl App {
chats: Vec::new(),
chat_list_state: state,
selected_chat_id: None,
current_messages: Vec::new(),
message_input: String::new(),
cursor_position: 0,
message_scroll_offset: 0,
selected_folder_id: None, // None = All
is_loading: true,
is_searching: false,
search_query: String::new(),
needs_redraw: true,
editing_message_id: None,
selected_message_index: None,
confirm_delete_message_id: None,
}
}
/// Помечает UI как требующий перерисовки
pub fn mark_dirty(&mut self) {
self.needs_redraw = true;
}
pub fn next_chat(&mut self) {
let filtered = self.get_filtered_chats();
if filtered.is_empty() {
@@ -111,18 +118,95 @@ impl App {
pub fn close_chat(&mut self) {
self.selected_chat_id = None;
self.current_messages.clear();
self.message_input.clear();
self.cursor_position = 0;
self.message_scroll_offset = 0;
self.editing_message_id = None;
self.selected_message_index = None;
// Очищаем данные в TdClient
self.td_client.current_chat_id = None;
self.td_client.current_chat_messages.clear();
}
pub fn select_first_chat(&mut self) {
if !self.chats.is_empty() {
self.chat_list_state.select(Some(0));
/// Начать выбор сообщения для редактирования (при стрелке вверх в пустом инпуте)
pub fn start_message_selection(&mut self) {
if self.td_client.current_chat_messages.is_empty() {
return;
}
// Начинаем с последнего сообщения (индекс 0 = самое новое снизу)
self.selected_message_index = Some(0);
}
/// Выбрать предыдущее сообщение (вверх по списку = увеличить индекс)
pub fn select_previous_message(&mut self) {
let total = self.td_client.current_chat_messages.len();
if total == 0 {
return;
}
self.selected_message_index = Some(
self.selected_message_index
.map(|i| (i + 1).min(total - 1))
.unwrap_or(0)
);
}
/// Выбрать следующее сообщение (вниз по списку = уменьшить индекс)
pub fn select_next_message(&mut self) {
self.selected_message_index = self.selected_message_index
.map(|i| if i > 0 { Some(i - 1) } else { None })
.flatten();
}
/// Получить выбранное сообщение
pub fn get_selected_message(&self) -> Option<&crate::tdlib::client::MessageInfo> {
self.selected_message_index.and_then(|idx| {
let total = self.td_client.current_chat_messages.len();
if total == 0 || idx >= total {
return None;
}
// idx=0 это последнее сообщение (total-1), idx=1 это предпоследнее (total-2), и т.д.
self.td_client.current_chat_messages.get(total - 1 - idx)
})
}
/// Начать редактирование выбранного сообщения
pub fn start_editing_selected(&mut self) -> bool {
// Сначала извлекаем данные из сообщения
let msg_data = self.get_selected_message().and_then(|msg| {
if msg.can_be_edited && msg.is_outgoing {
Some((msg.id, msg.content.clone()))
} else {
None
}
});
// Затем присваиваем
if let Some((id, content)) = msg_data {
self.editing_message_id = Some(id);
self.cursor_position = content.chars().count();
self.message_input = content;
self.selected_message_index = None;
return true;
}
false
}
/// Отменить редактирование
pub fn cancel_editing(&mut self) {
self.editing_message_id = None;
self.selected_message_index = None;
self.message_input.clear();
self.cursor_position = 0;
}
/// Проверить, находимся ли в режиме редактирования
pub fn is_editing(&self) -> bool {
self.editing_message_id.is_some()
}
/// Проверить, находимся ли в режиме выбора сообщения
pub fn is_selecting_message(&self) -> bool {
self.selected_message_index.is_some()
}
pub fn get_selected_chat_id(&self) -> Option<i64> {
@@ -217,4 +301,9 @@ impl App {
}
}
}
/// Проверить, показывается ли модалка подтверждения удаления
pub fn is_confirm_delete_shown(&self) -> bool {
self.confirm_delete_message_id.is_some()
}
}