Skip to content
This repository was archived by the owner on May 11, 2023. It is now read-only.

Commit 3a01aab

Browse files
committed
issue: Add tui issue info
1 parent df1c70b commit 3a01aab

3 files changed

Lines changed: 117 additions & 8 deletions

File tree

issue/src/tui.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ pub mod state;
1818
pub mod store;
1919
pub mod window;
2020

21-
use state::{Tab};
22-
use window::{BrowserWidget, TabWidget};
21+
use state::Tab;
22+
use store::ToogleProperty;
23+
use window::{BrowserWidget, InfoWidget, TabWidget};
2324

2425
type TabList = TabProperty<Tab>;
2526
type IssueList = ListProperty<(IssueId, Issue)>;
@@ -32,6 +33,7 @@ pub enum Action {
3233
Up,
3334
Down,
3435
NextTab,
36+
ToogleInfo,
3537
Quit,
3638
}
3739

@@ -40,7 +42,8 @@ lazy_static! {
4042
(Key::Up, Action::Up),
4143
(Key::Down, Action::Down),
4244
(Key::Tab, Action::NextTab),
43-
(Key::Char('q'), Action::Quit)
45+
(Key::Char('q'), Action::Quit),
46+
(Key::Char('i'), Action::ToogleInfo),
4447
]
4548
.iter()
4649
.cloned()
@@ -61,15 +64,20 @@ pub fn run(
6164
let mut app = Application::new(&update).store(vec![
6265
("app.title", Box::new(project.name.clone())),
6366
("app.browser.tabs", Box::new(TabProperty::new(tabs))),
64-
("app.shortcuts", Box::new(vec![String::from("q quit")])),
65-
("project.issues.open", Box::new(ListProperty::new(open))),
66-
("project.issues.closed", Box::new(ListProperty::new(closed))),
67+
(
68+
"app.shortcuts",
69+
Box::new(vec![String::from("i info"), String::from("q quit")]),
70+
),
71+
("app.browser.info", Box::new(ToogleProperty::new(false))),
72+
("project.issues.open", Box::new(IssueList::new(open))),
73+
("project.issues.closed", Box::new(IssueList::new(closed))),
6774
]);
6875

6976
let pages = vec![PageWidget {
7077
title: Rc::new(TitleWidget),
7178
widgets: vec![Rc::new(BrowserWidget {
7279
tabs: Rc::new(TabWidget),
80+
info: Rc::new(InfoWidget),
7381
})],
7482
shortcuts: Rc::new(ShortcutWidget),
7583
}];
@@ -106,6 +114,9 @@ pub fn on_action(store: &mut Store, key: Key) -> Result<(), Error> {
106114
Action::NextTab => {
107115
select_next_tab(store)?;
108116
}
117+
Action::ToogleInfo => {
118+
toogle_info(store)?;
119+
}
109120
}
110121
}
111122
Ok(())
@@ -153,3 +164,9 @@ pub fn select_next_tab(store: &mut Store) -> Result<(), Error> {
153164
tabs.select_next();
154165
Ok(())
155166
}
167+
168+
pub fn toogle_info(store: &mut Store) -> Result<(), Error> {
169+
let info = store.get_mut::<ToogleProperty>("app.browser.info")?;
170+
info.toggle();
171+
Ok(())
172+
}

issue/src/tui/store.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#[derive(Default)]
2+
pub struct ToogleProperty {
3+
state: bool,
4+
}
5+
6+
impl ToogleProperty {
7+
pub fn new(state: bool) -> Self {
8+
Self { state }
9+
}
10+
11+
pub fn toggle(&mut self) {
12+
self.state = !self.state
13+
}
14+
15+
pub fn is_on(&self) -> bool {
16+
self.state
17+
}
18+
}

issue/src/tui/window.rs

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use tui::backend::Backend;
88
use tui::layout::{Alignment, Direction, Rect};
99
use tui::style::{Modifier, Style};
1010
use tui::text::{Span, Spans};
11-
use tui::widgets::{ListItem, Tabs};
11+
use tui::widgets::{ListItem, Paragraph, Tabs};
1212
use tui::Frame;
1313

1414
use radicle_common::cobs::issue::{Issue, IssueId};
@@ -23,13 +23,15 @@ use term::tui::theme::Theme;
2323
use term::tui::window::Widget;
2424

2525
use super::state::Tab;
26+
use super::store::ToogleProperty;
2627

2728
type IssueList = ListProperty<(IssueId, Issue)>;
2829
type TabList = TabProperty<Tab>;
2930

3031
#[derive(Clone)]
3132
pub struct BrowserWidget<B: Backend> {
3233
pub tabs: Rc<dyn Widget<B>>,
34+
pub info: Rc<dyn Widget<B>>,
3335
}
3436

3537
impl<B> BrowserWidget<B>
@@ -93,13 +95,18 @@ where
9395
.collect();
9496

9597
let tab_h = self.tabs.height(inner);
96-
let heights = vec![tab_h, inner.height.saturating_sub(tab_h)];
98+
let info_h = self.info.height(inner);
99+
let area_h = inner.height.saturating_sub(tab_h + info_h);
100+
let heights = vec![tab_h, area_h, info_h];
97101
let areas = layout::split_area(inner, heights, Direction::Vertical);
98102

103+
// Render widgets
99104
self.tabs.draw(store, frame, areas[0], theme)?;
100105

101106
let (list, mut state) = template::list(items, issues.items().selected_index(), theme);
102107
frame.render_stateful_widget(list, areas[1], &mut state);
108+
109+
self.info.draw(store, frame, areas[2], theme)?;
103110
} else {
104111
let message = String::from("No issues found");
105112
let message =
@@ -159,3 +166,70 @@ where
159166
3_u16
160167
}
161168
}
169+
170+
#[derive(Clone)]
171+
pub struct InfoWidget;
172+
173+
impl<B> Widget<B> for InfoWidget
174+
where
175+
B: Backend,
176+
{
177+
fn draw(
178+
&self,
179+
store: &Store,
180+
frame: &mut Frame<B>,
181+
area: Rect,
182+
theme: &Theme,
183+
) -> Result<(), Error> {
184+
let info = store.get::<ToogleProperty>("app.browser.info")?;
185+
if info.is_on() {
186+
let title = String::from("Issue");
187+
let tabs = store.get::<TabList>("app.browser.tabs")?;
188+
let issues = match tabs.items().selected() {
189+
Some(Tab::Open) => store.get::<IssueList>("project.issues.open")?,
190+
Some(Tab::Closed) => store.get::<IssueList>("project.issues.closed")?,
191+
None => store.get::<IssueList>("project.issues.open")?,
192+
};
193+
194+
let (block, _) = template::block(theme, area, Padding { top: 0, left: 0 }, false);
195+
frame.render_widget(block, area);
196+
if let Some((id, issue)) = issues.items().selected() {
197+
let author = issue.author().name();
198+
let id = format!(" {} ", id);
199+
200+
let project_w = title.len() as u16 + 2;
201+
let id_w = id.len() as u16;
202+
let author_w = author.len() as u16 + 2;
203+
let comments_w = issue.comments().len().to_string().len() as u16 + 2;
204+
let title_w = area
205+
.width
206+
.checked_sub(project_w + id_w + comments_w + author_w)
207+
.unwrap_or(0);
208+
209+
let widths = vec![project_w, id_w, title_w, author_w, comments_w];
210+
let areas = layout::split_area(area, widths, Direction::Horizontal);
211+
212+
let title = template::paragraph_styled(&title, theme.highlight_invert);
213+
frame.render_widget(title, areas[0]);
214+
215+
let id = Paragraph::new(vec![Spans::from(id)]).style(theme.bg_bright_primary);
216+
frame.render_widget(id, areas[1]);
217+
218+
let title = template::paragraph_styled(&issue.title, theme.bg_bright_ternary);
219+
frame.render_widget(title, areas[2]);
220+
221+
let author = template::paragraph_styled(&author, theme.bg_bright_primary);
222+
frame.render_widget(author, areas[3]);
223+
224+
let count = &issue.comments().len().to_string();
225+
let comments = template::paragraph(count, theme.bg_dark_secondary);
226+
frame.render_widget(comments, areas[4]);
227+
}
228+
}
229+
Ok(())
230+
}
231+
232+
fn height(&self, _area: Rect) -> u16 {
233+
1_u16
234+
}
235+
}

0 commit comments

Comments
 (0)