1 use ::tui::buffer::Buffer;
2 use ::tui::layout::Rect;
3 use ::tui::style::{Color, Modifier, Style};
4 use ::tui::widgets::Widget;
5 
6 use crate::state::tiles::FileType;
7 use crate::state::FileToDelete;
8 use crate::ui::format::truncate_middle;
9 use crate::ui::grid::draw_filled_rect;
10 
truncated_file_name_line(file_to_delete: &FileToDelete, max_len: u16) -> String11 fn truncated_file_name_line(file_to_delete: &FileToDelete, max_len: u16) -> String {
12     let full_path = file_to_delete
13         .full_path()
14         .into_os_string()
15         .into_string()
16         .expect("could not convert os string to string");
17     let file_name = file_to_delete
18         .path_to_file
19         .last()
20         .expect("could not find file to delete")
21         .to_string_lossy();
22     #[cfg(test)]
23     let full_path = str::replace(&full_path, "\\", "/");
24     if max_len > full_path.len() as u16 {
25         full_path
26     } else {
27         truncate_middle(&file_name, max_len)
28     }
29 }
30 
31 fn render_deletion_prompt(buf: &mut Buffer, message_rect: &Rect, file_to_delete: &FileToDelete) {
32     let max_text_len = message_rect.width - 4;
33     let file_name_line = truncated_file_name_line(file_to_delete, max_text_len);
34     let text_style = Style::default()
35         .bg(Color::Black)
36         .fg(Color::Red)
37         .add_modifier(Modifier::BOLD);
38     let question_line = match file_to_delete.file_type {
39         FileType::File => {
40             if max_text_len >= 17 {
41                 "Delete this file?".to_string()
42             } else if max_text_len >= 3 {
43                 "Delete?".to_string()
44             } else {
45                 unreachable!("should not render if terminal is so small");
46             }
47         }
48         FileType::Folder => {
49             let children = file_to_delete
50                 .num_descendants
51                 .expect("folder should have descendants");
52             let full_line = format!("Delete folder with {} children?", children);
53             let short_line = "Delete folder?".to_string();
54             if max_text_len >= full_line.len() as u16 {
55                 full_line
56             } else if max_text_len >= short_line.len() as u16 {
57                 short_line
58             } else {
59                 unreachable!("should not render if terminal is so small");
60             }
61         }
62     };
63     let y_n_line = "(y/n)";
64     let question_line_start_position =
65         ((message_rect.width - question_line.len() as u16) as f64 / 2.0).ceil() as u16
66             + message_rect.x;
67     let file_name_line_start_position =
68         ((message_rect.width - file_name_line.len() as u16) as f64 / 2.0).ceil() as u16
69             + message_rect.x;
70     let y_n_line_start_position =
71         ((message_rect.width - y_n_line.len() as u16) as f64 / 2.0).ceil() as u16 + message_rect.x;
72     buf.set_string(
73         question_line_start_position,
74         message_rect.y + message_rect.height / 2 - 3,
75         question_line,
76         text_style,
77     );
78     buf.set_string(
79         file_name_line_start_position,
80         message_rect.y + message_rect.height / 2,
81         file_name_line,
82         text_style,
83     );
84     buf.set_string(
85         y_n_line_start_position,
86         message_rect.y + message_rect.height / 2 + 3,
87         y_n_line,
88         text_style,
89     );
90 }
91 
92 fn render_deletion_in_progress(
93     buf: &mut Buffer,
94     message_rect: &Rect,
95     file_to_delete: &FileToDelete,
96 ) {
97     let max_text_len = message_rect.width - 4;
98     let file_name_line = truncated_file_name_line(file_to_delete, max_text_len);
99     let deleting_line = "Deleting";
100     let text_style = Style::default()
101         .bg(Color::Black)
102         .fg(Color::Red)
103         .add_modifier(Modifier::BOLD);
104     let deleting_line_start_position =
105         ((message_rect.width - deleting_line.len() as u16) as f64 / 2.0).ceil() as u16
106             + message_rect.x;
107     let file_line_start_position = ((message_rect.width - file_name_line.len() as u16) as f64 / 2.0)
108         .ceil() as u16
109         + message_rect.x;
110     buf.set_string(
111         deleting_line_start_position,
112         message_rect.y + message_rect.height / 2 - 1,
113         deleting_line,
114         text_style,
115     );
116     buf.set_string(
117         file_line_start_position,
118         message_rect.y + message_rect.height / 2 + 1,
119         file_name_line,
120         text_style,
121     );
122 }
123 
124 pub struct MessageBox<'a> {
125     file_to_delete: &'a FileToDelete,
126     deletion_in_progress: bool,
127 }
128 
129 impl<'a> MessageBox<'a> {
130     pub fn new(file_to_delete: &'a FileToDelete, deletion_in_progress: bool) -> Self {
131         Self {
132             file_to_delete,
133             deletion_in_progress,
134         }
135     }
136 }
137 
138 impl<'a> Widget for MessageBox<'a> {
139     fn render(self, area: Rect, buf: &mut Buffer) {
140         let (width, height) = if area.width > 150 {
141             (150, 10)
142         } else if area.width >= 50 {
143             (area.width / 2, 10)
144         } else {
145             unreachable!("app should not be rendered if window is so small")
146         };
147 
148         // position self in the middle of the rect
149         let x = ((area.x + area.width) / 2) - width / 2;
150         let y = ((area.y + area.height) / 2) - height / 2;
151 
152         let message_rect = Rect {
153             x,
154             y,
155             width,
156             height,
157         };
158         let fill_style = Style::default()
159             .bg(Color::Black)
160             .fg(Color::Red)
161             .add_modifier(Modifier::BOLD);
162 
163         draw_filled_rect(buf, fill_style, &message_rect);
164         if self.deletion_in_progress {
165             render_deletion_in_progress(buf, &message_rect, &self.file_to_delete);
166         } else {
167             render_deletion_prompt(buf, &message_rect, &self.file_to_delete);
168         }
169     }
170 }
171