refactor: reduce nesting with early returns and guard clauses

Применены паттерны упрощения вложенности:
- handle_profile_mode: упрощён блок Enter с let-else
- handle_profile_open: применён early return guard
- handle_enter_key: разделена на 3 функции + early returns
  - edit_message() - редактирование сообщения
  - send_new_message() - отправка нового сообщения
  - Сокращено с ~130 до ~40 строк
- handle_message_search_mode: извлечена функция perform_message_search()
  - Упрощены блоки Backspace и Char с let-else

Результат: код стал более линейным, уменьшена глубина вложенности с 6+ до 2-3 уровней

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Kilin
2026-02-03 20:34:19 +03:00
parent 7e372bffef
commit 67fd7506b3

View File

@@ -73,18 +73,24 @@ async fn handle_profile_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent)
} }
KeyCode::Enter => { KeyCode::Enter => {
// Выполнить выбранное действие // Выполнить выбранное действие
if let Some(profile) = app.get_profile_info() { let Some(profile) = app.get_profile_info() else {
return;
};
let actions = get_available_actions_count(profile); let actions = get_available_actions_count(profile);
let action_index = app.get_selected_profile_action().unwrap_or(0); let action_index = app.get_selected_profile_action().unwrap_or(0);
if action_index < actions { // Guard: проверяем, что индекс действия валидный
if action_index >= actions {
return;
}
// Определяем какое действие выбрано // Определяем какое действие выбрано
let mut current_idx = 0; let mut current_idx = 0;
// Действие: Открыть в браузере // Действие: Открыть в браузере
if profile.username.is_some() {
if action_index == current_idx {
if let Some(username) = &profile.username { if let Some(username) = &profile.username {
if action_index == current_idx {
let url = format!( let url = format!(
"https://t.me/{}", "https://t.me/{}",
username.trim_start_matches('@') username.trim_start_matches('@')
@@ -107,7 +113,6 @@ async fn handle_profile_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent)
"Открытие URL недоступно (требуется feature 'url-open')".to_string() "Открытие URL недоступно (требуется feature 'url-open')".to_string()
); );
} }
}
return; return;
} }
current_idx += 1; current_idx += 1;
@@ -115,8 +120,7 @@ async fn handle_profile_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent)
// Действие: Скопировать ID // Действие: Скопировать ID
if action_index == current_idx { if action_index == current_idx {
app.status_message = app.status_message = Some(format!("ID скопирован: {}", profile.chat_id));
Some(format!("ID скопирован: {}", profile.chat_id));
return; return;
} }
current_idx += 1; current_idx += 1;
@@ -126,8 +130,6 @@ async fn handle_profile_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent)
app.show_leave_group_confirmation(); app.show_leave_group_confirmation();
} }
} }
}
}
_ => {} _ => {}
} }
} }
@@ -136,7 +138,10 @@ async fn handle_profile_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent)
/// ///
/// Загружает информацию о профиле и переключает в режим просмотра профиля /// Загружает информацию о профиле и переключает в режим просмотра профиля
async fn handle_profile_open<T: TdClientTrait>(app: &mut App<T>) { async fn handle_profile_open<T: TdClientTrait>(app: &mut App<T>) {
if let Some(chat_id) = app.selected_chat_id { let Some(chat_id) = app.selected_chat_id else {
return;
};
app.status_message = Some("Загрузка профиля...".to_string()); app.status_message = Some("Загрузка профиля...".to_string());
match with_timeout_msg( match with_timeout_msg(
Duration::from_secs(5), Duration::from_secs(5),
@@ -154,7 +159,6 @@ async fn handle_profile_open<T: TdClientTrait>(app: &mut App<T>) {
app.status_message = None; app.status_message = None;
} }
} }
}
} }
/// Обработка режима выбора сообщения для действий /// Обработка режима выбора сообщения для действий
@@ -284,34 +288,8 @@ async fn handle_escape_key<T: TdClientTrait>(app: &mut App<T>) {
} }
} }
/// Обработка клавиши Enter /// Редактирование существующего сообщения
/// async fn edit_message<T: TdClientTrait>(app: &mut App<T>, chat_id: i64, msg_id: MessageId, text: String) {
/// Обрабатывает три сценария:
/// 1. В режиме выбора сообщения: начать редактирование
/// 2. В открытом чате: отправить новое или редактировать существующее сообщение
/// 3. В списке чатов: открыть выбранный чат
async fn handle_enter_key<T: TdClientTrait>(app: &mut App<T>) {
if app.selected_chat_id.is_some() {
// Режим выбора сообщения
if app.is_selecting_message() {
// Начать редактирование выбранного сообщения
if app.start_editing_selected() {
// Редактирование начато
} else {
// Нельзя редактировать это сообщение
app.chat_state = crate::app::ChatState::Normal;
}
return;
}
// Отправка или редактирование сообщения
if is_non_empty(&app.message_input) {
if let Some(chat_id) = app.get_selected_chat_id() {
let text = app.message_input.clone();
if app.is_editing() {
// Режим редактирования
if let Some(msg_id) = app.chat_state.selected_message_id() {
// Проверяем, что сообщение есть в локальном кэше // Проверяем, что сообщение есть в локальном кэше
let msg_exists = app.td_client.current_chat_messages() let msg_exists = app.td_client.current_chat_messages()
.iter() .iter()
@@ -354,20 +332,22 @@ async fn handle_enter_key<T: TdClientTrait>(app: &mut App<T>) {
app.message_input.clear(); app.message_input.clear();
app.cursor_position = 0; app.cursor_position = 0;
app.chat_state = crate::app::ChatState::Normal; app.chat_state = crate::app::ChatState::Normal;
app.needs_redraw = true; // ВАЖНО: перерисовываем UI app.needs_redraw = true;
} }
Err(e) => { Err(e) => {
app.error_message = Some(e); app.error_message = Some(e);
} }
} }
} }
} else {
// Обычная отправка (или reply) /// Отправка нового сообщения (с опциональным reply)
async fn send_new_message<T: TdClientTrait>(app: &mut App<T>, chat_id: i64, text: String) {
let reply_to_id = if app.is_replying() { let reply_to_id = if app.is_replying() {
app.chat_state.selected_message_id() app.chat_state.selected_message_id()
} else { } else {
None None
}; };
// Создаём ReplyInfo ДО отправки, пока сообщение точно доступно // Создаём ReplyInfo ДО отправки, пока сообщение точно доступно
let reply_info = app.get_replying_to_message().map(|m| { let reply_info = app.get_replying_to_message().map(|m| {
crate::tdlib::ReplyInfo { crate::tdlib::ReplyInfo {
@@ -376,6 +356,7 @@ async fn handle_enter_key<T: TdClientTrait>(app: &mut App<T>) {
text: m.text().to_string(), text: m.text().to_string(),
} }
}); });
app.message_input.clear(); app.message_input.clear();
app.cursor_position = 0; app.cursor_position = 0;
// Сбрасываем режим reply если он был активен // Сбрасываем режим reply если он был активен
@@ -389,8 +370,7 @@ async fn handle_enter_key<T: TdClientTrait>(app: &mut App<T>) {
match with_timeout_msg( match with_timeout_msg(
Duration::from_secs(5), Duration::from_secs(5),
app.td_client app.td_client.send_message(ChatId::new(chat_id), text, reply_to_id, reply_info),
.send_message(ChatId::new(chat_id), text, reply_to_id, reply_info),
"Таймаут отправки", "Таймаут отправки",
) )
.await .await
@@ -405,11 +385,17 @@ async fn handle_enter_key<T: TdClientTrait>(app: &mut App<T>) {
app.error_message = Some(e); app.error_message = Some(e);
} }
} }
} }
}
} /// Обработка клавиши Enter
} else { ///
// Открываем чат /// Обрабатывает три сценария:
/// 1. В режиме выбора сообщения: начать редактирование
/// 2. В открытом чате: отправить новое или редактировать существующее сообщение
/// 3. В списке чатов: открыть выбранный чат
async fn handle_enter_key<T: TdClientTrait>(app: &mut App<T>) {
// Сценарий 1: Открытие чата из списка
if app.selected_chat_id.is_none() {
let prev_selected = app.selected_chat_id; let prev_selected = app.selected_chat_id;
app.select_current_chat(); app.select_current_chat();
@@ -418,6 +404,37 @@ async fn handle_enter_key<T: TdClientTrait>(app: &mut App<T>) {
open_chat_and_load_data(app, chat_id).await; open_chat_and_load_data(app, chat_id).await;
} }
} }
return;
}
// Сценарий 2: Режим выбора сообщения - начать редактирование
if app.is_selecting_message() {
if !app.start_editing_selected() {
// Нельзя редактировать это сообщение
app.chat_state = crate::app::ChatState::Normal;
}
return;
}
// Сценарий 3: Отправка или редактирование сообщения
if !is_non_empty(&app.message_input) {
return;
}
let Some(chat_id) = app.get_selected_chat_id() else {
return;
};
let text = app.message_input.clone();
if app.is_editing() {
// Редактирование существующего сообщения
if let Some(msg_id) = app.chat_state.selected_message_id() {
edit_message(app, chat_id, msg_id, text).await;
}
} else {
// Отправка нового сообщения
send_new_message(app, chat_id, text).await;
} }
} }
@@ -698,6 +715,27 @@ async fn handle_pinned_mode<T: TdClientTrait>(app: &mut App<T>, key: KeyEvent) {
} }
} }
/// Выполняет поиск по сообщениям с обновлением результатов
async fn perform_message_search<T: TdClientTrait>(app: &mut App<T>, query: &str) {
let Some(chat_id) = app.get_selected_chat_id() else {
return;
};
if query.is_empty() {
app.set_search_results(Vec::new());
return;
}
if let Ok(results) = with_timeout(
Duration::from_secs(3),
app.td_client.search_messages(ChatId::new(chat_id), query),
)
.await
{
app.set_search_results(results);
}
}
/// Обработка режима поиска по сообщениям в открытом чате /// Обработка режима поиска по сообщениям в открытом чате
/// ///
/// Обрабатывает: /// Обрабатывает:
@@ -735,43 +773,21 @@ async fn handle_message_search_mode<T: TdClientTrait>(app: &mut App<T>, key: Key
} }
KeyCode::Backspace => { KeyCode::Backspace => {
// Удаляем символ из запроса // Удаляем символ из запроса
if let Some(mut query) = app.get_search_query().map(|s| s.to_string()) { let Some(mut query) = app.get_search_query().map(|s| s.to_string()) else {
return;
};
query.pop(); query.pop();
app.update_search_query(query.clone()); app.update_search_query(query.clone());
// Выполняем поиск при изменении запроса perform_message_search(app, &query).await;
if let Some(chat_id) = app.get_selected_chat_id() {
if !query.is_empty() {
if let Ok(results) = with_timeout(
Duration::from_secs(3),
app.td_client.search_messages(ChatId::new(chat_id), &query),
)
.await
{
app.set_search_results(results);
}
} else {
app.set_search_results(Vec::new());
}
}
}
} }
KeyCode::Char(c) => { KeyCode::Char(c) => {
// Добавляем символ к запросу // Добавляем символ к запросу
if let Some(mut query) = app.get_search_query().map(|s| s.to_string()) { let Some(mut query) = app.get_search_query().map(|s| s.to_string()) else {
return;
};
query.push(c); query.push(c);
app.update_search_query(query.clone()); app.update_search_query(query.clone());
// Выполняем поиск при изменении запроса perform_message_search(app, &query).await;
if let Some(chat_id) = app.get_selected_chat_id() {
if let Ok(results) = with_timeout(
Duration::from_secs(3),
app.td_client.search_messages(ChatId::new(chat_id), &query),
)
.await
{
app.set_search_results(results);
}
}
}
} }
_ => {} _ => {}
} }