176 lines
6.7 KiB
Rust
176 lines
6.7 KiB
Rust
//! 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<T: TdClientTrait> {
|
||
/// 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<MessageInfo>;
|
||
|
||
/// 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<T: TdClientTrait> MessageMethods<T> for App<T> {
|
||
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<MessageInfo> {
|
||
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()
|
||
}
|
||
}
|