Compare commits
	
		
			2 Commits
		
	
	
		
			756a1089f6
			...
			9e7cdffd29
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9e7cdffd29 | |||
| ac67bb4310 | 
@ -2,7 +2,7 @@
 | 
			
		||||
name = "ghost-eye"
 | 
			
		||||
authors = ["str3tch <stretch@ghostchain.io>"]
 | 
			
		||||
description = "Application for interacting with Casper/Ghost nodes that are exposing RPC only to the localhost"
 | 
			
		||||
version = "0.3.50"
 | 
			
		||||
version = "0.3.52"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
homepage = "https://git.ghostchain.io/ghostchain"
 | 
			
		||||
repository = "https://git.ghostchain.io/ghostchain/ghost-eye"
 | 
			
		||||
 | 
			
		||||
@ -50,9 +50,14 @@ impl BondPopup {
 | 
			
		||||
            palette: StylePalette::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl BondPopup {
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn log_event(&mut self, message: String, level: ActionLevel) {
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(
 | 
			
		||||
@ -148,7 +153,7 @@ impl Component for BondPopup {
 | 
			
		||||
                KeyCode::Backspace => self.delete_char(),
 | 
			
		||||
                KeyCode::Left => self.move_cursor_left(),
 | 
			
		||||
                KeyCode::Right => self.move_cursor_right(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(), 
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -41,6 +41,13 @@ impl ChillPopup {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn submit_message(&mut self) {
 | 
			
		||||
        if let Some(network_tx) = &self.network_tx { 
 | 
			
		||||
            let _ = network_tx.send(Action::ChillFrom(self.secret_seed));
 | 
			
		||||
@ -85,7 +92,7 @@ impl Component for ChillPopup {
 | 
			
		||||
        if self.is_active && key.kind == KeyEventKind::Press {
 | 
			
		||||
            match key.code {
 | 
			
		||||
                KeyCode::Enter => self.submit_message(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(), 
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,7 @@ mod chill_popup;
 | 
			
		||||
mod unbond_popup;
 | 
			
		||||
mod rebond_popup;
 | 
			
		||||
mod withdraw_popup;
 | 
			
		||||
mod payee_popup;
 | 
			
		||||
 | 
			
		||||
use stash_details::StashDetails;
 | 
			
		||||
use staking_details::StakingDetails;
 | 
			
		||||
@ -48,6 +49,7 @@ use chill_popup::ChillPopup;
 | 
			
		||||
use unbond_popup::UnbondPopup;
 | 
			
		||||
use rebond_popup::RebondPopup;
 | 
			
		||||
use withdraw_popup::WithdrawPopup;
 | 
			
		||||
use payee_popup::PayeePopup;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
			
		||||
pub enum CurrentTab {
 | 
			
		||||
@ -66,6 +68,7 @@ pub enum CurrentTab {
 | 
			
		||||
    UnbondPopup,
 | 
			
		||||
    RebondPopup,
 | 
			
		||||
    WithdrawPopup,
 | 
			
		||||
    PayeePopup,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait PartialComponent: Component {
 | 
			
		||||
@ -104,6 +107,7 @@ impl Default for Validator {
 | 
			
		||||
                Box::new(UnbondPopup::default()),
 | 
			
		||||
                Box::new(RebondPopup::default()),
 | 
			
		||||
                Box::new(WithdrawPopup::default()),
 | 
			
		||||
                Box::new(PayeePopup::default()),
 | 
			
		||||
            ],
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -167,18 +171,10 @@ impl Component for Validator {
 | 
			
		||||
                CurrentTab::UnbondPopup |
 | 
			
		||||
                CurrentTab::RebondPopup |
 | 
			
		||||
                CurrentTab::WithdrawPopup |
 | 
			
		||||
                CurrentTab::PayoutPopup => match key.code {
 | 
			
		||||
                KeyCode::Esc => {
 | 
			
		||||
                    self.current_tab = self.previous_tab;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                _ => {
 | 
			
		||||
                CurrentTab::PayoutPopup => {
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.handle_key_event(key)?;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            _ => match key.code {
 | 
			
		||||
                KeyCode::Esc => {
 | 
			
		||||
@ -189,79 +185,49 @@ impl Component for Validator {
 | 
			
		||||
                    }
 | 
			
		||||
                    return Ok(Some(Action::SetActiveScreen(Mode::Menu)));
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('l') | KeyCode::Right => {
 | 
			
		||||
                    self.move_right();
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('h') | KeyCode::Left => {
 | 
			
		||||
                    self.move_left();
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('R') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::RotatePopup;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('V') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::ValidatePopup;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('U') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::UnbondPopup;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('C') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::ChillPopup;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('B') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::BondPopup;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('E') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::RebondPopup;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('W') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::WithdrawPopup;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('L') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::ListenAddresses;
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.set_active(self.current_tab.clone());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('I') => {
 | 
			
		||||
                    self.previous_tab = self.current_tab;
 | 
			
		||||
                    self.current_tab = CurrentTab::PayeePopup;
 | 
			
		||||
                },
 | 
			
		||||
                KeyCode::Char('l') | KeyCode::Right => self.move_right(),
 | 
			
		||||
                KeyCode::Char('h') | KeyCode::Left => self.move_left(),
 | 
			
		||||
                _ => {
 | 
			
		||||
                    for component in self.components.iter_mut() {
 | 
			
		||||
                        component.handle_key_event(key)?;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok(None)
 | 
			
		||||
@ -271,15 +237,14 @@ impl Component for Validator {
 | 
			
		||||
        match action {
 | 
			
		||||
            Action::SetActiveScreen(Mode::Validator) => {
 | 
			
		||||
                self.is_active = true;
 | 
			
		||||
                self.previous_tab = CurrentTab::NominatorsByValidator;
 | 
			
		||||
                self.current_tab = CurrentTab::NominatorsByValidator;
 | 
			
		||||
            }
 | 
			
		||||
            Action::PayoutValidatorPopup(_, _) => {
 | 
			
		||||
                self.previous_tab = self.current_tab;
 | 
			
		||||
                self.current_tab = CurrentTab::PayoutPopup;
 | 
			
		||||
            }
 | 
			
		||||
            Action::ClosePopup => {
 | 
			
		||||
                self.current_tab = self.previous_tab;
 | 
			
		||||
            },
 | 
			
		||||
            Action::ClosePopup => self.current_tab = self.previous_tab,
 | 
			
		||||
            _ => {},
 | 
			
		||||
        }
 | 
			
		||||
        for component in self.components.iter_mut() {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										365
									
								
								src/components/validator/payee_popup.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								src/components/validator/payee_popup.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,365 @@
 | 
			
		||||
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind};
 | 
			
		||||
use color_eyre::Result;
 | 
			
		||||
use ratatui::{
 | 
			
		||||
    layout::{Alignment, Constraint, Flex, Layout, Position, Rect}, 
 | 
			
		||||
    text::Text, 
 | 
			
		||||
    widgets::{Block, Cell, Clear, Paragraph, Row, Table, TableState}, 
 | 
			
		||||
    Frame,
 | 
			
		||||
};
 | 
			
		||||
use subxt::ext::sp_core::crypto::{
 | 
			
		||||
    ByteArray, Ss58Codec, Ss58AddressFormat, AccountId32,
 | 
			
		||||
};
 | 
			
		||||
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, RewardDestination}, 
 | 
			
		||||
    widgets::{Input, InputRequest},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct PayeePopup {
 | 
			
		||||
    is_active: bool,
 | 
			
		||||
    action_tx: Option<UnboundedSender<Action>>,
 | 
			
		||||
    network_tx: Option<Sender<Action>>,
 | 
			
		||||
    table_state: TableState,
 | 
			
		||||
    stash_secret_seed: [u8; 32],
 | 
			
		||||
    stash_account_id: [u8; 32],
 | 
			
		||||
    proposed_account_id: Option<[u8; 32]>,
 | 
			
		||||
    is_bonded: bool,
 | 
			
		||||
    is_account_chosen: bool,
 | 
			
		||||
    is_input_active: bool,
 | 
			
		||||
    address: Input,
 | 
			
		||||
    possible_payee_options: &'static [(&'static str, &'static str)],
 | 
			
		||||
    current_reward_destination: RewardDestination,
 | 
			
		||||
    palette: StylePalette
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for PayeePopup {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self::new()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PayeePopup {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            is_active: false,
 | 
			
		||||
            stash_secret_seed: [0u8; 32],
 | 
			
		||||
            stash_account_id: [0u8; 32],
 | 
			
		||||
            proposed_account_id: None,
 | 
			
		||||
            action_tx: None,
 | 
			
		||||
            network_tx: None,
 | 
			
		||||
            table_state: TableState::new(),
 | 
			
		||||
            is_bonded: false,
 | 
			
		||||
            is_account_chosen: false,
 | 
			
		||||
            is_input_active: false,
 | 
			
		||||
            address: Input::new(String::new()),
 | 
			
		||||
            current_reward_destination: Default::default(),
 | 
			
		||||
            possible_payee_options: &[
 | 
			
		||||
                ("Re-stake", "(pay into the stash account, increasing the amount at stake accordingly)"),
 | 
			
		||||
                ("Stake", "(pay into the stash account, not increasing the amount at stake)"),
 | 
			
		||||
                ("Account", "(pay into a specified account different from stash)"),
 | 
			
		||||
                ("None", "(refuse to receive all rewards from staking)"),
 | 
			
		||||
            ],
 | 
			
		||||
            palette: StylePalette::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn parse_index_from_destination(&mut self) -> usize {
 | 
			
		||||
        let (index, address) = match self.current_reward_destination {
 | 
			
		||||
            RewardDestination::Staked => (0, Default::default()),
 | 
			
		||||
            RewardDestination::Stash => (1, Default::default()),
 | 
			
		||||
            RewardDestination::Account(account_id) => {
 | 
			
		||||
                let address = AccountId32::from(account_id)
 | 
			
		||||
                    .to_ss58check_with_version(Ss58AddressFormat::custom(1996));
 | 
			
		||||
                (2, address)
 | 
			
		||||
            },
 | 
			
		||||
            RewardDestination::None => (3, Default::default()),
 | 
			
		||||
            _ => (0, Default::default()),
 | 
			
		||||
        };
 | 
			
		||||
        self.address = Input::new(address);
 | 
			
		||||
        index
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn move_to_row(&mut self, index: usize) {
 | 
			
		||||
        self.table_state.select(Some(index));
 | 
			
		||||
        self.is_account_chosen = index == 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn next_row(&mut self) {
 | 
			
		||||
        let i = match self.table_state.selected() {
 | 
			
		||||
            Some(i) => {
 | 
			
		||||
                if i >= self.possible_payee_options.len() - 1 {
 | 
			
		||||
                    i
 | 
			
		||||
                } else {
 | 
			
		||||
                    i + 1
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            None => 0,
 | 
			
		||||
        };
 | 
			
		||||
        self.move_to_row(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fn previous_row(&mut self) {
 | 
			
		||||
        let i = match self.table_state.selected() {
 | 
			
		||||
            Some(i) => {
 | 
			
		||||
                if i == 0 {
 | 
			
		||||
                    0
 | 
			
		||||
                } else {
 | 
			
		||||
                    i - 1
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            None => 0
 | 
			
		||||
        };
 | 
			
		||||
        self.move_to_row(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn log_event(&mut self, message: String, level: ActionLevel) {
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::EventLog(
 | 
			
		||||
                    message, 
 | 
			
		||||
                    level, 
 | 
			
		||||
                    ActionTarget::ValidatorLog));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn trigger_address_input(&mut self) {
 | 
			
		||||
        self.is_input_active = !self.is_input_active;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn submit_new_input(&mut self) {
 | 
			
		||||
        match AccountId32::from_ss58check_with_version(self.address.value()) {
 | 
			
		||||
            Ok((account_id, format)) => {
 | 
			
		||||
                if format != Ss58AddressFormat::custom(1996) {
 | 
			
		||||
                    self.log_event(
 | 
			
		||||
                        format!("provided public address for {} is not part of Casper/Ghost ecosystem", self.address.value()),
 | 
			
		||||
                        ActionLevel::Error);
 | 
			
		||||
                }
 | 
			
		||||
                let seed_vec = account_id.to_raw_vec();
 | 
			
		||||
                let mut account_id = [0u8; 32];
 | 
			
		||||
                account_id.copy_from_slice(&seed_vec);
 | 
			
		||||
 | 
			
		||||
                self.proposed_account_id = Some(account_id);
 | 
			
		||||
                self.submit_new_payee();
 | 
			
		||||
            },
 | 
			
		||||
            _ => {
 | 
			
		||||
                self.log_event(
 | 
			
		||||
                    format!("could not create valid account id from {}", self.address.value()),
 | 
			
		||||
                    ActionLevel::Error);
 | 
			
		||||
                self.proposed_account_id = None;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn submit_new_payee(&mut self) {
 | 
			
		||||
        if let Some(index) = self.table_state.selected() {
 | 
			
		||||
            let new_destination = match index {
 | 
			
		||||
                0 => RewardDestination::Staked,
 | 
			
		||||
                1 => RewardDestination::Stash,
 | 
			
		||||
                2 => {
 | 
			
		||||
                    let account_id = self.proposed_account_id
 | 
			
		||||
                        .expect("checked before in submit_new_input; qed");
 | 
			
		||||
                    RewardDestination::Account(account_id)
 | 
			
		||||
                }
 | 
			
		||||
                3 => RewardDestination::None,
 | 
			
		||||
                _ => RewardDestination::Staked,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if !self.is_bonded {
 | 
			
		||||
                self.log_event(
 | 
			
		||||
                    "no bond detected, stake minimum bond amount first".to_string(),
 | 
			
		||||
                    ActionLevel::Warn);
 | 
			
		||||
            } else if new_destination == self.current_reward_destination {
 | 
			
		||||
                self.log_event(
 | 
			
		||||
                    "same destination choosen, no need for transaction".to_string(),
 | 
			
		||||
                    ActionLevel::Warn);
 | 
			
		||||
            } else {
 | 
			
		||||
                if let Some(network_tx) = &self.network_tx {
 | 
			
		||||
                    let _ = network_tx.send(Action::SetPayee(
 | 
			
		||||
                            self.stash_secret_seed, 
 | 
			
		||||
                            new_destination,
 | 
			
		||||
                            ActionTarget::ValidatorLog));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
                let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn enter_char(&mut self, new_char: char) {
 | 
			
		||||
        let _ = self.address.handle(InputRequest::InsertChar(new_char));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn delete_char(&mut self) {
 | 
			
		||||
        let _ = self.address.handle(InputRequest::DeletePrevChar);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn move_cursor_right(&mut self) {
 | 
			
		||||
        let _ = self.address.handle(InputRequest::GoToNextChar);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn move_cursor_left(&mut self) {
 | 
			
		||||
        let _ = self.address.handle(InputRequest::GoToPrevChar);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialComponent for PayeePopup {
 | 
			
		||||
    fn set_active(&mut self, current_tab: CurrentTab) {
 | 
			
		||||
        match current_tab {
 | 
			
		||||
            CurrentTab::PayeePopup => self.is_active = true,
 | 
			
		||||
            _ => {
 | 
			
		||||
                self.is_active = false;
 | 
			
		||||
                self.is_account_chosen = false;
 | 
			
		||||
                self.is_input_active = false;
 | 
			
		||||
 | 
			
		||||
                let index = self.parse_index_from_destination();
 | 
			
		||||
                self.move_to_row(index);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Component for PayeePopup {
 | 
			
		||||
    fn register_network_handler(&mut self, tx: Sender<Action>) -> Result<()> {
 | 
			
		||||
        self.network_tx = Some(tx);
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> 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());
 | 
			
		||||
            self.palette.with_highlight_style(style.get("highlight_style").copied());
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> {
 | 
			
		||||
        if self.is_active && key.kind == KeyEventKind::Press {
 | 
			
		||||
            if self.is_input_active {
 | 
			
		||||
                match key.code {
 | 
			
		||||
                    KeyCode::Enter => self.submit_new_input(),
 | 
			
		||||
                    KeyCode::Char(to_insert) => self.enter_char(to_insert),
 | 
			
		||||
                    KeyCode::Backspace => self.delete_char(),
 | 
			
		||||
                    KeyCode::Left => self.move_cursor_left(),
 | 
			
		||||
                    KeyCode::Right => self.move_cursor_right(),
 | 
			
		||||
                    KeyCode::Esc => self.trigger_address_input(), 
 | 
			
		||||
                    _ => {},
 | 
			
		||||
                };
 | 
			
		||||
            } else {
 | 
			
		||||
                match key.code {
 | 
			
		||||
                    KeyCode::Enter if !self.is_account_chosen => self.submit_new_payee(),
 | 
			
		||||
                    KeyCode::Enter if self.is_account_chosen => self.trigger_address_input(),
 | 
			
		||||
                    KeyCode::Up | KeyCode::Char('k') => self.previous_row(),
 | 
			
		||||
                    KeyCode::Down | KeyCode::Char('j') => self.next_row(),
 | 
			
		||||
                    KeyCode::Esc => self.close_popup(),
 | 
			
		||||
                    _ => {},
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok(None)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn update(&mut self, action: Action) -> Result<Option<Action>> {
 | 
			
		||||
        match action {
 | 
			
		||||
            Action::SetStashAccount(account_id) => self.stash_account_id = account_id,
 | 
			
		||||
            Action::SetStashSecret(secret_seed) => self.stash_secret_seed = secret_seed,
 | 
			
		||||
            Action::SetIsBonded(is_bonded, account_id) if self.stash_account_id == account_id =>
 | 
			
		||||
                self.is_bonded = is_bonded,
 | 
			
		||||
            Action::SetStakingPayee(reward_destination, account_id) if self.stash_account_id == account_id => {
 | 
			
		||||
                let destination_changed = self.current_reward_destination != reward_destination;
 | 
			
		||||
                self.current_reward_destination = reward_destination;
 | 
			
		||||
                if destination_changed || self.table_state.selected().is_none() {
 | 
			
		||||
                    let index = self.parse_index_from_destination();
 | 
			
		||||
                    self.move_to_row(index);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => {}
 | 
			
		||||
        };
 | 
			
		||||
        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 size = area.as_size();
 | 
			
		||||
            let input_area = Rect::new(size.width / 2, size.height / 2, 51, 3); 
 | 
			
		||||
 | 
			
		||||
            let table = Table::new(
 | 
			
		||||
                self.possible_payee_options
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|data| {
 | 
			
		||||
                        Row::new(vec![
 | 
			
		||||
                            Cell::from(Text::from(data.0.to_string()).alignment(Alignment::Left)),
 | 
			
		||||
                            Cell::from(Text::from(data.1.to_string()).alignment(Alignment::Left)),
 | 
			
		||||
                        ])
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Vec<_>>(),
 | 
			
		||||
                [Constraint::Length(8), 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_style(self.palette.create_popup_title_style())
 | 
			
		||||
                .title_alignment(Alignment::Right)
 | 
			
		||||
                .title("Select reward destination"));
 | 
			
		||||
 | 
			
		||||
            let v = Layout::vertical([Constraint::Max(6)]).flex(Flex::Center);
 | 
			
		||||
            let h = Layout::horizontal([Constraint::Max(83)]).flex(Flex::Center);
 | 
			
		||||
            let [area] = v.areas(area);
 | 
			
		||||
            let [area] = h.areas(area);
 | 
			
		||||
 | 
			
		||||
            frame.render_widget(Clear, area);
 | 
			
		||||
            frame.render_stateful_widget(table, area, &mut self.table_state);
 | 
			
		||||
 | 
			
		||||
            if self.is_input_active {
 | 
			
		||||
                let input_amount = Paragraph::new(self.address.value())
 | 
			
		||||
                    .block(Block::bordered()
 | 
			
		||||
                        .border_style(border_style)
 | 
			
		||||
                        .border_type(border_type)
 | 
			
		||||
                        .title_style(self.palette.create_popup_title_style())
 | 
			
		||||
                        .title_alignment(Alignment::Right)
 | 
			
		||||
                        .title("Destination account"));
 | 
			
		||||
 | 
			
		||||
                let v = Layout::vertical([Constraint::Max(8)]).flex(Flex::Center);
 | 
			
		||||
                let h = Layout::horizontal([Constraint::Max(51)]).flex(Flex::Center);
 | 
			
		||||
                let [input_area] = v.areas(input_area);
 | 
			
		||||
                let [input_area] = h.areas(input_area);
 | 
			
		||||
 | 
			
		||||
                frame.render_widget(Clear, input_area);
 | 
			
		||||
                frame.render_widget(input_amount, input_area);
 | 
			
		||||
 | 
			
		||||
                frame.set_cursor_position(Position::new(
 | 
			
		||||
                        input_area.x + self.address.cursor() as u16 + 1,
 | 
			
		||||
                        input_area.y + 1
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -52,9 +52,14 @@ impl PayoutPopup {
 | 
			
		||||
        self.is_claimed = is_claimed;
 | 
			
		||||
        self.era_index = era_index; 
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PayoutPopup {
 | 
			
		||||
    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 {
 | 
			
		||||
@ -111,7 +116,7 @@ impl Component for PayoutPopup {
 | 
			
		||||
        if self.is_active && key.kind == KeyEventKind::Press {
 | 
			
		||||
            match key.code {
 | 
			
		||||
                KeyCode::Enter => self.start_payout(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(), 
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -44,9 +44,14 @@ impl RebondPopup {
 | 
			
		||||
            palette: StylePalette::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RebondPopup {
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn log_event(&mut self, message: String, level: ActionLevel) {
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(
 | 
			
		||||
@ -137,7 +142,7 @@ impl Component for RebondPopup {
 | 
			
		||||
                KeyCode::Backspace => self.delete_char(),
 | 
			
		||||
                KeyCode::Left => self.move_cursor_left(),
 | 
			
		||||
                KeyCode::Right => self.move_cursor_right(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(),
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,13 @@ impl RotatePopup {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn rotate_keys(&mut self) {
 | 
			
		||||
        if !self.cached_keys.is_empty() && self.cached_keys.len() == 258 {
 | 
			
		||||
            if let Some(network_tx) = &self.network_tx {
 | 
			
		||||
@ -123,7 +130,7 @@ impl Component for RotatePopup {
 | 
			
		||||
        if self.is_active && key.kind == KeyEventKind::Press {
 | 
			
		||||
            match key.code {
 | 
			
		||||
                KeyCode::Enter => self.rotate_keys(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(), 
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,13 @@ impl UnbondPopup {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn log_event(&mut self, message: String, level: ActionLevel) {
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(
 | 
			
		||||
@ -146,7 +153,7 @@ impl Component for UnbondPopup {
 | 
			
		||||
                KeyCode::Backspace => self.delete_char(),
 | 
			
		||||
                KeyCode::Left => self.move_cursor_left(),
 | 
			
		||||
                KeyCode::Right => self.move_cursor_right(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(), 
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -44,9 +44,14 @@ impl ValidatePopup {
 | 
			
		||||
            palette: StylePalette::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ValidatePopup {
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn log_event(&mut self, message: String, level: ActionLevel) {
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(
 | 
			
		||||
@ -137,7 +142,7 @@ impl Component for ValidatePopup {
 | 
			
		||||
                KeyCode::Backspace => self.delete_char(),
 | 
			
		||||
                KeyCode::Left => self.move_cursor_left(),
 | 
			
		||||
                KeyCode::Right => self.move_cursor_right(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(), 
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,13 @@ impl WithdrawPopup {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn close_popup(&mut self) {
 | 
			
		||||
        self.is_active = false;
 | 
			
		||||
        if let Some(action_tx) = &self.action_tx {
 | 
			
		||||
            let _ = action_tx.send(Action::ClosePopup);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn stash_should_be_killed(&self) -> bool {
 | 
			
		||||
        self.unlocking_is_empty && self.active_balance < self.existential_deposit
 | 
			
		||||
    }
 | 
			
		||||
@ -112,7 +119,7 @@ impl Component for WithdrawPopup {
 | 
			
		||||
        if self.is_active && key.kind == KeyEventKind::Press {
 | 
			
		||||
            match key.code {
 | 
			
		||||
                KeyCode::Enter => self.proceed(),
 | 
			
		||||
                KeyCode::Esc => self.is_active = false, 
 | 
			
		||||
                KeyCode::Esc => self.close_popup(), 
 | 
			
		||||
                _ => {},
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user