From 6ef492ee1011fde55a13f0f786cf6e3e886dc505 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Wed, 31 May 2023 22:27:26 -0700 Subject: [PATCH] feat: Added basic two level navigation --- src/app.rs | 27 +++++++++++++- src/main.rs | 35 ++++++++++++++---- src/ui.rs | 5 ++- src/uis/mod.rs | 3 ++ src/uis/new_transaction.rs | 76 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 src/uis/new_transaction.rs diff --git a/src/app.rs b/src/app.rs index bdd8058..134762d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,10 +1,21 @@ +use crate::uis::new_transaction::NewTransactionTabState; + pub type AppResult = std::result::Result>; +pub enum FocusedBlock { + Navigation, + Body, +} + pub struct App<'a> { pub running: bool, pub tabs: Vec<&'a str>, pub tab_index: usize, + pub focus: FocusedBlock, + + pub new_transaction_tab_state: NewTransactionTabState<'a>, + } impl<'a> App<'a> { @@ -12,8 +23,11 @@ impl<'a> App<'a> { App { running: true, - tabs: vec!["Tab1", "Tab2", "Tab3"], + tabs: vec!["History", "Tab2", "Tab3"], tab_index: 0, + focus: FocusedBlock::Navigation, + + new_transaction_tab_state: NewTransactionTabState::new(), } } @@ -27,4 +41,13 @@ impl<'a> App<'a> { } else { 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; + } +} diff --git a/src/main.rs b/src/main.rs index 0f624ef..3fbfcfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,9 @@ use ratatui::{ Terminal, }; -use recount::app::{App, AppResult}; +use recount::app::{App, AppResult, FocusedBlock}; use recount::tui::Tui; +use recount::uis::new_transaction::NewTransactionTabState; fn main() -> AppResult<()> { // Create an application. @@ -28,16 +29,34 @@ fn main() -> AppResult<()> { // Handle events. if let Event::Key(key) = event::read()? { - if key.kind == KeyEventKind::Press { - match key.code { - KeyCode::Char('q') => break, - KeyCode::Tab => app.next_tab(), - // KeyCode::Right => app.next(), - // KeyCode::Left => app.previous(), - _ => {} + 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 { + match key.code { + KeyCode::Char('q') => break, + KeyCode::Tab => app.next_tab(), + KeyCode::Enter => app.focus_body(), + // KeyCode::Right => app.next(), + // KeyCode::Left => app.previous(), + _ => {} + } + } } } } + std::thread::sleep(Duration::from_millis(20)); } diff --git a/src/ui.rs b/src/ui.rs index e0afaa9..fcae848 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -8,7 +8,7 @@ use ratatui::{ Frame, }; -use crate::uis::render_history_tab; +use crate::uis::{render_new_transaction_tab, render_history_tab}; pub fn render (f: &mut Frame, app: &App) { @@ -31,7 +31,8 @@ pub fn render (f: &mut Frame, app: &App) { .constraints([Constraint::Percentage(100)]) .split(chunks[1]); // 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 (f: &mut Frame, status_rect: Rect, app: &App) { diff --git a/src/uis/mod.rs b/src/uis/mod.rs index 8a5c59a..98d2ced 100644 --- a/src/uis/mod.rs +++ b/src/uis/mod.rs @@ -2,3 +2,6 @@ pub mod history; pub use self::history::render_history_tab; + +pub mod new_transaction; +pub use self::new_transaction::render_new_transaction_tab; diff --git a/src/uis/new_transaction.rs b/src/uis/new_transaction.rs new file mode 100644 index 0000000..421e986 --- /dev/null +++ b/src/uis/new_transaction.rs @@ -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 (f: &mut Frame, 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 = 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]) + } +}