use color_eyre::Result; use ratatui::{ text::Text, layout::{Alignment, Constraint, Rect}, widgets::{Block, Cell, Row, Table}, Frame }; use super::{Component, PartialComponent, CurrentTab}; use crate::{ widgets::DotSpinner, action::Action, config::Config, palette::StylePalette, }; #[derive(Debug)] pub struct Balance { is_active: bool, total_balance: Option, transferable_balance: Option, locked_balance: Option, reserved_balance: Option, nonce: Option, palette: StylePalette } impl Default for Balance { fn default() -> Self { Self::new() } } impl Balance { const TICKER: &str = " CSPR"; const DECIMALS: usize = 6; pub fn new() -> Self { Self { is_active: false, total_balance: None, transferable_balance: None, locked_balance: None, reserved_balance: None, nonce: None, palette: StylePalette::default(), } } fn prepare_u128(&self, maybe_value: Option) -> String { match maybe_value { Some(value) => { let value = value as f64 / 10f64.powi(18); let after = Self::DECIMALS; format!("{:.after$}{}", value, Self::TICKER) }, None => format!("{}{}", DotSpinner::default().to_string(), Self::TICKER) } } } impl PartialComponent for Balance { fn set_active(&mut self, current_tab: CurrentTab) { match current_tab { CurrentTab::Accounts => self.is_active = true, _ => self.is_active = false, } } } impl Component for Balance { fn register_config_handler(&mut self, config: Config) -> Result<()> { if let Some(style) = config.styles.get(&crate::app::Mode::Wallet) { self.palette.with_normal_style(style.get("normal_style").copied()); self.palette.with_hover_style(style.get("hover_style").copied()); self.palette.with_normal_border_style(style.get("normal_border_style").copied()); self.palette.with_hover_border_style(style.get("hover_border_style").copied()); self.palette.with_normal_title_style(style.get("normal_title_style").copied()); self.palette.with_hover_title_style(style.get("hover_title_style").copied()); } Ok(()) } fn update(&mut self, action: Action) -> Result> { match action { Action::BalanceSetActive(maybe_balance) => { match maybe_balance { Some(balance) => { self.total_balance = Some(balance.free); self.locked_balance = Some(balance.frozen); self.reserved_balance = Some(balance.reserved); self.nonce = Some(balance.nonce); let transferable = balance.free .saturating_sub(balance.reserved) .saturating_sub(balance.frozen); self.transferable_balance = Some(transferable); }, None => { self.transferable_balance = None; self.locked_balance = None; self.reserved_balance = None; self.total_balance = None; self.nonce = None; } } }, _ => {} }; Ok(None) } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { let [_, _, place, _] = super::account_layout(area); let (border_style, border_type) = self.palette .create_border_style(self.is_active); let table = Table::new( [ Row::new(vec![ Cell::from(Text::from("nonce: ".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.nonce .map(|n| n.to_string()) .unwrap_or(DotSpinner::default().to_string()) ).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("account: ".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_u128(self.total_balance)).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("free: ".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_u128(self.transferable_balance)).alignment(Alignment::Right)) ]), Row::new(vec![ Cell::from(Text::from("locked: ".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_u128(self.locked_balance)).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("reserved: ".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_u128(self.reserved_balance)).alignment(Alignment::Right)), ]), ], [ Constraint::Max(10), Constraint::Min(14), ] ) .block(Block::bordered() .border_style(border_style) .border_type(border_type) .title_alignment(Alignment::Right) .title_style(self.palette.create_title_style(false)) .title("Balance")); frame.render_widget(table, place); Ok(()) } }