use crate::ui::app::App;
use humansize::{format_size, DECIMAL};
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, List, ListItem, Paragraph};
use ratatui::Frame;
pub fn draw(f: &mut Frame, app: &mut App) {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Length(3), Constraint::Min(3), Constraint::Length(3)])
.split(f.area());
draw_header(f, chunks[0], app);
draw_list(f, chunks[1], app);
draw_footer(f, chunks[2], app);
}
fn draw_header(f: &mut Frame, area: Rect, app: &App) {
let node = app.current();
let text = Line::from(vec![
Span::styled(app.breadcrumb(), Style::default().fg(Color::White).add_modifier(Modifier::BOLD)),
Span::raw(" "),
Span::styled(format!("({})", format_size(node.size, DECIMAL)), Style::default().fg(Color::Yellow)),
]);
let p = Paragraph::new(text).block(Block::default().borders(Borders::ALL).title(" diskr "));
f.render_widget(p, area);
}
fn draw_list(f: &mut Frame, area: Rect, app: &mut App) {
let visible = area.height.saturating_sub(2) as usize;
app.set_visible_rows(visible);
app.list_area = area;
let node = app.current();
let total = node.children.len();
let max_size = node.children.iter().map(|c| c.size).max().unwrap_or(1).max(1);
let start = app.scroll.min(total.saturating_sub(1).max(0));
let end = (start + app.visible_rows).min(total);
let items: Vec<ListItem> = node.children[start..end]
.iter()
.enumerate()
.map(|(offset, c)| {
let i = start + offset;
let ratio = (c.size as f64 / max_size as f64 * 20.0) as usize;
let bar: String = "█".repeat(ratio.min(20));
let is_marked = app.marked.contains(&c.path);
let marker = if is_marked { "✓" } else { " " };
let name = c
.path
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| c.path.display().to_string());
let (kind_suffix, name_color) = if c.is_dir {
("/", Color::LightBlue)
} else {
("", Color::White)
};
let marker_color = if is_marked { Color::Green } else { Color::DarkGray };
let line = Line::from(vec![
Span::styled(format!(" {marker} "), Style::default().fg(marker_color).add_modifier(Modifier::BOLD)),
Span::styled(format!("{:>10} ", format_size(c.size, DECIMAL)), Style::default().fg(Color::Gray)),
Span::styled(format!("{bar:<20}"), Style::default().fg(Color::Cyan)),
Span::raw(" "),
Span::styled(format!("{name}{kind_suffix}"), Style::default().fg(name_color)),
]);
let style = if i == app.selected {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default()
};
ListItem::new(line).style(style)
})
.collect();
let title = if total == 0 {
" contents (empty) ".to_string()
} else {
format!(" contents {}/{} ", app.selected + 1, total)
};
let list = List::new(items).block(Block::default().borders(Borders::ALL).title(title));
f.render_widget(list, area);
}
fn draw_footer(f: &mut Frame, area: Rect, app: &App) {
let mut spans = vec![Span::styled(
"j/k move l/enter open h/⌫ back g/G top/bottom pgup/pgdn page space mark q quit click/scroll mouse",
Style::default().fg(Color::DarkGray),
)];
if !app.marked.is_empty() {
spans.push(Span::raw(" "));
spans.push(Span::styled(
format!("{} marked ({})", app.marked.len(), format_size(app.marked_total(), DECIMAL)),
Style::default().fg(Color::Green).add_modifier(Modifier::BOLD),
));
}
let p = Paragraph::new(Line::from(spans)).block(Block::default().borders(Borders::ALL));
f.render_widget(p, area);
}