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; use event_log::EventLogs; use current_validators::CurrentValidators; 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(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(70), Constraint::Percentage(30), ]).areas(place) }