From 46f9acd75ef4eacb87ecd177ff7b486538f6bd88 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Wed, 12 Jul 2023 14:49:03 +0200 Subject: [PATCH] Implement issue browser context on home page --- src/app/page.rs | 33 +++++++++++++++++++++++++-------- src/ui/context.rs | 8 ++++++++ src/ui/layout.rs | 4 ++-- src/ui/widget/common/context.rs | 16 ++++++++++++++++ src/ui/widget/common/list.rs | 4 +++- src/ui/widget/home.rs | 8 +++----- src/ui/widget/issue.rs | 26 ++++++++++++++++++++++++-- src/ui/widget/patch.rs | 8 ++++++-- 8 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/app/page.rs b/src/app/page.rs index 1ca9bac2..61d154f8 100644 --- a/src/app/page.rs +++ b/src/app/page.rs @@ -6,8 +6,8 @@ use radicle::cob::issue::{Issue, IssueId}; use radicle::cob::patch::{Patch, PatchId}; use radicle_tui::cob; -use radicle_tui::ui::widget::common::context::Shortcuts; -use tuirealm::{Frame, NoUserEvent, Sub, SubClause}; +use radicle_tui::ui::widget::common::context::{Progress, Shortcuts}; +use tuirealm::{Frame, NoUserEvent, StateValue, Sub, SubClause}; use radicle_tui::ui::context::Context; use radicle_tui::ui::layout; @@ -119,16 +119,33 @@ impl HomeView { fn update_context( &self, app: &mut Application, + context: &Context, theme: &Theme, cid: HomeCid, ) -> Result<()> { + use tuirealm::State; + let context = match cid { HomeCid::IssueBrowser => { - let context = widget::issue::browse_context(theme); + let state = app.state(&Cid::Home(HomeCid::IssueBrowser))?; + let progress = match state { + State::Tup2((StateValue::Usize(step), StateValue::Usize(total))) => { + Progress::Step(step, total) + } + _ => Progress::None, + }; + let context = widget::issue::browse_context(context, theme, progress); Some(context) } HomeCid::PatchBrowser => { - let context = widget::patch::browse_context(theme); + let state = app.state(&Cid::Home(HomeCid::PatchBrowser))?; + let progress = match state { + State::Tup2((StateValue::Usize(step), StateValue::Usize(total))) => { + Progress::Step(step, total) + } + _ => Progress::None, + }; + let context = widget::patch::browse_context(context, theme, progress); Some(context) } _ => None, @@ -180,7 +197,7 @@ impl ViewPage for HomeView { let active_component = Cid::Home(self.active_component.clone()); app.active(&active_component)?; self.update_shortcuts(app, self.active_component.clone())?; - self.update_context(app, theme, self.active_component.clone())?; + self.update_context(app, context, theme, self.active_component.clone())?; Ok(()) } @@ -198,7 +215,7 @@ impl ViewPage for HomeView { fn update( &mut self, app: &mut Application, - _context: &Context, + context: &Context, theme: &Theme, message: Message, ) -> Result> { @@ -209,9 +226,10 @@ impl ViewPage for HomeView { app.active(&active_component)?; self.update_shortcuts(app, self.active_component.clone())?; - self.update_context(app, theme, self.active_component.clone())?; } + self.update_context(app, context, theme, self.active_component.clone())?; + Ok(None) } @@ -476,7 +494,6 @@ impl ViewPage for PatchView { context: &Context, theme: &Theme, ) -> Result<()> { - let (id, patch) = &self.patch; let navigation = widget::patch::navigation(theme); let header = widget::common::app_header(context, theme, Some(navigation)).to_boxed(); let activity = widget::patch::activity(theme).to_boxed(); diff --git a/src/ui/context.rs b/src/ui/context.rs index 5743e11e..f9e2a6c1 100644 --- a/src/ui/context.rs +++ b/src/ui/context.rs @@ -1,3 +1,4 @@ +use radicle::cob::issue::{Issue, IssueId}; use radicle::prelude::{Id, Project}; use radicle::Profile; @@ -8,17 +9,20 @@ pub struct Context { id: Id, project: Project, repository: Repository, + issues: Vec<(IssueId, Issue)>, } impl Context { pub fn new(profile: Profile, id: Id, project: Project) -> Self { let repository = profile.storage.repository(id).unwrap(); + let issues = crate::cob::issue::all(&repository).unwrap_or_default(); Self { id, profile, project, repository, + issues, } } @@ -37,4 +41,8 @@ impl Context { pub fn repository(&self) -> &Repository { &self.repository } + + pub fn issues(&self) -> &Vec<(IssueId, Issue)> { + &self.issues + } } diff --git a/src/ui/layout.rs b/src/ui/layout.rs index 970a7db6..1d56e3c0 100644 --- a/src/ui/layout.rs +++ b/src/ui/layout.rs @@ -206,9 +206,9 @@ pub fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { } pub fn issue_page(area: Rect, shortcuts_h: u16) -> IssuePage { - let content_h = area.height.saturating_sub(shortcuts_h); let header_h = 3u16; - + let content_h = area.height.saturating_sub(header_h).saturating_sub(shortcuts_h); + let root = Layout::default() .direction(Direction::Vertical) .horizontal_margin(1) diff --git a/src/ui/widget/common/context.rs b/src/ui/widget/common/context.rs index a9442884..af810e9c 100644 --- a/src/ui/widget/common/context.rs +++ b/src/ui/widget/common/context.rs @@ -9,6 +9,22 @@ use crate::ui::layout; use crate::ui::theme::Theme; use crate::ui::widget::{Widget, WidgetComponent}; +pub enum Progress { + Percentage(usize), + Step(usize, usize), + None, +} + +impl ToString for Progress { + fn to_string(&self) -> std::string::String { + match self { + Progress::Percentage(value) => format!("{value} %"), + Progress::Step(step, total) => format!("{step}/{total}"), + _ => String::new(), + } + } +} + /// A shortcut that consists of a label displaying the "hotkey", a label that displays /// the action and a spacer between them. #[derive(Clone)] diff --git a/src/ui/widget/common/list.rs b/src/ui/widget/common/list.rs index 356b2579..47446474 100644 --- a/src/ui/widget/common/list.rs +++ b/src/ui/widget/common/list.rs @@ -271,7 +271,9 @@ where } fn state(&self) -> State { - State::None + let selected = self.state.selected().unwrap_or_default(); + let len = self.items.len(); + State::Tup2((StateValue::Usize(selected), StateValue::Usize(len))) } fn perform(&mut self, _properties: &Props, cmd: Cmd) -> CmdResult { diff --git a/src/ui/widget/home.rs b/src/ui/widget/home.rs index dc06420c..ba4f3bd5 100644 --- a/src/ui/widget/home.rs +++ b/src/ui/widget/home.rs @@ -67,11 +67,9 @@ impl IssueBrowser { let repo = context.repository(); let mut items = vec![]; - if let Ok(issues) = cob::issue::all(repo) { - for (id, issue) in issues { - if let Ok(item) = IssueItem::try_from((context.profile(), repo, id, issue)) { - items.push(item); - } + for (id, issue) in context.issues() { + if let Ok(item) = IssueItem::try_from((context.profile(), repo, *id, issue.clone())) { + items.push(item); } } diff --git a/src/ui/widget/issue.rs b/src/ui/widget/issue.rs index 17c71a4f..f63af348 100644 --- a/src/ui/widget/issue.rs +++ b/src/ui/widget/issue.rs @@ -10,6 +10,7 @@ use tuirealm::tui::layout::Layout; use super::common::container::Container; use super::common::container::LabeledContainer; use super::common::context::ContextBar; +use super::common::context::Progress; use super::common::label::Textarea; use super::common::list::List; use super::common::list::Property; @@ -273,6 +274,27 @@ pub fn details( Widget::new(discussion) } -pub fn browse_context(theme: &Theme) -> Widget { - common::context::bar(theme, "Browse", "", "", "", "") +pub fn browse_context(context: &Context, theme: &Theme, progress: Progress) -> Widget { + use radicle::cob::issue::State; + + let issues = context.issues(); + let open = issues + .iter() + .filter(|issue| *issue.1.state() == State::Open) + .collect::>() + .len(); + let closed = issues + .iter() + .filter(|issue| *issue.1.state() != State::Open) + .collect::>() + .len(); + + common::context::bar( + theme, + "Browse", + "", + "", + &format!("{open} open | {closed} closed"), + &progress.to_string(), + ) } diff --git a/src/ui/widget/patch.rs b/src/ui/widget/patch.rs index 97e0279b..5df3ab73 100644 --- a/src/ui/widget/patch.rs +++ b/src/ui/widget/patch.rs @@ -10,7 +10,7 @@ use super::{Widget, WidgetComponent}; use super::common; use super::common::container::Tabs; -use super::common::context::ContextBar; +use super::common::context::{ContextBar, Progress}; use super::common::label::Label; use crate::ui::context::Context; @@ -116,6 +116,10 @@ pub fn context(context: &Context, theme: &Theme, patch: (PatchId, Patch)) -> Wid common::context::bar(theme, "Patch", &id, title, &author, &comments.to_string()) } -pub fn browse_context(theme: &Theme) -> Widget { +pub fn browse_context( + _context: &Context, + theme: &Theme, + _progress: Progress, +) -> Widget { common::context::bar(theme, "Browse", "", "", "", "") }