diff options
Diffstat (limited to 'src/frontend')
| -rw-r--r-- | src/frontend/app.rs | 66 | ||||
| -rw-r--r-- | src/frontend/ui.rs | 77 |
2 files changed, 84 insertions, 59 deletions
diff --git a/src/frontend/app.rs b/src/frontend/app.rs index ce250cd..ca2c824 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -1,7 +1,8 @@ use crate::backend::bib::*; use std::error; -use ratatui::widgets::ListState; +use itertools::Itertools; +use ratatui::widgets::{ListState, TableState}; // Application result type. pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>; @@ -22,7 +23,7 @@ pub struct App { // list pub tag_list: TagList, // TODO: table items - pub entry_list: EntryList, + pub entry_table: EntryTable, // area pub current_area: CurrentArea, } @@ -73,42 +74,57 @@ impl FromIterator<String> for TagList { } } -impl FromIterator<(String, String)> for EntryList { +impl FromIterator<(String, String)> for EntryTable { fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self { - let entry_list_items = iter + // Has to be Vev<EntryTableItem> + let entry_table_items = iter .into_iter() - .map(|(authors, title)| EntryListItem::new(&authors, &title)) + // .map(|(authors, title)| EntryTableItem::new(&authors, &title)) + .map(|(authors, title)| EntryTableItem::new(&authors, &title)) + .sorted_by(|a, b| a.authors.cmp(&b.authors)) .collect(); - let entry_list_state = ListState::default(); + let entry_table_state = TableState::default().with_selected(0); Self { - entry_list_items, - entry_list_state, + entry_table_items, + entry_table_state, } } } // Define list containing entries as table #[derive(Debug)] -pub struct EntryList { - pub entry_list_items: Vec<EntryListItem>, - pub entry_list_state: ListState, +pub struct EntryTable { + pub entry_table_items: Vec<EntryTableItem>, + pub entry_table_state: TableState, } // Define contents of each entry table row #[derive(Debug)] -pub struct EntryListItem { +pub struct EntryTableItem { pub authors: String, pub title: String, // pub year: u16, } -impl EntryListItem { +impl EntryTableItem { pub fn new(authors: &str, title: &str) -> Self { Self { authors: authors.to_string(), title: title.to_string(), } } + + pub fn ref_vec(&self) -> Vec<&String> { + vec![&self.authors, &self.title] + } + + pub fn authors(&self) -> &str { + &self.authors + } + + pub fn title(&self) -> &str { + &self.title + } } impl Default for App { @@ -128,12 +144,10 @@ impl Default for App { ), ("Zora Neale Hurston".to_string(), "Barracoon".to_string()), ]; - // let mylist = ["Item 1", "Item 2"]; Self { running: true, - // INFO: here the function(s) for creating the list has to be placed inside the parantheses -> Bib::whatever tag_list: TagList::from_iter(lines), - entry_list: EntryList::from_iter(iter), + entry_table: EntryTable::from_iter(iter), current_area: CurrentArea::EntryArea, } } @@ -163,7 +177,7 @@ impl App { pub fn select_none(&mut self) { match self.current_area { - CurrentArea::EntryArea => self.entry_list.entry_list_state.select(None), + CurrentArea::EntryArea => self.entry_table.entry_table_state.select(None), CurrentArea::TagArea => self.tag_list.tag_list_state.select(None), } // self.tag_list.tag_list_state.select(None); @@ -171,14 +185,14 @@ impl App { pub fn select_next(&mut self) { match self.current_area { - CurrentArea::EntryArea => self.entry_list.entry_list_state.select_next(), + CurrentArea::EntryArea => self.entry_table.entry_table_state.select_next(), CurrentArea::TagArea => self.tag_list.tag_list_state.select_next(), } // self.tag_list.tag_list_state.select_next(); } pub fn select_previous(&mut self) { match self.current_area { - CurrentArea::EntryArea => self.entry_list.entry_list_state.select_previous(), + CurrentArea::EntryArea => self.entry_table.entry_table_state.select_previous(), CurrentArea::TagArea => self.tag_list.tag_list_state.select_previous(), } // self.tag_list.tag_list_state.select_previous(); @@ -186,7 +200,7 @@ impl App { pub fn select_first(&mut self) { match self.current_area { - CurrentArea::EntryArea => self.entry_list.entry_list_state.select_first(), + CurrentArea::EntryArea => self.entry_table.entry_table_state.select_first(), CurrentArea::TagArea => self.tag_list.tag_list_state.select_first(), } // self.tag_list.tag_list_state.select_first(); @@ -194,28 +208,28 @@ impl App { pub fn select_last(&mut self) { match self.current_area { - CurrentArea::EntryArea => self.entry_list.entry_list_state.select_last(), + CurrentArea::EntryArea => self.entry_table.entry_table_state.select_last(), CurrentArea::TagArea => self.tag_list.tag_list_state.select_last(), } // self.tag_list.tag_list_state.select_last(); } // pub fn select_none(&mut self) { - // self.entry_list.entry_list_state.select(None); + // self.entry_table.entry_table_state.select(None); // } // pub fn select_next(&mut self) { - // self.entry_list.entry_list_state.select_next(); + // self.entry_table.entry_table_state.select_next(); // } // pub fn select_previous(&mut self) { - // self.entry_list.entry_list_state.select_previous(); + // self.entry_table.entry_table_state.select_previous(); // } // pub fn select_first(&mut self) { - // self.entry_list.entry_list_state.select_first(); + // self.entry_table.entry_table_state.select_first(); // } // pub fn select_last(&mut self) { - // self.entry_list.entry_list_state.select_last(); + // self.entry_table.entry_table_state.select_last(); // } } diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs index ec5e612..9bb3c4c 100644 --- a/src/frontend/ui.rs +++ b/src/frontend/ui.rs @@ -6,15 +6,16 @@ use ratatui::{ Color, Modifier, Style, Stylize, }, symbols, - text::Line, + text::{Line, Text}, widgets::{ - Block, HighlightSpacing, List, ListItem, Padding, Paragraph, StatefulWidget, Widget, Wrap, + Block, Cell, HighlightSpacing, List, ListItem, Padding, Paragraph, Row, StatefulWidget, + Table, TableState, Widget, Wrap, }, }; use crate::frontend::app::{App, TagListItem}; -use super::app::EntryListItem; +use super::app::EntryTableItem; const MAIN_BLUE_COLOR: Color = Color::Indexed(39); const MAIN_PURPLE_COLOR: Color = Color::Indexed(129); @@ -22,8 +23,9 @@ const BOX_BORDER_STYLE_MAIN: Style = Style::new().fg(Color::White).bg(Color::Bla const NORMAL_ROW_BG: Color = Color::Black; const ALT_ROW_BG_COLOR: Color = Color::Indexed(234); const SELECTED_STYLE: Style = Style::new() - .fg(MAIN_BLUE_COLOR) - .add_modifier(Modifier::BOLD); + // .fg(MAIN_BLUE_COLOR) + .add_modifier(Modifier::BOLD) + .add_modifier(Modifier::REVERSED); const TEXT_FG_COLOR: Color = SLATE.c200; pub const fn alternate_colors(i: usize) -> Color { @@ -47,8 +49,8 @@ impl From<&TagListItem> for ListItem<'_> { } } -impl From<&EntryListItem> for ListItem<'_> { - fn from(value: &EntryListItem) -> Self { +impl From<&EntryTableItem> for ListItem<'_> { + fn from(value: &EntryTableItem) -> Self { let line = Line::styled(format!("{}, {}", value.authors, value.title), TEXT_FG_COLOR); ListItem::new(line) } @@ -73,7 +75,8 @@ impl Widget for &mut App { App::render_header(header_area, buf); App::render_footer(footer_area, buf); // Render list area where entry gets selected - self.render_entry_list(list_area, buf); + // self.render_entry_table(list_area, buf); + self.render_table(list_area, buf); // Render infos related to selected entry // TODO: only placeholder at the moment, has to be impl. self.render_taglist(tag_area, buf); @@ -95,7 +98,7 @@ impl App { .render(area, buf); } - pub fn render_entry_list(&mut self, area: Rect, buf: &mut Buffer) { + pub fn render_table(&mut self, area: Rect, buf: &mut Buffer) { let block = Block::bordered() .title( Line::raw(" Selection List ") @@ -106,33 +109,41 @@ impl App { .border_set(symbols::border::ROUNDED) .border_style(BOX_BORDER_STYLE_MAIN) .bg(Color::Black); // .bg(NORMAL_ROW_BG); - - // Iterate through all elements in the `items` and stylize them. - let items: Vec<ListItem> = self - .entry_list - .entry_list_items + let header_style = Style::default().bold(); + let selected_style = Style::default().add_modifier(Modifier::REVERSED); + + let header = ["Authors".underlined(), "Title".underlined()] + .into_iter() + .map(Cell::from) + .collect::<Row>() + .style(header_style) + .height(1); + let rows = self + .entry_table + .entry_table_items .iter() .enumerate() - .map(|(i, todo_item)| { - let color = alternate_colors(i); - ListItem::from(todo_item).bg(color) - }) - .collect(); - - // Create a List from all list items and highlight the currently selected one - let list = List::new(items) + .map(|(i, data)| { + let item = data.ref_vec(); + item.into_iter() + .map(|content| Cell::from(Text::from(format!("{content}")))) + .collect::<Row>() + .style(Style::new().fg(Color::White).bg(alternate_colors(i))) + .height(1) + }); + let entry_table = Table::new(rows, [Constraint::Percentage(20), Constraint::Fill(1)]) .block(block) - .highlight_style( - Style::new() - .fg(MAIN_PURPLE_COLOR) - .add_modifier(Modifier::BOLD), - ) - // .highlight_symbol("> ") + .header(header) + .column_spacing(2) + .highlight_style(selected_style) + .bg(Color::Black) .highlight_spacing(HighlightSpacing::Always); - - // We need to disambiguate this trait method as both `Widget` and `StatefulWidget` share the - // same method name `render`. - StatefulWidget::render(list, area, buf, &mut self.entry_list.entry_list_state); + StatefulWidget::render( + entry_table, + area, + buf, + &mut self.entry_table.entry_table_state, + ); } pub fn render_selected_item(&self, area: Rect, buf: &mut Buffer) { @@ -191,7 +202,7 @@ impl App { let list = List::new(items) .block(block) .highlight_style(SELECTED_STYLE) - .highlight_symbol("> ") + // .highlight_symbol("> ") .highlight_spacing(HighlightSpacing::Always); // We need to disambiguate this trait method as both `Widget` and `StatefulWidget` share the |
