use color_eyre::Result; use ratatui::layout::Constraint; use ratatui::{ text::Text, layout::{Alignment, Rect}, widgets::{Block, Cell, Row, Table}, Frame }; use super::{PartialComponent, Component, CurrentTab}; use crate::types::EraRewardPoints; use crate::widgets::DotSpinner; use crate::{ action::Action, config::Config, palette::StylePalette, }; pub struct RewardDetails { palette: StylePalette, commission: Option, nominators_blocked: bool, apy: String, treasury_apy: String, inflation: String, stash: [u8; 32], in_staking_validators: bool, in_queued_keys: bool, in_next_keys: bool, is_disabled: bool, in_rewards: bool, } impl Default for RewardDetails { fn default() -> Self { Self::new() } } impl RewardDetails { pub fn new() -> Self { Self { palette: StylePalette::default(), commission: None, nominators_blocked: false, apy: String::from("0.0%"), treasury_apy: String::from("0.0%"), inflation: String::from("0.0%"), stash: [0u8; 32], in_staking_validators: false, in_queued_keys: false, in_next_keys: false, is_disabled: false, in_rewards: false, } } fn comission_to_string(&self) -> String { match self.commission { Some(commission) => { if self.nominators_blocked { "blocked".to_string() } else { format!("{:.2}%", commission as f64 / 10_000_000.0) } }, None => DotSpinner::default().to_string(), } } fn update_individual(&mut self, individual: &Vec) { let (is_disabled, in_rewards) = individual .iter() .find(|data| data.account_id == self.stash) .map(|data| (data.disabled, true)) .unwrap_or((false, false)); self.is_disabled = is_disabled; self.in_rewards = in_rewards; } } impl PartialComponent for RewardDetails { fn set_active(&mut self, _current_tab: CurrentTab) { } } impl Component for RewardDetails { 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::SetStashAccount(stash) => self.stash = stash, Action::SetCurrentValidatorEraRewards(_, _, individual) => self.update_individual(&individual), Action::SetValidatorPrefs(commission, disabled, account_id) if self.stash == account_id => { self.commission = commission; self.in_staking_validators = commission.is_some(); self.nominators_blocked = disabled; } Action::SetSessionKey(name, session_key_info) => { if name.starts_with("q_") { self.in_queued_keys = !session_key_info.key.is_empty(); } else { self.in_next_keys = !session_key_info.key.is_empty(); } }, Action::Apy(apy) => self.apy = apy, Action::TreasuryApy(apy) => self.treasury_apy = apy, Action::Inflation(inflation) => self.inflation = inflation, _ => {} }; 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 status = if self.is_disabled { "Disabled" } else { let is_fully_in_session = self.in_queued_keys && self.in_next_keys; match (self.in_staking_validators, is_fully_in_session) { (true, true) => "Active", (true, false) => "Rotating", (false, true) if self.in_rewards => { "Stopping" } (false, true) if !self.in_rewards => { "Chill" } _ => "Nothing", } }; let staking_status = format!("Staking status: {status}"); let table = Table::new( vec![ Row::new(vec![ Cell::from(Text::from("Nominators".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.comission_to_string()).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("Validator APY".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.apy.clone()).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("Treasury APY".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.treasury_apy.clone()).alignment(Alignment::Right)), ]), Row::new(vec![ Cell::from(Text::from("Inflation".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.inflation.clone()).alignment(Alignment::Right)), ]), ], [ Constraint::Min(13), 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(staking_status)); frame.render_widget(table, place); Ok(()) } }