additional pop-up for balance detalization in address book
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
		
							parent
							
								
									9b1136e4ca
								
							
						
					
					
						commit
						853bdcd76e
					
				| @ -45,6 +45,7 @@ pub enum Action { | ||||
|     UpdateAddressBookRecord(String), | ||||
|     UpdateKnownValidator(String), | ||||
|     TransferTo(String), | ||||
|     AccountDetailsOf(String, Option<SystemAccount>), | ||||
| 
 | ||||
|     TransferBalance(String, [u8; 32], u128), | ||||
|     EventLog(String, ActionLevel, ActionTarget), | ||||
|  | ||||
| @ -231,6 +231,19 @@ impl AddressBook { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn show_account_details(&mut self) { | ||||
|         if let Some(index) = self.table_state.selected() { | ||||
|             if let Some(action_tx) = &self.action_tx { | ||||
|                 let _ = action_tx.send(Action::AccountDetailsOf( | ||||
|                         self.address_book[index].name.clone(), | ||||
|                         self.balances | ||||
|                             .get(&self.address_book[index].account_id) | ||||
|                             .map(|data| data.clone()), | ||||
|                 )); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn swap_up(&mut self) { | ||||
|         if let Some(src_index) = self.table_state.selected() { | ||||
|             let dst_index = src_index.saturating_sub(1); | ||||
| @ -390,6 +403,7 @@ impl Component for AddressBook { | ||||
|                 KeyCode::Char('J') => self.swap_down(), | ||||
|                 KeyCode::Char('D') => self.delete_row(), | ||||
|                 KeyCode::Char('R') => self.update_address_book_record(), | ||||
|                 KeyCode::Char('I') => self.show_account_details(), | ||||
|                 KeyCode::Enter => self.send_transfer_to(), | ||||
|                 _ => {}, | ||||
|             }; | ||||
| @ -407,11 +421,7 @@ impl Component for AddressBook { | ||||
|                 .map(|info| { | ||||
|                     let balance = self.balances | ||||
|                         .get(&info.account_id) | ||||
|                         .map(|inner_balance| { | ||||
|                             inner_balance.free | ||||
|                                 .saturating_add(inner_balance.reserved) | ||||
|                                 .saturating_add(inner_balance.frozen) | ||||
|                         }); | ||||
|                         .map(|inner_balance| inner_balance.free); | ||||
|                     Row::new(vec![ | ||||
|                         Cell::from(Text::from(info.name.clone()).alignment(Alignment::Left)), 
 | ||||
|                         Cell::from(Text::from(info.address.clone()).alignment(Alignment::Center)), 
 | ||||
|  | ||||
| @ -20,7 +20,7 @@ pub struct Balance { | ||||
|     total_balance: Option<u128>, | ||||
|     transferable_balance: Option<u128>, | ||||
|     locked_balance: Option<u128>, | ||||
|     bonded_balance: Option<u128>, | ||||
|     reserved_balance: Option<u128>, | ||||
|     nonce: Option<u32>, | ||||
|     palette: StylePalette | ||||
| } | ||||
| @ -41,7 +41,7 @@ impl Balance { | ||||
|             total_balance: None, | ||||
|             transferable_balance: None, | ||||
|             locked_balance: None, | ||||
|             bonded_balance: None, | ||||
|             reserved_balance: None, | ||||
|             nonce: None, | ||||
|             palette: StylePalette::default(), | ||||
|         } | ||||
| @ -87,19 +87,19 @@ impl Component for Balance { | ||||
|                 match maybe_balance { | ||||
|                     Some(balance) => { | ||||
|                         self.total_balance = Some(balance.free); | ||||
|                         self.locked_balance = Some(balance.reserved); | ||||
|                         self.bonded_balance = Some(balance.frozen); | ||||
|                         self.locked_balance = Some(balance.frozen); | ||||
|                         self.reserved_balance = Some(balance.reserved); | ||||
|                         self.nonce = Some(balance.nonce); | ||||
| 
 | ||||
|                         let transferable = balance.free | ||||
|                             .saturating_add(balance.reserved) | ||||
|                             .saturating_add(balance.frozen); | ||||
|                             .saturating_sub(balance.reserved) | ||||
|                             .saturating_sub(balance.frozen); | ||||
|                         self.transferable_balance = Some(transferable); | ||||
|                     }, | ||||
|                     None => { | ||||
|                         self.transferable_balance = None; | ||||
|                         self.locked_balance = None; | ||||
|                         self.bonded_balance = None; | ||||
|                         self.reserved_balance = None; | ||||
|                         self.total_balance = None; | ||||
|                         self.nonce = None; | ||||
|                     } | ||||
| @ -137,8 +137,8 @@ impl Component for Balance { | ||||
|                     Cell::from(Text::from(self.prepare_u128(self.locked_balance)).alignment(Alignment::Right)), | ||||
|                 ]), | ||||
|                 Row::new(vec![ | ||||
|                     Cell::from(Text::from("bonded: ".to_string()).alignment(Alignment::Left)), | ||||
|                     Cell::from(Text::from(self.prepare_u128(self.bonded_balance)).alignment(Alignment::Right)), | ||||
|                     Cell::from(Text::from("reserved: ".to_string()).alignment(Alignment::Left)), | ||||
|                     Cell::from(Text::from(self.prepare_u128(self.reserved_balance)).alignment(Alignment::Right)), | ||||
|                 ]), | ||||
|             ], | ||||
|             [ | ||||
|  | ||||
							
								
								
									
										202
									
								
								src/components/wallet/details.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								src/components/wallet/details.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,202 @@ | ||||
| use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; | ||||
| use color_eyre::Result; | ||||
| use ratatui::{ | ||||
|     layout::{Alignment, Constraint, Flex, Layout, Rect}, 
 | ||||
|     widgets::{Block, Cell, Clear, Row, Table}, 
 | ||||
|     text::Text, 
 | ||||
|     Frame, | ||||
| }; | ||||
| use tokio::sync::mpsc::UnboundedSender; | ||||
| 
 | ||||
| use super::{Component, PartialComponent, CurrentTab}; | ||||
| use crate::{ | ||||
|     action::Action, 
 | ||||
|     config::Config, 
 | ||||
|     palette::StylePalette, 
 | ||||
|     widgets::DotSpinner, | ||||
| }; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct AccountDetails { | ||||
|     is_active: bool, | ||||
|     action_tx: Option<UnboundedSender<Action>>, | ||||
|     palette: StylePalette, | ||||
|     name: String, | ||||
|     transferable_balance: Option<u128>, | ||||
|     locked_balance: Option<u128>, | ||||
|     reserved_balance: Option<u128>, | ||||
|     total_balance: Option<u128>, | ||||
|     nonce: Option<u32>, | ||||
| } | ||||
| 
 | ||||
| impl Default for AccountDetails { | ||||
|     fn default() -> Self { | ||||
|         Self::new() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl AccountDetails { | ||||
|     const TICKER: &str = " CSPR"; | ||||
|     const DECIMALS: usize = 6; | ||||
| 
 | ||||
|     pub fn new() -> Self { | ||||
|         Self { | ||||
|             is_active: false, | ||||
|             action_tx: None, | ||||
|             palette: StylePalette::default(), | ||||
|             name: String::new(), | ||||
|             transferable_balance: None, | ||||
|             locked_balance: None, | ||||
|             reserved_balance: None, | ||||
|             total_balance: None, | ||||
|             nonce: None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn close_popup(&mut self) { | ||||
|         self.is_active = false; | ||||
|         if let Some(action_tx) = &self.action_tx { | ||||
|             let _ = action_tx.send(Action::ClosePopup); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn prepare_u128(&self, maybe_value: Option<u128>) -> String { | ||||
|         match maybe_value { | ||||
|             Some(value) => { | ||||
|                 let value = value as f64 / 10f64.powi(18); | ||||
|                 let after = Self::DECIMALS; | ||||
|                 format!("{:.after$}{}", value, Self::TICKER) | ||||
|             }, | ||||
|             None => format!("{}{}", DotSpinner::default().to_string(), Self::TICKER) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialComponent for AccountDetails { | ||||
|     fn set_active(&mut self, current_tab: CurrentTab) { | ||||
|         match current_tab { | ||||
|             CurrentTab::AccountDetails => self.is_active = true, | ||||
|             _ => { | ||||
|                 if self.is_active { | ||||
|                     self.is_active = false; | ||||
|                     self.name = String::new(); | ||||
|                     self.transferable_balance = None; | ||||
|                     self.locked_balance = None; | ||||
|                     self.reserved_balance = None; | ||||
|                     self.total_balance = None; | ||||
|                     self.nonce = None; | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Component for AccountDetails { | ||||
|     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::AccountDetailsOf(name, maybe_account_info) => { | ||||
|                 self.name = name; | ||||
|                 match maybe_account_info { | ||||
|                     Some(account_info) => { | ||||
|                         self.total_balance = Some(account_info.free); | ||||
|                         self.locked_balance = Some(account_info.frozen); | ||||
|                         self.reserved_balance = Some(account_info.reserved); | ||||
|                         self.nonce = Some(account_info.nonce); | ||||
| 
 | ||||
|                         let transferable = account_info.free | ||||
|                             .saturating_sub(account_info.reserved) | ||||
|                             .saturating_sub(account_info.frozen); | ||||
|                         self.transferable_balance = Some(transferable); | ||||
|                     }, | ||||
|                     None => { | ||||
|                         self.transferable_balance = None; | ||||
|                         self.locked_balance = None; | ||||
|                         self.reserved_balance = None; | ||||
|                         self.total_balance = None; | ||||
|                         self.nonce = None; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             _ => {} | ||||
|         }; | ||||
|         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::Esc | KeyCode::Enter => self.close_popup(), 
 | ||||
|                 _ => {}, | ||||
|             }; | ||||
|         } | ||||
|         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 table = Table::new( | ||||
|                 [ | ||||
|                     Row::new(vec![ | ||||
|                         Cell::from(Text::from("nonce: ".to_string()).alignment(Alignment::Left)), | ||||
|                         Cell::from(Text::from(self.nonce | ||||
|                                 .map(|n| n.to_string()) | ||||
|                                 .unwrap_or(DotSpinner::default().to_string()) | ||||
|                         ).alignment(Alignment::Right)), | ||||
|                     ]), | ||||
|                     Row::new(vec![ | ||||
|                         Cell::from(Text::from("total: ".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("free: ".to_string()).alignment(Alignment::Left)), | ||||
|                         Cell::from(Text::from(self.prepare_u128(self.transferable_balance)).alignment(Alignment::Right)) | ||||
|                     ]), | ||||
|                     Row::new(vec![ | ||||
|                         Cell::from(Text::from("locked: ".to_string()).alignment(Alignment::Left)), | ||||
|                         Cell::from(Text::from(self.prepare_u128(self.locked_balance)).alignment(Alignment::Right)), | ||||
|                     ]), | ||||
|                     Row::new(vec![ | ||||
|                         Cell::from(Text::from("reserved: ".to_string()).alignment(Alignment::Left)), | ||||
|                         Cell::from(Text::from(self.prepare_u128(self.reserved_balance)).alignment(Alignment::Right)), | ||||
|                     ]), | ||||
|                 ], | ||||
|                 [ | ||||
|                     Constraint::Max(10), | ||||
|                     Constraint::Min(14), | ||||
|                 ] | ||||
|             ) | ||||
|             .block(Block::bordered() | ||||
|                 .border_style(border_style) | ||||
|                 .border_type(border_type) | ||||
|                 .title_alignment(Alignment::Right) | ||||
|                 .title_style(self.palette.create_title_style(false)) | ||||
|                 .title(format!("Details for {}", &self.name))); | ||||
| 
 | ||||
|             let v = Layout::vertical([Constraint::Max(7)]).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(table, area); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| @ -18,6 +18,7 @@ mod accounts; | ||||
| mod overview; | ||||
| mod add_address_book_record; | ||||
| mod rename_address_book_record; | ||||
| mod details; | ||||
| 
 | ||||
| use balance::Balance; | ||||
| use transfer::Transfer; | ||||
| @ -29,11 +30,12 @@ use accounts::Accounts; | ||||
| use overview::Overview; | ||||
| use add_address_book_record::AddAddressBookRecord; | ||||
| use rename_address_book_record::RenameAddressBookRecord; | ||||
| use details::AccountDetails; | ||||
| 
 | ||||
| use super::Component; | ||||
| use crate::{action::Action, app::Mode, config::Config}; | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[derive(Debug, Copy, Clone, PartialEq)] | ||||
| pub enum CurrentTab { | ||||
|     Nothing, | ||||
|     Accounts, | ||||
| @ -44,6 +46,7 @@ pub enum CurrentTab { | ||||
|     RenameAccount, | ||||
|     RenameAddressBookRecord, | ||||
|     Transfer, | ||||
|     AccountDetails, | ||||
| } | ||||
| 
 | ||||
| pub trait PartialComponent: Component { | ||||
| @ -53,6 +56,7 @@ pub trait PartialComponent: Component { | ||||
| pub struct Wallet { | ||||
|     is_active: bool, | ||||
|     current_tab: CurrentTab, | ||||
|     previous_tab: CurrentTab, | ||||
|     components: Vec<Box<dyn PartialComponent>>, | ||||
| } | ||||
| 
 | ||||
| @ -61,6 +65,7 @@ impl Default for Wallet { | ||||
|         Self { | ||||
|             is_active: false, | ||||
|             current_tab: CurrentTab::Accounts, | ||||
|             previous_tab: CurrentTab::Accounts, | ||||
|             components: vec![ | ||||
|                 Box::new(Overview::default()), | ||||
|                 Box::new(Accounts::default()), | ||||
| @ -72,6 +77,7 @@ impl Default for Wallet { | ||||
|                 Box::new(AddAddressBookRecord::default()), | ||||
|                 Box::new(RenameAddressBookRecord::default()), | ||||
|                 Box::new(Transfer::default()), | ||||
|                 Box::new(AccountDetails::default()), | ||||
|             ], | ||||
|         } | ||||
|     } | ||||
| @ -127,9 +133,10 @@ impl Component for Wallet { | ||||
|                 CurrentTab::RenameAccount | 
 | ||||
|                 CurrentTab::RenameAddressBookRecord | 
 | ||||
|                 CurrentTab::Transfer | | ||||
|                 CurrentTab::AccountDetails | | ||||
|                 CurrentTab::AddAddressBookRecord => match key.code { | ||||
|                     KeyCode::Esc => { | ||||
|                         self.current_tab = CurrentTab::Accounts; | ||||
|                         self.current_tab = self.previous_tab; | ||||
|                         for component in self.components.iter_mut() { | ||||
|                             component.set_active(self.current_tab.clone()); | ||||
|                         } | ||||
| @ -150,18 +157,21 @@ impl Component for Wallet { | ||||
|                     return Ok(Some(Action::SetActiveScreen(Mode::Menu))); | ||||
|                 }, | ||||
|                 KeyCode::Char('W') => { | ||||
|                     self.previous_tab = self.current_tab; | ||||
|                     self.current_tab = CurrentTab::AddAccount; | ||||
|                     for component in self.components.iter_mut() { | ||||
|                         component.set_active(self.current_tab.clone()); | ||||
|                     } | ||||
|                 }, | ||||
|                 KeyCode::Char('A') => { | ||||
|                     self.previous_tab = self.current_tab; | ||||
|                     self.current_tab = CurrentTab::AddAddressBookRecord; | ||||
|                     for component in self.components.iter_mut() { | ||||
|                         component.set_active(self.current_tab.clone()); | ||||
|                     } | ||||
|                 }, | ||||
|                 KeyCode::Char('T') => { | ||||
|                     self.previous_tab = self.current_tab; | ||||
|                     self.current_tab = CurrentTab::Transfer; | ||||
|                     for component in self.components.iter_mut() { | ||||
|                         component.set_active(self.current_tab.clone()); | ||||
| @ -194,15 +204,32 @@ impl Component for Wallet { | ||||
|             Action::SetActiveScreen(Mode::Wallet) => { | ||||
|                 self.is_active = true; | ||||
|                 self.current_tab = CurrentTab::Accounts; | ||||
|                 self.previous_tab = CurrentTab::Accounts; | ||||
|             }, | ||||
|             Action::UpdateAccountName(_) | Action::NewAccount(_) => { | ||||
|                 self.previous_tab = self.current_tab; | ||||
|                 self.current_tab = CurrentTab::Accounts; | ||||
|             }, | ||||
|             Action::UpdateAddressBookRecord(_) | Action::NewAddressBookRecord(_, _) | Action::ClosePopup => { | ||||
|                 self.previous_tab = self.current_tab; | ||||
|                 self.current_tab = CurrentTab::AddressBook; | ||||
|             }, | ||||
|             Action::RenameAccount(_) => { | ||||
|                 self.previous_tab = self.current_tab; | ||||
|                 self.current_tab = CurrentTab::RenameAccount; | ||||
|             }, | ||||
|             Action::RenameAddressBookRecord(_) => { | ||||
|                 self.previous_tab = self.current_tab; | ||||
|                 self.current_tab = CurrentTab::RenameAddressBookRecord; | ||||
|             } | ||||
|             Action::TransferTo(_) => { | ||||
|                 self.previous_tab = self.current_tab; | ||||
|                 self.current_tab = CurrentTab::Transfer; | ||||
|             }, | ||||
|             Action::AccountDetailsOf(_, _) => { | ||||
|                 self.previous_tab = self.current_tab; | ||||
|                 self.current_tab = CurrentTab::AccountDetails; | ||||
|             }, | ||||
|             Action::UpdateAccountName(_) | Action::NewAccount(_) => 
 | ||||
|                 self.current_tab = CurrentTab::Accounts, | ||||
|             Action::UpdateAddressBookRecord(_) | Action::NewAddressBookRecord(_, _) | Action::ClosePopup => 
 | ||||
|                 self.current_tab = CurrentTab::AddressBook, | ||||
|             Action::RenameAccount(_) => self.current_tab = CurrentTab::RenameAccount, | ||||
|             Action::RenameAddressBookRecord(_) => 
 | ||||
|                 self.current_tab = CurrentTab::RenameAddressBookRecord, | ||||
|             Action::TransferTo(_) => self.current_tab = CurrentTab::Transfer, | ||||
|             _ => {} | ||||
|         } | ||||
|         for component in self.components.iter_mut() { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user