initial commit
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I4a6b498153eccd5407510dd541b7f4816a6a6964
This commit is contained in:
commit
6a73d11c4b
124 changed files with 34856 additions and 0 deletions
183
crates/pinakes-tui/src/ui/statistics.rs
Normal file
183
crates/pinakes-tui/src/ui/statistics.rs
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Paragraph, Row, Table};
|
||||
|
||||
use crate::app::AppState;
|
||||
|
||||
pub fn render(f: &mut Frame, state: &AppState, area: Rect) {
|
||||
let Some(ref stats) = state.library_stats else {
|
||||
let msg = Paragraph::new("Loading statistics... (press X to refresh)")
|
||||
.block(Block::default().borders(Borders::ALL).title(" Statistics "));
|
||||
f.render_widget(msg, area);
|
||||
return;
|
||||
};
|
||||
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(8), // Overview
|
||||
Constraint::Length(10), // Media by type
|
||||
Constraint::Min(6), // Top tags & collections
|
||||
])
|
||||
.split(area);
|
||||
|
||||
// Overview section
|
||||
let overview_lines = vec![
|
||||
Line::from(vec![
|
||||
Span::styled(" Total Media: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
stats.total_media.to_string(),
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::raw(" "),
|
||||
Span::styled("Total Size: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
super::format_size(stats.total_size_bytes),
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
]),
|
||||
Line::from(vec![
|
||||
Span::styled(" Avg Size: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
super::format_size(stats.avg_file_size_bytes),
|
||||
Style::default().fg(Color::White),
|
||||
),
|
||||
]),
|
||||
Line::from(vec![
|
||||
Span::styled(" Tags: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
stats.total_tags.to_string(),
|
||||
Style::default().fg(Color::Green),
|
||||
),
|
||||
Span::raw(" "),
|
||||
Span::styled("Collections: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
stats.total_collections.to_string(),
|
||||
Style::default().fg(Color::Green),
|
||||
),
|
||||
Span::raw(" "),
|
||||
Span::styled("Duplicates: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
stats.total_duplicates.to_string(),
|
||||
Style::default().fg(Color::Yellow),
|
||||
),
|
||||
]),
|
||||
Line::from(vec![
|
||||
Span::styled(" Newest: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
stats
|
||||
.newest_item
|
||||
.as_deref()
|
||||
.map(super::format_date)
|
||||
.unwrap_or("-"),
|
||||
Style::default().fg(Color::White),
|
||||
),
|
||||
Span::raw(" "),
|
||||
Span::styled("Oldest: ", Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
stats
|
||||
.oldest_item
|
||||
.as_deref()
|
||||
.map(super::format_date)
|
||||
.unwrap_or("-"),
|
||||
Style::default().fg(Color::White),
|
||||
),
|
||||
]),
|
||||
];
|
||||
|
||||
let overview = Paragraph::new(overview_lines)
|
||||
.block(Block::default().borders(Borders::ALL).title(" Overview "));
|
||||
f.render_widget(overview, chunks[0]);
|
||||
|
||||
// Media by Type table
|
||||
let type_rows: Vec<Row> = stats
|
||||
.media_by_type
|
||||
.iter()
|
||||
.map(|tc| {
|
||||
let color = super::media_type_color(&tc.name);
|
||||
Row::new(vec![
|
||||
Span::styled(tc.name.clone(), Style::default().fg(color)),
|
||||
Span::styled(tc.count.to_string(), Style::default().fg(Color::White)),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let storage_rows: Vec<Row> = stats
|
||||
.storage_by_type
|
||||
.iter()
|
||||
.map(|tc| {
|
||||
Row::new(vec![
|
||||
Span::styled(tc.name.clone(), Style::default().fg(Color::Gray)),
|
||||
Span::styled(
|
||||
super::format_size(tc.count),
|
||||
Style::default().fg(Color::White),
|
||||
),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let type_cols = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||
.split(chunks[1]);
|
||||
|
||||
let type_table = Table::new(type_rows, [Constraint::Min(20), Constraint::Length(10)]).block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title(" Media by Type "),
|
||||
);
|
||||
f.render_widget(type_table, type_cols[0]);
|
||||
|
||||
let storage_table = Table::new(storage_rows, [Constraint::Min(20), Constraint::Length(12)])
|
||||
.block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title(" Storage by Type "),
|
||||
);
|
||||
f.render_widget(storage_table, type_cols[1]);
|
||||
|
||||
// Top tags and collections
|
||||
let bottom_cols = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||
.split(chunks[2]);
|
||||
|
||||
let tag_rows: Vec<Row> = stats
|
||||
.top_tags
|
||||
.iter()
|
||||
.map(|tc| {
|
||||
Row::new(vec![
|
||||
Span::styled(tc.name.clone(), Style::default().fg(Color::Green)),
|
||||
Span::styled(tc.count.to_string(), Style::default().fg(Color::White)),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let tags_table = Table::new(tag_rows, [Constraint::Min(20), Constraint::Length(10)])
|
||||
.block(Block::default().borders(Borders::ALL).title(" Top Tags "));
|
||||
f.render_widget(tags_table, bottom_cols[0]);
|
||||
|
||||
let col_rows: Vec<Row> = stats
|
||||
.top_collections
|
||||
.iter()
|
||||
.map(|tc| {
|
||||
Row::new(vec![
|
||||
Span::styled(tc.name.clone(), Style::default().fg(Color::Magenta)),
|
||||
Span::styled(tc.count.to_string(), Style::default().fg(Color::White)),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let cols_table = Table::new(col_rows, [Constraint::Min(20), Constraint::Length(10)]).block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title(" Top Collections "),
|
||||
);
|
||||
f.render_widget(cols_table, bottom_cols[1]);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue