diff --git a/src/app.rs b/src/app.rs index e56d954..a7a30f5 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc}; use sqlite::Connection; use crate::{data_layer, entities::*, enums::*}; @@ -9,6 +10,8 @@ pub struct App { pub trx_table: TrxTable, pub new_account: Account, pub new_transaction: Transaction, + pub selected_transaction_input: TransactionInput, + pub current_input: String, pub connection: Connection, } @@ -31,6 +34,8 @@ impl App { trx_table: TrxTable::new(), new_account: Account::new(0, String::new(), AccountType::Cash), new_transaction: Transaction::new_empty(), + selected_transaction_input: TransactionInput::Type, + current_input: String::new(), connection: con, }; } @@ -71,4 +76,89 @@ impl App { self.trx_table.add_tr(tr); self.new_transaction = Transaction::new_empty(); } + + pub fn next_tr_input(&mut self) { + match self.selected_transaction_input { + TransactionInput::Type => { + self.selected_transaction_input = TransactionInput::Amount; + self.new_transaction.set_type( + self.current_input + .parse::() + .expect("Failed to parse data"), + &self.connection, + ); + } + TransactionInput::Amount => { + self.selected_transaction_input = TransactionInput::Date; + self.new_transaction.set_amount( + self.current_input + .parse::() + .expect("Failed to parse data"), + ); + } + TransactionInput::Date => { + self.selected_transaction_input = TransactionInput::Description; + let date = NaiveDate::parse_from_str(&self.current_input, "%Y-%m-%d") + .expect("Faile to parse data"); + let time = NaiveTime::from_hms_opt(5, 0, 0).unwrap(); // to account for my local datetime + self.new_transaction + .set_date(Local.from_utc_datetime(&NaiveDateTime::new(date, time))); + } + TransactionInput::Description => { + self.new_transaction.set_desc(self.current_input.clone()) + } + } + self.set_current_input(); + } + pub fn previous_tr_input(&mut self) { + match self.selected_transaction_input { + TransactionInput::Type => { + self.new_transaction.set_type( + self.current_input + .parse::() + .expect("Failed to parse data"), + &self.connection, + ); + } + TransactionInput::Amount => { + self.selected_transaction_input = TransactionInput::Type; + self.new_transaction.set_amount( + self.current_input + .parse::() + .expect("Failed to parse data"), + ); + } + TransactionInput::Date => { + self.selected_transaction_input = TransactionInput::Amount; + let date = NaiveDate::parse_from_str(&self.current_input, "%Y-%m-%d") + .expect("Faile to parse data"); + let time = NaiveTime::from_hms_opt(5, 0, 0).unwrap(); // to account for my local datetime + self.new_transaction + .set_date(Local.from_utc_datetime(&NaiveDateTime::new(date, time))); + } + TransactionInput::Description => { + self.selected_transaction_input = TransactionInput::Date; + self.new_transaction.set_desc(self.current_input.clone()); + } + } + self.set_current_input(); + } + fn set_current_input(&mut self) { + match self.selected_transaction_input { + TransactionInput::Type => { + self.current_input = self.new_transaction.get_type().get_id().to_string() + } + TransactionInput::Amount => { + self.current_input = self.new_transaction.get_amount().to_string() + } + TransactionInput::Date => { + self.current_input = self + .new_transaction + .get_date() + .format("%Y-%m-%d") + .to_string() + } + TransactionInput::Description => self.current_input = self.new_transaction.get_desc(), + } + } } diff --git a/src/data_layer.rs b/src/data_layer.rs index 7339911..12be7ff 100644 --- a/src/data_layer.rs +++ b/src/data_layer.rs @@ -187,7 +187,7 @@ pub fn upsert_transaction(con: &Connection, tr: Transaction) -> Transaction { } let mut statement = con.prepare(query).unwrap(); - statement.bind((1, tr.get_account().get_id())).unwrap(); + statement.bind((1, tr.get_account_id())).unwrap(); statement.bind((2, tr.get_type().get_id())).unwrap(); statement.bind((3, tr.get_amount())).unwrap(); statement.bind((4, tr.get_date().timestamp())).unwrap(); @@ -206,7 +206,7 @@ pub fn upsert_transaction(con: &Connection, tr: Transaction) -> Transaction { return Transaction::new( id, - tr.get_account().get_id(), + tr.get_account_id(), tr.get_amount(), tr.get_date_utc(), tr.get_desc(), diff --git a/src/entities/transaction.rs b/src/entities/transaction.rs index e0dd454..4feec51 100644 --- a/src/entities/transaction.rs +++ b/src/entities/transaction.rs @@ -11,7 +11,6 @@ pub struct Transaction { description: String, type_id: i64, - account: Account, tr_type: TransactionType, } @@ -32,7 +31,6 @@ impl Transaction { date: date, description: desc, type_id: type_id, - account: data_layer::get_account(con, ac_id), tr_type: data_layer::get_transaction_type(con, type_id), } } @@ -45,7 +43,6 @@ impl Transaction { date: DateTime::from_timestamp(0, 0).unwrap(), description: "".to_string(), type_id: 0, - account: Account::new(0, "".to_string(), super::AccountType::Cash), tr_type: TransactionType::new(0, "".to_string()), } } @@ -57,6 +54,9 @@ impl Transaction { pub fn get_amount(&self) -> f64 { return self.amount; } + pub fn set_amount(&mut self, amnt: f64) { + self.amount = amnt; + } pub fn get_date(&self) -> DateTime { return Local.from_utc_datetime(&self.date.naive_local()); @@ -64,18 +64,31 @@ impl Transaction { pub fn get_date_utc(&self) -> DateTime { return self.date; } + pub fn set_date(&mut self, date: DateTime) { + self.date = date.to_utc(); + } pub fn get_desc(&self) -> String { return self.description.clone(); } + pub fn set_desc(&mut self, desc: String) { + self.description = desc; + } - pub fn get_account(&self) -> Account { - return self.account.clone(); + pub fn get_account_id(&self) -> i64 { + return self.account_id; + } + pub fn set_account_id(&mut self, ac_id: i64) { + self.account_id = ac_id; } pub fn get_type(&self) -> TransactionType { return self.tr_type.clone(); } + pub fn set_type(&mut self, tr_id: i64, con: &Connection) { + self.type_id = tr_id; + self.tr_type = data_layer::get_transaction_type(con, tr_id); + } } #[derive(Clone)] diff --git a/src/enums.rs b/src/enums.rs index eb0b98f..1b5ceaf 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -8,3 +8,11 @@ pub enum CurrentScreen { NewAccount, NewTransaction, } + +#[derive(PartialEq)] +pub enum TransactionInput { + Type, + Amount, + Date, + Description, +} diff --git a/src/main.rs b/src/main.rs index 58068c2..02bf46e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod entities; mod enums; mod ui; use crate::{app::App, enums::*, ui::ui}; +use chrono::Local; use entities::{Account, AccountType, Transaction}; use ratatui::{ Terminal, @@ -87,6 +88,9 @@ where } CurrentWidget::TrxList => { app.current_screen = CurrentScreen::NewTransaction; + app.new_transaction + .set_account_id(app.acc_list.get_selected_id()); + app.new_transaction.set_date(Local::now()); } _ => {} }, @@ -104,10 +108,22 @@ where _ => {} }, CurrentScreen::NewTransaction => match key.code { + KeyCode::Down => { + app.next_tr_input(); + } + KeyCode::Up => { + app.previous_tr_input(); + } KeyCode::Enter => { app.save_new_tr(); app.current_screen = CurrentScreen::Main; } + KeyCode::Backspace => { + app.current_input.pop(); + } + KeyCode::Char(value) => { + app.current_input.push(value); + } KeyCode::Esc => { app.current_screen = CurrentScreen::Main; app.new_transaction = Transaction::new_empty(); diff --git a/src/ui.rs b/src/ui.rs index d64ecc2..a2eff15 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -3,6 +3,7 @@ use crate::{ entities::{Account, Transaction}, enums::*, }; +use chrono::{Date, Local}; use ratatui::{ Frame, layout::{Constraint, Direction, Layout, Rect}, @@ -120,6 +121,41 @@ pub fn ui(frame: &mut Frame, app: &mut App) { let area = centered_rect(50, 40, frame.area()); frame.render_widget(popup, area); + + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(1) + .constraints([ + Constraint::Length(3), + Constraint::Length(3), + Constraint::Length(3), + Constraint::Length(3), + ]) + .split(area); + + let tr_type = Paragraph::new(tr_input_str(TransactionInput::Type, app)) + .style(tr_input_style(TransactionInput::Type, app)) + .block(Block::default().borders(Borders::BOTTOM).title("Type")); + frame.render_widget(tr_type, chunks[0]); + + let amnt = Paragraph::new(tr_input_str(TransactionInput::Amount, app)) + .style(tr_input_style(TransactionInput::Amount, app)) + .block(Block::default().borders(Borders::BOTTOM).title("Amount")); + frame.render_widget(amnt, chunks[1]); + + let date = Paragraph::new(tr_input_str(TransactionInput::Date, app)) + .style(tr_input_style(TransactionInput::Date, app)) + .block(Block::default().borders(Borders::BOTTOM).title("Date")); + frame.render_widget(date, chunks[2]); + + let desc = Paragraph::new(tr_input_str(TransactionInput::Description, app)) + .style(tr_input_style(TransactionInput::Description, app)) + .block( + Block::default() + .borders(Borders::BOTTOM) + .title("Description"), + ); + frame.render_widget(desc, chunks[3]); } if let CurrentScreen::Exiting = app.current_screen { @@ -162,6 +198,28 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { .split(popup_layout[1])[1]; } +fn tr_input_style(input: TransactionInput, app: &mut App) -> Style { + if app.selected_transaction_input == input { + return SELECTED_STYLE; + } + return Style::default(); +} +fn tr_input_str(input: TransactionInput, app: &mut App) -> String { + if app.selected_transaction_input == input { + return app.current_input.clone(); + } + match input { + TransactionInput::Type => app.new_transaction.get_type().get_id().to_string(), + TransactionInput::Amount => app.new_transaction.get_amount().to_string(), + TransactionInput::Date => app + .new_transaction + .get_date() + .format("%Y-%m-%d") + .to_string(), + TransactionInput::Description => app.new_transaction.get_desc(), + } +} + impl From<&Account> for ListItem<'_> { fn from(value: &Account) -> Self { let line = Line::styled(