début du ui

This commit is contained in:
thatscringebro 2025-12-17 07:55:40 -05:00
parent 55dfd16cd2
commit 33fb39e732
3 changed files with 137 additions and 12 deletions

View File

@ -1,19 +1,49 @@
use ratatui::widgets::ListState;
use sqlite::Connection; use sqlite::Connection;
use crate::{data_layer, entities::Account};
pub enum CurrentScreen { pub enum CurrentScreen {
Main, Main,
Exiting, Exiting,
} }
pub enum CurrentWidget {
AccountList,
TrxInfo,
TrxList,
}
pub struct AccountList {
accounts: Vec<Account>,
pub state: ListState,
}
impl AccountList {
fn new() -> AccountList {
return AccountList {
accounts: Vec::new(),
state: ListState::default(),
};
}
fn get_accounts(&self, con: &Connection) -> Vec<Account> {
if self.accounts.iter().count() == 0 {
return data_layer::get_accounts(con);
}
return self.accounts.clone();
}
}
pub struct App { pub struct App {
pub current_screen: CurrentScreen, pub current_screen: CurrentScreen,
connection: Connection, pub current_widget: CurrentWidget,
pub acc_list: AccountList,
pub connection: Connection,
exit: bool, exit: bool,
} }
impl App { impl App {
pub fn new() -> App { pub fn new() -> App {
let connection = match Connection::open("ft_rs.db") { let con = match Connection::open("ft_rs.db") {
Ok(con) => con, Ok(con) => con,
Err(e) => { Err(e) => {
eprintln!("Error opening database: {}", e); eprintln!("Error opening database: {}", e);
@ -22,8 +52,14 @@ impl App {
}; };
return App { return App {
current_screen: CurrentScreen::Main, current_screen: CurrentScreen::Main,
connection: connection, current_widget: CurrentWidget::AccountList,
acc_list: AccountList::new(),
connection: con,
exit: false, exit: false,
}; };
} }
pub fn get_list_accounts(&self) -> Vec<Account> {
return self.acc_list.get_accounts(&self.connection);
}
} }

View File

@ -6,6 +6,7 @@ use crate::{
app::{App, CurrentScreen}, app::{App, CurrentScreen},
ui::ui, ui::ui,
}; };
use app::CurrentWidget;
use ratatui::{ use ratatui::{
Terminal, Terminal,
crossterm::{ crossterm::{
@ -55,6 +56,12 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> io::Result<
KeyCode::Char('q') => { KeyCode::Char('q') => {
app.current_screen = CurrentScreen::Exiting; app.current_screen = CurrentScreen::Exiting;
} }
KeyCode::Right => {
app.current_widget = CurrentWidget::TrxList;
}
KeyCode::Left => {
app.current_widget = CurrentWidget::AccountList;
}
_ => {} _ => {}
}, },
CurrentScreen::Exiting => match key.code { CurrentScreen::Exiting => match key.code {
@ -100,7 +107,7 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> io::Result<
// match choice { // match choice {
// "1" => { // "1" => {
// let accounts = data_layer::get_accounts(&connection); // let accounts = data_layer::get_accounts)(&connection);
// let mut total = 0.0; // let mut total = 0.0;
// for ac in accounts.iter() { // for ac in accounts.iter() {
// let ac_total = ac.get_total(&connection); // let ac_total = ac.get_total(&connection);

View File

@ -1,16 +1,84 @@
use crate::app::{App, CurrentScreen}; use crate::{
app::{App, CurrentScreen, CurrentWidget},
entities::Account,
};
use ratatui::{ use ratatui::{
Frame, Frame,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
style::{Color, Style}, style::{
text::Text, Color, Modifier, Style, Stylize,
widgets::{Block, Borders, Clear, Paragraph, Wrap}, palette::tailwind::{BLUE, GREEN, SLATE},
},
text::{Line, Text},
widgets::{Block, Borders, Clear, HighlightSpacing, List, ListItem, Paragraph, Widget, Wrap},
}; };
pub fn ui(frame: &mut Frame, app: &App) { const NORMAL_ROW_BG: Color = SLATE.c950;
if let CurrentScreen::Exiting = app.current_screen { const ALT_ROW_BG_COLOR: Color = SLATE.c900;
frame.render_widget(Clear, frame.area()); const TEXT_FG_COLOR: Color = SLATE.c200;
const SELECTED_STYLE: Style = Style::new().bg(SLATE.c800).add_modifier(Modifier::BOLD);
pub fn ui(frame: &mut Frame, app: &App) {
let layout = Layout::default()
.direction(Direction::Horizontal)
.constraints(vec![Constraint::Percentage(20), Constraint::Percentage(80)])
.split(frame.area());
let right_layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Percentage(10), Constraint::Percentage(90)])
.split(layout[1]);
let mut ac_block = Block::default()
.title("Accounts")
.borders(Borders::ALL)
.border_style(Style::new().fg(Color::DarkGray));
let mut info_block = Block::default()
.title("Account info")
.borders(Borders::ALL)
.border_style(Style::new().fg(Color::DarkGray));
let mut trx_block = Block::default()
.borders(Borders::ALL)
.border_style(Style::new().fg(Color::DarkGray));
let active_style = Style::default();
match app.current_widget {
CurrentWidget::AccountList => ac_block = ac_block.border_style(active_style),
CurrentWidget::TrxInfo => info_block = info_block.border_style(active_style),
CurrentWidget::TrxList => trx_block = trx_block.border_style(active_style),
};
let items: Vec<ListItem> = app
.get_list_accounts()
.iter()
.enumerate()
.map(|(i, acc)| {
let color = alternate_colors(i);
ListItem::from(acc).bg(color)
})
.collect();
let list = List::new(items)
.block(ac_block)
.highlight_style(SELECTED_STYLE)
.highlight_symbol(">")
.highlight_spacing(HighlightSpacing::Always);
frame.render_widget(list, layout[0]);
let info = if let Some(i) = app.acc_list.state.selected() {
format!(
"Total: {}",
app.get_list_accounts()[i]
.get_total(&app.connection)
.to_string()
)
} else {
"No account selected...".to_string()
};
frame.render_widget(Paragraph::new(info).block(info_block), right_layout[0]);
frame.render_widget(Paragraph::new("inner 1").block(trx_block), right_layout[1]);
if let CurrentScreen::Exiting = app.current_screen {
let popup = Block::default() let popup = Block::default()
.title("Exiting program") .title("Exiting program")
.borders(Borders::all()) .borders(Borders::all())
@ -25,7 +93,7 @@ pub fn ui(frame: &mut Frame, app: &App) {
.block(popup) .block(popup)
.wrap(Wrap { trim: false }); .wrap(Wrap { trim: false });
let area = centered_rect(60, 20, frame.area()); let area = centered_rect(50, 20, frame.area());
frame.render_widget(exit_paragraph, area); frame.render_widget(exit_paragraph, area);
} }
} }
@ -49,3 +117,17 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
]) ])
.split(popup_layout[1])[1]; .split(popup_layout[1])[1];
} }
const fn alternate_colors(i: usize) -> Color {
if i % 2 == 0 {
NORMAL_ROW_BG
} else {
ALT_ROW_BG_COLOR
}
}
impl From<&Account> for ListItem<'_> {
fn from(value: &Account) -> Self {
let line = Line::styled(value.get_name(), TEXT_FG_COLOR);
ListItem::new(line)
}
}