use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; use color_eyre::Result; use ratatui::{ layout::{Position, Alignment, Constraint, Flex, Layout, Rect}, widgets::{Block, Clear, Paragraph}, Frame }; use tokio::sync::mpsc::UnboundedSender; use super::{Component, PartialComponent, CurrentTab}; use crate::{ widgets::{Input, InputRequest}, action::Action, config::Config, palette::StylePalette, }; #[derive(Debug)] pub struct RenameAccount { is_active: bool, action_tx: Option<UnboundedSender<Action>>, old_name: String, name: Input, palette: StylePalette } impl Default for RenameAccount { fn default() -> Self { Self::new() } } impl RenameAccount { pub fn new() -> Self { Self { is_active: false, old_name: String::new(), action_tx: None, name: Input::new(String::new()), palette: StylePalette::default(), } } } impl RenameAccount { fn submit_message(&mut self) { if let Some(action_tx) = &self.action_tx { let _ = action_tx.send(Action::UpdateAccountName(self.name.value().to_string())); } } fn enter_char(&mut self, new_char: char) { let _ = self.name.handle(InputRequest::InsertChar(new_char)); } fn delete_char(&mut self) { let _ = self.name.handle(InputRequest::DeletePrevChar); } fn move_cursor_right(&mut self) { let _ = self.name.handle(InputRequest::GoToNextChar); } fn move_cursor_left(&mut self) { let _ = self.name.handle(InputRequest::GoToPrevChar); } } impl PartialComponent for RenameAccount { fn set_active(&mut self, current_tab: CurrentTab) { match current_tab { CurrentTab::RenameAccount => self.is_active = true, _ => { self.is_active = false; self.old_name = String::new(); self.name = Input::new(String::new()); } }; } } impl Component for RenameAccount { 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()); } Ok(()) } fn update(&mut self, action: Action) -> Result<Option<Action>> { match action { Action::RenameAccount(old_name) => self.old_name = old_name, _ => {} }; Ok(None) } fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> { if self.is_active && key.kind == KeyEventKind::Press { match key.code { KeyCode::Enter => self.submit_message(), 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.is_active = false, _ => {}, }; } 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 input = Paragraph::new(self.name.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(format!("New name for '{}'", self.old_name))); 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(input, area); frame.set_cursor_position(Position::new( area.x + self.name.cursor() as u16 + 1, area.y + 1 )); } Ok(()) } }