use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; use color_eyre::Result; use ratatui::{ layout::{Alignment, Constraint, Flex, Layout, Rect}, widgets::{Block, Clear, Paragraph}, Frame }; use tokio::sync::mpsc::UnboundedSender; use std::sync::mpsc::Sender; use super::{Component, PartialComponent, CurrentTab}; use crate::{ action::Action, config::Config, palette::StylePalette, types::{ActionLevel, ActionTarget}, }; #[derive(Debug)] pub struct PayoutPopup { is_active: bool, action_tx: Option>, network_tx: Option>, secret_seed: [u8; 32], stash_account_id: [u8; 32], era_index: u32, is_claimed: bool, palette: StylePalette } impl Default for PayoutPopup { fn default() -> Self { Self::new() } } impl PayoutPopup { pub fn new() -> Self { Self { is_active: false, secret_seed: [0u8; 32], stash_account_id: [0u8; 32], era_index: 0u32, is_claimed: false, action_tx: None, network_tx: None, palette: StylePalette::default(), } } fn store_era_to_claim(&mut self, era_index: u32, is_claimed: bool) { self.is_claimed = is_claimed; self.era_index = era_index; } fn close_popup(&mut self) { self.is_active = false; if let Some(action_tx) = &self.action_tx { let _ = action_tx.send(Action::ClosePopup); } } fn start_payout(&mut self) { if self.is_claimed { if let Some(action_tx) = &self.action_tx { let _ = action_tx.send(Action::EventLog( format!("staking rewards for era index #{} already claimed", self.era_index), ActionLevel::Warn, ActionTarget::ValidatorLog)); } } else { if let Some(network_tx) = &self.network_tx { let _ = network_tx.send(Action::PayoutStakers( self.secret_seed, self.stash_account_id, self.era_index)); } } if let Some(action_tx) = &self.action_tx { let _ = action_tx.send(Action::ClosePopup); } } } impl PartialComponent for PayoutPopup { fn set_active(&mut self, current_tab: CurrentTab) { match current_tab { CurrentTab::PayoutPopup => self.is_active = true, _ => self.is_active = false, }; } } impl Component for PayoutPopup { fn register_network_handler(&mut self, tx: Sender) -> Result<()> { self.network_tx = Some(tx); Ok(()) } fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { self.action_tx = Some(tx); Ok(()) } 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_normal_border_style(style.get("normal_border_style").copied()); self.palette.with_normal_title_style(style.get("normal_title_style").copied()); self.palette.with_popup_style(style.get("popup_style").copied()); self.palette.with_popup_title_style(style.get("popup_title_style").copied()); } Ok(()) } fn handle_key_event(&mut self, key: KeyEvent) -> Result> { if self.is_active && key.kind == KeyEventKind::Press { match key.code { KeyCode::Enter => self.start_payout(), KeyCode::Esc => self.close_popup(), _ => {}, }; } Ok(None) } fn update(&mut self, action: Action) -> Result> { match action { Action::PayoutValidatorPopup(era_index, is_claimed) => self.store_era_to_claim(era_index, is_claimed), Action::SetStashSecret(secret_seed) => self.secret_seed = secret_seed, Action::SetStashAccount(account_id) => self.stash_account_id = account_id, _ => {} }; Ok(None) } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { if self.is_active { let (border_style, border_type) = self.palette.create_popup_style(); let popup = Paragraph::new(format!(" Do payout for era #{}", self.era_index)) .block(Block::bordered() .border_style(border_style) .border_type(border_type) .title_style(self.palette.create_popup_title_style()) .title_alignment(Alignment::Right) .title("Enter to proceed / Esc to close")); let v = Layout::vertical([Constraint::Max(3)]).flex(Flex::Center); let h = Layout::horizontal([Constraint::Max(50)]).flex(Flex::Center); let [area] = v.areas(area); let [area] = h.areas(area); frame.render_widget(Clear, area); frame.render_widget(popup, area); } Ok(()) } }