From 537793bb9f9b430c2702b8cafdc227dd9b911aac Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Fri, 22 Sep 2023 21:03:30 -0700 Subject: [PATCH] added manual transaction tab --- src/app.rs | 10 +- src/main.rs | 13 +- src/ui.rs | 9 +- src/uis/manual_transaction.rs | 422 +++++++++++++++++ src/uis/mod.rs | 7 +- src/uis/navigation_frame.rs | 5 +- ...ew_transaction.rs => quick_transaction.rs} | 36 +- src/uis/sub_screens/transaction_manual.rs | 425 ------------------ 8 files changed, 460 insertions(+), 467 deletions(-) create mode 100644 src/uis/manual_transaction.rs rename src/uis/{new_transaction.rs => quick_transaction.rs} (64%) diff --git a/src/app.rs b/src/app.rs index a806d78..fbbcd8b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,8 +5,9 @@ use log::warn; use crate::db::data_cache::DataCache; use crate::db::DB; use crate::uis::history::HistoryState; +use crate::uis::manual_transaction::ManualTransactionState; use crate::uis::navigation_frame::NavigationState; -use crate::uis::new_transaction::NewTransactionState; +use crate::uis::quick_transaction::QuickTransactionState; pub type AppResult = std::result::Result>; @@ -71,12 +72,14 @@ impl<'a> App<'a> { pub enum ActiveFrame { Navigation, NewTransaction, + ManualTransaction, History, } pub struct States<'a> { pub nav_state: NavigationState<'a>, - pub transactions: NewTransactionState<'a>, + pub transactions: QuickTransactionState<'a>, + pub manual_transactions: ManualTransactionState, pub history: HistoryState, pub active_frame: ActiveFrame, @@ -86,7 +89,8 @@ impl<'a> States<'a> { pub fn new() -> States<'a> { States { nav_state: NavigationState::new(), - transactions: NewTransactionState::new(), + transactions: QuickTransactionState::new(), + manual_transactions: ManualTransactionState::new(), history: HistoryState::new(), active_frame: ActiveFrame::Navigation, diff --git a/src/main.rs b/src/main.rs index 6950208..93d45d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,20 @@ +use crossterm::event::{self, Event, KeyCode}; +use recount::uis::manual_transaction::ManualTransactionState; use std::fs::File; use std::io; use std::time::Duration; -use crossterm::event::{self, Event, KeyCode}; use simplelog::*; use ratatui::{backend::CrosstermBackend, Terminal}; -use recount::app::{App, AppResult, ActiveFrame}; +use recount::app::{ActiveFrame, App, AppResult}; use recount::db::data_cache::DataCache; use recount::db::DB; use recount::tui::Tui; use recount::uis::history::HistoryState; use recount::uis::navigation_frame::NavigationState; -use recount::uis::new_transaction::NewTransactionState; +use recount::uis::quick_transaction::QuickTransactionState; #[tokio::main] async fn main() -> AppResult<()> { @@ -49,7 +50,6 @@ async fn main() -> AppResult<()> { tui.exit() } - pub fn poll_events(app: &mut App) -> AppResult<()> { if let Event::Key(key) = event::read()? { // 'q' needs to be handled at the top level so it can't be @@ -86,7 +86,10 @@ pub fn poll_events(app: &mut App) -> AppResult<()> { HistoryState::handle_event(key, app); } ActiveFrame::NewTransaction => { - NewTransactionState::handle_event(key, app); + QuickTransactionState::handle_event(key, app); + } + ActiveFrame::ManualTransaction => { + ManualTransactionState::handle_event(key, app); } } } diff --git a/src/ui.rs b/src/ui.rs index 61155b0..e20c78f 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,6 +1,6 @@ use crate::{ app::{ActiveFrame, App}, - uis::render_history_tab, + uis::{render_history_tab, render_manual_transaction}, }; use log; use ratatui::{ @@ -11,7 +11,7 @@ use ratatui::{ Frame, }; -use crate::uis::{render_navigation_frame, render_new_transaction_tab}; +use crate::uis::{render_navigation_frame, render_quick_transaction}; pub fn render(f: &mut Frame, app: &mut App) { let size = f.size(); @@ -50,7 +50,10 @@ pub fn render(f: &mut Frame, app: &mut App) { render_history_tab(f, bottom_chunk[0], app); } ActiveFrame::NewTransaction => { - render_new_transaction_tab(f, bottom_chunk[0], app); + render_quick_transaction(f, bottom_chunk[0], app); + } + ActiveFrame::ManualTransaction => { + render_manual_transaction(f, bottom_chunk[0], app); } _ => { panic!("ui.rs Render encountered a thought impossible state") diff --git a/src/uis/manual_transaction.rs b/src/uis/manual_transaction.rs new file mode 100644 index 0000000..ac7f261 --- /dev/null +++ b/src/uis/manual_transaction.rs @@ -0,0 +1,422 @@ +use ratatui::{ + backend::Backend, + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Color, Style}, + text::Text, + widgets::{Block, Borders, ListItem, Paragraph}, + Frame, +}; + +use crate::{ + app::App, + db::tables::{Account, Buckets, PartialTransactionBreakdown}, + uis::render_popup, +}; + +use chrono::prelude::Local; +use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; + +pub struct ManualTransactionState { + pub focus: Option, + pub show_popup: bool, + + pub account: Option, + pub account_index: usize, + pub amount: Option, + pub date: Option, + pub bucket: Option, + pub bucket_index: usize, + pub description: Option, + + pub editing_breakdown: PartialTransactionBreakdown, + pub breakdowns: Vec, +} + +impl ManualTransactionState { + pub fn new() -> ManualTransactionState { + ManualTransactionState { + focus: None, + show_popup: true, + account: None, + account_index: 0, + amount: None, + date: Some(format!("+{}", Local::now().format("%m-%d-%Y"))), + bucket: None, + bucket_index: 0, + description: None, + editing_breakdown: PartialTransactionBreakdown::new_empty(), + breakdowns: Vec::new(), + } + } + pub fn send_tab(&mut self) { + let next = if self.focus.is_some() { + match self.focus.unwrap() { + ManualDataFocus::Account => ManualDataFocus::Amount, + ManualDataFocus::Amount => ManualDataFocus::Date, + ManualDataFocus::Date => ManualDataFocus::Bucket, + ManualDataFocus::Bucket => ManualDataFocus::Description, + ManualDataFocus::Description => ManualDataFocus::Breakdowns, + ManualDataFocus::Breakdowns => ManualDataFocus::Account, + } + } else { + ManualDataFocus::Account + }; + self.focus = Some(next); + } + + pub fn handle_event(event: KeyEvent, app: &mut App) { + if app.states.manual_transactions.focus.is_some() { + match event.code { + KeyCode::Tab => match app.states.manual_transactions.focus.unwrap() { + ManualDataFocus::Account => { + if app.states.manual_transactions.show_popup { + app.states.manual_transactions.account_index += 1; + if app.states.manual_transactions.account_index + > app.data_cache.accounts.lock().unwrap().len() - 1 + { + app.states.manual_transactions.account_index = 0; + } + } else { + app.states.manual_transactions.send_tab(); + } + } + ManualDataFocus::Bucket => { + if app.states.manual_transactions.show_popup { + app.states.manual_transactions.bucket_index += 1; + if app.states.manual_transactions.bucket_index + > app.data_cache.buckets.lock().unwrap().len() - 1 + { + app.states.manual_transactions.bucket_index = 0; + } + } else { + app.states.manual_transactions.show_popup = false; + app.states.manual_transactions.send_tab(); + } + } + ManualDataFocus::Date => { + if let Some(ref mut x) = app.states.manual_transactions.date { + if x.len() == 0 { + x.push_str(&format!("+{}", Local::now().format("%m-%d-%Y"))); + } + } + app.states.manual_transactions.send_tab() + } + _ => app.states.manual_transactions.send_tab(), + }, + KeyCode::Enter => match app.states.manual_transactions.focus.unwrap() { + ManualDataFocus::Account => { + app.states.manual_transactions.show_popup = + !app.states.manual_transactions.show_popup; + + if !app.states.manual_transactions.show_popup { + app.states.manual_transactions.account = app + .data_cache + .accounts + .lock() + .unwrap() + .get(app.states.manual_transactions.account_index) + .cloned(); + + app.states.manual_transactions.send_tab() + } + } + ManualDataFocus::Bucket => { + app.states.manual_transactions.show_popup = + !app.states.manual_transactions.show_popup; + + if !app.states.manual_transactions.show_popup { + app.states.manual_transactions.bucket = app + .data_cache + .buckets + .lock() + .unwrap() + .get(app.states.manual_transactions.bucket_index) + .cloned(); + + app.states.manual_transactions.send_tab() + } + } + _ => {} + }, + KeyCode::Backspace => match app.states.manual_transactions.focus.unwrap() { + ManualDataFocus::Amount => { + if let Some(ref mut s) = app.states.manual_transactions.amount { + s.pop(); + } + } + ManualDataFocus::Description => { + if let Some(ref mut s) = app.states.manual_transactions.description { + s.pop(); + } + } + ManualDataFocus::Date => { + if let Some(ref mut s) = app.states.manual_transactions.date { + s.pop(); + } + } + _ => {} + }, + KeyCode::Char(value) => match app.states.manual_transactions.focus.unwrap() { + ManualDataFocus::Amount => { + if value.is_digit(10) || value == '.' { + if let Some(ref mut s) = app.states.manual_transactions.amount { + s.push(value); + } else { + app.states.manual_transactions.amount = Some(value.to_string()); + } + } + } + ManualDataFocus::Description => { + if let Some(ref mut s) = app.states.manual_transactions.description { + s.push(value); + } else { + app.states.manual_transactions.description = Some(value.to_string()); + } + } + ManualDataFocus::Date => { + if value.is_digit(10) { + if let Some(ref mut s) = app.states.manual_transactions.date { + if s.len() < 10 { + s.push(value); + } + if s.len() == 2 || s.len() == 5 { + s.push('-'); + } + } else { + app.states.manual_transactions.date = Some(value.to_string()); + } + } + } + _ => {} + }, + _ => {} + } + if let Some(ManualDataFocus::Date) = app.states.manual_transactions.focus { + if let Some(ref mut x) = app.states.manual_transactions.date { + if x.starts_with("+") { + x.clear(); + } + } + } + } else { + match event.code { + KeyCode::Enter => { + app.states.manual_transactions.focus = Some(ManualDataFocus::Account); + } + _ => {} + }; + } + } +} + +pub fn render_manual_transaction(f: &mut Frame, body_rect: Rect, app: &App) { + // Render the custom tab bar + let mut constraints: Vec = vec![]; + + let constraints: Vec = vec![ + Constraint::Length(1), + Constraint::Length(1), // account + Constraint::Length(1), + Constraint::Length(1), // amount + Constraint::Length(1), + Constraint::Length(1), // date + Constraint::Length(1), + Constraint::Length(1), // bucket + Constraint::Length(1), + Constraint::Max(5), // description + Constraint::Length(1), + Constraint::Length(1), // Breakdown + Constraint::Length(1), + ]; + + let split_body = Layout::default() + .direction(Direction::Vertical) + .constraints(constraints) + .split(body_rect); + + { + let manual_state = &app.states.manual_transactions; + + render_manual_row( + f, + split_body[1], + "Account: ", + manual_state + .account + .as_ref() + .map(|val| val.acnt_dsply_name.clone()) + .unwrap_or_default(), + manual_state.focus, + ManualDataFocus::Account, + ); + + render_manual_row( + f, + split_body[3], + "Amount: ", + manual_state + .amount + .as_ref() + .map(|val| val.to_string()) + .unwrap_or_default(), + manual_state.focus, + ManualDataFocus::Amount, + ); + + render_manual_row( + f, + split_body[5], + "Date: ", + manual_state.date.clone().unwrap_or_default(), + manual_state.focus, + ManualDataFocus::Date, + ); + + render_manual_row( + f, + split_body[7], + "Bucket: ", + manual_state + .bucket + .as_ref() + .map(|val| val.bkt_dsply_code.clone()) + .unwrap_or_default(), + manual_state.focus, + ManualDataFocus::Bucket, + ); + + render_manual_row( + f, + split_body[split_body.len() - 4], + "Description: ", + manual_state.description.clone().unwrap_or("".to_string()), + manual_state.focus, + ManualDataFocus::Description, + ); + + render_manual_row( + f, + split_body[split_body.len() - 2], + "Transaction Breakdown: ", + "[ + ]".to_string(), + manual_state.focus, + ManualDataFocus::Breakdowns, + ); + + if app.states.manual_transactions.focus == Some(ManualDataFocus::Account) + && app.states.manual_transactions.show_popup + { + let horizontal_pieces = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(35), + Constraint::Percentage(45), + Constraint::Percentage(20), + ]) + .split(split_body[1]); + + let list_items: Vec = app + .data_cache + .accounts + .lock() + .unwrap() + .iter() + .map(|account| ListItem::new(account.acnt_description.clone())) + .enumerate() + .map(|(i, item)| { + if app.states.manual_transactions.account_index == i { + item.style(Style::default().bg(Color::Yellow).fg(Color::Black)) + } else { + item + } + }) + .collect(); + + render_popup(f, horizontal_pieces[1], list_items); + } + if app.states.manual_transactions.focus == Some(ManualDataFocus::Bucket) + && app.states.manual_transactions.show_popup + { + let horizontal_pieces = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(35), + Constraint::Percentage(45), + Constraint::Percentage(20), + ]) + .split(split_body[7]); + + let list_items: Vec = app + .data_cache + .buckets + .lock() + .unwrap() + .iter() + .map(|bucket| ListItem::new(bucket.bkt_dsply_code.clone())) + .enumerate() + .map(|(i, item)| { + if app.states.manual_transactions.bucket_index == i { + item.style(Style::default().bg(Color::Yellow).fg(Color::Black)) + } else { + item + } + }) + .collect(); + + render_popup(f, horizontal_pieces[1], list_items); + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum ManualDataFocus { + Account, + Amount, + Date, + Bucket, + Description, + Breakdowns, +} + +pub fn render_manual_row( + f: &mut Frame, + row_body_rect: Rect, + left_text: &str, + right_text: String, + focus: Option, + matching: ManualDataFocus, +) { + let is_active = focus.map(|focus| focus == matching).unwrap_or(false); + + let horizontal_pieces = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(35), + Constraint::Percentage(45), + Constraint::Percentage(20), + ]) + .split(row_body_rect); + + f.render_widget( + Paragraph::new(Text::styled(left_text, Style::default().fg(Color::Yellow))) + .alignment(Alignment::Right), + horizontal_pieces[0], + ); + + let right_bg_color = if is_active { + Color::Yellow + } else { + Color::White + }; + + f.render_widget( + Paragraph::new(Text::styled(right_text, Style::default().fg(Color::Black))) + .alignment(Alignment::Center) + .block( + Block::default() + .borders(Borders::NONE) + .style(Style::default().bg(right_bg_color)), + ), + horizontal_pieces[1], + ); +} diff --git a/src/uis/mod.rs b/src/uis/mod.rs index 75c8e4c..dce21f3 100644 --- a/src/uis/mod.rs +++ b/src/uis/mod.rs @@ -7,8 +7,11 @@ use ratatui::Frame; pub mod history; pub use self::history::render_history_tab; -pub mod new_transaction; -pub use self::new_transaction::render_new_transaction_tab; +pub mod quick_transaction; +pub use self::quick_transaction::render_quick_transaction; + +pub mod manual_transaction; +pub use self::manual_transaction::render_manual_transaction; pub mod navigation_frame; pub use self::navigation_frame::render_navigation_frame; diff --git a/src/uis/navigation_frame.rs b/src/uis/navigation_frame.rs index 340571d..5227575 100644 --- a/src/uis/navigation_frame.rs +++ b/src/uis/navigation_frame.rs @@ -21,7 +21,7 @@ pub struct NavigationState<'a> { impl<'a> NavigationState<'a> { pub fn new() -> NavigationState<'a> { NavigationState { - tabs: vec!["History", "New Transaction"], + tabs: vec!["History", "Manual Transaction", "New Transaction"], tab_index: 0, cur_tab_index: 0, message: None, @@ -43,7 +43,8 @@ impl<'a> NavigationState<'a> { pub fn get_active_tab_frametype(&self) -> Option { match self.tab_index { 0 => Some(ActiveFrame::History), - 1 => Some(ActiveFrame::NewTransaction), + 1 => Some(ActiveFrame::ManualTransaction), + 2 => Some(ActiveFrame::NewTransaction), _ => todo!(), } } diff --git a/src/uis/new_transaction.rs b/src/uis/quick_transaction.rs similarity index 64% rename from src/uis/new_transaction.rs rename to src/uis/quick_transaction.rs index ae1a18a..2c73482 100644 --- a/src/uis/new_transaction.rs +++ b/src/uis/quick_transaction.rs @@ -1,7 +1,4 @@ -use crate::{ - app::App, - uis::sub_screens::transaction_manual::{handle_manual_event, render_manual_entry, ManualData}, -}; +use crate::app::App; use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; use ratatui::{ backend::Backend, @@ -12,19 +9,16 @@ use ratatui::{ Frame, }; -pub struct NewTransactionState<'a> { +pub struct QuickTransactionState<'a> { pub cur_tab_index: usize, pub tabs: Vec<&'a str>, - - pub manual_data: ManualData, } -impl<'a> NewTransactionState<'a> { - pub fn new() -> NewTransactionState<'a> { - NewTransactionState { +impl<'a> QuickTransactionState<'a> { + pub fn new() -> QuickTransactionState<'a> { + QuickTransactionState { cur_tab_index: 0, tabs: vec!["Quick Entry", "Manual Entry"], - manual_data: ManualData::new(), } } @@ -36,19 +30,15 @@ impl<'a> NewTransactionState<'a> { let transact_state = &app.states.transactions; if event.kind == KeyEventKind::Press { - if transact_state.cur_tab_index == 1 { - handle_manual_event(event, app); - } else { - match event.code { - KeyCode::Tab => app.states.transactions.next_tab(), - _ => {} - } + match event.code { + KeyCode::Tab => app.states.transactions.next_tab(), + _ => {} } } } } -pub fn render_new_transaction_tab(f: &mut Frame, body_rect: Rect, app: &App) { +pub fn render_quick_transaction(f: &mut Frame, body_rect: Rect, app: &App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(3), Constraint::Min(0)]) @@ -81,12 +71,4 @@ pub fn render_new_transaction_tab(f: &mut Frame, body_rect: Rect, })); f.render_widget(tab, tab_chunks[i]) } - - match app.states.transactions.tabs[app.states.transactions.cur_tab_index] { - "Quick Entry" => render_quick_entry(f, chunks[1], app), - "Manual Entry" => render_manual_entry(f, chunks[1], app), - _ => return, - }; } - -pub fn render_quick_entry(f: &mut Frame, area: Rect, app: &App) {} diff --git a/src/uis/sub_screens/transaction_manual.rs b/src/uis/sub_screens/transaction_manual.rs index 4115cbe..8b13789 100644 --- a/src/uis/sub_screens/transaction_manual.rs +++ b/src/uis/sub_screens/transaction_manual.rs @@ -1,426 +1 @@ -use crate::{ - app::App, - db::tables::{Account, Buckets, PartialTransactionBreakdown}, - uis::render_popup, -}; -use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; -use chrono::prelude::Local; -use ratatui::{ - backend::Backend, - layout::{Alignment, Constraint, Direction, Layout, Rect}, - style::{Color, Style}, - text::Text, - widgets::{Block, Borders, ListItem, Paragraph}, - Frame, -}; -// use substring::Substring; - -// use log::debug; -// use rust_decimal::Decimal; -// use time::Date; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum ManualDataFocus { - Account, - Amount, - Date, - Bucket, - Description, - Breakdowns, -} - -pub struct ManualData { - pub focus: Option, - pub show_popup: bool, - - pub account: Option, - pub account_index: usize, - pub amount: Option, - pub date: Option, - pub bucket: Option, - pub bucket_index: usize, - pub description: Option, - - pub editing_breakdown: PartialTransactionBreakdown, - pub breakdowns: Vec, -} - -impl ManualData { - pub fn new() -> ManualData { - ManualData { - focus: None, - show_popup: true, - account: None, - account_index: 0, - amount: None, - date: Some(format!("+{}", Local::now().format("%m-%d-%Y"))), - bucket: None, - bucket_index: 0, - description: None, - editing_breakdown: PartialTransactionBreakdown::new_empty(), - breakdowns: Vec::new(), - } - } - pub fn send_tab(&mut self) { - let next = if self.focus.is_some() { - match self.focus.unwrap() { - ManualDataFocus::Account => ManualDataFocus::Amount, - ManualDataFocus::Amount => ManualDataFocus::Date, - ManualDataFocus::Date => ManualDataFocus::Bucket, - ManualDataFocus::Bucket => ManualDataFocus::Description, - ManualDataFocus::Description => ManualDataFocus::Breakdowns, - ManualDataFocus::Breakdowns => ManualDataFocus::Account, - } - } else { - ManualDataFocus::Account - }; - self.focus = Some(next); - } -} - -pub fn handle_manual_event(event: KeyEvent, app: &mut App) { - if app.states.transactions.manual_data.focus.is_some() { - match event.code { - KeyCode::Tab => match app.states.transactions.manual_data.focus.unwrap() { - ManualDataFocus::Account => { - if app.states.transactions.manual_data.show_popup { - app.states.transactions.manual_data.account_index += 1; - if app.states.transactions.manual_data.account_index - > app.data_cache.accounts.lock().unwrap().len() - 1 - { - app.states.transactions.manual_data.account_index = 0; - } - } else { - app.states.transactions.manual_data.send_tab(); - } - } - ManualDataFocus::Bucket => { - if app.states.transactions.manual_data.show_popup { - app.states.transactions.manual_data.bucket_index += 1; - if app.states.transactions.manual_data.bucket_index - > app.data_cache.buckets.lock().unwrap().len() - 1 - { - app.states.transactions.manual_data.bucket_index = 0; - } - } else { - app.states.transactions.manual_data.show_popup = false; - app.states.transactions.manual_data.send_tab(); - } - } - ManualDataFocus::Date => { - if let Some(ref mut x) = app.states.transactions.manual_data.date { - if x.len() == 0 { - x.push_str(&format!("+{}", Local::now().format("%m-%d-%Y"))); - } - } - app.states.transactions.manual_data.send_tab() - } - _ => app.states.transactions.manual_data.send_tab(), - }, - KeyCode::Enter => match app.states.transactions.manual_data.focus.unwrap() { - ManualDataFocus::Account => { - app.states.transactions.manual_data.show_popup = - !app.states.transactions.manual_data.show_popup; - - if !app.states.transactions.manual_data.show_popup { - app.states.transactions.manual_data.account = app - .data_cache - .accounts - .lock() - .unwrap() - .get(app.states.transactions.manual_data.account_index) - .cloned(); - - app.states.transactions.manual_data.send_tab() - } - } - ManualDataFocus::Bucket => { - app.states.transactions.manual_data.show_popup = - !app.states.transactions.manual_data.show_popup; - - if !app.states.transactions.manual_data.show_popup { - app.states.transactions.manual_data.bucket = app - .data_cache - .buckets - .lock() - .unwrap() - .get(app.states.transactions.manual_data.bucket_index) - .cloned(); - - app.states.transactions.manual_data.send_tab() - } - } - _ => {} - }, - KeyCode::Backspace => match app.states.transactions.manual_data.focus.unwrap() { - ManualDataFocus::Amount => { - if let Some(ref mut s) = app.states.transactions.manual_data.amount { - s.pop(); - } - } - ManualDataFocus::Description => { - if let Some(ref mut s) = app.states.transactions.manual_data.description { - s.pop(); - } - } - ManualDataFocus::Date => { - if let Some(ref mut s) = app.states.transactions.manual_data.date { - s.pop(); - } - } - _ => {} - }, - KeyCode::Char(value) => match app.states.transactions.manual_data.focus.unwrap() { - ManualDataFocus::Amount => { - if value.is_digit(10) || value == '.' { - if let Some(ref mut s) = app.states.transactions.manual_data.amount { - s.push(value); - } else { - app.states.transactions.manual_data.amount = Some(value.to_string()); - } - } - } - ManualDataFocus::Description => { - if let Some(ref mut s) = app.states.transactions.manual_data.description { - s.push(value); - } else { - app.states.transactions.manual_data.description = Some(value.to_string()); - } - } - ManualDataFocus::Date => { - if value.is_digit(10) { - if let Some(ref mut s) = app.states.transactions.manual_data.date { - if s.len() < 10 { - s.push(value); - } - if s.len() == 2 || s.len() == 5 { - s.push('-'); - } - } else { - app.states.transactions.manual_data.date = Some(value.to_string()); - } - } - } - _ => {} - }, - _ => {} - } - if let Some(ManualDataFocus::Date) = app.states.transactions.manual_data.focus { - if let Some(ref mut x) = app.states.transactions.manual_data.date { - if x.starts_with("+") { - x.clear(); - } - } - } - } else { - match event.code { - KeyCode::Tab => { - app.states.transactions.next_tab(); - } - KeyCode::Enter => { - app.states.transactions.manual_data.focus = Some(ManualDataFocus::Account); - } - _ => {} - }; - } -} - -pub fn render_manual_entry(f: &mut Frame, area: Rect, app: &App) { - let constraints: Vec = vec![ - Constraint::Length(1), - Constraint::Length(1), // account - Constraint::Length(1), - Constraint::Length(1), // amount - Constraint::Length(1), - Constraint::Length(1), // date - Constraint::Length(1), - Constraint::Length(1), // bucket - Constraint::Length(1), - Constraint::Max(5), // description - Constraint::Length(1), - Constraint::Length(1), // Breakdown - Constraint::Length(1), - ]; - - let split_body = Layout::default() - .direction(Direction::Vertical) - .constraints(constraints) - .split(area); - - { - let manual_state = &app.states.transactions.manual_data; - - render_manual_row( - f, - split_body[1], - "Account: ", - manual_state - .account - .as_ref() - .map(|val| val.acnt_dsply_name.clone()) - .unwrap_or_default(), - manual_state.focus, - ManualDataFocus::Account, - ); - - render_manual_row( - f, - split_body[3], - "Amount: ", - manual_state - .amount - .as_ref() - .map(|val| val.to_string()) - .unwrap_or_default(), - manual_state.focus, - ManualDataFocus::Amount, - ); - - render_manual_row( - f, - split_body[5], - "Date: ", - manual_state.date.clone().unwrap_or_default(), - manual_state.focus, - ManualDataFocus::Date, - ); - - render_manual_row( - f, - split_body[7], - "Bucket: ", - manual_state - .bucket - .as_ref() - .map(|val| val.bkt_dsply_code.clone()) - .unwrap_or_default(), - manual_state.focus, - ManualDataFocus::Bucket, - ); - - render_manual_row( - f, - split_body[split_body.len() - 4], - "Description: ", - manual_state.description.clone().unwrap_or("".to_string()), - manual_state.focus, - ManualDataFocus::Description, - ); - - render_manual_row( - f, - split_body[split_body.len() - 2], - "Transaction Breakdown: ", - "[ + ]".to_string(), - manual_state.focus, - ManualDataFocus::Breakdowns, - ); - - if app.states.transactions.manual_data.focus == Some(ManualDataFocus::Account) - && app.states.transactions.manual_data.show_popup - { - let horizontal_pieces = Layout::default() - .direction(Direction::Horizontal) - .constraints([ - Constraint::Percentage(35), - Constraint::Percentage(45), - Constraint::Percentage(20), - ]) - .split(split_body[1]); - - let list_items: Vec = app - .data_cache - .accounts - .lock() - .unwrap() - .iter() - .map(|account| ListItem::new(account.acnt_description.clone())) - .enumerate() - .map(|(i, item)| { - if app.states.transactions.manual_data.account_index == i { - item.style(Style::default().bg(Color::Yellow).fg(Color::Black)) - } else { - item - } - }) - .collect(); - - render_popup(f, horizontal_pieces[1], list_items); - } - if app.states.transactions.manual_data.focus == Some(ManualDataFocus::Bucket) - && app.states.transactions.manual_data.show_popup - { - let horizontal_pieces = Layout::default() - .direction(Direction::Horizontal) - .constraints([ - Constraint::Percentage(35), - Constraint::Percentage(45), - Constraint::Percentage(20), - ]) - .split(split_body[7]); - - let list_items: Vec = app - .data_cache - .buckets - .lock() - .unwrap() - .iter() - .map(|bucket| ListItem::new(bucket.bkt_dsply_code.clone())) - .enumerate() - .map(|(i, item)| { - if app.states.transactions.manual_data.bucket_index == i { - item.style(Style::default().bg(Color::Yellow).fg(Color::Black)) - } else { - item - } - }) - .collect(); - - render_popup(f, horizontal_pieces[1], list_items); - } - } -} - -pub fn render_manual_row( - f: &mut Frame, - row_area: Rect, - left_text: &str, - right_text: String, - focus: Option, - matching: ManualDataFocus, -) { - let is_active = focus.map(|focus| focus == matching).unwrap_or(false); - - let horizontal_pieces = Layout::default() - .direction(Direction::Horizontal) - .constraints([ - Constraint::Percentage(35), - Constraint::Percentage(45), - Constraint::Percentage(20), - ]) - .split(row_area); - - f.render_widget( - Paragraph::new(Text::styled(left_text, Style::default().fg(Color::Yellow))) - .alignment(Alignment::Right), - horizontal_pieces[0], - ); - - let right_bg_color = if is_active { - Color::Yellow - } else { - Color::White - }; - - f.render_widget( - Paragraph::new(Text::styled(right_text, Style::default().fg(Color::Black))) - .alignment(Alignment::Center) - .block( - Block::default() - .borders(Borders::NONE) - .style(Style::default().bg(right_bg_color)), - ), - horizontal_pieces[1], - ); -}