aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
authorlukeflo2024-09-22 23:55:38 +0200
committerlukeflo2024-09-22 23:55:38 +0200
commitf3cfa231055e36910a12d59107dcf33f9251b37a (patch)
tree3df5cc4d091853d650467c956e9346fe0a113c94 /src/frontend
parentdc45b960a4eda299058e597f6867e4d4be109b1b (diff)
downloadbibiman-f3cfa231055e36910a12d59107dcf33f9251b37a.tar.gz
bibiman-f3cfa231055e36910a12d59107dcf33f9251b37a.zip
implemented entry list as table
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/app.rs66
-rw-r--r--src/frontend/ui.rs77
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