Files
telegram-tui/src/ui/chat_list.rs
Mikhail Kilin ffd52d2384 refactor: complete Phase 13 deep architecture refactoring (etaps 3-7)
Split monolithic files into modular architecture:
- ui/messages.rs (893→365 lines): extract modals/, compose_bar.rs
- tdlib/messages.rs (836→3 files): split into messages/mod, convert, operations
- config/mod.rs (642→3 files): extract validation.rs, loader.rs
- Code duplication cleanup: shared components, ~220 lines removed
- Documentation: PROJECT_STRUCTURE.md rewrite, 16 files got //! docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 15:28:11 +03:00

106 lines
4.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Chat list panel: search box, chat items, and user online status.
use crate::app::App;
use crate::app::methods::{compose::ComposeMethods, search::SearchMethods};
use crate::tdlib::TdClientTrait;
use crate::tdlib::UserOnlineStatus;
use crate::ui::components;
use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
widgets::{Block, Borders, List, ListItem, Paragraph},
Frame,
};
pub fn render<T: TdClientTrait>(f: &mut Frame, area: Rect, app: &mut App<T>) {
let chat_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3), // Search box
Constraint::Min(0), // Chat list
Constraint::Length(3), // User status
])
.split(area);
// Search box
let search_text = if app.is_searching {
if app.search_query.is_empty() {
"🔍 Введите для поиска...".to_string()
} else {
format!("🔍 {}", app.search_query)
}
} else {
"🔍 Ctrl+S для поиска".to_string()
};
let search_style = if app.is_searching {
Style::default().fg(Color::Yellow)
} else {
Style::default().fg(Color::DarkGray)
};
let search = Paragraph::new(search_text)
.block(Block::default().borders(Borders::ALL))
.style(search_style);
f.render_widget(search, chat_chunks[0]);
// Chat list (filtered if searching)
let filtered_chats = app.get_filtered_chats();
let items: Vec<ListItem> = filtered_chats
.iter()
.map(|chat| {
let is_selected = app.selected_chat_id == Some(chat.id);
let user_status = app.td_client.get_user_status_by_chat_id(chat.id);
components::render_chat_list_item(chat, is_selected, user_status)
})
.collect();
// Заголовок блока: обычный или режим пересылки
let block = if app.is_forwarding() {
Block::default()
.title(" ↪ Выберите чат ")
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Cyan))
} else {
Block::default().borders(Borders::ALL)
};
let chats_list = List::new(items).block(block).highlight_style(
Style::default()
.add_modifier(Modifier::ITALIC)
.fg(Color::Yellow),
);
f.render_stateful_widget(chats_list, chat_chunks[1], &mut app.chat_list_state);
// User status - показываем статус выбранного или выделенного чата
let status_chat_id = if app.selected_chat_id.is_some() {
app.selected_chat_id
} else {
let filtered = app.get_filtered_chats();
app.chat_list_state.selected().and_then(|i| filtered.get(i).map(|c| c.id))
};
let (status_text, status_color) = match status_chat_id {
Some(chat_id) => format_user_status(app.td_client.get_user_status_by_chat_id(chat_id)),
None => ("".to_string(), Color::DarkGray),
};
let status = Paragraph::new(status_text)
.block(Block::default().borders(Borders::ALL))
.style(Style::default().fg(status_color));
f.render_widget(status, chat_chunks[2]);
}
/// Форматирует статус пользователя для отображения в статус-баре
fn format_user_status(status: Option<&UserOnlineStatus>) -> (String, Color) {
match status {
Some(UserOnlineStatus::Online) => ("● онлайн".to_string(), Color::Green),
Some(UserOnlineStatus::Recently) => ("был(а) недавно".to_string(), Color::Yellow),
Some(UserOnlineStatus::Offline(was_online)) => {
(crate::utils::format_was_online(*was_online), Color::Gray)
}
Some(UserOnlineStatus::LastWeek) => ("был(а) на этой неделе".to_string(), Color::DarkGray),
Some(UserOnlineStatus::LastMonth) => ("был(а) в этом месяце".to_string(), Color::DarkGray),
Some(UserOnlineStatus::LongTimeAgo) => ("был(а) давно".to_string(), Color::DarkGray),
None => ("".to_string(), Color::DarkGray),
}
}