use color_eyre::Result; use ratatui::layout::Constraint; use ratatui::{ text::Text, layout::{Alignment, Rect}, widgets::{Block, Cell, Row, Table}, Frame }; use std::sync::mpsc::Sender; use super::{PartialComponent, Component, CurrentTab}; use crate::widgets::DotSpinner; use crate::{ action::Action, config::Config, palette::StylePalette, }; pub struct StashDetails { palette: StylePalette, network_tx: Option>, is_bonded: bool, free_balance: Option, staked_total: Option, staked_active: Option, stash_account_id: [u8; 32], stash_secret: [u8; 32], } impl Default for StashDetails { fn default() -> Self { Self::new() } } impl StashDetails { const TICKER: &str = " CSPR"; const DECIMALS: usize = 5; pub fn new() -> Self { Self { palette: StylePalette::default(), network_tx: None, is_bonded: false, free_balance: None, staked_total: None, staked_active: None, stash_account_id: [0u8; 32], stash_secret: [0u8; 32], } } 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) } } fn is_bonded_to_string(&self) -> String { if self.is_bonded { "bonded".to_string() } else { "no bond".to_string() } } } impl PartialComponent for StashDetails { fn set_active(&mut self, _current_tab: CurrentTab) { } } impl Component for StashDetails { fn register_network_handler(&mut self, tx: Sender) -> Result<()> { self.network_tx = Some(tx); Ok(()) } fn register_config_handler(&mut self, config: Config) -> Result<()> { if let Some(style) = config.styles.get(&crate::app::Mode::Validator) { 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()); self.palette.with_highlight_style(style.get("highlight_style").copied()); self.palette.with_scrollbar_style(style.get("scrollbar_style").copied()); } Ok(()) } fn update(&mut self, action: Action) -> Result> { match action { Action::SetStashSecret(secret) => self.stash_secret = secret, Action::SetStashAccount(account_id) => self.stash_account_id = account_id, Action::SetIsBonded(is_bonded, account_id) if self.stash_account_id == account_id => self.is_bonded = is_bonded, Action::SetStakedAmountRatio(total, active, account_id) if self.stash_account_id == account_id => { self.staked_total = total; self.staked_active = active; }, Action::BalanceResponse(account_id, maybe_balance) if account_id == self.stash_account_id => { if let Some(network_tx) = &self.network_tx { let _ = network_tx.send(Action::SetSender( hex::encode(self.stash_secret), maybe_balance.clone().map(|b| b.nonce))); } self.free_balance = maybe_balance.map(|balance| balance.free .saturating_sub(balance.frozen) .saturating_sub(balance.reserved)); }, _ => {} }; Ok(None) } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { let [place, _, _] = super::validator_balance_layout(area); let (border_style, border_type) = self.palette.create_border_style(false); let table = Table::new( vec![ Row::new(vec![ Cell::from(Text::from("Bond ready".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.is_bonded_to_string()).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("Free balance".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_u128(self.free_balance)).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("Total staked".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_u128(self.staked_total)).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("Active staked".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_u128(self.staked_active)).alignment(Alignment::Right)), ]), ], [ Constraint::Min(14), Constraint::Min(0), ], ) .highlight_style(self.palette.create_highlight_style()) .column_spacing(1) .block(Block::bordered() .border_style(border_style) .border_type(border_type) .title_alignment(Alignment::Right) .title_style(self.palette.create_title_style(false)) .title("Stash details")); frame.render_widget(table, place); Ok(()) } }