From b547e6758c635682c94794e5c13070a73c918203 Mon Sep 17 00:00:00 2001 From: pablu Date: Tue, 2 Jun 2026 18:49:48 +0200 Subject: wip: refactor architecture --- src/screens/installed_packages.rs | 170 ++++++++++++++++++++++++++++++++++++++ src/screens/mod.rs | 2 + src/screens/screen.rs | 11 +++ 3 files changed, 183 insertions(+) create mode 100644 src/screens/installed_packages.rs create mode 100644 src/screens/mod.rs create mode 100644 src/screens/screen.rs (limited to 'src/screens') diff --git a/src/screens/installed_packages.rs b/src/screens/installed_packages.rs new file mode 100644 index 0000000..7e65fd5 --- /dev/null +++ b/src/screens/installed_packages.rs @@ -0,0 +1,170 @@ +use ratatui::{ + Frame, + crossterm::event::{KeyCode, KeyEvent, KeyModifiers}, + layout::{Constraint, Layout, Rect}, + style::{Color, Modifier, Style}, + text::{Line, Span}, + widgets::{Block, Borders, Clear, List, ListState, Paragraph}, +}; +use ratatui_textarea::{Key, TextArea}; + +use crate::{ + actions::Signal, + gentoo::Portage, + screens::screen::Screen, + theme::Theme, + widgets::{ + helpers::search_popup_rect, package_metadata::render_package_metadata, + use_flags::render_use_flags, + }, +}; + +#[derive(Debug, Default)] +struct SearchPopup { + pub(crate) visible: bool, + pub(crate) textarea: TextArea<'static>, +} + +#[derive(Debug, Default)] +pub struct InstalledPackagesScreen { + list_state: ListState, + + search_popup: SearchPopup, +} + +impl InstalledPackagesScreen { + fn render_packages(&mut self, frame: &mut Frame, area: Rect, repo: &Portage) { + // let items: Vec = repo + // .installed_packages() + // .iter() + // .map(|x| x.atom.qualified_name()) + // .collect(); + let items: Vec = vec![]; + + 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 self.list_state); + } +} + +impl Screen for InstalledPackagesScreen { + fn draw(&mut self, frame: &mut Frame, area: Rect, repo: &Portage) { + 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]); + + self.render_packages(frame, split[0], repo); + render_use_flags(frame, split_vert[0], &repo.installed_packages[0]); + render_package_metadata(frame, split_vert[1], &repo.installed_packages[0]); + + 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(); + // 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 self.search_popup.visible { + 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()); + // } + // } + + // TODO: Only do this in init, not every time + self.search_popup.textarea.set_block(popup_block); + self.search_popup.textarea.set_style(Theme::muted()); + self.search_popup + .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(&self.search_popup.textarea, area); + } + } + + fn update(&mut self, key: KeyEvent) -> Option { + if self.search_popup.visible { + match key.code { + KeyCode::Esc => todo!("Toggle search window"), + KeyCode::Enter => todo!("Send search, get back matches"), + _ => self.search_popup.textarea.input_without_shortcuts(key), //TODO: Run "search + //logic" to get + //jumping while typing, + }; + } else { + match key.modifiers { + KeyModifiers::CONTROL => match key.code { + KeyCode::Char('d') => todo!("next page"), + KeyCode::Char('u') => todo!("prev page"), + _ => {} + }, + + _ => match key.code { + KeyCode::Char('q') => return Some(Signal::Quit), + KeyCode::Tab => return Some(Signal::CycleTab), + KeyCode::Char('j') => self.list_state.select_next(), + KeyCode::Char('k') => self.list_state.select_previous(), + KeyCode::Char('/') => todo!("Toggle search window"), + KeyCode::Char('n') => todo!("Next search"), + KeyCode::Char('N') => todo!("prev search"), + + _ => {} + }, + } + } + + None + } +} diff --git a/src/screens/mod.rs b/src/screens/mod.rs new file mode 100644 index 0000000..db3be11 --- /dev/null +++ b/src/screens/mod.rs @@ -0,0 +1,2 @@ +pub mod installed_packages; +pub mod screen; diff --git a/src/screens/screen.rs b/src/screens/screen.rs new file mode 100644 index 0000000..a87329b --- /dev/null +++ b/src/screens/screen.rs @@ -0,0 +1,11 @@ +use ratatui::{Frame, crossterm::event::KeyEvent, layout::Rect}; + +use crate::{ + actions::{Action, Signal}, + gentoo::Portage, +}; + +pub(crate) trait Screen { + fn draw(&mut self, frame: &mut Frame, area: Rect, repo: &Portage); + fn update(&mut self, action: KeyEvent) -> Option; +} -- cgit 1.3.1