got working history tab
This commit is contained in:
parent
b3ab5a5865
commit
20700e8a38
9 changed files with 215 additions and 225 deletions
67
src/app.rs
67
src/app.rs
|
@ -1,69 +1,18 @@
|
||||||
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossterm::event::{Event, self, KeyCode};
|
use crossterm::event::{Event, self, KeyCode};
|
||||||
use tokio;
|
use tokio;
|
||||||
use ratatui::widgets::ListState;
|
|
||||||
|
|
||||||
use crossbeam_channel::Receiver;
|
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use crate::db::DB;
|
use crate::db::DB;
|
||||||
|
use crate::db::data_cache::DataCache;
|
||||||
use crate::uis::history::HistoryState;
|
use crate::uis::history::HistoryState;
|
||||||
use crate::uis::new_transaction::NewTransactionTabState;
|
use crate::uis::new_transaction::NewTransactionTabState;
|
||||||
use crate::uis::navigation_frame::NavigationState;
|
use crate::uis::navigation_frame::NavigationState;
|
||||||
use crate::db::transaction::TransactionRecord;
|
|
||||||
|
|
||||||
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 struct StatefulList<T> {
|
|
||||||
pub state: ListState,
|
|
||||||
pub items: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> StatefulList<T> {
|
|
||||||
pub fn with_items(items: Vec<T>) -> StatefulList<T> {
|
|
||||||
StatefulList {
|
|
||||||
state: ListState::default(),
|
|
||||||
items,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
|
||||||
let i = match self.state.selected() {
|
|
||||||
Some(i) => {
|
|
||||||
if i >= self.items.len() - 1 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
self.state.select(Some(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn previous(&mut self) {
|
|
||||||
let i = match self.state.selected() {
|
|
||||||
Some(i) => {
|
|
||||||
if i == 0 {
|
|
||||||
self.items.len() - 1
|
|
||||||
} else {
|
|
||||||
i - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
self.state.select(Some(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unselect(&mut self) {
|
|
||||||
self.state.select(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum InputMode {
|
pub enum InputMode {
|
||||||
Insert,
|
Insert,
|
||||||
Normal,
|
Normal,
|
||||||
|
@ -77,17 +26,17 @@ pub struct App<'a> {
|
||||||
pub input_mode: InputMode,
|
pub input_mode: InputMode,
|
||||||
|
|
||||||
pub db: Arc<tokio::sync::Mutex<DB>>,
|
pub db: Arc<tokio::sync::Mutex<DB>>,
|
||||||
pub records: Arc<Mutex<Vec<TransactionRecord>>>,
|
pub data_cache: DataCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl<'a> App<'a> {
|
||||||
pub fn new(db: DB, records: Arc<Mutex<Vec<TransactionRecord>>>, r: Receiver<bool>) -> App<'a> {
|
pub fn new(db: DB, data_cache: DataCache) -> App<'a> {
|
||||||
App {
|
App {
|
||||||
running: true,
|
running: true,
|
||||||
states: States::new(r),
|
states: States::new(),
|
||||||
input_mode: InputMode::Normal,
|
input_mode: InputMode::Normal,
|
||||||
db: Arc::new(tokio::sync::Mutex::new(db)),
|
db: Arc::new(tokio::sync::Mutex::new(db)),
|
||||||
records,
|
data_cache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,20 +109,16 @@ pub struct States<'a> {
|
||||||
pub transactions: NewTransactionTabState<'a>,
|
pub transactions: NewTransactionTabState<'a>,
|
||||||
pub history: HistoryState,
|
pub history: HistoryState,
|
||||||
|
|
||||||
pub new_data: Receiver<bool>,
|
|
||||||
|
|
||||||
pub active_frame: ActiveFrame,
|
pub active_frame: ActiveFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> States<'a> {
|
impl<'a> States<'a> {
|
||||||
pub fn new(r: Receiver<bool>) -> States<'a> {
|
pub fn new() -> States<'a> {
|
||||||
States {
|
States {
|
||||||
nav_state: NavigationState::new(),
|
nav_state: NavigationState::new(),
|
||||||
transactions: NewTransactionTabState::new(),
|
transactions: NewTransactionTabState::new(),
|
||||||
history: HistoryState::new(),
|
history: HistoryState::new(),
|
||||||
|
|
||||||
new_data: r,
|
|
||||||
|
|
||||||
active_frame: ActiveFrame::Navigation,
|
active_frame: ActiveFrame::Navigation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +1,46 @@
|
||||||
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crossbeam_channel::Sender;
|
|
||||||
|
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
|
|
||||||
use sqlx::Error;
|
use sqlx::Error;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use sqlx::Row;
|
|
||||||
use sqlx::postgres::PgPoolOptions;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
use sqlx::postgres::types::PgMoney;
|
|
||||||
use time::Date;
|
|
||||||
|
|
||||||
use crate::db::transaction::TransactionRecord;
|
use super::data_cache::DataCache;
|
||||||
|
use super::tables::Transaction;
|
||||||
|
|
||||||
pub struct DB {
|
pub struct DB {
|
||||||
conn_pool: PgPool,
|
conn_pool: PgPool,
|
||||||
|
|
||||||
new_data_notify: Sender<bool>,
|
data_cache: DataCache,
|
||||||
records: Arc<Mutex<Vec<TransactionRecord>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl DB {
|
impl DB {
|
||||||
pub async fn new(records: Arc<Mutex<Vec<TransactionRecord>>>, s: Sender<bool>) -> Result<DB, sqlx::Error> {
|
pub async fn new(data_cache: DataCache) -> Result<DB, sqlx::Error> {
|
||||||
let connection_pool = PgPoolOptions::new()
|
let connection_pool = PgPoolOptions::new()
|
||||||
.max_connections(3)
|
.max_connections(3)
|
||||||
.connect("postgres://rcntuser:Devel@pmentPa$$w0rd@10.0.0.183/Borealis").await?;
|
.connect("postgres://rcntuser:Devel@pmentPa$$w0rd@10.0.0.183/Borealis").await?;
|
||||||
Ok(DB {
|
Ok(DB {
|
||||||
conn_pool: connection_pool,
|
conn_pool: connection_pool,
|
||||||
new_data_notify: s,
|
data_cache,
|
||||||
records,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_records(&mut self) -> Result<(), Error> {
|
pub async fn get_all_records(&mut self) -> Result<(), Error> {
|
||||||
let mut rows = sqlx::query("SELECT trns_id, trns_amount, trns_description, trns_account, trns_bucket, trns_date FROM rcnt.transactions")
|
let mut rows = sqlx::query_as::<_, Transaction>("SELECT trns_id, trns_amount, trns_description, trns_account, trns_bucket, trns_date FROM rcnt.transactions ORDER BY trns_id DESC")
|
||||||
.fetch(&self.conn_pool);
|
.fetch(&self.conn_pool);
|
||||||
|
|
||||||
|
let mut temp_transactions: Vec<Transaction> = Vec::new();
|
||||||
|
|
||||||
while let Some(row) = rows.try_next().await? {
|
while let Some(row) = rows.try_next().await? {
|
||||||
let id: i32 = row.try_get("trns_id")?;
|
temp_transactions.push(row);
|
||||||
let amount: PgMoney = row.try_get("trns_amount")?;
|
|
||||||
let date: Date = row.try_get("trns_date")?;
|
|
||||||
self.records.lock().unwrap().clear();
|
|
||||||
|
|
||||||
self.records.lock().unwrap().push(
|
|
||||||
TransactionRecord {
|
|
||||||
id: id.into(),
|
|
||||||
amount: amount.to_decimal(2).to_string(),
|
|
||||||
date: date.to_string()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.new_data_notify.try_send(true).unwrap();
|
|
||||||
|
{
|
||||||
|
let mut transactions = self.data_cache.transactions.lock().unwrap();
|
||||||
|
transactions.clear();
|
||||||
|
transactions.append(&mut temp_transactions);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
||||||
|
|
32
src/db/data_cache.rs
Normal file
32
src/db/data_cache.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use super::tables;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DataCache {
|
||||||
|
|
||||||
|
pub accounts: Arc<Mutex<Vec<tables::Account>>>,
|
||||||
|
|
||||||
|
pub buckets: Arc<Mutex<Vec<tables::Buckets>>>,
|
||||||
|
|
||||||
|
pub transaction_catagories: Arc<Mutex<Vec<tables::TransactionCatagories>>>,
|
||||||
|
|
||||||
|
pub transaction_breakdowns: Arc<Mutex<Vec<tables::TransactionBreakdown>>>,
|
||||||
|
|
||||||
|
pub transactions: Arc<Mutex<Vec<tables::Transaction>>>,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl DataCache {
|
||||||
|
pub fn new() -> DataCache {
|
||||||
|
DataCache {
|
||||||
|
accounts: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
buckets: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
transaction_catagories: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
transaction_breakdowns: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
transactions: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
|
|
||||||
pub mod transaction;
|
|
||||||
pub use self::transaction::TransactionRecord;
|
|
||||||
|
|
||||||
pub mod connection;
|
pub mod connection;
|
||||||
pub use self::connection::DB;
|
pub use self::connection::DB;
|
||||||
|
|
||||||
pub mod tables;
|
pub mod tables;
|
||||||
|
pub mod data_cache;
|
||||||
|
|
65
src/db/tables.rs
Normal file
65
src/db/tables.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use sqlx::{FromRow, postgres::types::PgMoney};
|
||||||
|
use time::Date;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, FromRow)]
|
||||||
|
pub struct Account {
|
||||||
|
pub acnt_id: i32,
|
||||||
|
pub acnt_dsply_name: String,
|
||||||
|
pub acnt_description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, FromRow)]
|
||||||
|
pub struct Buckets {
|
||||||
|
pub bkt_id: i32,
|
||||||
|
pub bkt_dsply_code: String,
|
||||||
|
pub bkt_dsply_name: String,
|
||||||
|
pub bkt_description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, FromRow)]
|
||||||
|
pub struct TransactionCatagories {
|
||||||
|
pub trns_ctgry_id: i32,
|
||||||
|
pub trns_ctgry_dsply_code: String,
|
||||||
|
pub trns_ctgry_dsply_name: String,
|
||||||
|
pub trns_ctgry_description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, FromRow)]
|
||||||
|
pub struct TransactionBreakdown {
|
||||||
|
pub trns_brkdwn_id: i32,
|
||||||
|
pub trns_brkdwn_amount: PgMoney,
|
||||||
|
pub trns_brkdwn_parent_transaction: i32,
|
||||||
|
pub trns_brkdwn_catagory: i32,
|
||||||
|
pub trns_brkdwn_bucket: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, FromRow)]
|
||||||
|
pub struct Transaction{
|
||||||
|
pub trns_id: i32,
|
||||||
|
pub trns_amount: PgMoney,
|
||||||
|
pub trns_description: String,
|
||||||
|
pub trns_bucket: i32,
|
||||||
|
pub trns_date: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transaction {
|
||||||
|
|
||||||
|
pub fn get_header() -> String {
|
||||||
|
return format!(" {:<7} | {:<9} | {:<10}", "Id", "Amount", "Date")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
return format!(" T{:0>6} | {:>9} | {:>10}", self.trns_id, self.trns_amount.to_decimal(2).to_string(), self.trns_date.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> Cow<str> {
|
||||||
|
return self.to_string().into()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
use sqlx::FromRow;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, FromRow)]
|
|
||||||
pub struct Account {
|
|
||||||
pub acnt_id: i32,
|
|
||||||
pub acnt_dsply_name: String,
|
|
||||||
pub acnt_description: String,
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
|
|
||||||
// cargo add crust_decimal
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TransactionRecord {
|
|
||||||
pub id: i64,
|
|
||||||
// pub amount: Decimal,
|
|
||||||
pub amount: String,
|
|
||||||
//pub record_date: Date,
|
|
||||||
pub date: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TransactionRecord {
|
|
||||||
pub fn new(id: i64, amount: String, record_date: String) -> TransactionRecord {
|
|
||||||
TransactionRecord {
|
|
||||||
id,
|
|
||||||
amount,
|
|
||||||
date: record_date
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_header() -> String {
|
|
||||||
return format!(" {:<7} | {:<9} | {:<10}", "Id", "Amount", "Date")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string(&self) -> String {
|
|
||||||
return format!(" T{:0>6} | {:>9} | {:>10}", self.id, self.amount, self.date)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_str(&self) -> Cow<str> {
|
|
||||||
return self.to_string().into()
|
|
||||||
}
|
|
||||||
}
|
|
17
src/main.rs
17
src/main.rs
|
@ -1,10 +1,6 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crossbeam_channel::bounded;
|
|
||||||
|
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
|
||||||
|
@ -13,10 +9,10 @@ use ratatui::{
|
||||||
Terminal,
|
Terminal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use recount::db::DB;
|
||||||
|
use recount::db::data_cache::DataCache;
|
||||||
use recount::app::{App, AppResult};
|
use recount::app::{App, AppResult};
|
||||||
use recount::tui::Tui;
|
use recount::tui::Tui;
|
||||||
use recount::db::DB;
|
|
||||||
use recount::db::tables;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> AppResult<()> {
|
async fn main() -> AppResult<()> {
|
||||||
|
@ -24,13 +20,12 @@ async fn main() -> AppResult<()> {
|
||||||
let log_file = "testing_log.txt".to_string();
|
let log_file = "testing_log.txt".to_string();
|
||||||
init_logger(log_file);
|
init_logger(log_file);
|
||||||
|
|
||||||
let records = Arc::new(Mutex::new(Vec::new()));
|
let data_cache = DataCache::new();
|
||||||
let (s, r) = bounded::<bool>(2);
|
let db = DB::new(data_cache.clone()).await?;
|
||||||
let db = DB::new(Arc::clone(&records), s).await?;
|
|
||||||
|
|
||||||
|
|
||||||
// Create an application.
|
// Create an application.
|
||||||
let mut app = App::new(db, records, r);
|
let mut app = App::new(db, data_cache);
|
||||||
|
app.refresh();
|
||||||
|
|
||||||
// Initialize the terminal user interface.
|
// Initialize the terminal user interface.
|
||||||
let backend = CrosstermBackend::new(io::stderr());
|
let backend = CrosstermBackend::new(io::stderr());
|
||||||
|
|
|
@ -1,65 +1,71 @@
|
||||||
use crossterm::event::{KeyEvent, KeyEventKind, KeyCode};
|
use crossterm::event::{KeyEvent, KeyEventKind, KeyCode};
|
||||||
use ratatui::{backend::Backend, Frame, layout::{Rect, Layout, Direction, Constraint}, widgets::{Block, Borders, List, ListItem, Paragraph}, text::{Text, Line, Span}, style::{Style, Color, Modifier}};
|
use ratatui::{backend::Backend, Frame, layout::{Rect, Layout, Direction, Constraint}, widgets::{Block, Borders, List, ListItem, Paragraph}, text::{Text, Line, Span}, style::{Style, Color}};
|
||||||
use crate::{app::{App, StatefulList}, db::TransactionRecord};
|
use crate::{app::App, db::tables::Transaction};
|
||||||
|
|
||||||
|
|
||||||
pub struct HistoryState {
|
pub struct HistoryState {
|
||||||
pub transacts_list: StatefulList<TransactionRecord>
|
pub selected_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HistoryState {
|
impl HistoryState {
|
||||||
|
|
||||||
pub fn new() -> HistoryState {
|
pub fn new() -> HistoryState {
|
||||||
HistoryState {
|
HistoryState {
|
||||||
transacts_list: StatefulList::with_items(vec![
|
selected_index: None,
|
||||||
TransactionRecord::new(1, "$10.00".to_string(), "05-01-2020".to_string()),
|
|
||||||
TransactionRecord::new(2, "$10.00".to_string(), "05-01-2020".to_string()),
|
|
||||||
TransactionRecord::new(3, "$10.00".to_string(), "05-01-2020".to_string()),
|
|
||||||
TransactionRecord::new(4, "$10.00".to_string(), "05-01-2020".to_string()),
|
|
||||||
TransactionRecord::new(5, "$10.00".to_string(), "05-01-2020".to_string()),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_event(event: KeyEvent, app: &mut App) {
|
pub fn handle_event(event: KeyEvent, app: &mut App) {
|
||||||
|
|
||||||
|
if app.states.history.selected_index.is_none() {
|
||||||
|
app.states.history.selected_index = Some(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let max_index = app.data_cache.transactions.lock().unwrap().len();
|
||||||
|
|
||||||
if event.kind == KeyEventKind::Press {
|
if event.kind == KeyEventKind::Press {
|
||||||
match event.code {
|
match event.code {
|
||||||
KeyCode::Tab => app.states.transactions.next_tab(),
|
KeyCode::Up | KeyCode::Tab => app.states.history.next(max_index),
|
||||||
KeyCode::Up => app.states.history.transacts_list.previous(),
|
KeyCode::Down => app.states.history.previous(),
|
||||||
KeyCode::Down => app.states.history.transacts_list.next(),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_transactions(app: &mut App) {
|
pub fn next(&mut self, max_index: usize) {
|
||||||
app.states.history.transacts_list.items.clear();
|
|
||||||
for i in app.records.lock().unwrap().iter() {
|
if self.selected_index.is_some() {
|
||||||
app.states.history.transacts_list.items.push(i.clone());
|
let cur_index = self.selected_index.unwrap();
|
||||||
|
if cur_index + 1 < max_index {
|
||||||
|
self.selected_index = Some(cur_index + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn previous(&mut self) {
|
||||||
|
|
||||||
|
if self.selected_index.is_some() {
|
||||||
|
let cur_index = self.selected_index.unwrap();
|
||||||
|
if cur_index > 0 {
|
||||||
|
self.selected_index = Some(cur_index - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render_history_tab<B: Backend> (f: &mut Frame<B>, body_rect: Rect, app: &mut App) {
|
pub fn render_history_tab<B: Backend> (f: &mut Frame<B>, body_rect: Rect, app: &mut App) {
|
||||||
|
|
||||||
let do_update = match app.states.new_data.try_recv() {
|
|
||||||
Ok(val) => val,
|
|
||||||
Err(_) => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if do_update {
|
|
||||||
HistoryState::update_transactions(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let split_body = Layout::default()
|
let split_body = Layout::default()
|
||||||
.direction(Direction::Horizontal)
|
.direction(Direction::Horizontal)
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
.split(body_rect);
|
.split(body_rect);
|
||||||
|
|
||||||
let mut lines: Vec<Line> = vec![];
|
let mut lines: Vec<Line> = vec![];
|
||||||
if app.states.history.transacts_list.state.selected().is_some(){
|
{
|
||||||
let selected_item: &TransactionRecord = &app.states.history.transacts_list.items[app.states.history.transacts_list.state.selected().unwrap()];
|
let transacts_list = app.data_cache.transactions.lock().unwrap();
|
||||||
|
if app.states.history.selected_index.is_some() {
|
||||||
|
let selected_item: &Transaction = &transacts_list[app.states.history.selected_index.unwrap()];
|
||||||
|
|
||||||
let ident_style: Style = Style::default().fg(Color::Yellow);
|
let ident_style: Style = Style::default().fg(Color::Yellow);
|
||||||
let value_style: Style = Style::default().fg(Color::LightBlue);
|
let value_style: Style = Style::default().fg(Color::LightBlue);
|
||||||
|
@ -67,19 +73,19 @@ pub fn render_history_tab<B: Backend> (f: &mut Frame<B>, body_rect: Rect, app: &
|
||||||
lines.push(
|
lines.push(
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
Span::styled("Transaction Id: ", ident_style),
|
Span::styled("Transaction Id: ", ident_style),
|
||||||
Span::styled(format!("T{:0>6}", selected_item.id), value_style),
|
Span::styled(format!("T{:0>6}", selected_item.trns_id), value_style),
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
lines.push(
|
lines.push(
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
Span::styled("Amount: ", ident_style),
|
Span::styled("Amount: ", ident_style),
|
||||||
Span::styled(format!("{}", selected_item.amount), value_style)
|
Span::styled(format!("{}", selected_item.trns_amount.to_decimal(2).to_string()), value_style)
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
lines.push(
|
lines.push(
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
Span::styled("Transaction Date: ", ident_style),
|
Span::styled("Transaction Date: ", ident_style),
|
||||||
Span::styled(format!("{}", selected_item.date), value_style)
|
Span::styled(format!("{}", selected_item.trns_date.to_string()), value_style)
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -96,28 +102,34 @@ pub fn render_history_tab<B: Backend> (f: &mut Frame<B>, body_rect: Rect, app: &
|
||||||
.split(split_body[0]);
|
.split(split_body[0]);
|
||||||
|
|
||||||
let list_header = Paragraph::new(
|
let list_header = Paragraph::new(
|
||||||
Text::styled(TransactionRecord::get_header(), Style::default().fg(Color::Black).bg(Color::Cyan))
|
Text::styled(Transaction::get_header(), Style::default().fg(Color::Black).bg(Color::Cyan))
|
||||||
).block(Block::default().borders(Borders::NONE));
|
).block(Block::default().borders(Borders::NONE));
|
||||||
|
|
||||||
f.render_widget(list_header, list_chunks[0]);
|
f.render_widget(list_header, list_chunks[0]);
|
||||||
|
|
||||||
// Iterate through all elements in the `items` app and append some debug text to it.
|
let mut items: Vec<ListItem> = Vec::new();
|
||||||
let items: Vec<ListItem> = app
|
|
||||||
.states.history.transacts_list
|
for i in 0..transacts_list.len() {
|
||||||
.items
|
let style = match app.states.history.selected_index {
|
||||||
.iter()
|
Some(val) => {
|
||||||
.map(|i| {
|
if val == i {
|
||||||
ListItem::new(Text::from(i.as_str())).style(Style::default().fg(Color::Black).bg(Color::White))
|
Style::default().fg(Color::Black).bg(Color::Yellow)
|
||||||
})
|
} else {
|
||||||
.collect();
|
Style::default().fg(Color::Black).bg(Color::White)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => Style::default().fg(Color::Black).bg(Color::White),
|
||||||
|
};
|
||||||
|
|
||||||
|
items.push(ListItem::new(
|
||||||
|
Text::from(transacts_list.get(i).unwrap().as_str())
|
||||||
|
).style(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let history_items = List::new(items)
|
let history_items = List::new(items)
|
||||||
.block(Block::default().borders(Borders::NONE))
|
.block(Block::default().borders(Borders::NONE));
|
||||||
.highlight_style(
|
|
||||||
Style::default()
|
|
||||||
.bg(Color::Gray)
|
|
||||||
.add_modifier(Modifier::BOLD)
|
|
||||||
);
|
|
||||||
|
|
||||||
f.render_stateful_widget(history_items, list_chunks[1], &mut app.states.history.transacts_list.state)
|
f.render_widget(history_items, list_chunks[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue