diff --git a/Cargo.toml b/Cargo.toml index 025c654..d9ab5ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "ghost-eye" authors = ["str3tch "] description = "Application for interacting with Casper/Ghost nodes that are exposing RPC only to the localhost" -version = "0.3.49" +version = "0.3.50" edition = "2021" homepage = "https://git.ghostchain.io/ghostchain" repository = "https://git.ghostchain.io/ghostchain/ghost-eye" diff --git a/config/config.json5 b/config/config.json5 index 06054ed..3464148 100644 --- a/config/config.json5 +++ b/config/config.json5 @@ -41,17 +41,6 @@ "popup_style": "blue", "popup_title_style": "blue", }, - "Nominator": { - "normal_style": "", - "hover_style": "bold yellow italic on blue", - "normal_border_style": "blue", - "hover_border_style": "blue", - "normal_title_style": "blue", - "hover_title_style": "", - "highlight_style": "yellow bold", - "popup_style": "blue", - "popup_title_style": "blue", - }, }, "keybindings": { "Menu": { @@ -77,12 +66,6 @@ "": "Quit", "": "Suspend", }, - "Nominator": { - "": "Quit", - "": "Quit", - "": "Quit", - "": "Suspend", - }, "Empty": { "": "Quit", "": "Quit", diff --git a/src/app.rs b/src/app.rs index 8ca4327..0b34018 100644 --- a/src/app.rs +++ b/src/app.rs @@ -12,7 +12,7 @@ use crate::{ tui::{Event, Tui}, components::{ menu::Menu, version::Version, explorer::Explorer, wallet::Wallet, - validator::Validator, nominator::Nominator, empty::Empty, + validator::Validator, empty::Empty, health::Health, fps::FpsCounter, Component, }, @@ -24,7 +24,6 @@ pub enum Mode { Explorer, Wallet, Validator, - Nominator, Empty, } @@ -73,7 +72,6 @@ impl App { Box::new(Explorer::default()), Box::new(Wallet::default()), Box::new(Validator::default()), - Box::new(Nominator::default()), Box::new(Empty::default()), ], should_quite: false, @@ -268,15 +266,6 @@ impl App { } } }, - Mode::Nominator => { - if let Some(component) = self.components.get_mut(7) { - if let Err(err) = component.draw(frame, frame.area()) { - let _ = self - .action_tx - .send(Action::Error(format!("failed to draw: {:?}", err))); - } - } - }, _ => { if let Some(component) = self.components.last_mut() { if let Err(err) = component.draw(frame, frame.area()) { diff --git a/src/components/menu.rs b/src/components/menu.rs index a180af1..feea7de 100644 --- a/src/components/menu.rs +++ b/src/components/menu.rs @@ -30,7 +30,6 @@ impl Menu { String::from("Explorer"), String::from("Wallet"), String::from("Validator"), - String::from("Nominator"), String::from("Prices"), String::from("Governance"), String::from("Operations"), @@ -59,7 +58,6 @@ impl Menu { 0 => Ok(Some(Action::SetMode(Mode::Explorer))), 1 => Ok(Some(Action::SetMode(Mode::Wallet))), 2 => Ok(Some(Action::SetMode(Mode::Validator))), - 3 => Ok(Some(Action::SetMode(Mode::Nominator))), _ => Ok(Some(Action::SetMode(Mode::Empty))), } } @@ -80,7 +78,6 @@ impl Menu { 0 => Ok(Some(Action::SetMode(Mode::Explorer))), 1 => Ok(Some(Action::SetMode(Mode::Wallet))), 2 => Ok(Some(Action::SetMode(Mode::Validator))), - 3 => Ok(Some(Action::SetMode(Mode::Nominator))), _ => Ok(Some(Action::SetMode(Mode::Empty))), } } @@ -121,7 +118,6 @@ impl Component for Menu { Some(0) => Ok(Some(Action::SetActiveScreen(Mode::Explorer))), Some(1) => Ok(Some(Action::SetActiveScreen(Mode::Wallet))), Some(2) => Ok(Some(Action::SetActiveScreen(Mode::Validator))), - Some(3) => Ok(Some(Action::SetActiveScreen(Mode::Nominator))), _ => Ok(Some(Action::SetActiveScreen(Mode::Empty))), } }, diff --git a/src/components/mod.rs b/src/components/mod.rs index 8077170..f609fde 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -16,7 +16,6 @@ pub mod version; pub mod explorer; pub mod wallet; pub mod validator; -pub mod nominator; pub mod empty; pub trait Component { diff --git a/src/components/nominator/event_log.rs b/src/components/nominator/event_log.rs deleted file mode 100644 index a5c7b42..0000000 --- a/src/components/nominator/event_log.rs +++ /dev/null @@ -1,217 +0,0 @@ -use color_eyre::Result; -use crossterm::event::{KeyCode, KeyEvent}; -use ratatui::{ - layout::{Alignment, Constraint, Margin, Rect}, - style::{Color, Style}, - text::Text, - widgets::{ - Block, Padding, Cell, Row, Scrollbar, ScrollbarOrientation, - ScrollbarState, Table, TableState, - }, - Frame -}; - -use super::{Component, PartialComponent, CurrentTab}; -use crate::{ - types::ActionLevel, - action::Action, - config::Config, - palette::StylePalette, -}; - -#[derive(Debug, Default)] -struct LogDetails { - time: chrono::DateTime, - level: ActionLevel, - message: String, -} - -#[derive(Debug)] -pub struct EventLogs { - is_active: bool, - scroll_state: ScrollbarState, - table_state: TableState, - logs: std::collections::VecDeque, - palette: StylePalette -} - -// TODO: remove later -impl Default for EventLogs { - fn default() -> Self { - EventLogs { - is_active: false, - scroll_state: Default::default(), - table_state: Default::default(), - logs: std::collections::VecDeque::from(vec![ - LogDetails { - time: chrono::Local::now(), - level: ActionLevel::Warn, - message: "NOT FINALIZED PAGE! NEEDED IN ORDER TO SEE VALIDATORS POINTS".to_string(), - }, - ]), - palette: Default::default(), - } - } -} - -impl EventLogs { - //const MAX_LOGS: usize = 50; - - //fn add_new_log(&mut self, message: String, level: ActionLevel) { - // self.logs.push_front(LogDetails { - // time: chrono::Local::now(), - // level, - // message, - // }); - - // if self.logs.len() > Self::MAX_LOGS { - // let _ = self.logs.pop_back(); - // } - //} - - fn first_row(&mut self) { - if self.logs.len() > 0 { - self.table_state.select(Some(0)); - self.scroll_state = self.scroll_state.position(0); - } - } - - fn next_row(&mut self) { - let i = match self.table_state.selected() { - Some(i) => { - if i >= self.logs.len() - 1 { - i - } else { - i + 1 - } - }, - None => 0, - }; - self.table_state.select(Some(i)); - self.scroll_state = self.scroll_state.position(i); - } - - fn last_row(&mut self) { - if self.logs.len() > 0 { - let last = self.logs.len() - 1; - self.table_state.select(Some(last)); - self.scroll_state = self.scroll_state.position(last); - } - } - - fn previous_row(&mut self) { - let i = match self.table_state.selected() { - Some(i) => { - if i == 0 { - 0 - } else { - i - 1 - } - }, - None => 0 - }; - self.table_state.select(Some(i)); - self.scroll_state = self.scroll_state.position(i); - } -} - -impl PartialComponent for EventLogs { - fn set_active(&mut self, current_tab: CurrentTab) { - match current_tab { - CurrentTab::EventLogs => self.is_active = true, - _ => { - self.is_active = false; - self.table_state.select(None); - self.scroll_state = self.scroll_state.position(0); - } - } - } -} - -impl Component for EventLogs { - fn register_config_handler(&mut self, config: Config) -> Result<()> { - if let Some(style) = config.styles.get(&crate::app::Mode::Nominator) { - 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 handle_key_event(&mut self, key: KeyEvent) -> Result> { - match key.code { - KeyCode::Up | KeyCode::Char('k') if self.is_active => self.previous_row(), - KeyCode::Down | KeyCode::Char('j') if self.is_active => self.next_row(), - KeyCode::Char('g') if self.is_active => self.first_row(), - KeyCode::Char('G') if self.is_active => self.last_row(), - _ => {}, - }; - Ok(None) - } - - fn update(&mut self, _action: Action) -> Result> { - //match action { - // Action::EventLog(message, level, target) if target == ActionTarget::NominatorLog => - // self.add_new_log(message, level), - // _ => {} - //}; - Ok(None) - } - - fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { - let [_, _, place] = super::nominator_layout(area); - - let (border_style, border_type) = self.palette.create_border_style(self.is_active); - let error_style = Style::new().fg(Color::Red); - let warn_style = Style::new().fg(Color::Yellow); - let info_style = Style::new().fg(Color::Green); - - let table = Table::new( - self.logs - .iter() - .map(|log| { - let style = match log.level { - ActionLevel::Info => info_style, - ActionLevel::Warn => warn_style, - ActionLevel::Error => error_style, - }; - Row::new(vec![ - Cell::from(Text::from(log.time.format("%H:%M:%S").to_string()).style(style).alignment(Alignment::Left)), - Cell::from(Text::from(log.message.clone()).style(style).alignment(Alignment::Left)), - ]) - }), - [ - Constraint::Max(8), - Constraint::Min(0), - ], - ) - .column_spacing(1) - .highlight_style(self.palette.create_highlight_style()) - .block(Block::bordered() - .border_style(border_style) - .border_type(border_type) - .padding(Padding::right(2)) - .title_alignment(Alignment::Right) - .title_style(self.palette.create_title_style(false)) - .title("Action Logs")); - - let scrollbar = Scrollbar::default() - .orientation(ScrollbarOrientation::VerticalRight) - .begin_symbol(None) - .end_symbol(None) - .style(self.palette.create_scrollbar_style()); - - frame.render_stateful_widget(table, place, &mut self.table_state); - frame.render_stateful_widget( - scrollbar, - place.inner(Margin { vertical: 1, horizontal: 1 }), - &mut self.scroll_state, - ); - Ok(()) - } -} diff --git a/src/components/nominator/mod.rs b/src/components/nominator/mod.rs deleted file mode 100644 index 79197c4..0000000 --- a/src/components/nominator/mod.rs +++ /dev/null @@ -1,185 +0,0 @@ -use color_eyre::Result; -use crossterm::event::{KeyCode, KeyEvent}; -use ratatui::{ - layout::{Constraint, Layout, Rect}, - Frame, -}; - -use std::sync::mpsc::Sender; -use tokio::sync::mpsc::UnboundedSender; - -use super::Component; -use crate::{action::Action, app::Mode, config::Config}; - -mod event_log; -mod current_validators; -mod rename_known_validator; -mod current_validator_details; - -use event_log::EventLogs; -use current_validators::CurrentValidators; -use current_validator_details::CurrentValidatorDetails; -use rename_known_validator::RenameKnownValidator; - -#[derive(Debug, Clone, PartialEq)] -pub enum CurrentTab { - Nothing, - CurrentValidators, - EventLogs, - RenameKnownValidator, -} - -pub trait PartialComponent: Component { - fn set_active(&mut self, current_tab: CurrentTab); -} - -pub struct Nominator { - is_active: bool, - current_tab: CurrentTab, - components: Vec>, -} - -impl Default for Nominator { - fn default() -> Self { - Self { - is_active: false, - current_tab: CurrentTab::Nothing, - components: vec![ - Box::new(CurrentValidators::default()), - Box::new(CurrentValidatorDetails::default()), - Box::new(EventLogs::default()), - Box::new(RenameKnownValidator::default()), - ], - } - } -} - -impl Nominator { - fn move_left(&mut self) { - match self.current_tab { - CurrentTab::EventLogs => self.current_tab = CurrentTab::CurrentValidators, - _ => {} - } - } - - fn move_right(&mut self) { - match self.current_tab { - CurrentTab::CurrentValidators => self.current_tab = CurrentTab::EventLogs, - _ => {} - } - } -} - -impl Component for Nominator { - fn register_network_handler(&mut self, tx: Sender) -> Result<()> { - for component in self.components.iter_mut() { - component.register_network_handler(tx.clone())?; - } - Ok(()) - } - - fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { - for component in self.components.iter_mut() { - component.register_action_handler(tx.clone())?; - } - Ok(()) - } - - fn register_config_handler(&mut self, config: Config) -> Result<()> { - for component in self.components.iter_mut() { - component.register_config_handler(config.clone())?; - } - Ok(()) - } - - fn handle_key_event(&mut self, key: KeyEvent) -> Result> { - if !self.is_active { return Ok(None) } - - match self.current_tab { - CurrentTab::RenameKnownValidator => match key.code { - KeyCode::Esc => { - self.current_tab = CurrentTab::CurrentValidators; - for component in self.components.iter_mut() { - component.set_active(self.current_tab.clone()); - } - }, - _ => { - for component in self.components.iter_mut() { - component.handle_key_event(key)?; - } - } - }, - _ => match key.code { - KeyCode::Esc => { - self.is_active = false; - self.current_tab = CurrentTab::Nothing; - for component in self.components.iter_mut() { - component.set_active(self.current_tab.clone()); - } - 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()); - } - }, - _ => { - for component in self.components.iter_mut() { - component.handle_key_event(key)?; - } - } - } - } - Ok(None) - } - - fn update(&mut self, action: Action) -> Result> { - match action { - Action::RenameKnownValidatorRecord => - self.current_tab = CurrentTab::RenameKnownValidator, - Action::UpdateKnownValidator(_) => - self.current_tab = CurrentTab::CurrentValidators, - Action::SetActiveScreen(Mode::Nominator) => { - self.is_active = true; - self.current_tab = CurrentTab::CurrentValidators; - }, - _ => {}, - } - for component in self.components.iter_mut() { - component.set_active(self.current_tab.clone()); - component.update(action.clone())?; - } - Ok(None) - } - - fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { - let screen = super::screen_layout(area); - for component in self.components.iter_mut() { - component.draw(frame, screen)?; - } - Ok(()) - } -} - -pub fn nominator_layout(area: Rect) -> [Rect; 3] { - Layout::vertical([ - Constraint::Percentage(25), - Constraint::Percentage(50), - Constraint::Percentage(25), - ]).areas(area) -} - -pub fn validator_details_layout(area: Rect) -> [Rect; 2] { - let [place, _, _] = nominator_layout(area); - Layout::horizontal([ - Constraint::Percentage(60), - Constraint::Percentage(40), - ]).areas(place) -} diff --git a/src/components/wallet/details.rs b/src/components/wallet/account_details.rs similarity index 100% rename from src/components/wallet/details.rs rename to src/components/wallet/account_details.rs diff --git a/src/components/nominator/current_validator_details.rs b/src/components/wallet/current_validator_details.rs similarity index 61% rename from src/components/nominator/current_validator_details.rs rename to src/components/wallet/current_validator_details.rs index cb51d5c..4731ee7 100644 --- a/src/components/nominator/current_validator_details.rs +++ b/src/components/wallet/current_validator_details.rs @@ -113,7 +113,12 @@ impl CurrentValidatorDetails { } impl PartialComponent for CurrentValidatorDetails { - fn set_active(&mut self, _current_tab: CurrentTab) {} + fn set_active(&mut self, current_tab: CurrentTab) { + match current_tab { + CurrentTab::CurrentValidatorsPopup => self.is_active = true, + _ => self.is_active = false, + } + } } impl Component for CurrentValidatorDetails { @@ -123,7 +128,7 @@ impl Component for CurrentValidatorDetails { } fn register_config_handler(&mut self, config: Config) -> Result<()> { - if let Some(style) = config.styles.get(&crate::app::Mode::Nominator) { + 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()); @@ -154,63 +159,65 @@ impl Component for CurrentValidatorDetails { } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { - let [_, place] = super::validator_details_layout(area); - let (border_style, border_type) = self.palette.create_border_style(self.is_active); + if self.is_active { + let (border_style, border_type) = self.palette.create_border_style(self.is_active); + let [_, place] = super::nominator_layout(area); + let table = Table::new( + vec![ + Row::new(vec![ + Cell::from(Text::from("Forbidden".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(self.is_nomination_disabled.to_string()).alignment(Alignment::Right)), + ]), + Row::new(vec![ + Cell::from(Text::from("Nominators".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(self.others_len.to_string()).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.total_balance)).alignment(Alignment::Right)), + ]), + Row::new(vec![ + Cell::from(Text::from("Own stake".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(self.prepare_u128(self.own_balance)).alignment(Alignment::Right)), + ]), + Row::new(vec![ + Cell::from(Text::from("Imbalance".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(self.prepare_stake_imbalance()).alignment(Alignment::Right)), + ]), + Row::new(vec![ + Cell::from(Text::from("Commission".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(format!("{:.4}%", self.commission)).alignment(Alignment::Right)), + ]), + Row::new(vec![ + Cell::from(Text::from("Points ratio".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(format!("{:.4}%", self.points_ratio)).alignment(Alignment::Right)), + ]), + Row::new(vec![ + Cell::from(Text::from("In next era".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(self.prepare_state_string()).alignment(Alignment::Right)), + ]), + Row::new(vec![ + Cell::from(Text::from("Last payout".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(format!("{} days ago", self.latest_era_claim)).alignment(Alignment::Right)), + ]), + ], + [ + Constraint::Max(12), + Constraint::Min(0), + ], + ) + .column_spacing(1) + .highlight_style(self.palette.create_highlight_style()) + .block(Block::bordered() + .border_style(border_style) + .border_type(border_type) + .title_alignment(Alignment::Right) + .title_style(self.palette.create_title_style(false)) + .title("Validator details")); - let table = Table::new( - vec![ - Row::new(vec![ - Cell::from(Text::from("Forbidden".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(self.is_nomination_disabled.to_string()).alignment(Alignment::Right)), - ]), - Row::new(vec![ - Cell::from(Text::from("Nominators".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(self.others_len.to_string()).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.total_balance)).alignment(Alignment::Right)), - ]), - Row::new(vec![ - Cell::from(Text::from("Own stake".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(self.prepare_u128(self.own_balance)).alignment(Alignment::Right)), - ]), - Row::new(vec![ - Cell::from(Text::from("Imbalance".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(self.prepare_stake_imbalance()).alignment(Alignment::Right)), - ]), - Row::new(vec![ - Cell::from(Text::from("Commission".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(format!("{:.4}%", self.commission)).alignment(Alignment::Right)), - ]), - Row::new(vec![ - Cell::from(Text::from("Points ratio".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(format!("{:.4}%", self.points_ratio)).alignment(Alignment::Right)), - ]), - Row::new(vec![ - Cell::from(Text::from("In next era".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(self.prepare_state_string()).alignment(Alignment::Right)), - ]), - Row::new(vec![ - Cell::from(Text::from("Last payout".to_string()).alignment(Alignment::Left)), - Cell::from(Text::from(format!("{} days ago", self.latest_era_claim)).alignment(Alignment::Right)), - ]), - ], - [ - Constraint::Max(12), - Constraint::Min(0), - ], - ) - .column_spacing(1) - .highlight_style(self.palette.create_highlight_style()) - .block(Block::bordered() - .border_style(border_style) - .border_type(border_type) - .title_alignment(Alignment::Right) - .title_style(self.palette.create_title_style(false)) - .title("Validator details")); + frame.render_widget(table, place); + } - frame.render_widget(table, place); Ok(()) } } diff --git a/src/components/nominator/current_validators.rs b/src/components/wallet/current_validators.rs similarity index 80% rename from src/components/nominator/current_validators.rs rename to src/components/wallet/current_validators.rs index 6275734..fa917ed 100644 --- a/src/components/nominator/current_validators.rs +++ b/src/components/wallet/current_validators.rs @@ -6,6 +6,7 @@ use color_eyre::Result; use crossterm::event::{KeyCode, KeyEvent}; use ratatui::layout::{Constraint, Margin}; use ratatui::style::{Stylize, Modifier}; +use ratatui::widgets::Clear; use ratatui::{ text::Text, layout::{Alignment, Rect}, @@ -38,6 +39,8 @@ pub struct CurrentValidators { total_points: u32, era_index: u32, my_stash_id: Option<[u8; 32]>, + account_id: [u8; 32], + account_secret_seed: [u8; 32], } impl Default for CurrentValidators { @@ -62,10 +65,37 @@ impl CurrentValidators { total_points: 0, era_index: 0, my_stash_id: None, + account_id: [0u8; 32], + account_secret_seed: [0u8; 32], 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 move_selected(&mut self, index: usize) { + if self.individual.len() > 0 { + self.table_state.select(Some(index)); + self.scroll_state = self.scroll_state.position(index); + self.update_choosen_details(index); + } + } + + fn update_used_account(&mut self, account_id: [u8; 32], secret_seed_str: String) { + let secret_seed: [u8; 32] = hex::decode(secret_seed_str) + .expect("stored seed is valid hex string; qed") + .as_slice() + .try_into() + .expect("stored seed is valid length; qed"); + self.account_id = account_id; + self.account_secret_seed = secret_seed; + } + fn update_choosen_details(&self, index: usize) { if let Some(action_tx) = &self.action_tx { let (selected_account_id, selected_points) = self.individual @@ -143,9 +173,7 @@ impl CurrentValidators { fn first_row(&mut self) { if self.individual.len() > 0 { - self.table_state.select(Some(0)); - self.scroll_state = self.scroll_state.position(0); - self.update_choosen_details(0); + self.move_selected(0); } } @@ -160,17 +188,13 @@ impl CurrentValidators { }, None => 0, }; - self.table_state.select(Some(i)); - self.scroll_state = self.scroll_state.position(i); - self.update_choosen_details(i); + self.move_selected(i); } fn last_row(&mut self) { if self.individual.len() > 0 { let last = self.individual.len() - 1; - self.table_state.select(Some(last)); - self.scroll_state = self.scroll_state.position(last); - self.update_choosen_details(last); + self.move_selected(last); } } @@ -185,9 +209,7 @@ impl CurrentValidators { }, None => 0 }; - self.table_state.select(Some(i)); - self.scroll_state = self.scroll_state.position(i); - self.update_choosen_details(i); + self.move_selected(i); } fn update_era_rewards( @@ -207,11 +229,6 @@ impl CurrentValidators { .position(|item| item.account_id == account_id) { self.individual.swap(0, index); } - let current_index = self.table_state - .selected() - .unwrap_or_default(); - self.table_state.select(Some(current_index)); - self.update_choosen_details(current_index); } } @@ -222,7 +239,7 @@ impl CurrentValidators { impl PartialComponent for CurrentValidators { fn set_active(&mut self, current_tab: CurrentTab) { match current_tab { - CurrentTab::CurrentValidators => self.is_active = true, + CurrentTab::CurrentValidatorsPopup => self.is_active = true, _ => self.is_active = false, } } @@ -235,7 +252,7 @@ impl Component for CurrentValidators { } fn register_config_handler(&mut self, config: Config) -> Result<()> { - if let Some(style) = config.styles.get(&crate::app::Mode::Nominator) { + 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()); @@ -255,6 +272,7 @@ impl Component for CurrentValidators { fn update(&mut self, action: Action) -> Result> { match action { Action::UpdateKnownValidator(validator_name) => self.save_validator_name(validator_name), + Action::UsedAccount(account_id, secret_seed) => self.update_used_account(account_id, secret_seed), Action::SetStashAccount(account_id) => self.my_stash_id = Some(account_id), Action::SetCurrentValidatorEraRewards(era_index, total_points, individual) => self.update_era_rewards(era_index, total_points, &individual), @@ -273,6 +291,7 @@ impl Component for CurrentValidators { KeyCode::Char('R') => self.update_known_validator_record(), KeyCode::Char('C') => self.clear_choosen(), KeyCode::Enter => self.flip_validator_check(), + KeyCode::Esc => self.close_popup(), _ => {}, }; } @@ -280,10 +299,11 @@ impl Component for CurrentValidators { } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { - let [place, _] = super::validator_details_layout(area); - let (border_style, border_type) = self.palette.create_border_style(self.is_active); - let table = Table::new( - self.individual + if self.is_active { + let (border_style, border_type) = self.palette.create_border_style(self.is_active); + let [place, _] = super::nominator_layout(area); + let table = Table::new( + self.individual .iter() .enumerate() .map(|(index, info)| { @@ -337,30 +357,32 @@ impl Component for CurrentValidators { Constraint::Min(0), Constraint::Length(6), ], - ) - .style(self.palette.create_basic_style(false)) - .highlight_style(self.palette.create_basic_style(true)) - .column_spacing(1) - .block(Block::bordered() - .border_style(border_style) - .border_type(border_type) - .padding(Padding::right(2)) - .title_alignment(Alignment::Right) - .title_style(self.palette.create_title_style(false)) - .title(format!("Validators | Total points: {}", self.total_points))); + ) + .style(self.palette.create_basic_style(false)) + .highlight_style(self.palette.create_basic_style(true)) + .column_spacing(1) + .block(Block::bordered() + .border_style(border_style) + .border_type(border_type) + .padding(Padding::right(2)) + .title_alignment(Alignment::Right) + .title_style(self.palette.create_title_style(false)) + .title(format!("Validators {} | Total points: {}", self.individual.len(), self.total_points))); - let scrollbar = Scrollbar::default() - .orientation(ScrollbarOrientation::VerticalRight) - .begin_symbol(None) - .end_symbol(None) - .style(self.palette.create_scrollbar_style()); + let scrollbar = Scrollbar::default() + .orientation(ScrollbarOrientation::VerticalRight) + .begin_symbol(None) + .end_symbol(None) + .style(self.palette.create_scrollbar_style()); - frame.render_stateful_widget(table, place, &mut self.table_state); - frame.render_stateful_widget( - scrollbar, - place.inner(Margin { vertical: 1, horizontal: 1 }), - &mut self.scroll_state, - ); + frame.render_widget(Clear, place); + frame.render_stateful_widget(table, place, &mut self.table_state); + frame.render_stateful_widget( + scrollbar, + place.inner(Margin { vertical: 1, horizontal: 1 }), + &mut self.scroll_state, + ); + } Ok(()) } diff --git a/src/components/wallet/mod.rs b/src/components/wallet/mod.rs index ac004d2..be0320f 100644 --- a/src/components/wallet/mod.rs +++ b/src/components/wallet/mod.rs @@ -1,7 +1,7 @@ use color_eyre::Result; use crossterm::event::{KeyCode, KeyEvent}; use ratatui::{ - layout::{Constraint, Layout, Rect}, + layout::{Constraint, Flex, Layout, Rect}, Frame, }; @@ -18,10 +18,13 @@ mod accounts; mod overview; mod add_address_book_record; mod rename_address_book_record; -mod details; +mod account_details; mod staking_ledger; mod bond_popup; mod payee_popup; +mod current_validators; +mod current_validator_details; +mod rename_known_validator; use balance::Balance; use transfer::Transfer; @@ -33,10 +36,13 @@ use accounts::Accounts; use overview::Overview; use add_address_book_record::AddAddressBookRecord; use rename_address_book_record::RenameAddressBookRecord; -use details::AccountDetails; +use account_details::AccountDetails; use staking_ledger::StakingLedger; use bond_popup::BondPopup; use payee_popup::PayeePopup; +use current_validators::CurrentValidators; +use current_validator_details::CurrentValidatorDetails; +use rename_known_validator::RenameKnownValidator; use super::Component; use crate::{action::Action, app::Mode, config::Config}; @@ -55,6 +61,7 @@ pub enum CurrentTab { AccountDetails, BondPopup, PayeePopup, + CurrentValidatorsPopup, } pub trait PartialComponent: Component { @@ -89,6 +96,9 @@ impl Default for Wallet { Box::new(AccountDetails::default()), Box::new(BondPopup::default()), Box::new(PayeePopup::default()), + Box::new(CurrentValidators::default()), + Box::new(CurrentValidatorDetails::default()), + Box::new(RenameKnownValidator::default()), ], } } @@ -147,6 +157,7 @@ impl Component for Wallet { CurrentTab::AccountDetails | CurrentTab::BondPopup | CurrentTab::PayeePopup | + CurrentTab::CurrentValidatorsPopup | CurrentTab::AddAddressBookRecord => { for component in self.components.iter_mut() { component.handle_key_event(key)?; @@ -178,6 +189,10 @@ impl Component for Wallet { self.previous_tab = self.current_tab; self.current_tab = CurrentTab::PayeePopup; }, + KeyCode::Char('N') => { + self.previous_tab = self.current_tab; + self.current_tab = CurrentTab::CurrentValidatorsPopup; + }, KeyCode::Char('l') | KeyCode::Right => self.move_right(), KeyCode::Char('h') | KeyCode::Left => self.move_left(), _ => { @@ -256,3 +271,12 @@ pub fn account_layout(area: Rect) -> [Rect; 4] { Constraint::Max(6), ]).areas(place) } + +pub fn nominator_layout(area: Rect) -> [Rect; 2] { + let v = Layout::vertical([Constraint::Max(11)]).flex(Flex::Center); + let [area] = v.areas(area); + Layout::horizontal([ + Constraint::Percentage(60), + Constraint::Percentage(40), + ]).areas(area) +} diff --git a/src/components/nominator/rename_known_validator.rs b/src/components/wallet/rename_known_validator.rs similarity index 89% rename from src/components/nominator/rename_known_validator.rs rename to src/components/wallet/rename_known_validator.rs index c9df1fe..c21de1c 100644 --- a/src/components/nominator/rename_known_validator.rs +++ b/src/components/wallet/rename_known_validator.rs @@ -38,14 +38,18 @@ impl RenameKnownValidator { palette: StylePalette::default(), } } -} -impl RenameKnownValidator { + fn close_popup(&mut self) { + self.is_active = false; + self.name = Input::new(String::new()); + } + fn submit_message(&mut self) { if let Some(action_tx) = &self.action_tx { let _ = action_tx.send(Action::UpdateKnownValidator( self.name.value().to_string())); } + self.close_popup(); } fn enter_char(&mut self, new_char: char) { @@ -66,15 +70,7 @@ impl RenameKnownValidator { } impl PartialComponent for RenameKnownValidator { - fn set_active(&mut self, current_tab: CurrentTab) { - match current_tab { - CurrentTab::RenameKnownValidator => self.is_active = true, - _ => { - self.is_active = false; - self.name = Input::new(String::new()); - }, - }; - } + fn set_active(&mut self, _current_tab: CurrentTab) { } } impl Component for RenameKnownValidator { @@ -83,8 +79,16 @@ impl Component for RenameKnownValidator { Ok(()) } + fn update(&mut self, action: Action) -> Result> { + match action { + Action::RenameKnownValidatorRecord => self.is_active = true, + _ => {} + }; + Ok(None) + } + fn register_config_handler(&mut self, config: Config) -> Result<()> { - if let Some(style) = config.styles.get(&crate::app::Mode::Nominator) { + 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()); @@ -102,7 +106,7 @@ impl Component for RenameKnownValidator { 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(), _ => {}, }; }