Skip to content

Commit

Permalink
Implement widget
Browse files Browse the repository at this point in the history
  • Loading branch information
mertwole committed Sep 6, 2024
1 parent d288184 commit 657baf2
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 10 deletions.
8 changes: 8 additions & 0 deletions app/src/screen/asset/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ pub enum InputEvent {
#[description = "Quit application"]
Quit,

#[key = 'h']
#[description = "Open/close navigation help"]
NavigationHelp,

#[key = 'b']
#[description = "Return one screen back"]
Back,
Expand Down Expand Up @@ -60,6 +64,10 @@ pub(super) fn process_input<L: LedgerApiT, C: CoinPriceApiT, M: BlockchainMonito

match event {
InputEvent::Quit => Some(OutgoingMessage::Exit),
InputEvent::NavigationHelp => {
model.show_navigation_help ^= true;
None
}
InputEvent::Back => Some(OutgoingMessage::Back),
InputEvent::OpenDepositScreen => Some(OutgoingMessage::SwitchScreen(ScreenName::Deposit)),
InputEvent::SelectTimeInterval(event) => {
Expand Down
2 changes: 2 additions & 0 deletions app/src/screen/asset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Model<L: LedgerApiT, C: CoinPriceApiT, M: BlockchainMonitoringApiT> {
coin_price_history: Option<Vec<PriceHistoryPoint>>,
transactions: Option<Vec<(TransactionUid, TransactionInfo)>>,
selected_time_period: TimePeriod,
show_navigation_help: bool,

state: StateRegistry,
apis: ApiRegistry<L, C, M>,
Expand Down Expand Up @@ -98,6 +99,7 @@ impl<L: LedgerApiT, C: CoinPriceApiT, M: BlockchainMonitoringApiT> ScreenT<L, C,
coin_price_history: Default::default(),
transactions: Default::default(),
selected_time_period: DEFAULT_SELECTED_TIME_PERIOD,
show_navigation_help: false,

state,
apis: api_registry,
Expand Down
61 changes: 57 additions & 4 deletions app/src/screen/asset/view.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use input_mapping_common::InputMappingT;
use ratatui::{
layout::{Alignment, Constraint, Direction, Layout, Rect},
layout::{Alignment, Constraint, Direction, Flex, Layout, Margin, Rect},
style::{Style, Stylize},
symbols,
symbols::{self},
text::{Line, Span, Text},
widgets::{
Axis, Block, Borders, Chart, Dataset, GraphType, HighlightSpacing, Padding, Row, Table,
Axis, Block, BorderType, Borders, Chart, Dataset, GraphType, HighlightSpacing, Padding,
Row, Table,
},
Frame,
};
Expand All @@ -21,7 +23,10 @@ use crate::{
ledger::LedgerApiT,
},
screen::{
common::{format_address, network_symbol, render_centered_text, BackgroundWidget},
common::{
format_address, network_symbol, render_centered_text, BackgroundWidget,
NavigationHelpWidget,
},
resources::Resources,
},
};
Expand Down Expand Up @@ -103,6 +108,10 @@ pub(super) fn render<L: LedgerApiT, C: CoinPriceApiT, M: BlockchainMonitoringApi
render_tx_list_placeholder(frame, inner_txs_list_area);
}
}

if model.show_navigation_help {
render_navigation_help(frame, resources);
}
}

fn render_price_chart(
Expand Down Expand Up @@ -253,3 +262,47 @@ fn render_tx_list_placeholder(frame: &mut Frame<'_>, area: Rect) {
let text = Text::raw("Fetching transactions...");
render_centered_text(frame, area, text)
}

fn render_navigation_help(frame: &mut Frame<'_>, resources: &Resources) {
let area = frame.size();

let bindings = super::controller::InputEvent::get_mapping()
.mapping
.into_iter()
.map(|map| (map.key, map.description))
.collect();

let widget = NavigationHelpWidget::new(bindings);

let block_area = area.inner(Margin::new(8, 4));

let width = widget.min_width().max(block_area.width as usize / 2);
let height = widget.height();

let block = Block::new()
.border_type(BorderType::Double)
.borders(Borders::all())
.border_style(resources.main_color)
.padding(Padding::proportional(1))
.title("Help")
.title_alignment(Alignment::Center)
.bg(resources.background_color)
.fg(resources.main_color);

let block_inner = block.inner(block_area);

let [widget_area] = Layout::horizontal([Constraint::Length(width as u16)])
.flex(Flex::Center)
.areas(block_inner);
let [widget_area] = Layout::vertical([Constraint::Length(height as u16)])
.flex(Flex::Center)
.areas(widget_area);

frame.render_widget(
BackgroundWidget::new(resources.background_color),
block_area,
);
frame.render_widget(block, block_area);

frame.render_widget(widget, widget_area);
}
3 changes: 2 additions & 1 deletion app/src/screen/common/background_widget.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use ratatui::{
buffer::Buffer,
layout::Rect,
style::{Color, Stylize},
text::Line,
Expand All @@ -16,7 +17,7 @@ impl BackgroundWidget {
}

impl Widget for BackgroundWidget {
fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer)
fn render(self, area: Rect, buf: &mut Buffer)
where
Self: Sized,
{
Expand Down
55 changes: 50 additions & 5 deletions app/src/screen/common/navigation_help_widget.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use ratatui::{
buffer::Buffer,
crossterm::event::KeyCode,
layout::Rect,
style::{Color, Stylize},
text::Line,
layout::{Alignment, Rect},
text::Text,
widgets::Widget,
};

Expand All @@ -14,13 +14,58 @@ impl NavigationHelpWidget {
pub fn new(key_bindings: Vec<(KeyCode, String)>) -> Self {
Self { key_bindings }
}

pub fn height(&self) -> usize {
self.key_bindings.len()
}

pub fn min_width(&self) -> usize {
self.key_bindings
.iter()
.map(|(key, description)| min_line_length(&description, &key_name(key)))
.max()
.unwrap_or_default()
}
}

impl Widget for NavigationHelpWidget {
fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer)
fn render(self, area: Rect, buf: &mut Buffer)
where
Self: Sized,
{
todo!()
let width = area.width as usize;

let text: String = self
.key_bindings
.iter()
.map(|(key, description)| {
let key_name = key_name(key);
let line_len = min_line_length(&description, &key_name);

let padding = width - line_len.min(width);
let padding_str: String = vec![".".to_string(); padding + 1].into_iter().collect();

format!("[{}]{}{}", key_name, padding_str, description)
})
.intersperse("\n".to_string())
.collect();

let text = Text::raw(text).alignment(Alignment::Center);
text.render(area, buf);
}
}

// TODO: Add arrow keys
fn key_name(key: &KeyCode) -> String {
match key {
KeyCode::Char(ch) => ch.to_string(),
_ => "N/A".to_string(),
}
}

fn min_line_length(description: &str, key_name: &str) -> usize {
const BRACKETS_LEN: usize = 2;
const MINIMAL_SPACING: usize = 1;

description.len() + key_name.len() + BRACKETS_LEN + MINIMAL_SPACING
}

0 comments on commit 657baf2

Please sign in to comment.