use super::*;
use crate::app::ChecksumView;
use crate::checksum::Report;
fn rows_of(line: &str, width: usize) -> Vec<String> {
let mut rows = vec![String::new()];
let mut used = 0;
for character in line.chars() {
let cell = unicode_width::UnicodeWidthChar::width(character).unwrap_or(0);
if used + cell > width && used > 0 {
rows.push(String::new());
used = 0;
}
rows.last_mut().expect("never empty").push(character);
used += cell;
}
rows
}
pub(super) fn render_checksums_popup(f: &mut ratatui::Frame<'_>, area: Rect, view: &mut ChecksumView) {
let popup_area = popup_rect(60, area);
let inner = popup_area.inner(Margin { vertical: 1, horizontal: 2 });
let rows: Vec<String> = view.report.lines().iter().flat_map(|line| rows_of(&printable_name(line), (inner.width as usize).max(1))).collect();
let (title, keys): (String, &[&str]) = match &view.report {
Report::Computed { .. } => (format!(" {} ", t!("Checksums")), &[t!("Tab - Algorithm"), t!("C - Copy"), t!("Enter - Write"), t!("Esc - Close")]),
Report::Checked { file, .. } => (format!(" {} ", t!("Checked against {file}", file = shown_name(file))), &[t!("C - Copy"), t!("Esc - Close")]),
};
let keys = keys_in_rows(keys, inner.width as usize);
let mut head = vec![Line::from(Span::styled(view.report.summary(), style_title())), Line::from("")];
if let Some(shown) = view.report.shown() {
let mut options = Vec::new();
for algorithm in crate::checksum::Algorithm::ALL {
if !options.is_empty() {
options.push(Span::raw(" "));
}
let style = if algorithm == shown { style_selection() } else { style_columns() };
options.push(Span::styled(format!(" {} ", algorithm.name()), style));
}
head.extend([Line::from(options), Line::from("")]);
}
let room = (inner.height as usize).saturating_sub(head.len() + 1 + keys.len()).max(1);
view.room = room;
view.scroll = view.scroll.min(rows.len().saturating_sub(room));
let mut block = Block::default().title(Line::from(Span::styled(title, style_title())).centered()).borders(Borders::ALL).style(style_border());
if room < rows.len() {
let shown = format!(" {}-{}/{} ", view.scroll + 1, (view.scroll + room).min(rows.len()), rows.len());
block = block.title_bottom(Line::from(Span::styled(shown, style_columns())).right_aligned());
}
clear(f, popup_area);
f.render_widget(block, popup_area);
let mut shown = head;
shown.extend(rows.into_iter().skip(view.scroll).take(room).map(|row| Line::from(Span::styled(row, style_file()))));
f.render_widget(Paragraph::new(shown), inner);
let height = (keys.len() as u16).min(inner.height);
let bottom = Rect { y: inner.bottom() - height, height, ..inner };
f.render_widget(Paragraph::new(keys.into_iter().map(|row| Line::from(Span::styled(row, style_columns()))).collect::<Vec<_>>()), bottom);
}
fn keys_in_rows(keys: &[&str], width: usize) -> Vec<String> {
let mut rows: Vec<String> = Vec::new();
for key in keys {
match rows.last_mut() {
Some(row) if display_width(row) + 4 + display_width(key) <= width => {
row.push_str(" ");
row.push_str(key);
}
_ => rows.push((*key).to_string()),
}
}
rows
}