//! Message methods for App //! //! Handles message selection, editing, and operations use crate::app::{App, ChatState}; use crate::tdlib::{MessageInfo, TdClientTrait}; /// Message operation methods pub trait MessageMethods { /// Start message selection mode (triggered by Up arrow in empty input) fn start_message_selection(&mut self); /// Select previous message (up in history = older) fn select_previous_message(&mut self); /// Select next message (down in history = newer) fn select_next_message(&mut self); /// Get currently selected message fn get_selected_message(&self) -> Option; /// Start editing the selected message /// Returns true if editing started, false if message cannot be edited fn start_editing_selected(&mut self) -> bool; /// Cancel message editing and clear input fn cancel_editing(&mut self); /// Check if currently in editing mode fn is_editing(&self) -> bool; /// Check if currently in message selection mode fn is_selecting_message(&self) -> bool; } impl MessageMethods for App { fn start_message_selection(&mut self) { let messages = self.td_client.current_chat_messages(); let total = messages.len(); if total == 0 { return; } // Начинаем с последнего сообщения (индекс len-1 = самое новое внизу) // Если оно часть альбома — перемещаемся к первому элементу альбома let mut idx = total - 1; let album_id = messages[idx].media_album_id(); if album_id != 0 { while idx > 0 && messages[idx - 1].media_album_id() == album_id { idx -= 1; } } self.chat_state = ChatState::MessageSelection { selected_index: idx }; } fn select_previous_message(&mut self) { if let ChatState::MessageSelection { selected_index } = &mut self.chat_state { if *selected_index > 0 { let messages = self.td_client.current_chat_messages(); let current_album_id = messages[*selected_index].media_album_id(); // Перескакиваем через все сообщения текущего альбома назад let mut new_index = *selected_index - 1; if current_album_id != 0 { while new_index > 0 && messages[new_index].media_album_id() == current_album_id { new_index -= 1; } } // Если попали в середину другого альбома — перемещаемся к его первому элементу let target_album_id = messages[new_index].media_album_id(); if target_album_id != 0 { while new_index > 0 && messages[new_index - 1].media_album_id() == target_album_id { new_index -= 1; } } *selected_index = new_index; self.stop_playback(); } } } fn select_next_message(&mut self) { let total = self.td_client.current_chat_messages().len(); if total == 0 { return; } if let ChatState::MessageSelection { selected_index } = &mut self.chat_state { if *selected_index < total - 1 { let messages = self.td_client.current_chat_messages(); let current_album_id = messages[*selected_index].media_album_id(); // Перескакиваем через все сообщения текущего альбома вперёд let mut new_index = *selected_index + 1; if current_album_id != 0 { while new_index < total - 1 && messages[new_index].media_album_id() == current_album_id { new_index += 1; } // Если мы ещё на последнем элементе альбома — нужно шагнуть на следующее if messages[new_index].media_album_id() == current_album_id && new_index < total - 1 { new_index += 1; } } if new_index < total { *selected_index = new_index; self.stop_playback(); } // Если new_index >= total — остаёмся на текущем } // Если уже на последнем — ничего не делаем, остаёмся на месте } } fn get_selected_message(&self) -> Option { self.chat_state .selected_message_index() .and_then(|idx| self.td_client.current_chat_messages().get(idx).cloned()) } fn start_editing_selected(&mut self) -> bool { // Получаем selected_index из текущего состояния let selected_idx = match &self.chat_state { ChatState::MessageSelection { selected_index } => Some(*selected_index), _ => None, }; let Some(selected_idx) = selected_idx else { return false; }; // Сначала извлекаем данные из сообщения let msg_data = self.get_selected_message().and_then(|msg| { // Проверяем: // 1. Можно редактировать // 2. Это исходящее сообщение // 3. ID не временный (временные ID в TDLib отрицательные) if msg.can_be_edited() && msg.is_outgoing() && msg.id().as_i64() > 0 { Some((msg.id(), msg.text().to_string(), selected_idx)) } else { None } }); // Затем присваиваем if let Some((id, content, idx)) = msg_data { self.cursor_position = content.chars().count(); self.message_input = content; self.chat_state = ChatState::Editing { message_id: id, selected_index: idx }; return true; } false } fn cancel_editing(&mut self) { self.chat_state = ChatState::Normal; self.message_input.clear(); self.cursor_position = 0; } fn is_editing(&self) -> bool { self.chat_state.is_editing() } fn is_selecting_message(&self) -> bool { self.chat_state.is_message_selection() } }