use crate::app::App;
use crate::core::search::SearchType;
use crate::ui::{Component, centered_rect, get_border_type};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::{
Frame,
layout::{Constraint, Direction, Layout, Margin, Rect},
widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Tabs},
};
use ratatui_image::picker::Picker;
pub struct SearchView;
impl Component for SearchView {
fn render(&self, f: &mut Frame, area: Rect, app: &mut App, _picker: &mut Picker) {
let border_type = get_border_type(&app.config);
let area = centered_rect(80, 80, area);
f.render_widget(Clear, area);
let block = Block::default()
.borders(Borders::ALL)
.border_type(border_type)
.title(" Search ");
f.render_widget(block, area);
let inner_area = area.inner(Margin {
vertical: 1,
horizontal: 1,
});
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3), Constraint::Length(3), Constraint::Min(0), ])
.split(inner_area);
let titles = vec!["Local", "Global", "Bookmarks", "Chapters"];
let index = match app.search_type {
SearchType::Local => 0,
SearchType::Global => 1,
SearchType::Bookmark => 2,
SearchType::Chapter => 3,
};
let tabs = Tabs::new(titles)
.block(Block::default().borders(Borders::BOTTOM))
.select(index)
.highlight_style(
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
);
f.render_widget(tabs, chunks[0]);
let input_title = if app.search_case_sensitive {
" Query [Case Sensitive] "
} else {
" Query [Case Insensitive] "
};
let input_block = Block::default()
.borders(Borders::ALL)
.border_type(border_type)
.title(input_title);
let input = Paragraph::new(app.search_query.as_str()).block(input_block);
f.render_widget(input, chunks[1]);
f.set_cursor_position((
chunks[1].x + app.search_cursor_position as u16 + 1,
chunks[1].y + 1,
));
let results: Vec<ListItem> = app
.search_results
.iter()
.map(|res| {
let mut line = Vec::new();
if !res.chapter_title.is_empty() {
line.push(Span::styled(
format!("[{}] ", res.chapter_title),
Style::default().fg(Color::Cyan),
));
}
line.push(Span::raw(&res.context_before));
line.push(Span::styled(
&res.match_text,
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD),
));
line.push(Span::raw(&res.context_after));
ListItem::new(Line::from(line))
})
.collect();
let border_type = get_border_type(&app.config);
let results_list = List::new(results)
.block(
Block::default()
.borders(Borders::ALL)
.border_type(border_type)
.title(" Results "),
)
.highlight_style(
Style::default()
.bg(Color::DarkGray)
.add_modifier(Modifier::BOLD),
)
.highlight_symbol(">> ");
f.render_stateful_widget(results_list, chunks[2], &mut app.search_list_state);
}
}