From 0f9492c0da3ac6d391b7b0d32ea2a391b94a18f4 Mon Sep 17 00:00:00 2001 From: pablu Date: Tue, 2 Jun 2026 19:55:57 +0200 Subject: near feature parity with previous architecture --- src/screens/installed_packages.rs | 148 +++++++++++++++++++++++++++++--------- 1 file changed, 115 insertions(+), 33 deletions(-) (limited to 'src/screens/installed_packages.rs') diff --git a/src/screens/installed_packages.rs b/src/screens/installed_packages.rs index 7e65fd5..48b0513 100644 --- a/src/screens/installed_packages.rs +++ b/src/screens/installed_packages.rs @@ -6,11 +6,11 @@ use ratatui::{ text::{Line, Span}, widgets::{Block, Borders, Clear, List, ListState, Paragraph}, }; -use ratatui_textarea::{Key, TextArea}; +use ratatui_textarea::TextArea; use crate::{ actions::Signal, - gentoo::Portage, + gentoo::{InstalledPackage, Portage}, screens::screen::Screen, theme::Theme, widgets::{ @@ -19,13 +19,61 @@ use crate::{ }, }; -#[derive(Debug, Default)] +#[derive(Debug)] struct SearchPopup { pub(crate) visible: bool, pub(crate) textarea: TextArea<'static>, + pub(crate) result: Option, } -#[derive(Debug, Default)] +impl Default for SearchPopup { + fn default() -> Self { + let mut search_popup = Self { + visible: bool::default(), + textarea: TextArea::default(), + result: Option::default(), + }; + + search_popup.textarea.set_style(Theme::muted()); + search_popup + .textarea + .set_cursor_line_style(Style::default()); + + return search_popup; + } +} + +impl SearchPopup { + pub fn toggle(&mut self) { + self.visible = !self.visible; + self.textarea.clear(); + } + + pub fn search(&mut self, repo: &Portage) -> Option { + let indexes: Vec = repo + .installed_packages + .iter() + .enumerate() + .filter(|(_, s)| { + s.atom + .qualified_name() + .to_lowercase() + .contains(&self.textarea.lines()[0].to_lowercase()) + }) + .map(|(i, _)| i) + .collect(); + + if indexes.len() >= 1 { + self.result = Some(indexes[0]); + return Some(indexes[0]); + } else { + self.result = None; + return None; + } + } +} + +#[derive(Debug)] pub struct InstalledPackagesScreen { list_state: ListState, @@ -34,12 +82,12 @@ pub struct InstalledPackagesScreen { 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![]; + // TODO: Put this into portage method + let items: Vec = repo + .installed_packages + .iter() + .map(|x| x.atom.qualified_name()) + .collect(); let list = List::new(items) .style(Color::White) @@ -56,6 +104,17 @@ impl InstalledPackagesScreen { } } +impl Default for InstalledPackagesScreen { + fn default() -> Self { + let mut list_state = ListState::default(); + list_state.select(Some(0)); + Self { + list_state: list_state, + search_popup: Default::default(), + } + } +} + impl Screen for InstalledPackagesScreen { fn draw(&mut self, frame: &mut Frame, area: Rect, repo: &Portage) { let constraints = [Constraint::Fill(1), Constraint::Length(3)]; @@ -69,9 +128,16 @@ impl Screen for InstalledPackagesScreen { let split_vert = Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]) .split(split[1]); + // TODO: Atleast this doesnt crash but its still weird, it should show some Info that this + // package is completly unkown or placeholder data, or at best a warning + let mut pkg: Option<&InstalledPackage> = None; + if repo.installed_packages.len() > self.list_state.selected().unwrap_or(0) { + pkg = Some(&repo.installed_packages[self.list_state.selected().unwrap_or(0)]); + } + 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]); + render_use_flags(frame, split_vert[0], pkg); + render_package_metadata(frame, split_vert[1], pkg); let text = if self.search_popup.visible { "(esc) to quit search | (enter) to search".to_string() @@ -107,20 +173,13 @@ impl Screen for InstalledPackagesScreen { .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()); - // } - // } + if let Some(_) = self.search_popup.result { + 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); @@ -134,20 +193,43 @@ impl Screen for InstalledPackagesScreen { } } - fn update(&mut self, key: KeyEvent) -> Option { + fn update(&mut self, key: KeyEvent, repo: &Portage) -> 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, + KeyCode::Esc => self.search_popup.toggle(), + KeyCode::Enter => { + let result = self.search_popup.search(repo); + self.search_popup.toggle(); + + if let Some(index) = result { + self.list_state.select(Some(index)); + } + } + _ => { + self.search_popup.textarea.input_without_shortcuts(key); + let result = self.search_popup.search(repo); + + if let Some(index) = result { + self.list_state.select(Some(index)); + } + } }; } else { match key.modifiers { KeyModifiers::CONTROL => match key.code { - KeyCode::Char('d') => todo!("next page"), - KeyCode::Char('u') => todo!("prev page"), + KeyCode::Char('d') => self + .list_state + .select(Some(self.list_state.selected().unwrap_or(0) + 30)), + KeyCode::Char('u') => { + if let Some(selected) = self.list_state.selected() { + if selected < 30 { + self.list_state.select(Some(0)); + } else { + self.list_state.select(Some(selected - 30)); + } + } + } + _ => {} }, @@ -156,7 +238,7 @@ impl Screen for InstalledPackagesScreen { 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('/') => self.search_popup.toggle(), KeyCode::Char('n') => todo!("Next search"), KeyCode::Char('N') => todo!("prev search"), -- cgit 1.3.1