multiverse/widgets/search/
indexing.rs

1use ratatui::{
2    layout::Flex,
3    prelude::*,
4    widgets::{Block, BorderType, Clear, Paragraph, Wrap},
5};
6use throbber_widgets_tui::ThrobberState;
7
8use crate::{HEADER_BG, NORMAL_ROW_COLOR, TEXT_COLOR, popup_area};
9
10pub enum IndexingMessage {
11    Progress(usize),
12    Error(String),
13}
14
15impl Default for IndexingMessage {
16    fn default() -> Self {
17        IndexingMessage::Progress(0)
18    }
19}
20
21#[derive(Default)]
22pub struct IndexingView {
23    throbber_state: ThrobberState,
24    message: IndexingMessage,
25}
26
27impl IndexingView {
28    pub fn new() -> Self {
29        Self::default()
30    }
31
32    pub fn on_tick(&mut self) {
33        self.throbber_state.calc_next();
34    }
35
36    pub fn set_message(&mut self, message: IndexingMessage) {
37        self.message = message;
38    }
39}
40
41impl Widget for &mut IndexingView {
42    fn render(self, area: Rect, buf: &mut Buffer) {
43        let outer_area = popup_area(area, 80, 80);
44        let block = Block::bordered()
45            .border_type(BorderType::Double)
46            .border_style(Style::default().fg(TEXT_COLOR).bg(HEADER_BG))
47            .style(Style::default().fg(TEXT_COLOR).bg(NORMAL_ROW_COLOR));
48        Clear.render(outer_area, buf);
49
50        let inner_area = block.inner(outer_area);
51        block.render(outer_area, buf);
52
53        match &self.message {
54            IndexingMessage::Error(err) => {
55                let message = format!(
56                    "An error occurred during indexing, press Escape to return to main screen: {err}"
57                );
58
59                let [area] = Layout::horizontal([Constraint::Length(message.len() as u16)])
60                    .flex(Flex::Center)
61                    .areas(inner_area);
62                let [area] =
63                    Layout::vertical([Constraint::Length(1)]).flex(Flex::Center).areas(area);
64
65                let paragraph = Paragraph::new(message).wrap(Wrap { trim: true });
66
67                paragraph.render(area, buf);
68            }
69            IndexingMessage::Progress(progress) => {
70                let label = format!("Indexing...({})", progress);
71
72                let [area] = Layout::horizontal([Constraint::Length(label.len() as u16)])
73                    .flex(Flex::Center)
74                    .areas(inner_area);
75                let [area] =
76                    Layout::vertical([Constraint::Length(1)]).flex(Flex::Center).areas(area);
77
78                let throbber = throbber_widgets_tui::Throbber::default()
79                    .label(label)
80                    .style(Style::default().fg(TEXT_COLOR).bg(NORMAL_ROW_COLOR))
81                    .throbber_style(Style::default().fg(TEXT_COLOR).bg(NORMAL_ROW_COLOR))
82                    .throbber_set(throbber_widgets_tui::BRAILLE_EIGHT_DOUBLE)
83                    .use_type(throbber_widgets_tui::WhichUse::Spin);
84
85                StatefulWidget::render(throbber, area, buf, &mut self.throbber_state);
86            }
87        }
88    }
89}