diff --git a/radicle-tui/src/app/page.rs b/radicle-tui/src/app/page.rs index 54591379..b32bccb8 100644 --- a/radicle-tui/src/app/page.rs +++ b/radicle-tui/src/app/page.rs @@ -1,10 +1,9 @@ use anyhow::Result; -use radicle::cob::{ - issue::{Issue, IssueId}, - patch::{Patch, PatchId}, -}; -use tuirealm::{Frame, NoUserEvent}; +use radicle::cob::issue::{Issue, IssueId}; +use radicle::cob::patch::{Patch, PatchId}; + +use tuirealm::{Frame, NoUserEvent, Sub, SubClause}; use radicle_tui::ui::layout; use radicle_tui::ui::theme::Theme; @@ -41,6 +40,14 @@ pub trait ViewPage { /// Will be called whenever a view page is on top of the page stack and needs to be rendered. fn view(&mut self, app: &mut Application, frame: &mut Frame); + + /// Will be called whenever this view page is pushed to the stack, or it is on top of the stack again + /// after another view page was popped from the stack. + fn subscribe(&self, app: &mut Application) -> Result<()>; + + /// Will be called whenever this view page is on top of the stack and another view page is pushed + /// to the stack, or if this is popped from the stack. + fn unsubscribe(&self, app: &mut Application) -> Result<()>; } /// @@ -71,11 +78,7 @@ impl ViewPage for HomeView { let issue_browser = widget::home::issues(theme, &context.id, &context.profile).to_boxed(); let patch_browser = widget::home::patches(theme, &context.id, &context.profile).to_boxed(); - app.remount( - Cid::Home(HomeCid::Navigation), - navigation, - subscription::navigation(), - )?; + app.remount(Cid::Home(HomeCid::Navigation), navigation, vec![])?; app.remount(Cid::Home(HomeCid::Dashboard), dashboard, vec![])?; app.remount(Cid::Home(HomeCid::IssueBrowser), issue_browser, vec![])?; @@ -114,6 +117,27 @@ impl ViewPage for HomeView { app.view(&Cid::Home(HomeCid::Navigation), frame, layout[0]); app.view(&self.active_component, frame, layout[1]); } + + fn subscribe(&self, app: &mut Application) -> Result<()> { + app.subscribe( + &Cid::Home(HomeCid::Navigation), + Sub::new( + subscription::navigation_clause::(), + SubClause::Always, + ), + )?; + + Ok(()) + } + + fn unsubscribe(&self, app: &mut Application) -> Result<()> { + app.unsubscribe( + &Cid::Home(HomeCid::Navigation), + subscription::navigation_clause::(), + )?; + + Ok(()) + } } /// @@ -171,6 +195,27 @@ impl ViewPage for IssuePage { app.view(&Cid::Patch(PatchCid::Navigation), frame, layout[0]); app.view(&self.active_component, frame, layout[1]); } + + fn subscribe(&self, app: &mut Application) -> Result<()> { + app.subscribe( + &Cid::Home(HomeCid::Navigation), + Sub::new( + subscription::navigation_clause::(), + SubClause::Always, + ), + )?; + + Ok(()) + } + + fn unsubscribe(&self, app: &mut Application) -> Result<()> { + app.unsubscribe( + &Cid::Home(HomeCid::Navigation), + subscription::navigation_clause::(), + )?; + + Ok(()) + } } /// @@ -202,11 +247,7 @@ impl ViewPage for PatchView { let activity = widget::patch::activity(theme, (*id, patch), &context.profile).to_boxed(); let files = widget::patch::files(theme, (*id, patch), &context.profile).to_boxed(); - app.remount( - Cid::Patch(PatchCid::Navigation), - navigation, - subscription::navigation(), - )?; + app.remount(Cid::Patch(PatchCid::Navigation), navigation, vec![])?; app.remount(Cid::Patch(PatchCid::Activity), activity, vec![])?; app.remount(Cid::Patch(PatchCid::Files), files, vec![])?; @@ -242,6 +283,27 @@ impl ViewPage for PatchView { app.view(&Cid::Patch(PatchCid::Navigation), frame, layout[0]); app.view(&self.active_component, frame, layout[1]); } + + fn subscribe(&self, app: &mut Application) -> Result<()> { + app.subscribe( + &Cid::Patch(PatchCid::Navigation), + Sub::new( + subscription::navigation_clause::(), + SubClause::Always, + ), + )?; + + Ok(()) + } + + fn unsubscribe(&self, app: &mut Application) -> Result<()> { + app.unsubscribe( + &Cid::Patch(PatchCid::Navigation), + subscription::navigation_clause::(), + )?; + + Ok(()) + } } /// View pages need to preserve their state (e.g. selected navigation tab, contents @@ -265,16 +327,25 @@ impl PageStack { context: &Context, theme: &Theme, ) -> Result<()> { + if let Some(page) = self.pages.last() { + page.unsubscribe(app)?; + } + page.mount(app, context, theme)?; + page.subscribe(app)?; + self.pages.push(page); Ok(()) } pub fn pop(&mut self, app: &mut Application) -> Result<()> { + self.peek_mut()?.unsubscribe(app)?; self.peek_mut()?.unmount(app)?; self.pages.pop(); + self.peek_mut()?.subscribe(app)?; + Ok(()) } diff --git a/radicle-tui/src/app/subscription.rs b/radicle-tui/src/app/subscription.rs index df4e336e..2442873b 100644 --- a/radicle-tui/src/app/subscription.rs +++ b/radicle-tui/src/app/subscription.rs @@ -3,18 +3,15 @@ use std::hash::Hash; use tuirealm::event::{Key, KeyEvent, KeyModifiers}; use tuirealm::{Sub, SubClause, SubEventClause}; -pub fn navigation() -> Vec> +pub fn navigation_clause() -> SubEventClause where Id: Clone + Hash + Eq + PartialEq, UserEvent: Clone + Eq + PartialEq + PartialOrd, { - vec![Sub::new( - SubEventClause::Keyboard(KeyEvent { - code: Key::Tab, - modifiers: KeyModifiers::NONE, - }), - SubClause::Always, - )] + SubEventClause::Keyboard(KeyEvent { + code: Key::Tab, + modifiers: KeyModifiers::NONE, + }) } pub fn global() -> Vec>