aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpablu <me@pablu.de>2026-05-08 15:32:12 +0200
committerpablu <me@pablu.de>2026-05-08 15:32:12 +0200
commitb6487e2009cb2191ef70fc6feefb38a0b6db1543 (patch)
treee316d8b314ec1388372e159fb60dbf0bece2469b /src
parent8a1f6b186bde43323003c440910d43e0db8a7bc3 (diff)
some dashboard stuff
Diffstat (limited to 'src')
-rw-r--r--src/app.rs13
-rw-r--r--src/gentoo/package.rs3
-rw-r--r--src/gentoo/portage.rs15
-rw-r--r--src/main.rs3
-rw-r--r--src/ui.rs71
5 files changed, 83 insertions, 22 deletions
diff --git a/src/app.rs b/src/app.rs
index fb18558..522998f 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -39,6 +39,10 @@ impl<'a> App<'a> {
}
}
+ pub fn world_count(&self) -> usize {
+ self.portage.world_packages.len()
+ }
+
pub fn installed_packages(&self) -> Vec<Package> {
self.portage.installed_packages.clone()
}
@@ -52,6 +56,15 @@ impl<'a> App<'a> {
self.portage.installed_packages[selected_package_index].clone()
}
+ pub fn total_installed_size(&self) -> usize {
+ self.portage
+ .installed_packages
+ .clone()
+ .into_iter()
+ .map(|p| p.size)
+ .sum()
+ }
+
pub fn toggle_search_window(&mut self) {
self.showing_search_window = !self.showing_search_window;
self.textarea.clear();
diff --git a/src/gentoo/package.rs b/src/gentoo/package.rs
index 1d7b3f3..3ead2a4 100644
--- a/src/gentoo/package.rs
+++ b/src/gentoo/package.rs
@@ -11,6 +11,7 @@ pub struct Package {
pub description: Option<String>,
pub homepage: Option<Vec<String>>,
pub license: Option<String>,
+ pub size: usize,
}
#[allow(dead_code)]
@@ -19,6 +20,7 @@ impl Package {
name: String,
version: String,
repository: String,
+ size: usize,
homepage: Option<Vec<String>>,
license: Option<String>,
description: Option<String>,
@@ -34,6 +36,7 @@ impl Package {
description: description,
homepage: homepage,
license: license,
+ size,
}
}
}
diff --git a/src/gentoo/portage.rs b/src/gentoo/portage.rs
index a28ed19..28d05da 100644
--- a/src/gentoo/portage.rs
+++ b/src/gentoo/portage.rs
@@ -7,6 +7,7 @@ use crate::gentoo::{Package, UseFlag};
#[derive(Debug)]
pub struct Portage {
pub installed_packages: Vec<Package>,
+ pub world_packages: Vec<String>,
}
fn split_pkg(input: &str) -> (&str, Option<&str>) {
@@ -70,9 +71,16 @@ impl Portage {
pub fn new() -> Self {
Self {
installed_packages: vec![],
+ world_packages: vec![],
}
}
+ pub fn load_world_packages(&mut self) -> io::Result<()> {
+ let world = fs::read_to_string("/var/lib/portage/world")?;
+ self.world_packages = world.split_whitespace().map(|s| s.to_string()).collect();
+ Ok(())
+ }
+
pub fn load_installed_packages(&mut self) -> io::Result<()> {
let categories = fs::read_dir("/var/db/pkg")?;
@@ -113,7 +121,6 @@ impl Portage {
})
.collect();
- // let category = fs::read_to_string(pkg.path().join("CATEGORY"))?;
let repository = fs::read_to_string(pkg.path().join("repository"))?
.trim()
.to_string();
@@ -136,6 +143,11 @@ impl Portage {
Err(_) => None,
};
+ let size: usize = match fs::read_to_string(pkg.path().join("SIZE")) {
+ Ok(size) => size.trim().parse().unwrap_or(0),
+ Err(_) => 0,
+ };
+
let repo_path = PathBuf::from("/var/db/repos/")
.join(&repository)
.join(cat_name.to_str().unwrap())
@@ -148,6 +160,7 @@ impl Portage {
format!("{}/{}", cat_name.to_str().unwrap(), pkg_name),
pkg_version.unwrap().into(),
repository,
+ size,
homepage,
license,
description,
diff --git a/src/main.rs b/src/main.rs
index 1c25018..0835fb7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -37,14 +37,13 @@ fn main() -> color_eyre::Result<()> {
let mut tui = init_tui()?;
let mut p = Portage::new();
+ p.load_world_packages()?;
p.load_installed_packages()?;
let mut app = App::new(p);
run(&mut tui, &mut app)?;
- // restore_tui()?;
-
Ok(())
}
diff --git a/src/ui.rs b/src/ui.rs
index 61941a9..d0a5f9e 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -1,6 +1,6 @@
use ratatui::{
Frame,
- layout::{Alignment, Constraint, Direction, Layout},
+ layout::{Alignment, Constraint, Direction, Layout, Spacing},
prelude::Rect,
style::{Color, Modifier, Style, Stylize},
text::{Line, Span},
@@ -29,30 +29,30 @@ fn render_dashboard(frame: &mut Frame, app: &mut App) {
let constraints = [
Constraint::Length(9),
- Constraint::Percentage(10),
- Constraint::Percentage(10),
- Constraint::Percentage(10),
+ Constraint::Percentage(30),
Constraint::Fill(1),
Constraint::Length(3),
];
let layout = Layout::vertical(constraints);
- let [
- logo_top,
- top_stats,
- middle_stats,
- bottom_stats,
- _fill,
- key_hints,
- ] = frame.area().layout(&layout);
+ let [logo_top, stats, _fill, key_hints] = frame.area().layout(&layout);
+
+ let [stats_top, stats_middle, stats_bottom] = Layout::vertical([
+ Constraint::Fill(1),
+ Constraint::Fill(1),
+ Constraint::Fill(1),
+ ])
+ .spacing(Spacing::Overlap(1))
+ .areas(stats);
let splits = Layout::horizontal([
Constraint::Fill(1),
Constraint::Fill(1),
Constraint::Fill(1),
])
- .split(top_stats);
+ .spacing(Spacing::Overlap(1))
+ .split(stats_top);
let logo = Paragraph::new(logo);
frame.render_widget(logo, logo_top);
@@ -74,9 +74,11 @@ fn render_dashboard(frame: &mut Frame, app: &mut App) {
Constraint::Fill(1),
Constraint::Fill(1),
])
- .split(middle_stats);
+ .spacing(Spacing::Overlap(1))
+ .split(stats_middle);
- let world_packages = create_stats("World Packages", "203");
+ let world_package_count = app.world_count().to_string();
+ let world_packages = create_stats("World Packages", &world_package_count);
let pending_updates = create_stats("Pending Updates", "16");
let last_emerge = create_stats("Last Emerge", "11:24 today");
@@ -89,9 +91,12 @@ fn render_dashboard(frame: &mut Frame, app: &mut App) {
Constraint::Fill(1),
Constraint::Fill(1),
])
- .split(bottom_stats);
+ .spacing(Spacing::Overlap(1))
+ .split(stats_bottom);
- let installed_size = create_stats("Installed Size", "38.2 GB");
+ let installed_size = human_size(app.total_installed_size());
+
+ let installed_size = create_stats("Installed Size", &installed_size);
let distfiles_cache = create_stats("Distfiles Cache", "12.8 GB");
let portage_news = create_stats("Portage News", "3 unread");
@@ -100,13 +105,35 @@ fn render_dashboard(frame: &mut Frame, app: &mut App) {
frame.render_widget(portage_news, splits[2]);
}
+fn human_size(bytes: usize) -> String {
+ const UNITS: [&str; 5] = ["B", "KB", "MB", "GB", "TB"];
+
+ let mut size = bytes as f64;
+ let mut unit = 0;
+
+ while size >= 1024.0 && unit < UNITS.len() - 1 {
+ size /= 1024.0;
+ unit += 1;
+ }
+
+ if unit == 0 {
+ format!("{} {}", bytes, UNITS[unit])
+ } else {
+ format!("{:.1} {}", size, UNITS[unit])
+ }
+}
+
fn create_stats<'a>(title: &'a str, value: &'a str) -> Paragraph<'a> {
Paragraph::new(vec![
Line::from(Span::styled(title, Style::default().bold())),
Line::from(""),
Line::from(value),
])
- .block(Block::default().borders(Borders::ALL))
+ .block(
+ Block::default()
+ .borders(Borders::ALL)
+ .merge_borders(ratatui::symbols::merge::MergeStrategy::Exact),
+ )
.alignment(Alignment::Center)
}
@@ -202,8 +229,14 @@ fn render_package_metadata(frame: &mut Frame, area: Rect, app: &mut App) {
Span::raw(pkg.description.as_deref().unwrap_or("Unknown")),
]);
+ let size = Line::from_iter([
+ Span::styled("Size: ", bold_style),
+ Span::raw(human_size(pkg.size)),
+ ]);
+
+ let mut lines = vec![maintainer, version, repository, license, description, size];
+
let mut homepage = homepage_lines(&pkg, bold_style);
- let mut lines = vec![maintainer, version, repository, license, description];
lines.append(&mut homepage);
let paragraph = Paragraph::new(lines)