From 51eae854f818d19d8ad36c8f7294b21b03ef15cd Mon Sep 17 00:00:00 2001 From: pauldelucia Date: Tue, 29 Oct 2024 15:42:16 +0700 Subject: [PATCH 1/7] feat: view more keys pop-up in identities screen --- src/ui/identities/identities_screen.rs | 332 +++++++++++++++++-------- 1 file changed, 225 insertions(+), 107 deletions(-) diff --git a/src/ui/identities/identities_screen.rs b/src/ui/identities/identities_screen.rs index 5f29ec0d0..315f768a4 100644 --- a/src/ui/identities/identities_screen.rs +++ b/src/ui/identities/identities_screen.rs @@ -23,9 +23,12 @@ use egui::{Color32, Frame, Margin, RichText, Ui}; use egui_extras::{Column, TableBuilder}; use std::sync::{Arc, Mutex}; +#[derive(Clone)] pub struct IdentitiesScreen { pub identities: Arc>>, pub app_context: Arc, + show_more_keys_popup: Option<[u8; 32]>, // Store identity ID instead of QualifiedIdentity + close_more_keys_popup: bool, // Flag to close the pop-up } impl IdentitiesScreen { @@ -34,6 +37,7 @@ impl IdentitiesScreen { ui.label(alias.clone()); } } + fn show_identity_id(ui: &mut Ui, qualified_identity: &QualifiedIdentity) { let (encoding, helper) = match qualified_identity.identity_type { IdentityType::User => (Encoding::Base58, "UserId".to_string()), @@ -41,10 +45,20 @@ impl IdentitiesScreen { (Encoding::Hex, "ProTxHash".to_string()) } }; - let identifier_as_string = qualified_identity.identity.id().to_string(encoding); - ui.add(egui::Label::new(identifier_as_string).sense(egui::Sense::hover())) - .on_hover_text(helper); + let identifier_as_string_first_8_chars: String = qualified_identity + .identity + .id() + .to_string(encoding) + .chars() + .take(8) + .collect(); + ui.add( + egui::Label::new(format!("{}...", identifier_as_string_first_8_chars)) + .sense(egui::Sense::hover()), + ) + .on_hover_text(helper); } + fn show_balance(ui: &mut Ui, qualified_identity: &QualifiedIdentity) { // Calculate the balance in DASH (10^-11 conversion) let balance_in_dash = qualified_identity.identity.balance() as f64 * 1e-11; @@ -73,15 +87,9 @@ impl IdentitiesScreen { }; let name = match key.purpose() { - Purpose::AUTHENTICATION => { - format!("A{}", key.id()) - } - Purpose::ENCRYPTION => { - format!("En{}", key.id()) - } - Purpose::DECRYPTION => { - format!("De{}", key.id()) - } + Purpose::AUTHENTICATION => format!("A{}", key.id()), + Purpose::ENCRYPTION => format!("En{}", key.id()), + Purpose::DECRYPTION => format!("De{}", key.id()), Purpose::TRANSFER => format!("T{}", key.id()), Purpose::SYSTEM => format!("S{}", key.id()), Purpose::VOTING => format!("V{}", key.id()), @@ -108,59 +116,63 @@ impl IdentitiesScreen { fn render_no_identities_view(&self, ui: &mut Ui) { ui.vertical_centered(|ui| { - ui.add_space(20.0); // Add some space from the top - - // Use a larger font for the heading - ui.label( - RichText::new("Not Tracking Any Identities") - .heading() - .size(30.0), // Larger size for heading - ); - - ui.add_space(10.0); - - // Use larger text for the labels - ui.label( - RichText::new( - "It looks like you are not tracking any Identities, Evonodes or Masternodes yet.", - ) - .size(20.0), - ); - - ui.add_space(30.0); - - ui.label( - RichText::new( - "* You can load an Evonode/Masternode/Identity by clicking on \"Load Identity\" on the top right of the screen.", - ) - .size(18.0), - ); - - ui.add_space(10.0); - - ui.label(RichText::new("Or").size(22.0).strong()); // Emphasized text - - ui.add_space(10.0); - - ui.label( - RichText::new( - "* You can create a wallet and then register an Identity on Dash Evo.", - ) - .size(18.0), - ); - - ui.add_space(30.0); - - ui.label( - RichText::new( - "(Make sure Dash Core is running, you can check in the settings tab on the left)", - ) - .size(18.0), - ); - }); + ui.add_space(20.0); // Add some space from the top + + // Use a larger font for the heading + ui.label( + RichText::new("Not Tracking Any Identities") + .heading() + .size(30.0), // Larger size for heading + ); + + ui.add_space(10.0); + + // Use larger text for the labels + ui.label( + RichText::new( + "It looks like you are not tracking any Identities, Evonodes or Masternodes yet.", + ) + .size(20.0), + ); + + ui.add_space(30.0); + + ui.label( + RichText::new( + "* You can load an Evonode/Masternode/Identity by clicking on \"Load Identity\" on the top right of the screen.", + ) + .size(18.0), + ); + + ui.add_space(10.0); + + ui.label(RichText::new("Or").size(22.0).strong()); // Emphasized text + + ui.add_space(10.0); + + ui.label( + RichText::new( + "* You can create a wallet and then register an Identity on Dash Evo.", + ) + .size(18.0), + ); + + ui.add_space(30.0); + + ui.label( + RichText::new( + "(Make sure Dash Core is running, you can check in the settings tab on the left)", + ) + .size(18.0), + ); + }); } - fn render_identities_view(&self, ui: &mut Ui, identities: &[QualifiedIdentity]) -> AppAction { + fn render_identities_view( + &mut self, + ui: &mut Ui, + identities: &[QualifiedIdentity], + ) -> AppAction { let mut action = AppAction::None; egui::ScrollArea::vertical().show(ui, |ui| { @@ -180,9 +192,9 @@ impl IdentitiesScreen { .cell_layout(egui::Layout::left_to_right(Align::Center)) // Define columns with resizing and alignment .column(Column::initial(40.0).resizable(true)) // Name - .column(Column::initial(200.0).resizable(true)) // Identity ID + .column(Column::initial(100.0).resizable(true)) // Identity ID .column(Column::initial(100.0).resizable(true)) // Balance - .column(Column::initial(100.0).resizable(true)) // Type + .column(Column::initial(80.0).resizable(true)) // Type .column(Column::initial(80.0).resizable(true)) // Refresh .column(Column::initial(80.0).resizable(true)) // Keys .column(Column::initial(80.0).resizable(true)) // Withdraw @@ -245,35 +257,72 @@ impl IdentitiesScreen { } }); row.col(|ui| { - for (key_id, key) in public_keys.iter() { - let holding_private_key = qualified_identity - .encrypted_private_keys - .get(&(PrivateKeyOnMainIdentity, *key_id)) - .map(|(_, p)| p); - action |= self.show_public_key( - ui, - qualified_identity, - key, - holding_private_key, - ); - } - if let Some(voting_identity_public_keys) = - voter_identity_public_keys - { - for (key_id, key) in voting_identity_public_keys.iter() - { + let mut total_keys_shown = 0; + let max_keys_to_show = 3; + let mut more_keys_available = false; + + // Show keys from main identity + let public_keys_vec: Vec<_> = public_keys.iter().collect(); + for (key_id, key) in public_keys_vec.iter() { + if total_keys_shown < max_keys_to_show { let holding_private_key = qualified_identity .encrypted_private_keys - .get(&(PrivateKeyOnVoterIdentity, *key_id)) + .get(&(PrivateKeyOnMainIdentity, **key_id)) .map(|(_, p)| p); action |= self.show_public_key( ui, qualified_identity, - key, + *key, holding_private_key, ); + total_keys_shown += 1; + } else { + more_keys_available = true; + break; + } + } + + // If we have not reached max keys, show keys from voter identity + if total_keys_shown < max_keys_to_show { + if let Some(voting_identity_public_keys) = + voter_identity_public_keys + { + let voter_public_keys_vec: Vec<_> = + voting_identity_public_keys.iter().collect(); + for (key_id, key) in voter_public_keys_vec.iter() { + if total_keys_shown < max_keys_to_show { + let holding_private_key = + qualified_identity + .encrypted_private_keys + .get(&( + PrivateKeyOnVoterIdentity, + **key_id, + )) + .map(|(_, p)| p); + action |= self.show_public_key( + ui, + qualified_identity, + *key, + holding_private_key, + ); + total_keys_shown += 1; + } else { + more_keys_available = true; + break; + } + } + } + } + + // If there are more keys, show "View More" button + if more_keys_available { + if ui.button("View More").clicked() { + self.show_more_keys_popup = Some( + qualified_identity.identity.id().to_buffer(), + ); } } + if qualified_identity.can_sign_with_master_key().is_some() && ui.button("Add Key").clicked() { @@ -313,6 +362,58 @@ impl IdentitiesScreen { action } + + fn show_more_keys(&mut self, ui: &mut Ui, qualified_identity: &QualifiedIdentity) -> AppAction { + let mut action = AppAction::None; + + // Get keys from main identity + let identity = &qualified_identity.identity; + let public_keys = identity.public_keys(); + let public_keys_vec: Vec<_> = public_keys.iter().collect(); + + // Skip the first three keys + let main_identity_rest_keys = public_keys_vec.iter().skip(3); + + ui.label(format!( + "{}...", + identity + .id() + .to_string(Encoding::Base58) + .chars() + .take(8) + .collect::() + )); + for (key_id, key) in main_identity_rest_keys { + let holding_private_key = qualified_identity + .encrypted_private_keys + .get(&(PrivateKeyOnMainIdentity, **key_id)) + .map(|(_, p)| p); + action |= self.show_public_key(ui, qualified_identity, *key, holding_private_key); + } + + // Get keys from voter identity + if let Some((voter_identity, _)) = qualified_identity.associated_voter_identity.as_ref() { + let voter_public_keys = voter_identity.public_keys(); + let voter_public_keys_vec: Vec<_> = voter_public_keys.iter().collect(); + + // Assuming we want to show all keys from voter identity + ui.label("Voter Identity Keys:"); + for (key_id, key) in voter_public_keys_vec.iter() { + let holding_private_key = qualified_identity + .encrypted_private_keys + .get(&(PrivateKeyOnVoterIdentity, **key_id)) + .map(|(_, p)| p); + action |= self.show_public_key(ui, qualified_identity, *key, holding_private_key); + } + } + + // Close button + if ui.button("Close").clicked() { + self.close_more_keys_popup = true; + } + + action + } } impl ScreenLike for IdentitiesScreen { @@ -325,28 +426,10 @@ impl ScreenLike for IdentitiesScreen { } fn ui(&mut self, ctx: &Context) -> AppAction { - let right_buttons = { - // Acquire a read lock on wallets - // let create_wallet_or_identity = if !self.app_context.has_wallet.load(Ordering::Relaxed) - // { - // ( - // "Create Wallet", - // DesiredAppAction::AddScreenType(ScreenType::AddNewWallet), - // ) - // } else { - // ( - // "Create Identity", - // DesiredAppAction::AddScreenType(ScreenType::AddNewIdentity), - // ) - // }; - vec![ - // create_wallet_or_identity, - ( - "Load Identity", - DesiredAppAction::AddScreenType(ScreenType::AddExistingIdentity), - ), - ] - }; + let right_buttons = vec![( + "Load Identity", + DesiredAppAction::AddScreenType(ScreenType::AddExistingIdentity), + )]; let mut action = add_top_panel( ctx, &self.app_context, @@ -356,7 +439,11 @@ impl ScreenLike for IdentitiesScreen { action |= add_left_panel(ctx, &self.app_context, RootScreenType::RootScreenIdentities); - let identities = self.identities.lock().unwrap(); + // Limit the scope of the MutexGuard by enclosing in a block + let identities = { + let identities_guard = self.identities.lock().unwrap(); + identities_guard.clone() + }; // Main content egui::CentralPanel::default().show(ctx, |ui| { @@ -367,6 +454,35 @@ impl ScreenLike for IdentitiesScreen { } }); + // Check if we need to show the pop-up + if let Some(identity_id) = self.show_more_keys_popup { + // Fetch the latest QualifiedIdentity + let qualified_identity = { + let identities_guard = self.identities.lock().unwrap(); + identities_guard + .iter() + .find(|qi| qi.identity.id().to_buffer() == identity_id) + .cloned() + }; + + if let Some(qualified_identity) = qualified_identity { + egui::Window::new("More Keys") + .collapsible(false) + .show(ctx, |ui| { + action |= self.show_more_keys(ui, &qualified_identity); + }); + } else { + // If identity not found, close the pop-up + self.show_more_keys_popup = None; + } + + // Close the pop-up if the flag is set + if self.close_more_keys_popup { + self.show_more_keys_popup = None; + self.close_more_keys_popup = false; + } + } + action } } @@ -381,6 +497,8 @@ impl IdentitiesScreen { Self { identities, app_context: app_context.clone(), + show_more_keys_popup: None, + close_more_keys_popup: false, } } } From 7ff839d8fd87a07362ca358c20e2764d91bcd924 Mon Sep 17 00:00:00 2001 From: pauldelucia Date: Tue, 29 Oct 2024 15:53:42 +0700 Subject: [PATCH 2/7] close pop-up on screen refresh --- src/ui/identities/identities_screen.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/identities/identities_screen.rs b/src/ui/identities/identities_screen.rs index 315f768a4..7a8d05914 100644 --- a/src/ui/identities/identities_screen.rs +++ b/src/ui/identities/identities_screen.rs @@ -423,6 +423,10 @@ impl ScreenLike for IdentitiesScreen { .app_context .load_local_qualified_identities() .unwrap_or_default(); + + // Reset the pop-up state when refreshing + self.show_more_keys_popup = None; + self.close_more_keys_popup = false; } fn ui(&mut self, ctx: &Context) -> AppAction { From 9a24018fa14dab2b3774e4676df3f879cd631f45 Mon Sep 17 00:00:00 2001 From: pauldelucia Date: Tue, 29 Oct 2024 15:54:53 +0700 Subject: [PATCH 3/7] fix: remove clone implementation for identities screen --- src/ui/identities/identities_screen.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/identities/identities_screen.rs b/src/ui/identities/identities_screen.rs index 7a8d05914..a32b61889 100644 --- a/src/ui/identities/identities_screen.rs +++ b/src/ui/identities/identities_screen.rs @@ -23,7 +23,6 @@ use egui::{Color32, Frame, Margin, RichText, Ui}; use egui_extras::{Column, TableBuilder}; use std::sync::{Arc, Mutex}; -#[derive(Clone)] pub struct IdentitiesScreen { pub identities: Arc>>, pub app_context: Arc, From 2d7d29938e258960083e506da9b5848f6f51beba Mon Sep 17 00:00:00 2001 From: pauldelucia Date: Tue, 29 Oct 2024 15:58:02 +0700 Subject: [PATCH 4/7] fixes --- src/ui/identities/identities_screen.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ui/identities/identities_screen.rs b/src/ui/identities/identities_screen.rs index a32b61889..36ffe049e 100644 --- a/src/ui/identities/identities_screen.rs +++ b/src/ui/identities/identities_screen.rs @@ -26,8 +26,8 @@ use std::sync::{Arc, Mutex}; pub struct IdentitiesScreen { pub identities: Arc>>, pub app_context: Arc, - show_more_keys_popup: Option<[u8; 32]>, // Store identity ID instead of QualifiedIdentity - close_more_keys_popup: bool, // Flag to close the pop-up + show_more_keys_popup: Option<[u8; 32]>, + close_more_keys_popup: bool, } impl IdentitiesScreen { @@ -423,7 +423,6 @@ impl ScreenLike for IdentitiesScreen { .load_local_qualified_identities() .unwrap_or_default(); - // Reset the pop-up state when refreshing self.show_more_keys_popup = None; self.close_more_keys_popup = false; } From 30d0ac6692056a813a30bf5cfa6fe797a977737f Mon Sep 17 00:00:00 2001 From: pauldelucia Date: Tue, 29 Oct 2024 16:55:08 +0700 Subject: [PATCH 5/7] put back commented out functionality --- src/ui/identities/identities_screen.rs | 53 ++++++++++++++++---------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/ui/identities/identities_screen.rs b/src/ui/identities/identities_screen.rs index 36ffe049e..b77f72fc2 100644 --- a/src/ui/identities/identities_screen.rs +++ b/src/ui/identities/identities_screen.rs @@ -31,6 +31,20 @@ pub struct IdentitiesScreen { } impl IdentitiesScreen { + pub fn new(app_context: &Arc) -> Self { + let identities = Arc::new(Mutex::new( + app_context + .load_local_qualified_identities() + .unwrap_or_default(), + )); + Self { + identities, + app_context: app_context.clone(), + show_more_keys_popup: None, + close_more_keys_popup: false, + } + } + fn show_alias(ui: &mut Ui, qualified_identity: &QualifiedIdentity) { if let Some(alias) = qualified_identity.alias.as_ref() { ui.label(alias.clone()); @@ -428,10 +442,25 @@ impl ScreenLike for IdentitiesScreen { } fn ui(&mut self, ctx: &Context) -> AppAction { - let right_buttons = vec![( - "Load Identity", - DesiredAppAction::AddScreenType(ScreenType::AddExistingIdentity), - )]; + let right_buttons = { + // Acquire a read lock on wallets + // let create_wallet_or_identity = if !self.app_context.has_wallet.load(Ordering::Relaxed) + // { + // ( + // "Create Wallet", + // DesiredAppAction::AddScreenType(ScreenType::AddNewWallet), + // ) + // } else { + // ( + // "Create Identity", + // DesiredAppAction::AddScreenType(ScreenType::AddNewIdentity), + // ) + // }; + vec![( + "Load Identity", + DesiredAppAction::AddScreenType(ScreenType::AddExistingIdentity), + )] + }; let mut action = add_top_panel( ctx, &self.app_context, @@ -488,19 +517,3 @@ impl ScreenLike for IdentitiesScreen { action } } - -impl IdentitiesScreen { - pub fn new(app_context: &Arc) -> Self { - let identities = Arc::new(Mutex::new( - app_context - .load_local_qualified_identities() - .unwrap_or_default(), - )); - Self { - identities, - app_context: app_context.clone(), - show_more_keys_popup: None, - close_more_keys_popup: false, - } - } -} From a6b460391574733e780bca73dd7eaad295498390 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 29 Oct 2024 17:02:44 +0700 Subject: [PATCH 6/7] cleanup --- src/ui/identities/identities_screen.rs | 49 ++++++++------------------ src/ui/withdraws_status_screen.rs | 14 +++++--- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/src/ui/identities/identities_screen.rs b/src/ui/identities/identities_screen.rs index 36ffe049e..2e3ff7c9a 100644 --- a/src/ui/identities/identities_screen.rs +++ b/src/ui/identities/identities_screen.rs @@ -26,8 +26,7 @@ use std::sync::{Arc, Mutex}; pub struct IdentitiesScreen { pub identities: Arc>>, pub app_context: Arc, - show_more_keys_popup: Option<[u8; 32]>, - close_more_keys_popup: bool, + pub show_more_keys_popup: Option, } impl IdentitiesScreen { @@ -316,9 +315,8 @@ impl IdentitiesScreen { // If there are more keys, show "View More" button if more_keys_available { if ui.button("View More").clicked() { - self.show_more_keys_popup = Some( - qualified_identity.identity.id().to_buffer(), - ); + self.show_more_keys_popup = + Some(qualified_identity.clone()); } } @@ -362,8 +360,11 @@ impl IdentitiesScreen { action } - fn show_more_keys(&mut self, ui: &mut Ui, qualified_identity: &QualifiedIdentity) -> AppAction { + fn show_more_keys(&mut self, ui: &mut Ui) -> AppAction { let mut action = AppAction::None; + let Some(qualified_identity) = self.show_more_keys_popup.as_ref() else { + return action; + }; // Get keys from main identity let identity = &qualified_identity.identity; @@ -408,7 +409,7 @@ impl IdentitiesScreen { // Close button if ui.button("Close").clicked() { - self.close_more_keys_popup = true; + self.show_more_keys_popup = None; } action @@ -424,7 +425,6 @@ impl ScreenLike for IdentitiesScreen { .unwrap_or_default(); self.show_more_keys_popup = None; - self.close_more_keys_popup = false; } fn ui(&mut self, ctx: &Context) -> AppAction { @@ -457,32 +457,12 @@ impl ScreenLike for IdentitiesScreen { }); // Check if we need to show the pop-up - if let Some(identity_id) = self.show_more_keys_popup { - // Fetch the latest QualifiedIdentity - let qualified_identity = { - let identities_guard = self.identities.lock().unwrap(); - identities_guard - .iter() - .find(|qi| qi.identity.id().to_buffer() == identity_id) - .cloned() - }; - - if let Some(qualified_identity) = qualified_identity { - egui::Window::new("More Keys") - .collapsible(false) - .show(ctx, |ui| { - action |= self.show_more_keys(ui, &qualified_identity); - }); - } else { - // If identity not found, close the pop-up - self.show_more_keys_popup = None; - } - - // Close the pop-up if the flag is set - if self.close_more_keys_popup { - self.show_more_keys_popup = None; - self.close_more_keys_popup = false; - } + if self.show_more_keys_popup.is_some() { + egui::Window::new("More Keys") + .collapsible(false) + .show(ctx, |ui| { + action |= self.show_more_keys(ui); + }); } action @@ -500,7 +480,6 @@ impl IdentitiesScreen { identities, app_context: app_context.clone(), show_more_keys_popup: None, - close_more_keys_popup: false, } } } diff --git a/src/ui/withdraws_status_screen.rs b/src/ui/withdraws_status_screen.rs index 4ba13b5a0..a5f0f366c 100644 --- a/src/ui/withdraws_status_screen.rs +++ b/src/ui/withdraws_status_screen.rs @@ -215,12 +215,18 @@ impl WithdrawsStatusScreen { if selected != old_selected { self.pagination_items_per_page.set(selected); } - println!("computing with:{}", self.pagination_items_per_page.get() as usize); - let total_pages = (data.withdrawals.len() + (self.pagination_items_per_page.get() as usize) - 1) / (self.pagination_items_per_page.get() as usize); + println!( + "computing with:{}", + self.pagination_items_per_page.get() as usize + ); + let total_pages = + (data.withdrawals.len() + (self.pagination_items_per_page.get() as usize) - 1) + / (self.pagination_items_per_page.get() as usize); let mut current_page = self.pagination_current_page.get().min(total_pages - 1); // Clamp to valid page range - // Calculate the slice of data for the current page + // Calculate the slice of data for the current page let start_index = current_page * (self.pagination_items_per_page.get() as usize); - let end_index = (start_index + (self.pagination_items_per_page.get() as usize)).min(data.withdrawals.len()); + let end_index = (start_index + (self.pagination_items_per_page.get() as usize)) + .min(data.withdrawals.len()); ui.separator(); TableBuilder::new(ui) .striped(true) From 63ffa5d2e067913b816a1a8678d2316240706623 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 29 Oct 2024 17:04:58 +0700 Subject: [PATCH 7/7] fmt --- src/ui/identities/identities_screen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/identities/identities_screen.rs b/src/ui/identities/identities_screen.rs index 187683bd3..429550e06 100644 --- a/src/ui/identities/identities_screen.rs +++ b/src/ui/identities/identities_screen.rs @@ -495,4 +495,4 @@ impl ScreenLike for IdentitiesScreen { action } -} \ No newline at end of file +}