fixes
This commit is contained in:
116
src/ui/messages.rs
Normal file
116
src/ui/messages.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use ratatui::{
|
||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Line, Span},
|
||||
widgets::{Block, Borders, Paragraph},
|
||||
Frame,
|
||||
};
|
||||
use crate::app::App;
|
||||
use crate::utils::format_timestamp;
|
||||
|
||||
pub fn render(f: &mut Frame, area: Rect, app: &App) {
|
||||
if let Some(chat) = app.get_selected_chat() {
|
||||
let message_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(3), // Chat header
|
||||
Constraint::Min(0), // Messages
|
||||
Constraint::Length(3), // Input box
|
||||
])
|
||||
.split(area);
|
||||
|
||||
// Chat header
|
||||
let header = Paragraph::new(format!("👤 {}", chat.title))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.style(
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
f.render_widget(header, message_chunks[0]);
|
||||
|
||||
// Messages
|
||||
let mut lines: Vec<Line> = Vec::new();
|
||||
|
||||
for msg in &app.current_messages {
|
||||
let sender_style = if msg.is_outgoing {
|
||||
Style::default()
|
||||
.fg(Color::Green)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
} else {
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
};
|
||||
|
||||
let sender_name = if msg.is_outgoing {
|
||||
"You".to_string()
|
||||
} else {
|
||||
msg.sender_name.clone()
|
||||
};
|
||||
|
||||
let read_mark = if msg.is_outgoing {
|
||||
if msg.is_read { " ✓✓" } else { " ✓" }
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
// Форматируем время
|
||||
let time = format_timestamp(msg.date);
|
||||
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled(format!("{} ", sender_name), sender_style),
|
||||
Span::raw("── "),
|
||||
Span::styled(format!("{}{}", time, read_mark), Style::default().fg(Color::DarkGray)),
|
||||
]));
|
||||
lines.push(Line::from(msg.content.clone()));
|
||||
lines.push(Line::from(""));
|
||||
}
|
||||
|
||||
if lines.is_empty() {
|
||||
lines.push(Line::from(Span::styled(
|
||||
"Нет сообщений",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)));
|
||||
}
|
||||
|
||||
// Вычисляем скролл с учётом пользовательского offset
|
||||
let visible_height = message_chunks[1].height.saturating_sub(2) as usize;
|
||||
let total_lines = lines.len();
|
||||
|
||||
let base_scroll = if total_lines > visible_height {
|
||||
total_lines - visible_height
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let scroll_offset = base_scroll.saturating_sub(app.message_scroll_offset) as u16;
|
||||
|
||||
let messages_widget = Paragraph::new(lines)
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.scroll((scroll_offset, 0));
|
||||
f.render_widget(messages_widget, message_chunks[1]);
|
||||
|
||||
// Input box
|
||||
let input_text = if app.message_input.is_empty() {
|
||||
"> Введите сообщение...".to_string()
|
||||
} else {
|
||||
format!("> {}", app.message_input)
|
||||
};
|
||||
let input_style = if app.message_input.is_empty() {
|
||||
Style::default().fg(Color::DarkGray)
|
||||
} else {
|
||||
Style::default().fg(Color::Yellow)
|
||||
};
|
||||
let input = Paragraph::new(input_text)
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.style(input_style);
|
||||
f.render_widget(input, message_chunks[2]);
|
||||
} else {
|
||||
let empty = Paragraph::new("Выберите чат")
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.style(Style::default().fg(Color::DarkGray))
|
||||
.alignment(Alignment::Center);
|
||||
f.render_widget(empty, area);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user