aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpablu <me@pablu.de>2026-06-02 20:00:18 +0200
committerpablu <me@pablu.de>2026-06-02 20:00:18 +0200
commit9a0d2b1c0e7b31ace9f3477622ef907f8d11ad7c (patch)
tree30b74183fcc2c2cecca47368efa4f2948d1b1610
parent0f9492c0da3ac6d391b7b0d32ea2a391b94a18f4 (diff)
remove unused code, update signal to be own 'module'
-rw-r--r--src/actions/mod.rs3
-rw-r--r--src/app.rs2
-rw-r--r--src/main.rs2
-rw-r--r--src/screens/dashboard.rs11
-rw-r--r--src/screens/installed_packages.rs4
-rw-r--r--src/screens/screen.rs2
-rw-r--r--src/signal.rs (renamed from src/actions/signal.rs)0
-rw-r--r--src/ui.rs415
-rw-r--r--src/widgets/package_metadata.rs1
9 files changed, 10 insertions, 430 deletions
diff --git a/src/actions/mod.rs b/src/actions/mod.rs
deleted file mode 100644
index 39af0f6..0000000
--- a/src/actions/mod.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub mod signal;
-
-pub use signal::Signal;
diff --git a/src/app.rs b/src/app.rs
index 2fb3b23..ef0e92b 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -9,11 +9,11 @@ use ratatui::{
};
use crate::{
- actions::Signal,
gentoo::portage::Portage,
screens::{
dashboard::DashboardScreen, installed_packages::InstalledPackagesScreen, screen::Screen,
},
+ signal::Signal,
theme::Theme,
widgets::tabs::render_tab,
};
diff --git a/src/main.rs b/src/main.rs
index 120721b..5a8940b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
-mod actions;
mod app;
mod gentoo;
mod screens;
+mod signal;
mod theme;
mod widgets;
diff --git a/src/screens/dashboard.rs b/src/screens/dashboard.rs
index e03624d..9a6c277 100644
--- a/src/screens/dashboard.rs
+++ b/src/screens/dashboard.rs
@@ -5,7 +5,10 @@ use ratatui::{
widgets::{Block, Borders, Paragraph},
};
-use crate::{actions::Signal, screens::screen::Screen, theme::Theme, widgets::helpers::human_size};
+use crate::{
+ gentoo::Portage, screens::screen::Screen, signal::Signal, theme::Theme,
+ widgets::helpers::human_size,
+};
#[derive(Debug, Default)]
pub struct DashboardScreen {}
@@ -129,11 +132,7 @@ impl Screen for DashboardScreen {
frame.render_widget(portage_news, splits[2]);
}
- fn update(
- &mut self,
- key: ratatui::crossterm::event::KeyEvent,
- _: &crate::gentoo::Portage,
- ) -> Option<crate::actions::Signal> {
+ fn update(&mut self, key: ratatui::crossterm::event::KeyEvent, _: &Portage) -> Option<Signal> {
match key.code {
KeyCode::Char('q') => Some(Signal::Quit),
KeyCode::Tab => Some(Signal::CycleTab),
diff --git a/src/screens/installed_packages.rs b/src/screens/installed_packages.rs
index 48b0513..6175e08 100644
--- a/src/screens/installed_packages.rs
+++ b/src/screens/installed_packages.rs
@@ -9,9 +9,9 @@ use ratatui::{
use ratatui_textarea::TextArea;
use crate::{
- actions::Signal,
gentoo::{InstalledPackage, Portage},
screens::screen::Screen,
+ signal::Signal,
theme::Theme,
widgets::{
helpers::search_popup_rect, package_metadata::render_package_metadata,
@@ -142,7 +142,7 @@ impl Screen for InstalledPackagesScreen {
let text = if self.search_popup.visible {
"(esc) to quit search | (enter) to search".to_string()
} else {
- let mut main_key_hint = "(q) to quit | (j) down | (k) up | (/) to search".to_string();
+ let main_key_hint = "(q) to quit | (j) down | (k) up | (/) to search".to_string();
// if let (Some(current), Some(total)) = (app.current_search_index, app.search_indexes_len)
// {
// let _ = write!(
diff --git a/src/screens/screen.rs b/src/screens/screen.rs
index f299578..330e4c9 100644
--- a/src/screens/screen.rs
+++ b/src/screens/screen.rs
@@ -1,6 +1,6 @@
use ratatui::{Frame, crossterm::event::KeyEvent, layout::Rect};
-use crate::{actions::Signal, gentoo::Portage};
+use crate::{gentoo::Portage, signal::Signal};
pub(crate) trait Screen {
fn draw(&mut self, frame: &mut Frame, area: Rect, repo: &Portage);
diff --git a/src/actions/signal.rs b/src/signal.rs
index 1210e17..1210e17 100644
--- a/src/actions/signal.rs
+++ b/src/signal.rs
diff --git a/src/ui.rs b/src/ui.rs
deleted file mode 100644
index fa515ce..0000000
--- a/src/ui.rs
+++ /dev/null
@@ -1,415 +0,0 @@
-use std::fmt::Write as _;
-
-use ratatui::{
- Frame,
- layout::{Alignment, Constraint, Direction, Layout, Spacing},
- prelude::Rect,
- style::{Color, Modifier, Style, Stylize},
- symbols,
- text::{Line, Span, Text},
- widgets::{Block, Borders, Clear, List, ListItem, ListState, Paragraph, Tabs, Wrap},
-};
-
-use crate::{
- app::{App, ViewState},
- gentoo::InstalledPackage,
- theme::Theme,
-};
-
-pub fn ui(frame: &mut Frame, app: &mut App) {
- frame.render_widget(Block::default().bg(Theme::BG), frame.area());
-
- let layout = Layout::vertical(vec![Constraint::Length(3), Constraint::Fill(1)]);
- let [tab_bar, rest] = frame.area().layout(&layout);
-
- render_tab(frame, tab_bar, &app.view);
-
- match app.view {
- crate::app::ViewState::Dashboard => render_dashboard(frame, rest, app),
- crate::app::ViewState::InstalledPackages => render_installed_packages(frame, rest, app),
- crate::app::ViewState::AvailablePackages => {
- frame.render_widget(Text::from("NOT IMPLEMENTED"), rest)
- }
- }
-}
-
-fn render_tab(frame: &mut Frame, area: Rect, selected_tab: &ViewState) {
- let selected_index = match selected_tab {
- ViewState::Dashboard => 0,
- ViewState::InstalledPackages => 1,
- ViewState::AvailablePackages => 2,
- };
-
- let tabs = Tabs::new(vec!["Dashboard", "Installed", "Browse"])
- .block(Block::default().borders(Borders::ALL).style(Theme::block()))
- .highlight_style(Theme::success())
- .select(selected_index)
- .divider(symbols::DOT)
- .padding(" ", " ");
- frame.render_widget(tabs, area);
-}
-
-fn render_dashboard(frame: &mut Frame, area: Rect, app: &App) {
- let logo = "
- ██████╗ ██╗ ██╗██╗███████╗██╗ ██╗
- ██╔═══██╗██║ ██║██║██╔════╝██║ ██║
- ██║ ██║██║ ██║██║█████╗ ██║ █╗ ██║
- ██║▄▄ ██║╚██╗ ██╔╝██║██╔══╝ ██║███╗██║
- ╚██████╔╝ ╚████╔╝ ██║███████╗╚███╔███╔╝
- ╚══▀▀═╝ ╚═══╝ ╚═╝╚══════╝ ╚══╝╚══╝
- gentoo portage dashboard
- ";
-
- let constraints = [
- Constraint::Length(9),
- Constraint::Min(15),
- Constraint::Fill(1),
- Constraint::Length(3),
- ];
-
- let layout = Layout::vertical(constraints);
-
- let [logo_top, stats, _fill, key_hints] = 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),
- ])
- .spacing(Spacing::Overlap(1))
- .split(stats_top);
-
- let logo = Paragraph::new(Text::styled(logo, Theme::title()));
- frame.render_widget(logo, logo_top);
-
- let keys = Paragraph::new(Span::styled(
- "(q) to quit | (tab) to switch tabs",
- Theme::muted(),
- ))
- .block(
- Block::default()
- .borders(Borders::ALL)
- .border_style(Theme::block()),
- );
- frame.render_widget(keys, key_hints);
-
- let installed_packages_len = app.installed_packages().len().to_string();
- let installed_packages = create_stats("Installed Packages", installed_packages_len.as_str());
- let global_use_flags = create_stats("Global USE Flags", "COMING SOON");
- let repository_state = create_stats("Repository state", "COMING SOON");
- frame.render_widget(installed_packages, splits[0]);
- frame.render_widget(global_use_flags, splits[1]);
- frame.render_widget(repository_state, splits[2]);
-
- let splits = Layout::horizontal([
- Constraint::Fill(1),
- Constraint::Fill(1),
- Constraint::Fill(1),
- ])
- .spacing(Spacing::Overlap(1))
- .split(stats_middle);
-
- 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", "COMING SOON");
- let last_emerge = create_stats("Last Emerge", "COMING SOON");
-
- frame.render_widget(world_packages, splits[0]);
- frame.render_widget(pending_updates, splits[1]);
- frame.render_widget(last_emerge, splits[2]);
-
- let splits = Layout::horizontal([
- Constraint::Fill(1),
- Constraint::Fill(1),
- Constraint::Fill(1),
- ])
- .spacing(Spacing::Overlap(1))
- .split(stats_bottom);
-
- 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", "COMING SOON");
- let portage_news = create_stats("Portage News", "COMING SOON");
-
- frame.render_widget(installed_size, splits[0]);
- frame.render_widget(distfiles_cache, splits[1]);
- 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, Theme::title())),
- Line::from(""),
- Line::from(value),
- ])
- .block(
- Block::default()
- .borders(Borders::ALL)
- .border_style(Theme::block())
- .merge_borders(ratatui::symbols::merge::MergeStrategy::Exact),
- )
- .style(Theme::text())
- .alignment(Alignment::Center)
-}
-
-fn render_installed_packages(frame: &mut Frame, area: Rect, app: &mut App) {
- let constraints = [Constraint::Fill(1), Constraint::Length(3)];
-
- let layout = Layout::vertical(constraints);
- let [top, bottom] = area.layout(&layout);
-
- let split =
- Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]).split(top);
-
- let split_vert =
- Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]).split(split[1]);
-
- render_packages(frame, split[0], app);
- render_use_flags(frame, split_vert[0], app);
- render_package_metadata(frame, split_vert[1], app);
-
- let text = if app.showing_search_window {
- "(esc) to quit search | (enter) to search".to_string()
- } else {
- let mut main_key_hint = "(q) to quit | (j) down | (k) up | (/) to search".to_string();
- if let (Some(current), Some(total)) = (app.current_search_index, app.search_indexes_len) {
- let _ = write!(
- main_key_hint,
- " | (n) for next search | (N) for previous search | Searches found: {} / {}",
- current + 1,
- total
- );
- }
-
- main_key_hint
- };
-
- let key_hint = Span::styled(text, Theme::muted());
-
- let key_notes_footer = Paragraph::new(Line::from(key_hint)).block(
- Block::default()
- .borders(Borders::ALL)
- .border_style(Theme::block()),
- );
- frame.render_widget(key_notes_footer, bottom);
-
- if app.showing_search_window {
- let mut popup_block = Block::default()
- .title("Search")
- .borders(Borders::ALL)
- .border_type(ratatui::widgets::BorderType::Rounded)
- .border_style(Theme::block())
- .style(Style::default().bg(Theme::BG));
-
- if let Some(found) = app.search_found {
- if found {
- popup_block = popup_block.border_style(Theme::success());
- } else {
- popup_block = popup_block.border_style(Theme::error());
- }
- }
-
- app.textarea.set_block(popup_block);
- app.textarea.set_style(Theme::muted());
- app.textarea.set_cursor_line_style(Style::default());
-
- let area = search_popup_rect(70, area);
-
- frame.render_widget(
- Block::default().style(Style::default().bg(Theme::BG).add_modifier(Modifier::DIM)),
- frame.area(),
- );
- frame.render_widget(Clear, area);
- frame.render_widget(Block::default().style(Style::default().bg(Theme::BG)), area);
- frame.render_widget(&app.textarea, area);
- }
-}
-
-fn render_package_metadata(frame: &mut Frame, area: Rect, app: &App) {
- let pkg = app.current_package();
-
- let bold_style = Theme::title(); //Style::default().add_modifier(Modifier::BOLD);
- let maintainer = Line::from_iter([
- Span::styled("Maintainer: ", bold_style),
- Span::raw(pkg.metadata.maintainer.as_deref().unwrap_or("Unknown")),
- ]);
-
- let version = Line::from_iter([
- Span::styled("Version: ", bold_style),
- Span::raw(&pkg.version),
- ]);
-
- let repository = Line::from_iter([
- Span::styled("Repository: ", bold_style),
- Span::raw(&pkg.metadata.repository),
- ]);
-
- let license = Line::from_iter([
- Span::styled("License: ", bold_style),
- Span::raw(pkg.metadata.license.as_deref().unwrap_or("Unknown")),
- ]);
-
- let description = Line::from_iter([
- Span::styled("Description: ", bold_style),
- Span::raw(pkg.metadata.description.as_deref().unwrap_or("Unknown")),
- ]);
-
- let size = Line::from_iter([
- Span::styled("Size: ", bold_style),
- Span::raw(human_size(pkg.size)),
- ]);
-
- let build_time = Line::from_iter([
- Span::styled("Build time: ", bold_style),
- Span::raw(pkg.build_time.to_string()),
- ]);
-
- let mut lines = vec![
- maintainer,
- version,
- repository,
- build_time,
- license,
- description,
- size,
- ];
-
- let mut homepage = homepage_lines(pkg, bold_style);
- lines.append(&mut homepage);
-
- let paragraph = Paragraph::new(lines)
- .block(
- Block::default()
- .title("Metadata")
- .borders(Borders::ALL)
- .border_style(Theme::block()),
- )
- .wrap(Wrap { trim: false });
-
- frame.render_widget(paragraph, area);
-}
-
-fn homepage_lines(pkg: &InstalledPackage, bold_style: Style) -> Vec<Line<'_>> {
- let mut lines = Vec::new();
- lines.push(Line::from(vec![
- Span::styled("Homepage: ", bold_style),
- Span::raw(""),
- ]));
-
- for url in pkg.metadata.homepage.iter().filter(|s| !s.is_empty()) {
- lines.push(Line::from(vec![
- Span::raw(" - "), // indentation
- Span::styled(
- url,
- Style::default()
- .fg(Color::LightBlue)
- .add_modifier(Modifier::UNDERLINED),
- ),
- ]));
- }
-
- lines
-}
-
-fn search_popup_rect(percent_x: u16, r: Rect) -> Rect {
- // Cut the given rectangle into three vertical pieces
- let popup_layout = Layout::default()
- .direction(Direction::Vertical)
- .constraints([Constraint::Length(10), Constraint::Length(3)])
- .split(r);
-
- // Then cut the middle vertical piece into three width-wise pieces
- Layout::default()
- .direction(Direction::Horizontal)
- .constraints([
- Constraint::Percentage((100 - percent_x) / 2),
- Constraint::Percentage(percent_x),
- Constraint::Percentage((100 - percent_x) / 2),
- ])
- .split(popup_layout[1])[1] // Return the middle chunk
-}
-
-fn render_packages(frame: &mut Frame, area: Rect, app: &mut App) {
- let items: Vec<String> = app
- .installed_packages()
- .iter()
- .map(|x| x.atom.qualified_name())
- .collect();
-
- let list = List::new(items)
- .style(Color::White)
- .highlight_style(Theme::selected())
- .highlight_symbol("> ")
- .block(
- Block::default()
- .borders(Borders::ALL)
- .border_style(Theme::block())
- .title("Installed packages"),
- );
-
- frame.render_stateful_widget(list, area, &mut app.list_state);
-}
-
-fn render_use_flags(frame: &mut Frame, area: Rect, app: &App) {
- let selected_package = app.current_package();
-
- let items = selected_package.iuse.iter().map(|x| {
- let text_style = if selected_package.enabled_use_flags.contains(&x.name) {
- Theme::success()
- } else if x.default {
- Theme::info()
- } else {
- Theme::error()
- };
-
- let text_style = if x.default {
- text_style.add_modifier(Modifier::ITALIC)
- } else {
- text_style
- };
-
- ListItem::new(x.name.clone()).style(text_style)
- });
- let list = List::new(items)
- .style(Color::White)
- .scroll_padding(1)
- .direction(ratatui::widgets::ListDirection::TopToBottom)
- .block(
- Block::default()
- .borders(Borders::ALL)
- .title("USE Flags")
- .border_style(Theme::block()),
- );
-
- let mut list_state = ListState::default();
- list_state.select_first();
-
- frame.render_stateful_widget(list, area, &mut list_state);
-}
diff --git a/src/widgets/package_metadata.rs b/src/widgets/package_metadata.rs
index 7377cbc..ee46f62 100644
--- a/src/widgets/package_metadata.rs
+++ b/src/widgets/package_metadata.rs
@@ -6,7 +6,6 @@ use ratatui::{
};
use crate::{
- app::App,
gentoo::InstalledPackage,
theme::Theme,
widgets::helpers::{homepage_lines, human_size},