tui: Implement new table design for patches

This commit is contained in:
Erik Kundt 2023-04-21 16:20:25 +02:00 committed by Alexis Sellier
parent b1c92f4a0d
commit 7c7379c733
No known key found for this signature in database
5 changed files with 67 additions and 65 deletions

View File

@ -81,7 +81,7 @@ impl ViewPage for Home {
fn view(&mut self, app: &mut Application<Cid, Message, NoUserEvent>, frame: &mut Frame) {
let area = frame.size();
let navigation_h = 2u16;
let navigation_h = 1u16;
let layout = layout::default_page(area, navigation_h);
app.view(&Cid::Home(HomeCid::Navigation), frame, layout[0]);

View File

@ -69,15 +69,15 @@ impl List for (PatchId, Patch) {
let author = format_author(patch, profile);
let author = TextSpan::from(author).fg(theme.colors.browser_patch_list_author);
let tags = format_tags(patch);
let tags = TextSpan::from(tags).fg(theme.colors.browser_patch_list_tags);
let timestamp = format_timestamp(patch);
let timestamp = TextSpan::from(timestamp).fg(theme.colors.browser_patch_list_timestamp);
let comments = format_comments(patch);
let comments = TextSpan::from(comments).fg(theme.colors.browser_patch_list_comments);
let timestamp = format_timestamp(patch);
let timestamp = TextSpan::from(timestamp).fg(theme.colors.browser_patch_list_timestamp);
let tags = format_tags(patch);
let tags = TextSpan::from(tags).fg(theme.colors.browser_patch_list_tags);
vec![status, title, author, tags, comments, timestamp]
vec![status, title, author, timestamp, comments, tags]
}
}

View File

@ -1,10 +1,11 @@
use radicle::Profile;
use tuirealm::command::{Cmd, CmdResult, Direction};
use tuirealm::command::{Cmd, CmdResult};
use tuirealm::props::{
AttrValue, Attribute, Color, PropPayload, PropValue, Props, Style, TextModifiers, TextSpan,
AttrValue, Attribute, BorderSides, BorderType, Color, PropPayload, PropValue, Props, Style,
TextSpan,
};
use tuirealm::tui::layout::{Constraint, Rect};
use tuirealm::tui::widgets::{Cell, Row, TableState};
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
use tuirealm::tui::widgets::{Block, Cell, Row, TableState};
use tuirealm::{Frame, MockComponent, State, StateValue};
use crate::ui::components::common::label::Label;
@ -12,6 +13,8 @@ use crate::ui::layout;
use crate::ui::theme::Theme;
use crate::ui::widget::{Widget, WidgetComponent};
use super::container::Header;
pub trait List {
fn row(&self, theme: &Theme, profile: &Profile) -> Vec<TextSpan>;
}
@ -105,18 +108,17 @@ impl WidgetComponent for PropertyList {
}
pub struct Table {
header: Widget<Header>,
state: TableState,
}
impl Default for Table {
fn default() -> Self {
impl Table {
pub fn new(header: Widget<Header>) -> Self {
let mut state = TableState::default();
state.select(Some(0));
Self { state }
Self { header, state }
}
}
impl Table {
fn select_previous(&mut self) {
let index = match self.state.selected() {
Some(selected) if selected == 0 => 0,
@ -135,18 +137,6 @@ impl Table {
self.state.select(Some(index));
}
fn header<'a>(spans: Vec<PropValue>) -> Row<'a> {
Row::new(
spans
.iter()
.map(|span| {
Cell::from(span.clone().unwrap_text_span().content)
.style(Style::default().add_modifier(TextModifiers::BOLD))
})
.collect::<Vec<_>>(),
)
}
fn rows<'a>(spans: Vec<Vec<TextSpan>>) -> Vec<Row<'a>> {
spans
.iter()
@ -173,19 +163,9 @@ impl WidgetComponent for Table {
let content = properties
.get_or(Attribute::Content, AttrValue::Table(vec![]))
.unwrap_table();
let background = properties
.get_or(Attribute::Background, AttrValue::Color(Color::Reset))
.unwrap_color();
let highlight = properties
.get_or(Attribute::HighlightedColor, AttrValue::Color(Color::Reset))
.unwrap_color();
let header = properties
.get_or(
Attribute::Custom("header"),
AttrValue::Payload(PropPayload::Vec(vec![])),
)
.unwrap_payload()
.unwrap_vec();
let widths = properties
.get_or(
Attribute::Custom("widths"),
@ -194,18 +174,27 @@ impl WidgetComponent for Table {
.unwrap_payload()
.unwrap_vec();
let header = Self::header(header);
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Length(3), Constraint::Min(1)])
.split(area);
let rows = Self::rows(content);
let widths = Self::widths(widths);
let table = tuirealm::tui::widgets::Table::new(rows)
let rows = tuirealm::tui::widgets::Table::new(rows)
.block(
Block::default()
.borders(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT)
.border_style(Style::default().fg(Color::Rgb(48, 48, 48)))
.border_type(BorderType::Rounded),
)
.highlight_style(Style::default().bg(highlight))
.style(Style::default().bg(background))
.column_spacing(3u16)
.header(header)
.widths(&widths);
frame.render_stateful_widget(table, area, &mut self.state);
self.header.view(frame, layout[0]);
frame.render_stateful_widget(rows, layout[1], &mut self.state);
}
fn state(&self) -> State {
@ -213,6 +202,8 @@ impl WidgetComponent for Table {
}
fn perform(&mut self, properties: &Props, cmd: Cmd) -> CmdResult {
use tuirealm::command::Direction;
let content = properties
.get_or(Attribute::Content, AttrValue::Table(vec![]))
.unwrap_table();

View File

@ -38,6 +38,22 @@ pub fn container_header(theme: &Theme, label: &str) -> Widget<Header> {
.custom("widths", widths)
}
pub fn table_header(theme: &Theme, labels: &[&str], widths: &[u16]) -> Widget<Header> {
let content = labels
.iter()
.map(|label| {
PropValue::TextSpan(TextSpan::from(label.to_string()).fg(theme.colors.default_fg))
})
.collect::<Vec<_>>();
let widths = AttrValue::Payload(PropPayload::Vec(
widths.iter().map(|w| PropValue::U16(*w)).collect(),
));
Widget::new(Header::default())
.content(AttrValue::Payload(PropPayload::Vec(content)))
.custom("widths", widths)
}
pub fn labeled_container(
theme: &Theme,
title: &str,
@ -105,12 +121,25 @@ pub fn tabs(theme: &Theme, tabs: Vec<Widget<Label>>) -> Widget<Tabs> {
.highlight(theme.colors.tabs_highlighted_fg)
}
pub fn table(theme: &Theme, items: &[impl List], profile: &Profile) -> Widget<Table> {
let table = Table::default();
pub fn table(
theme: &Theme,
labels: &[&str],
widths: &[u16],
items: &[impl List],
profile: &Profile,
) -> Widget<Table> {
let items = items.iter().map(|item| item.row(theme, profile)).collect();
let header = table_header(theme, labels, widths);
let table = Table::new(header);
let widths = AttrValue::Payload(PropPayload::Vec(
widths.iter().map(|w| PropValue::U16(*w)).collect(),
));
Widget::new(table)
.content(AttrValue::Table(items))
.custom("widths", widths)
.background(theme.colors.labeled_container_bg)
.highlight(theme.colors.item_list_highlighted_bg)
}

View File

@ -1,8 +1,6 @@
use radicle::cob::patch::{Patch, PatchId};
use radicle::identity::{Id, Project};
use radicle::Profile;
use tuirealm::props::{PropPayload, PropValue, TextSpan};
use tuirealm::AttrValue;
use crate::ui::components::common::container::Tabs;
use crate::ui::components::common::Browser;
@ -63,26 +61,10 @@ pub fn patches(
],
);
let widths = AttrValue::Payload(PropPayload::Vec(vec![
PropValue::U16(2),
PropValue::U16(43),
PropValue::U16(15),
PropValue::U16(15),
PropValue::U16(5),
PropValue::U16(20),
]));
let header = AttrValue::Payload(PropPayload::Vec(vec![
PropValue::TextSpan(TextSpan::from("")),
PropValue::TextSpan(TextSpan::from("title")),
PropValue::TextSpan(TextSpan::from("author")),
PropValue::TextSpan(TextSpan::from("tags")),
PropValue::TextSpan(TextSpan::from("comments")),
PropValue::TextSpan(TextSpan::from("date")),
]));
let labels = vec!["", "title", "author", "time", "comments", "tags"];
let widths = vec![3u16, 42, 15, 10, 5, 25];
let table = common::table(theme, items, profile)
.custom("widths", widths)
.custom("header", header);
let table = common::table(theme, &labels, &widths, items, profile);
let browser: Browser<(PatchId, Patch)> = Browser::new(table, shortcuts);
Widget::new(browser)