Files
telegram-tui/src/ui/modals/search.rs
2026-05-17 13:14:59 +03:00

116 lines
3.9 KiB
Rust

//! Message search modal
use crate::app::App;
use crate::tdlib::TdClientTrait;
use crate::ui::components::{calculate_scroll_offset, render_help_bar, render_message_item};
use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Paragraph},
Frame,
};
/// Renders message search mode
pub fn render<T: TdClientTrait>(f: &mut Frame, area: Rect, app: &App<T>) {
// Извлекаем данные из ChatState
let (query, results, selected_index) =
if let crate::app::ChatState::SearchInChat { query, results, selected_index } =
&app.chat_state
{
(query.as_str(), results.as_slice(), *selected_index)
} else {
return; // Некорректное состояние, не рендерим
};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3), // Search input
Constraint::Min(0), // Search results
Constraint::Length(3), // Help bar
])
.split(area);
// Search input
let total = results.len();
let current = if total > 0 { selected_index + 1 } else { 0 };
let input_line = if query.is_empty() {
Line::from(vec![
Span::styled("🔍 ", Style::default().fg(Color::Yellow)),
Span::styled("", Style::default().fg(Color::Yellow)),
Span::styled(" Введите текст для поиска...", Style::default().fg(Color::Gray)),
])
} else {
Line::from(vec![
Span::styled("🔍 ", Style::default().fg(Color::Yellow)),
Span::styled(query, Style::default().fg(Color::White)),
Span::styled("", Style::default().fg(Color::Yellow)),
Span::styled(format!(" ({}/{})", current, total), Style::default().fg(Color::Gray)),
])
};
let search_input = Paragraph::new(input_line).block(
Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Yellow))
.title(" Поиск по сообщениям ")
.title_style(
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
),
);
f.render_widget(search_input, chunks[0]);
// Search results
let content_width = chunks[1].width.saturating_sub(2) as usize;
let mut lines: Vec<Line> = Vec::new();
if results.is_empty() {
if !query.is_empty() {
lines.push(Line::from(Span::styled(
"Ничего не найдено",
Style::default().fg(Color::Gray),
)));
}
} else {
for (idx, msg) in results.iter().enumerate() {
if idx > 0 {
lines.push(Line::from(""));
}
lines.extend(render_message_item(
msg,
idx == selected_index,
content_width,
2,
));
}
}
// Скролл к выбранному результату
let scroll_offset = calculate_scroll_offset(selected_index, 4, chunks[1].height);
let results_widget = Paragraph::new(lines)
.block(
Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Yellow)),
)
.scroll((scroll_offset, 0));
f.render_widget(results_widget, chunks[1]);
// Help bar
let help = render_help_bar(
&[
("↑↓", "навигация", Color::Yellow),
("n/N", "след./пред.", Color::Yellow),
("Enter", "перейти", Color::Green),
("Esc", "выход", Color::Red),
],
Color::Yellow,
);
f.render_widget(help, chunks[2]);
}