162 lines
6.6 KiB
Rust
162 lines
6.6 KiB
Rust
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)
|
||
}
|