feat: Added basic two level navigation

This commit is contained in:
Nickiel12 2023-05-31 22:27:26 -07:00
parent e4a840d7e4
commit 6ef492ee10
5 changed files with 134 additions and 12 deletions

View file

@ -1,10 +1,21 @@
use crate::uis::new_transaction::NewTransactionTabState;
pub type AppResult<T> = std::result::Result<T, Box<dyn std::error::Error>>; pub type AppResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
pub enum FocusedBlock {
Navigation,
Body,
}
pub struct App<'a> { pub struct App<'a> {
pub running: bool, pub running: bool,
pub tabs: Vec<&'a str>, pub tabs: Vec<&'a str>,
pub tab_index: usize, pub tab_index: usize,
pub focus: FocusedBlock,
pub new_transaction_tab_state: NewTransactionTabState<'a>,
} }
impl<'a> App<'a> { impl<'a> App<'a> {
@ -12,8 +23,11 @@ impl<'a> App<'a> {
App { App {
running: true, running: true,
tabs: vec!["Tab1", "Tab2", "Tab3"], tabs: vec!["History", "Tab2", "Tab3"],
tab_index: 0, tab_index: 0,
focus: FocusedBlock::Navigation,
new_transaction_tab_state: NewTransactionTabState::new(),
} }
} }
@ -27,4 +41,13 @@ impl<'a> App<'a> {
} else { } else {
self.tab_index = self.tabs.len() - 1; self.tab_index = self.tabs.len() - 1;
} }
}} }
pub fn focus_navigation(&mut self) {
self.focus = FocusedBlock::Navigation;
}
pub fn focus_body(&mut self) {
self.focus = FocusedBlock::Body;
}
}

View file

@ -7,8 +7,9 @@ use ratatui::{
Terminal, Terminal,
}; };
use recount::app::{App, AppResult}; use recount::app::{App, AppResult, FocusedBlock};
use recount::tui::Tui; use recount::tui::Tui;
use recount::uis::new_transaction::NewTransactionTabState;
fn main() -> AppResult<()> { fn main() -> AppResult<()> {
// Create an application. // Create an application.
@ -28,16 +29,34 @@ fn main() -> AppResult<()> {
// Handle events. // Handle events.
if let Event::Key(key) = event::read()? { if let Event::Key(key) = event::read()? {
match app.focus {
FocusedBlock::Body => {
match app.tab_index {
2 => {
NewTransactionTabState::handle_event(key, &mut app);
},
_ => {
// Work around "You entered an empty body, and now, I am dead" loops
app.focus_navigation();
}
}
}
FocusedBlock::Navigation => {
if key.kind == KeyEventKind::Press { if key.kind == KeyEventKind::Press {
match key.code { match key.code {
KeyCode::Char('q') => break, KeyCode::Char('q') => break,
KeyCode::Tab => app.next_tab(), KeyCode::Tab => app.next_tab(),
KeyCode::Enter => app.focus_body(),
// KeyCode::Right => app.next(), // KeyCode::Right => app.next(),
// KeyCode::Left => app.previous(), // KeyCode::Left => app.previous(),
_ => {} _ => {}
} }
} }
} }
}
}
std::thread::sleep(Duration::from_millis(20)); std::thread::sleep(Duration::from_millis(20));
} }

View file

@ -8,7 +8,7 @@ use ratatui::{
Frame, Frame,
}; };
use crate::uis::render_history_tab; use crate::uis::{render_new_transaction_tab, render_history_tab};
pub fn render<B: Backend> (f: &mut Frame<B>, app: &App) { pub fn render<B: Backend> (f: &mut Frame<B>, app: &App) {
@ -31,7 +31,8 @@ pub fn render<B: Backend> (f: &mut Frame<B>, app: &App) {
.constraints([Constraint::Percentage(100)]) .constraints([Constraint::Percentage(100)])
.split(chunks[1]); .split(chunks[1]);
// if app.tabs selected == history, // if app.tabs selected == history,
render_history_tab(f, bottom_chunk[0], app); //render_history_tab(f, bottom_chunk[0], app);
render_new_transaction_tab(f, bottom_chunk[0], app);
} }
pub fn render_statusbar<B: Backend> (f: &mut Frame<B>, status_rect: Rect, app: &App) { pub fn render_statusbar<B: Backend> (f: &mut Frame<B>, status_rect: Rect, app: &App) {

View file

@ -2,3 +2,6 @@
pub mod history; pub mod history;
pub use self::history::render_history_tab; pub use self::history::render_history_tab;
pub mod new_transaction;
pub use self::new_transaction::render_new_transaction_tab;

View file

@ -0,0 +1,76 @@
use crate::app::App;
use crossterm::event::{Event, KeyEvent, KeyEventKind, KeyCode};
use ratatui::{backend::Backend, Frame, layout::{Rect, Layout, Direction, Constraint}, widgets::{Paragraph, Borders, Block}, text::Text, style::{Style, Color}};
pub struct NewTransactionTabState<'a> {
pub cur_tab_index: usize,
pub tabs: Vec<&'a str>,
}
impl<'a> NewTransactionTabState<'a> {
pub fn new() -> NewTransactionTabState<'a> {
NewTransactionTabState {
cur_tab_index: 1,
tabs: vec!["Quick Entry", "Manual Entry"]
}
}
pub fn next_tab(&mut self) {
self.cur_tab_index = (self.cur_tab_index + 1) % self.tabs.len();
}
pub fn handle_event(event: KeyEvent, app: &mut App) {
if event.kind == KeyEventKind::Press {
match event.code {
KeyCode::Char('q') => app.focus_navigation(),
KeyCode::Tab => app.new_transaction_tab_state.next_tab(),
// KeyCode::Right => app.next(),
// KeyCode::Left => app.previous(),
_ => {}
}
}
}
}
pub fn render_new_transaction_tab<B: Backend> (f: &mut Frame<B>, body_rect: Rect, app: &App) {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Length(3), Constraint::Min(0)])
.split(body_rect);
// Render the custom tab bar
let mut constraints: Vec<Constraint> = vec![];
let tab_percent: u16 = (100 / app.new_transaction_tab_state.tabs.len()) as u16;
for _ in 0..app.new_transaction_tab_state.tabs.len() {
constraints.push(Constraint::Percentage(tab_percent));
}
let tab_chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints(constraints)
.split(chunks[0]);
for i in 0..app.new_transaction_tab_state.tabs.len() {
let tab = Paragraph::new(
Text::styled(app.new_transaction_tab_state.tabs[i],
Style::default().fg(Color::White)
)
)
.alignment(ratatui::layout::Alignment::Center)
.block(
Block::default()
.borders(Borders::ALL)
.style({
if app.new_transaction_tab_state.cur_tab_index == i {
Style::default().bg(Color::Blue)
} else {
Style::default()
}
})
);
f.render_widget(tab, tab_chunks[i])
}
}