This commit is contained in:
Mikhail Kilin
2026-01-21 21:20:18 +03:00
parent 0a9ae8b448
commit 1ef341d907
9 changed files with 326 additions and 95 deletions

View File

@@ -5,6 +5,7 @@ use ratatui::{
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()
@@ -43,7 +44,14 @@ pub fn render(f: &mut Frame, area: Rect, app: &mut App) {
.map(|chat| {
let is_selected = app.selected_chat_id == Some(chat.id);
let pin_icon = if chat.is_pinned { "📌 " } else { "" };
let prefix = if is_selected { "" } 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))
@@ -55,8 +63,13 @@ pub fn render(f: &mut Frame, area: Rect, app: &mut App) {
String::new()
};
let content = format!("{}{}{}{}{}", prefix, pin_icon, chat.title, username_text, unread_badge);
let style = Style::default().fg(Color::White);
let content = format!("{}{}{}{}{}{}", prefix, status_icon, pin_icon, chat.title, username_text, 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)
})
@@ -72,9 +85,75 @@ pub fn render(f: &mut Frame, area: Rect, app: &mut App) {
f.render_stateful_widget(chats_list, chat_chunks[1], &mut app.chat_list_state);
// User status
let status = Paragraph::new("[User: Online]")
// 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(Color::Green));
.style(Style::default().fg(status_color));
f.render_widget(status, chat_chunks[2]);
}
/// Форматирование времени "был(а) в ..."
fn format_was_online(timestamp: i32) -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i32;
let diff = now - timestamp;
if diff < 60 {
"был(а) только что".to_string()
} else if diff < 3600 {
let mins = diff / 60;
format!("был(а) {} мин. назад", mins)
} else if diff < 86400 {
let hours = diff / 3600;
format!("был(а) {} ч. назад", hours)
} else {
// Показываем дату
let datetime = chrono::DateTime::from_timestamp(timestamp as i64, 0)
.map(|dt| dt.format("%d.%m %H:%M").to_string())
.unwrap_or_else(|| "давно".to_string());
format!("был(а) {}", datetime)
}
}

View File

@@ -36,19 +36,29 @@ pub fn render(f: &mut Frame, app: &mut App) {
fn render_folders(f: &mut Frame, area: Rect, app: &App) {
let mut spans = vec![];
for (i, folder) in app.folders.iter().enumerate() {
let style = if i == app.selected_folder {
// "All" всегда первая (клавиша 1)
let all_style = if app.selected_folder_id.is_none() {
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(Color::White)
};
spans.push(Span::styled(" 1:All ", all_style));
// Папки из TDLib (клавиши 2, 3, 4...)
for (i, folder) in app.td_client.folders.iter().enumerate() {
spans.push(Span::raw(""));
let style = if app.selected_folder_id == Some(folder.id) {
Style::default()
.fg(Color::Cyan)
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(Color::White)
};
spans.push(Span::styled(format!(" {}:{} ", i + 1, folder), style));
if i < app.folders.len() - 1 {
spans.push(Span::raw(""));
}
spans.push(Span::styled(format!(" {}:{} ", i + 2, folder.name), style));
}
let folders_line = Line::from(spans);