tui: Move shortcuts to root widget
This commit is contained in:
parent
95b0029267
commit
e13bf0b75b
|
|
@ -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<()> {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Reference in New Issue