Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
tui: Move shortcuts to root widget
Erik Kundt committed 3 years ago
commit 689413ac3d0330829f8d64c428f2e1218fc0f92d
parent f94900c46951205e201ddc468c1cc3cf187611e1
4 files changed +172 -92
modified radicle-tui/src/app.rs
@@ -4,7 +4,6 @@ use tui_realm_stdlib::Phantom;
use tuirealm::application::PollStrategy;
use tuirealm::command::{Cmd, CmdResult, Direction as MoveDirection};
use tuirealm::event::{Event, Key, KeyEvent};
-
use tuirealm::props::{AttrValue, Attribute};
use tuirealm::{Application, Frame, MockComponent, NoUserEvent, State, StateValue};

use radicle_tui::cob::patch::{self};
@@ -40,7 +39,6 @@ pub enum PatchCid {
    Navigation,
    Activity,
    Files,
-
    Context,
}

/// All component ids known to this application.
@@ -48,7 +46,6 @@ pub enum PatchCid {
pub enum Cid {
    Home(HomeCid),
    Patch(PatchCid),
-
    Shortcuts,
    GlobalListener,
}

@@ -232,15 +229,6 @@ impl ViewPage for Home {
        let issue_browser = ui::issue_browser(theme).to_boxed();
        let patch_browser = ui::patch_browser(theme, &context.patches, &context.profile).to_boxed();

-
        let shortcuts = ui::shortcuts(
-
            theme,
-
            vec![
-
                ui::shortcut(theme, "tab", "section"),
-
                ui::shortcut(theme, "q", "quit"),
-
            ],
-
        )
-
        .to_boxed();
-

        app.remount(
            Cid::Home(HomeCid::Navigation),
            navigation,
@@ -251,7 +239,6 @@ impl ViewPage for Home {
        app.remount(Cid::Home(HomeCid::IssueBrowser), issue_browser, vec![])?;
        app.remount(Cid::Home(HomeCid::PatchBrowser), patch_browser, vec![])?;

-
        app.remount(Cid::Shortcuts, shortcuts, vec![])?;
        Ok(())
    }

@@ -269,17 +256,10 @@ 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 shortcuts_h = app
-
            .query(&Cid::Shortcuts, Attribute::Height)
-
            .ok()
-
            .flatten()
-
            .unwrap_or(AttrValue::Size(0))
-
            .unwrap_size();
-
        let layout = layout::default_page(area, navigation_h, shortcuts_h);
+
        let layout = layout::default_page(area, navigation_h);

        app.view(&Cid::Home(HomeCid::Navigation), frame, layout[0]);
        app.view(&self.active_component, frame, layout[1]);
-
        app.view(&Cid::Shortcuts, frame, layout[2]);
    }

    fn activate(&self, app: &mut Application<Cid, Message, NoUserEvent>) -> Result<()> {
@@ -312,18 +292,8 @@ impl ViewPage for PatchView {
    ) -> Result<()> {
        if let Some((id, patch)) = context.patches.get(context.selected_patch) {
            let navigation = ui::patch_navigation(theme).to_boxed();
-
            let activity = ui::patch_activity(theme).to_boxed();
-
            let files = ui::patch_files(theme).to_boxed();
-
            let context = ui::patch_context(theme, (*id, patch), &context.profile).to_boxed();
-
            let shortcuts = ui::shortcuts(
-
                theme,
-
                vec![
-
                    ui::shortcut(theme, "esc", "back"),
-
                    ui::shortcut(theme, "tab", "section"),
-
                    ui::shortcut(theme, "q", "quit"),
-
                ],
-
            )
-
            .to_boxed();
+
            let activity = ui::patch_activity(theme, (*id, patch), &context.profile).to_boxed();
+
            let files = ui::patch_files(theme, (*id, patch), &context.profile).to_boxed();

            app.remount(
                Cid::Patch(PatchCid::Navigation),
@@ -332,8 +302,6 @@ impl ViewPage for PatchView {
            )?;
            app.remount(Cid::Patch(PatchCid::Activity), activity, vec![])?;
            app.remount(Cid::Patch(PatchCid::Files), files, vec![])?;
-
            app.remount(Cid::Patch(PatchCid::Context), context, vec![])?;
-
            app.remount(Cid::Shortcuts, shortcuts, vec![])?;
        }
        Ok(())
    }
@@ -351,19 +319,11 @@ impl ViewPage for PatchView {
    fn view(&mut self, app: &mut Application<Cid, Message, NoUserEvent>, frame: &mut Frame) {
        let area = frame.size();
        let navigation_h = 2u16;
-
        let context_h = 1u16;
-
        let shortcuts_h = app
-
            .query(&Cid::Shortcuts, Attribute::Height)
-
            .ok()
-
            .flatten()
-
            .unwrap_or(AttrValue::Size(0))
-
            .unwrap_size();
-
        let layout = layout::page_with_context(area, navigation_h, context_h, shortcuts_h);
+

+
        let layout = layout::default_page(area, navigation_h);

        app.view(&Cid::Patch(PatchCid::Navigation), frame, layout[0]);
        app.view(&self.active_component, frame, layout[1]);
-
        app.view(&Cid::Patch(PatchCid::Context), frame, layout[2]);
-
        app.view(&Cid::Shortcuts, frame, layout[3]);
    }

    fn activate(&self, app: &mut Application<Cid, Message, NoUserEvent>) -> Result<()> {
modified radicle-tui/src/ui.rs
@@ -122,8 +122,16 @@ pub fn table(theme: &theme::Theme, items: &[impl List], profile: &Profile) -> Wi
}

pub fn issue_browser(theme: &theme::Theme) -> Widget<IssueBrowser> {
+
    let shortcuts = shortcuts(
+
        theme,
+
        vec![
+
            shortcut(theme, "tab", "section"),
+
            shortcut(theme, "q", "quit"),
+
        ],
+
    );
+

    let not_implemented = label("not implemented").foreground(theme.colors.default_fg);
-
    let browser = IssueBrowser::new(not_implemented);
+
    let browser = IssueBrowser::new(not_implemented, shortcuts);

    Widget::new(browser)
}
@@ -133,6 +141,16 @@ pub fn patch_browser(
    items: &[(PatchId, Patch)],
    profile: &Profile,
) -> Widget<Browser<(PatchId, Patch)>> {
+
    let shortcuts = shortcuts(
+
        theme,
+
        vec![
+
            shortcut(theme, "tab", "section"),
+
            shortcut(theme, "↑/↓", "navigate"),
+
            shortcut(theme, "enter", "show"),
+
            shortcut(theme, "q", "quit"),
+
        ],
+
    );
+

    let widths = AttrValue::Payload(PropPayload::Vec(vec![
        PropValue::U16(2),
        PropValue::U16(43),
@@ -153,21 +171,51 @@ pub fn patch_browser(
    let table = table(theme, items, profile)
        .custom("widths", widths)
        .custom("header", header);
-
    let browser: Browser<(PatchId, Patch)> = Browser::new(table);
+
    let browser: Browser<(PatchId, Patch)> = Browser::new(table, shortcuts);

    Widget::new(browser)
}

-
pub fn patch_activity(theme: &theme::Theme) -> Widget<PatchActivity> {
+
pub fn patch_activity(
+
    theme: &theme::Theme,
+
    patch: (PatchId, &Patch),
+
    profile: &Profile,
+
) -> Widget<PatchActivity> {
+
    let (id, patch) = patch;
+
    let shortcuts = shortcuts(
+
        theme,
+
        vec![
+
            shortcut(theme, "esc", "back"),
+
            shortcut(theme, "tab", "section"),
+
            shortcut(theme, "q", "quit"),
+
        ],
+
    );
+
    let context = patch_context(theme, (id, patch), profile);
+

    let not_implemented = label("not implemented").foreground(theme.colors.default_fg);
-
    let activity = PatchActivity::new(not_implemented);
+
    let activity = PatchActivity::new(not_implemented, context, shortcuts);

    Widget::new(activity)
}

-
pub fn patch_files(theme: &theme::Theme) -> Widget<PatchFiles> {
+
pub fn patch_files(
+
    theme: &theme::Theme,
+
    patch: (PatchId, &Patch),
+
    profile: &Profile,
+
) -> Widget<PatchFiles> {
+
    let (id, patch) = patch;
+
    let shortcuts = shortcuts(
+
        theme,
+
        vec![
+
            shortcut(theme, "esc", "back"),
+
            shortcut(theme, "tab", "section"),
+
            shortcut(theme, "q", "quit"),
+
        ],
+
    );
+
    let context = patch_context(theme, (id, patch), profile);
+

    let not_implemented = label("not implemented").foreground(theme.colors.default_fg);
-
    let files = PatchFiles::new(not_implemented);
+
    let files = PatchFiles::new(not_implemented, context, shortcuts);

    Widget::new(files)
}
@@ -198,7 +246,7 @@ pub fn patch_context(
        .background(Color::Rgb(50, 50, 50));

    let context_bar = ContextBar::new(context, id, author, title, comments);
-
    Widget::new(context_bar)
+
    Widget::new(context_bar).height(1)
}

pub fn home_navigation(theme: &theme::Theme) -> Widget<Tabs> {
@@ -226,7 +274,14 @@ pub fn dashboard(theme: &theme::Theme, id: &Id, project: &Project) -> Widget<Das
        )
        .to_boxed(),
    );
-
    let dashboard = Dashboard::new(about);
+
    let shortcuts = shortcuts(
+
        theme,
+
        vec![
+
            shortcut(theme, "tab", "section"),
+
            shortcut(theme, "q", "quit"),
+
        ],
+
    );
+
    let dashboard = Dashboard::new(about, shortcuts);

    Widget::new(dashboard)
}
modified radicle-tui/src/ui/components/workspace.rs
@@ -2,25 +2,28 @@ use std::marker::PhantomData;

use tuirealm::command::{Cmd, CmdResult};
use tuirealm::props::Props;
-
use tuirealm::tui::layout::{Constraint, Direction, Layout, Rect};
+
use tuirealm::tui::layout::Rect;
use tuirealm::{AttrValue, Attribute, Frame, MockComponent, State};

use crate::ui::layout;
use crate::ui::widget::{Widget, WidgetComponent};

use super::container::LabeledContainer;
+
use super::context::{ContextBar, Shortcuts};
use super::label::Label;
use super::list::{List, Table};

pub struct Browser<T> {
    list: Widget<Table>,
+
    shortcuts: Widget<Shortcuts>,
    phantom: PhantomData<T>,
}

impl<T: List> Browser<T> {
-
    pub fn new(list: Widget<Table>) -> Self {
+
    pub fn new(list: Widget<Table>, shortcuts: Widget<Shortcuts>) -> Self {
        Self {
            list,
+
            shortcuts,
            phantom: PhantomData,
        }
    }
@@ -28,12 +31,15 @@ impl<T: List> Browser<T> {

impl<T: List> WidgetComponent for Browser<T> {
    fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
-
        let layout = Layout::default()
-
            .direction(Direction::Vertical)
-
            .constraints(vec![Constraint::Min(1)].as_ref())
-
            .split(area);
+
        let shortcuts_h = self
+
            .shortcuts
+
            .query(Attribute::Height)
+
            .unwrap_or(AttrValue::Size(0))
+
            .unwrap_size();
+
        let layout = layout::root_component(area, shortcuts_h);

        self.list.view(frame, layout[0]);
+
        self.shortcuts.view(frame, layout[1]);
    }

    fn state(&self) -> State {
@@ -47,20 +53,25 @@ impl<T: List> WidgetComponent for Browser<T> {

pub struct Dashboard {
    about: Widget<LabeledContainer>,
+
    shortcuts: Widget<Shortcuts>,
}
impl Dashboard {
-
    pub fn new(about: Widget<LabeledContainer>) -> Self {
-
        Self { about }
+
    pub fn new(about: Widget<LabeledContainer>, shortcuts: Widget<Shortcuts>) -> Self {
+
        Self { about, shortcuts }
    }
}

impl WidgetComponent for Dashboard {
    fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
-
        let layout = Layout::default()
-
            .direction(Direction::Vertical)
-
            .constraints(vec![Constraint::Length(4)].as_ref())
-
            .split(area);
+
        let shortcuts_h = self
+
            .shortcuts
+
            .query(Attribute::Height)
+
            .unwrap_or(AttrValue::Size(0))
+
            .unwrap_size();
+
        let layout = layout::root_component(area, shortcuts_h);
+

        self.about.view(frame, layout[0]);
+
        self.shortcuts.view(frame, layout[1]);
    }

    fn state(&self) -> State {
@@ -74,11 +85,12 @@ impl WidgetComponent for Dashboard {

pub struct IssueBrowser {
    label: Widget<Label>,
+
    shortcuts: Widget<Shortcuts>,
}

impl IssueBrowser {
-
    pub fn new(label: Widget<Label>) -> Self {
-
        Self { label }
+
    pub fn new(label: Widget<Label>, shortcuts: Widget<Shortcuts>) -> Self {
+
        Self { label, shortcuts }
    }
}

@@ -89,9 +101,16 @@ impl WidgetComponent for IssueBrowser {
            .query(Attribute::Width)
            .unwrap_or(AttrValue::Size(1))
            .unwrap_size();
-
        let rect = layout::centered_label(label_w, area);
+
        let shortcuts_h = self
+
            .shortcuts
+
            .query(Attribute::Height)
+
            .unwrap_or(AttrValue::Size(0))
+
            .unwrap_size();
+
        let layout = layout::root_component(area, shortcuts_h);

-
        self.label.view(frame, rect);
+
        self.label
+
            .view(frame, layout::centered_label(label_w, layout[0]));
+
        self.shortcuts.view(frame, layout[1])
    }

    fn state(&self) -> State {
@@ -105,11 +124,21 @@ impl WidgetComponent for IssueBrowser {

pub struct PatchActivity {
    label: Widget<Label>,
+
    context: Widget<ContextBar>,
+
    shortcuts: Widget<Shortcuts>,
}

impl PatchActivity {
-
    pub fn new(label: Widget<Label>) -> Self {
-
        Self { label }
+
    pub fn new(
+
        label: Widget<Label>,
+
        context: Widget<ContextBar>,
+
        shortcuts: Widget<Shortcuts>,
+
    ) -> Self {
+
        Self {
+
            label,
+
            context,
+
            shortcuts,
+
        }
    }
}

@@ -120,9 +149,22 @@ impl WidgetComponent for PatchActivity {
            .query(Attribute::Width)
            .unwrap_or(AttrValue::Size(1))
            .unwrap_size();
-
        let rect = layout::centered_label(label_w, area);
+
        let context_h = self
+
            .context
+
            .query(Attribute::Height)
+
            .unwrap_or(AttrValue::Size(0))
+
            .unwrap_size();
+
        let shortcuts_h = self
+
            .shortcuts
+
            .query(Attribute::Height)
+
            .unwrap_or(AttrValue::Size(0))
+
            .unwrap_size();
+
        let layout = layout::root_component_with_context(area, context_h, shortcuts_h);

-
        self.label.view(frame, rect);
+
        self.label
+
            .view(frame, layout::centered_label(label_w, layout[0]));
+
        self.context.view(frame, layout[1]);
+
        self.shortcuts.view(frame, layout[2]);
    }

    fn state(&self) -> State {
@@ -136,11 +178,21 @@ impl WidgetComponent for PatchActivity {

pub struct PatchFiles {
    label: Widget<Label>,
+
    context: Widget<ContextBar>,
+
    shortcuts: Widget<Shortcuts>,
}

impl PatchFiles {
-
    pub fn new(label: Widget<Label>) -> Self {
-
        Self { label }
+
    pub fn new(
+
        label: Widget<Label>,
+
        context: Widget<ContextBar>,
+
        shortcuts: Widget<Shortcuts>,
+
    ) -> Self {
+
        Self {
+
            label,
+
            context,
+
            shortcuts,
+
        }
    }
}

@@ -151,9 +203,22 @@ impl WidgetComponent for PatchFiles {
            .query(Attribute::Width)
            .unwrap_or(AttrValue::Size(1))
            .unwrap_size();
-
        let rect = layout::centered_label(label_w, area);
+
        let context_h = self
+
            .context
+
            .query(Attribute::Height)
+
            .unwrap_or(AttrValue::Size(0))
+
            .unwrap_size();
+
        let shortcuts_h = self
+
            .shortcuts
+
            .query(Attribute::Height)
+
            .unwrap_or(AttrValue::Size(0))
+
            .unwrap_size();
+
        let layout = layout::root_component_with_context(area, context_h, shortcuts_h);

-
        self.label.view(frame, rect);
+
        self.label
+
            .view(frame, layout::centered_label(label_w, layout[0]));
+
        self.context.view(frame, layout[1]);
+
        self.shortcuts.view(frame, layout[2]);
    }

    fn state(&self) -> State {
modified radicle-tui/src/ui/layout.rs
@@ -46,18 +46,24 @@ pub fn h_stack(
    widgets.into_iter().zip(layout.into_iter()).collect()
}

-
pub fn default_page(area: Rect, nav_h: u16, shortcuts_h: u16) -> Vec<Rect> {
+
pub fn default_page(area: Rect, nav_h: u16) -> Vec<Rect> {
    let margin_h = 1u16;
-
    let content_h = area
-
        .height
-
        .saturating_sub(shortcuts_h.saturating_add(nav_h).saturating_add(margin_h));
+
    let content_h = area.height.saturating_sub(nav_h.saturating_add(margin_h));

    Layout::default()
        .direction(Direction::Vertical)
        .horizontal_margin(margin_h)
+
        .constraints([Constraint::Length(nav_h), Constraint::Length(content_h)].as_ref())
+
        .split(area)
+
}
+

+
pub fn root_component(area: Rect, shortcuts_h: u16) -> Vec<Rect> {
+
    let content_h = area.height.saturating_sub(shortcuts_h);
+

+
    Layout::default()
+
        .direction(Direction::Vertical)
        .constraints(
            [
-
                Constraint::Length(nav_h),
                Constraint::Length(content_h),
                Constraint::Length(shortcuts_h),
            ]
@@ -66,21 +72,15 @@ pub fn default_page(area: Rect, nav_h: u16, shortcuts_h: u16) -> Vec<Rect> {
        .split(area)
}

-
pub fn page_with_context(area: Rect, nav_h: u16, context_h: u16, shortcuts_h: u16) -> Vec<Rect> {
-
    let margin_h = 1u16;
-
    let content_h = area.height.saturating_sub(
-
        shortcuts_h
-
            .saturating_add(nav_h)
-
            .saturating_add(context_h)
-
            .saturating_add(margin_h),
-
    );
+
pub fn root_component_with_context(area: Rect, context_h: u16, shortcuts_h: u16) -> Vec<Rect> {
+
    let content_h = area
+
        .height
+
        .saturating_sub(shortcuts_h.saturating_add(context_h));

    Layout::default()
        .direction(Direction::Vertical)
-
        .horizontal_margin(margin_h)
        .constraints(
            [
-
                Constraint::Length(nav_h),
                Constraint::Length(content_h),
                Constraint::Length(context_h),
                Constraint::Length(shortcuts_h),