Files
telegram-tui/src/ui/chat_list.rs
2026-01-27 13:41:29 +03:00

162 lines
6.6 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.

use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
widgets::{Block, Borders, List, ListItem, Paragraph},
Frame,
};
use crate::app::App;
use crate::tdlib::UserOnlineStatus;
pub fn render(f: &mut Frame, area: Rect, app: &mut App) {
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 pin_icon = if chat.is_pinned { "📌 " } else { "" };
let mute_icon = if chat.is_muted { "🔇 " } else { "" };
// Онлайн-статус (зелёная точка для онлайн)
let status_icon = match app.td_client.get_user_status_by_chat_id(chat.id) {
Some(UserOnlineStatus::Online) => "",
_ => " ",
};
let prefix = if is_selected { "" } else { " " };
let username_text = chat.username.as_ref()
.map(|u| format!(" {}", u))
.unwrap_or_default();
// Индикатор упоминаний @
let mention_badge = if chat.unread_mention_count > 0 {
" @".to_string()
} else {
String::new()
};
// Индикатор черновика ✎
let draft_badge = if chat.draft_text.is_some() {
"".to_string()
} else {
String::new()
};
let unread_badge = if chat.unread_count > 0 {
format!(" ({})", chat.unread_count)
} else {
String::new()
};
let content = format!("{}{}{}{}{}{}{}{}{}", prefix, status_icon, pin_icon, mute_icon, chat.title, username_text, mention_badge, draft_badge, unread_badge);
// Цвет: онлайн — зелёные, остальные — белые
let style = match app.td_client.get_user_status_by_chat_id(chat.id) {
Some(UserOnlineStatus::Online) => Style::default().fg(Color::Green),
_ => Style::default().fg(Color::White),
};
ListItem::new(content).style(style)
})
.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_text, status_color) = if let Some(chat_id) = app.selected_chat_id {
match app.td_client.get_user_status_by_chat_id(chat_id) {
Some(UserOnlineStatus::Online) => ("● онлайн".to_string(), Color::Green),
Some(UserOnlineStatus::Recently) => ("был(а) недавно".to_string(), Color::Yellow),
Some(UserOnlineStatus::Offline(was_online)) => {
let formatted = format_was_online(*was_online);
(formatted, 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), // Для групп/каналов
}
} else {
// Показываем статус выделенного в списке чата
let filtered = app.get_filtered_chats();
if let Some(i) = app.chat_list_state.selected() {
if let Some(chat) = filtered.get(i) {
match app.td_client.get_user_status_by_chat_id(chat.id) {
Some(UserOnlineStatus::Online) => ("● онлайн".to_string(), Color::Green),
Some(UserOnlineStatus::Recently) => ("был(а) недавно".to_string(), Color::Yellow),
Some(UserOnlineStatus::Offline(was_online)) => {
let formatted = format_was_online(*was_online);
(formatted, 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),
}
} else {
("".to_string(), Color::DarkGray)
}
} else {
("".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_was_online(timestamp: i32) -> String {
crate::utils::format_was_online(timestamp)
}