fixes
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
//! Priority order: modals → search → compose → chat → chat list.
|
||||
|
||||
use crate::app::App;
|
||||
use crate::app::InputMode;
|
||||
use crate::app::methods::{
|
||||
compose::ComposeMethods,
|
||||
messages::MessageMethods,
|
||||
@@ -30,14 +31,10 @@ use crossterm::event::KeyEvent;
|
||||
|
||||
|
||||
|
||||
/// Обработка клавиши Esc
|
||||
///
|
||||
/// Обрабатывает отмену текущего действия или закрытие чата:
|
||||
/// - В режиме выбора сообщения: отменить выбор
|
||||
/// - В режиме редактирования: отменить редактирование
|
||||
/// - В режиме ответа: отменить ответ
|
||||
/// - В открытом чате: сохранить черновик и закрыть чат
|
||||
async fn handle_escape_key<T: TdClientTrait>(app: &mut App<T>) {
|
||||
/// Обработка клавиши Esc в Normal mode
|
||||
///
|
||||
/// Закрывает чат с сохранением черновика
|
||||
async fn handle_escape_normal<T: TdClientTrait>(app: &mut App<T>) {
|
||||
// Закрываем модальное окно изображения если открыто
|
||||
#[cfg(feature = "images")]
|
||||
if app.image_modal.is_some() {
|
||||
@@ -46,34 +43,16 @@ async fn handle_escape_key<T: TdClientTrait>(app: &mut App<T>) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Early return для режима выбора сообщения
|
||||
if app.is_selecting_message() {
|
||||
app.chat_state = crate::app::ChatState::Normal;
|
||||
return;
|
||||
}
|
||||
|
||||
// Early return для режима редактирования
|
||||
if app.is_editing() {
|
||||
app.cancel_editing();
|
||||
return;
|
||||
}
|
||||
|
||||
// Early return для режима ответа
|
||||
if app.is_replying() {
|
||||
app.cancel_reply();
|
||||
return;
|
||||
}
|
||||
|
||||
// Закрытие чата с сохранением черновика
|
||||
let Some(chat_id) = app.selected_chat_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Сохраняем черновик если есть текст в инпуте
|
||||
if !app.message_input.is_empty() && !app.is_editing() && !app.is_replying() {
|
||||
if !app.message_input.is_empty() {
|
||||
let draft_text = app.message_input.clone();
|
||||
let _ = app.td_client.set_draft_message(chat_id, draft_text).await;
|
||||
} else if app.message_input.is_empty() {
|
||||
} else {
|
||||
// Очищаем черновик если инпут пустой
|
||||
let _ = app.td_client.set_draft_message(chat_id, String::new()).await;
|
||||
}
|
||||
@@ -81,79 +60,169 @@ async fn handle_escape_key<T: TdClientTrait>(app: &mut App<T>) {
|
||||
app.close_chat();
|
||||
}
|
||||
|
||||
/// Обработка клавиши Esc в Insert mode
|
||||
///
|
||||
/// Отменяет Reply/Editing и возвращает в Normal + MessageSelection
|
||||
fn handle_escape_insert<T: TdClientTrait>(app: &mut App<T>) {
|
||||
if app.is_editing() {
|
||||
app.cancel_editing();
|
||||
}
|
||||
if app.is_replying() {
|
||||
app.cancel_reply();
|
||||
}
|
||||
app.input_mode = InputMode::Normal;
|
||||
app.start_message_selection();
|
||||
}
|
||||
|
||||
/// Главный обработчик ввода - роутер для всех режимов приложения
|
||||
pub async fn handle<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent) {
|
||||
// Глобальные команды (работают всегда)
|
||||
let command = app.get_command(key);
|
||||
|
||||
// 1. Insert mode + чат открыт → только текст, Enter, Esc
|
||||
// (Ctrl+C обрабатывается в main.rs до вызова router)
|
||||
if app.selected_chat_id.is_some() && app.input_mode == InputMode::Insert {
|
||||
// Модальные окна всё равно обрабатываем (image modal, delete confirmation etc.)
|
||||
#[cfg(feature = "images")]
|
||||
if app.image_modal.is_some() {
|
||||
handle_image_modal_mode(app, key).await;
|
||||
return;
|
||||
}
|
||||
if app.is_confirm_delete_shown() {
|
||||
handle_delete_confirmation(app, key).await;
|
||||
return;
|
||||
}
|
||||
if app.is_reaction_picker_mode() {
|
||||
handle_reaction_picker_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
if app.is_profile_mode() {
|
||||
handle_profile_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
if app.is_message_search_mode() {
|
||||
handle_message_search_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
if app.is_pinned_mode() {
|
||||
handle_pinned_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
if app.is_forwarding() {
|
||||
handle_forward_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
|
||||
match command {
|
||||
Some(crate::config::Command::Cancel) => {
|
||||
handle_escape_insert(app);
|
||||
return;
|
||||
}
|
||||
Some(crate::config::Command::SubmitMessage) => {
|
||||
handle_enter_key(app).await;
|
||||
return;
|
||||
}
|
||||
Some(crate::config::Command::DeleteWord) => {
|
||||
// Ctrl+W → удалить слово
|
||||
if app.cursor_position > 0 {
|
||||
let chars: Vec<char> = app.message_input.chars().collect();
|
||||
let mut new_pos = app.cursor_position;
|
||||
// Пропускаем пробелы
|
||||
while new_pos > 0 && chars[new_pos - 1] == ' ' {
|
||||
new_pos -= 1;
|
||||
}
|
||||
// Пропускаем слово
|
||||
while new_pos > 0 && chars[new_pos - 1] != ' ' {
|
||||
new_pos -= 1;
|
||||
}
|
||||
let new_input: String = chars[..new_pos]
|
||||
.iter()
|
||||
.chain(chars[app.cursor_position..].iter())
|
||||
.collect();
|
||||
app.message_input = new_input;
|
||||
app.cursor_position = new_pos;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Some(crate::config::Command::MoveToStart) => {
|
||||
app.cursor_position = 0;
|
||||
return;
|
||||
}
|
||||
Some(crate::config::Command::MoveToEnd) => {
|
||||
app.cursor_position = app.message_input.chars().count();
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Весь остальной ввод → текст
|
||||
handle_open_chat_keyboard_input(app, key).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Глобальные команды (Ctrl+R, Ctrl+S, Ctrl+P, Ctrl+F)
|
||||
if handle_global_commands(app, key).await {
|
||||
return;
|
||||
}
|
||||
|
||||
// Получаем команду из keybindings
|
||||
let command = app.get_command(key);
|
||||
|
||||
// Модальное окно просмотра изображения (приоритет высокий)
|
||||
// 4. Модальное окно просмотра изображения
|
||||
#[cfg(feature = "images")]
|
||||
if app.image_modal.is_some() {
|
||||
handle_image_modal_mode(app, key).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Режим профиля
|
||||
// 5. Режим профиля
|
||||
if app.is_profile_mode() {
|
||||
handle_profile_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Режим поиска по сообщениям
|
||||
// 6. Режим поиска по сообщениям
|
||||
if app.is_message_search_mode() {
|
||||
handle_message_search_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Режим просмотра закреплённых сообщений
|
||||
// 7. Режим просмотра закреплённых сообщений
|
||||
if app.is_pinned_mode() {
|
||||
handle_pinned_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Обработка ввода в режиме выбора реакции
|
||||
// 8. Обработка ввода в режиме выбора реакции
|
||||
if app.is_reaction_picker_mode() {
|
||||
handle_reaction_picker_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Модалка подтверждения удаления
|
||||
// 9. Модалка подтверждения удаления
|
||||
if app.is_confirm_delete_shown() {
|
||||
handle_delete_confirmation(app, key).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Режим выбора чата для пересылки
|
||||
// 10. Режим выбора чата для пересылки
|
||||
if app.is_forwarding() {
|
||||
handle_forward_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Режим поиска
|
||||
// 11. Режим поиска чатов
|
||||
if app.is_searching {
|
||||
handle_chat_search_mode(app, key, command).await;
|
||||
return;
|
||||
}
|
||||
|
||||
// Обработка команд через keybindings
|
||||
// 12. Normal mode commands (Enter, Esc, Profile)
|
||||
match command {
|
||||
Some(crate::config::Command::SubmitMessage) => {
|
||||
// Enter - открыть чат, отправить сообщение или редактировать
|
||||
handle_enter_key(app).await;
|
||||
return;
|
||||
}
|
||||
Some(crate::config::Command::Cancel) => {
|
||||
// Esc - отменить выбор/редактирование/reply или закрыть чат
|
||||
handle_escape_key(app).await;
|
||||
handle_escape_normal(app).await;
|
||||
return;
|
||||
}
|
||||
Some(crate::config::Command::OpenProfile) => {
|
||||
// Открыть профиль (обычно 'i')
|
||||
if app.selected_chat_id.is_some() {
|
||||
handle_profile_open(app).await;
|
||||
return;
|
||||
@@ -162,17 +231,15 @@ pub async fn handle<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent) {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Режим открытого чата
|
||||
// 13. Normal mode в чате → MessageSelection
|
||||
if app.selected_chat_id.is_some() {
|
||||
// Режим выбора сообщения для редактирования/удаления
|
||||
if app.is_selecting_message() {
|
||||
handle_message_selection(app, key, command).await;
|
||||
return;
|
||||
// Auto-enter MessageSelection if not already in it
|
||||
if !app.is_selecting_message() {
|
||||
app.start_message_selection();
|
||||
}
|
||||
|
||||
handle_open_chat_keyboard_input(app, key).await;
|
||||
handle_message_selection(app, key, command).await;
|
||||
} else {
|
||||
// В режиме списка чатов - навигация стрелками и переключение папок
|
||||
// 14. Список чатов
|
||||
handle_chat_list_navigation(app, key, command).await;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user