Skip to main content

hac_client/pages/
error_popup.rs

1use ratatui::buffer::Buffer;
2use ratatui::layout::{Constraint, Direction, Flex, Layout, Rect};
3use ratatui::style::{Style, Stylize};
4use ratatui::widgets::{Block, Borders, Clear, Padding, Paragraph, Widget, Wrap};
5
6#[derive(Debug, PartialEq)]
7pub struct ErrorPopupLayout {
8    message_pane: Rect,
9    confirmation_pane: Rect,
10}
11
12pub struct ErrorPopup<'a> {
13    message: String,
14    colors: &'a hac_colors::Colors,
15}
16
17impl<'a> ErrorPopup<'a> {
18    pub fn new(message: String, colors: &'a hac_colors::Colors) -> Self {
19        ErrorPopup { message, colors }
20    }
21
22    fn build_popup(&self) -> (Paragraph<'_>, Paragraph<'_>) {
23        let message = Paragraph::new(self.message.clone().fg(self.colors.normal.red))
24            .wrap(Wrap { trim: true });
25
26        let confirmation = Paragraph::new("(O)k".fg(self.colors.normal.green).into_centered_line())
27            .wrap(Wrap { trim: true });
28
29        (message, confirmation)
30    }
31
32    fn layout(&self, size: &Rect) -> ErrorPopupLayout {
33        let size = Rect::new(
34            size.x + 2,
35            size.y + 2,
36            size.width.saturating_sub(4),
37            size.height.saturating_sub(4),
38        );
39
40        let [message_pane, confirmation_pane] = Layout::default()
41            .direction(Direction::Vertical)
42            .flex(Flex::SpaceBetween)
43            .constraints([Constraint::Fill(1), Constraint::Length(1)])
44            .areas(size);
45
46        ErrorPopupLayout {
47            message_pane,
48            confirmation_pane,
49        }
50    }
51
52    fn build_container(&self) -> Block<'_> {
53        Block::default()
54            .borders(Borders::ALL)
55            .border_style(Style::default().fg(self.colors.bright.black))
56            .padding(Padding::new(2, 2, 1, 1))
57            .bg(self.colors.normal.black)
58    }
59}
60
61impl Widget for ErrorPopup<'_> {
62    fn render(self, size: Rect, buf: &mut Buffer)
63    where
64        Self: Sized,
65    {
66        Clear.render(size, buf);
67        let layout = self.layout(&size);
68        let (message, confirmation) = self.build_popup();
69        let full_block = self.build_container();
70
71        full_block.render(size, buf);
72        message.render(layout.message_pane, buf);
73        confirmation.render(layout.confirmation_pane, buf);
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_build_with_correct_message() {
83        let colors = hac_colors::Colors::default();
84        let popup = ErrorPopup::new("my error message".into(), &colors);
85
86        let (message, confirmation) = popup.build_popup();
87
88        assert_eq!(
89            message,
90            Paragraph::new("my error message".fg(colors.normal.red)).wrap(Wrap { trim: true })
91        );
92
93        assert_eq!(
94            confirmation,
95            Paragraph::new("(O)k".fg(colors.normal.green).into_centered_line())
96                .wrap(Wrap { trim: true })
97        );
98    }
99
100    #[test]
101    fn test_build_layout_correctly() {
102        let colors = hac_colors::Colors::default();
103        let popup = ErrorPopup::new("my error message".into(), &colors);
104        let rect = Rect::new(0, 0, 10, 10);
105        let expected = ErrorPopupLayout {
106            message_pane: Rect::new(2, 2, 6, 5),
107            confirmation_pane: Rect::new(2, 7, 6, 1),
108        };
109
110        let layout = popup.layout(&rect);
111
112        assert_eq!(layout, expected);
113    }
114
115    #[test]
116    fn test_build_container_correctly() {
117        let colors = hac_colors::Colors::default();
118        let popup = ErrorPopup::new("my error message".into(), &colors);
119
120        let expected = Block::default()
121            .borders(Borders::ALL)
122            .border_style(Style::default().fg(colors.bright.black))
123            .padding(Padding::new(2, 2, 1, 1))
124            .bg(colors.normal.black);
125
126        let block = popup.build_container();
127
128        assert_eq!(expected, block);
129    }
130}