wallet + ui: delete wallet, show recovery phrase, update translations

This commit is contained in:
ardocrat
2023-08-14 03:17:54 +03:00
parent 09d3835082
commit 48630fc6be
9 changed files with 294 additions and 140 deletions
+8 -11
View File
@@ -14,7 +14,6 @@
use egui::{Align, Align2, Layout, Margin, RichText, Rounding, ScrollArea, TextStyle, Widget};
use egui_extras::{Size, StripBuilder};
use grin_core::global::ChainTypes;
use crate::AppConfig;
use crate::gui::Colors;
@@ -142,15 +141,11 @@ impl WalletsContent {
self.wallets.add(wallet);
});
} else {
let chain_type = AppConfig::chain_type();
let list = if chain_type == ChainTypes::Mainnet {
&mut self.wallets.main_list
} else {
&mut self.wallets.test_list
};
for wallet in list.iter_mut() {
let selected_id = self.wallets.selected_id.clone();
let list = self.wallets.mut_list();
for wallet in list {
// Show content for selected wallet.
if self.wallets.selected_id == Some(wallet.config.id) {
if selected_id == Some(wallet.config.id) {
// Setup wallet content width.
let mut rect = ui.available_rect_before_wrap();
let mut width = ui.available_width();
@@ -348,7 +343,9 @@ impl WalletsContent {
rect.set_width(width);
ui.allocate_ui(rect.size(), |ui| {
let list = self.wallets.list().clone();
let mut list = self.wallets.list().clone();
// Remove deleted wallet from the list.
list.retain(|w| !w.is_deleted());
for wallet in &list {
// Check if wallet reopen is needed.
if !wallet.is_open() && wallet.reopen_needed() {
@@ -479,7 +476,7 @@ impl WalletsContent {
} else {
let tx_progress = wallet.txs_sync_progress();
if tx_progress == 0 {
t!("wallets.tx_loading")
format!("{} {}", SPINNER, t!("wallets.tx_loading"))
} else {
format!("{} {}: {}%",
SPINNER,
+2 -2
View File
@@ -71,7 +71,7 @@ impl CommonSetup {
_: &mut eframe::Frame,
wallet: &mut Wallet,
cb: &dyn PlatformCallbacks) {
// Draw modal content for this ui container.
// Show modal content for this ui container.
self.modal_content_ui(ui, wallet, cb);
ui.vertical_centered(|ui| {
@@ -142,7 +142,7 @@ impl CommonSetup {
});
}
/// Draw modal content for current ui container.
/// Draw [`Modal`] content for this ui container.
fn modal_content_ui(&mut self,
ui: &mut egui::Ui,
wallet: &mut Wallet,
+30 -55
View File
@@ -38,9 +38,6 @@ pub struct ConnectionSetup {
/// Flag to show URL format error.
ext_node_url_error: bool,
/// Flag to show closing progress at confirmation [`Modal`] to reopen the [`Wallet`].
show_closing_progress: bool,
/// [`Modal`] identifiers allowed at this ui container.
modal_ids: Vec<&'static str>
}
@@ -59,7 +56,6 @@ impl Default for ConnectionSetup {
ext_node_url_edit: "".to_string(),
ext_node_secret_edit: "".to_string(),
ext_node_url_error: false,
show_closing_progress: false,
modal_ids: vec![
ADD_EXT_CONNECTION_MODAL
]
@@ -135,7 +131,11 @@ impl ConnectionSetup {
if changed {
wallet.config.save();
self.show_reopen_confirmation_modal();
// Show reopen confirmation modal.
Modal::new(REOPEN_WALLET_CONFIRMATION_MODAL)
.position(ModalPosition::Center)
.title(t!("modal.confirmation"))
.show();
}
}
@@ -423,66 +423,41 @@ impl ConnectionSetup {
});
}
/// Show confirmation modal to reopen the [`Wallet`] after connection change.
fn show_reopen_confirmation_modal(&mut self,) {
self.show_closing_progress = false;
// Show modal.
Modal::new(REOPEN_WALLET_CONFIRMATION_MODAL)
.title(t!("modal.confirmation"))
.show();
}
/// Draw confirmation modal content to reopen the [`Wallet`].
fn reopen_modal_content(&mut self,
ui: &mut egui::Ui,
wallet: &Wallet,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
if self.show_closing_progress {
if !wallet.is_closing() {
modal.close();
return;
}
ui.add_space(16.0);
ui.vertical_centered(|ui| {
View::small_loading_spinner(ui);
ui.add_space(12.0);
ui.label(RichText::new(t!("wallets.wallet_closing"))
.size(17.0)
.color(Colors::TEXT));
});
ui.add_space(10.0);
} else {
ui.add_space(8.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("wallets.change_server_confirmation"))
.size(17.0)
.color(Colors::TEXT));
});
ui.add_space(10.0);
ui.add_space(8.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("wallets.change_server_confirmation"))
.size(17.0)
.color(Colors::TEXT));
});
ui.add_space(10.0);
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, "OK".to_owned(), Colors::WHITE, || {
modal.disable_closing();
self.show_closing_progress = true;
wallet.set_reopen(true);
wallet.close();
});
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, "OK".to_owned(), Colors::WHITE, || {
modal.disable_closing();
wallet.set_reopen(true);
wallet.close();
modal.close()
});
});
ui.add_space(6.0);
});
}
ui.add_space(6.0);
});
}
}
+165 -42
View File
@@ -12,10 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use egui::RichText;
use egui::{Align, Id, Layout, RichText, TextStyle, Widget};
use grin_chain::SyncStatus;
use grin_util::ZeroingString;
use crate::gui::Colors;
use crate::gui::icons::{EYE, STETHOSCOPE, TRASH, WRENCH};
use crate::gui::icons::{EYE, EYE_SLASH, STETHOSCOPE, TRASH, WRENCH};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, View};
use crate::gui::views::types::ModalPosition;
@@ -28,8 +30,11 @@ pub struct RecoverySetup {
pass_edit: String,
/// Flag to check if wrong password was entered.
wrong_pass: bool,
/// Flag to show recovery phrase when password check was passed.
show_recovery_phrase: bool,
/// Flag to show/hide old password at [`egui::TextEdit`] field.
hide_pass: bool,
/// Recovery phrase value.
recovery_phrase: Option<ZeroingString>,
}
/// Identifier for recovery phrase [`Modal`].
@@ -41,8 +46,9 @@ impl Default for RecoverySetup {
fn default() -> Self {
Self {
wrong_pass: false,
hide_pass: false,
pass_edit: "".to_string(),
show_recovery_phrase: false,
recovery_phrase: None,
}
}
}
@@ -53,7 +59,7 @@ impl RecoverySetup {
_: &mut eframe::Frame,
wallet: &mut Wallet,
cb: &dyn PlatformCallbacks) {
// Draw modal content for this ui container.
// Show modal content for this ui container.
self.modal_content_ui(ui, wallet, cb);
ui.add_space(10.0);
@@ -66,17 +72,12 @@ impl RecoverySetup {
ui.vertical_centered(|ui| {
let integrated_node = wallet.get_current_ext_conn_id().is_none();
let integrated_node_ready = Node::get_sync_status() == Some(SyncStatus::NoSync);
if wallet.sync_error() || (integrated_node && !integrated_node_ready) {
ui.add_space(8.0);
ui.add_space(6.0);
ui.label(RichText::new(t!("wallets.repair_unavailable"))
.size(16.0)
.color(Colors::RED));
} else if wallet.is_repairing() {
ui.add_space(8.0);
View::small_loading_spinner(ui);
ui.add_space(1.0);
} else {
} else if !wallet.is_repairing() {
ui.add_space(6.0);
// Draw button to repair the wallet.
let repair_text = format!("{} {}", STETHOSCOPE, t!("wallets.repair_wallet"));
@@ -94,49 +95,35 @@ impl RecoverySetup {
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
let recovery_phrase_text = format!("{}:", t!("wallets.recovery_phrase"));
ui.label(RichText::new(recovery_phrase_text).size(16.0).color(Colors::GRAY));
let recovery_text = format!("{}:", t!("wallets.recovery_phrase"));
ui.label(RichText::new(recovery_text).size(16.0).color(Colors::GRAY));
ui.add_space(6.0);
// Draw button to show recovery phrase.
let repair_text = format!("{} {}", EYE, t!("show"));
View::button(ui, repair_text, Colors::BUTTON, || {
// Setup modal values.
self.pass_edit = "".to_string();
self.wrong_pass = false;
self.show_recovery_phrase = false;
// Show recovery phrase modal.
Modal::new(RECOVERY_PHRASE_MODAL)
.position(ModalPosition::CenterTop)
.title(t!("wallets.recovery_phrase"))
.show();
cb.show_keyboard();
let show_text = format!("{} {}", EYE, t!("show"));
View::button(ui, show_text, Colors::BUTTON, || {
self.show_recovery_phrase_modal(cb);
});
ui.add_space(12.0);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
ui.label(RichText::new(t!("wallets.delete_desc")).size(16.0).color(Colors::GRAY));
ui.label(RichText::new(t!("wallets.delete_desc")).size(16.0).color(Colors::TEXT));
ui.add_space(6.0);
// Draw button to delete the wallet.
let delete_text = format!("{} {}", TRASH, t!("wallets.delete"));
View::button(ui, delete_text, Colors::GOLD, || {
// Setup modal values.
self.pass_edit = "".to_string();
self.wrong_pass = false;
// Show wallet deletion confirmation modal.
Modal::new(DELETE_CONFIRMATION_MODAL)
.position(ModalPosition::CenterTop)
.position(ModalPosition::Center)
.title(t!("modal.confirmation"))
.show();
cb.show_keyboard();
});
ui.add_space(8.0);
});
}
/// Draw modal content for current ui container.
/// Draw [`Modal`] content for this ui container.
fn modal_content_ui(&mut self,
ui: &mut egui::Ui,
wallet: &mut Wallet,
@@ -152,7 +139,7 @@ impl RecoverySetup {
}
DELETE_CONFIRMATION_MODAL => {
Modal::ui(ui.ctx(), |ui, modal| {
self.delete_confirmation_modal_ui(ui, wallet, modal, cb);
self.deletion_modal_ui(ui, wallet, modal, cb);
});
}
_ => {}
@@ -161,21 +148,157 @@ impl RecoverySetup {
}
}
/// Show recovery phrase [`Modal`].
fn show_recovery_phrase_modal(&mut self, cb: &dyn PlatformCallbacks) {
// Setup modal values.
self.pass_edit = "".to_string();
self.wrong_pass = false;
self.hide_pass = true;
self.recovery_phrase = None;
// Show recovery phrase modal.
Modal::new(RECOVERY_PHRASE_MODAL)
.position(ModalPosition::CenterTop)
.title(t!("wallets.recovery_phrase"))
.show();
cb.show_keyboard();
}
/// Draw recovery phrase [`Modal`] content.
fn recovery_phrase_modal_ui(&mut self,
ui: &mut egui::Ui,
wallet: &mut Wallet,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
ui.add_space(6.0);
if self.recovery_phrase.is_some() {
ui.vertical_centered(|ui| {
ui.label(RichText::new(self.recovery_phrase.clone().unwrap().to_string())
.size(17.0)
.color(Colors::BLACK));
});
ui.add_space(6.0);
ui.vertical_centered_justified(|ui| {
View::button(ui, t!("close"), Colors::WHITE, || {
self.recovery_phrase = None;
modal.close();
});
});
} else {
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("wallets.pass"))
.size(17.0)
.color(Colors::GRAY));
ui.add_space(6.0);
});
let mut rect = ui.available_rect_before_wrap();
rect.set_height(34.0);
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
// Draw button to show/hide current password.
let eye_icon = if self.hide_pass { EYE } else { EYE_SLASH };
View::button(ui, eye_icon.to_string(), Colors::WHITE, || {
self.hide_pass = !self.hide_pass;
});
let layout_size = ui.available_size();
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
// Draw current wallet password text edit.
let pass_resp = egui::TextEdit::singleline(&mut self.pass_edit)
.id(Id::from(modal.id).with(wallet.config.id).with("recovery_phrase"))
.font(TextStyle::Heading)
.desired_width(ui.available_width())
.cursor_at_end(true)
.password(self.hide_pass)
.ui(ui);
if pass_resp.clicked() {
cb.show_keyboard();
}
pass_resp.request_focus();
});
});
// Show information when password is empty.
ui.vertical_centered(|ui| {
if self.pass_edit.is_empty() {
ui.add_space(8.0);
ui.label(RichText::new(t!("wallets.pass_empty"))
.size(17.0)
.color(Colors::INACTIVE_TEXT));
} else if self.wrong_pass {
ui.add_space(8.0);
ui.label(RichText::new(t!("wallets.wrong_pass"))
.size(17.0)
.color(Colors::RED));
}
ui.add_space(10.0);
});
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
self.recovery_phrase = None;
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, "OK".to_owned(), Colors::WHITE, || {
match wallet.get_recovery(self.pass_edit.clone()) {
Ok(phrase) => {
self.wrong_pass = false;
self.recovery_phrase = Some(phrase);
cb.hide_keyboard();
}
Err(_) => {
self.wrong_pass = true;
}
}
});
});
});
});
}
ui.add_space(6.0);
}
/// Draw recovery phrase [`Modal`] content.
fn delete_confirmation_modal_ui(&mut self,
ui: &mut egui::Ui,
wallet: &mut Wallet,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
/// Draw wallet deletion [`Modal`] content.
fn deletion_modal_ui(&mut self,
ui: &mut egui::Ui,
wallet: &mut Wallet,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
ui.add_space(8.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("wallets.delete_conf"))
.size(17.0)
.color(Colors::TEXT));
});
ui.add_space(10.0);
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("delete"), Colors::WHITE, || {
modal.disable_closing();
wallet.set_reopen(true);
wallet.delete_wallet();
});
});
});
ui.add_space(6.0);
});
}
}
+2 -2
View File
@@ -198,8 +198,8 @@ impl WalletContent {
let integrated_node = wallet.get_current_ext_conn_id().is_none();
let integrated_node_ready = Node::get_sync_status() == Some(SyncStatus::NoSync);
let sync_after_opening = wallet.get_data().is_none() && !wallet.sync_error();
// Block navigation if wallet is repairing and integrated node is not launching,
// or wallet is closing or syncing after opening when there is no data to show.
// Block navigation if wallet is repairing and integrated node is not launching
// and if wallet is closing or syncing after opening when there is no data to show.
(wallet.is_repairing() && (integrated_node_ready || !integrated_node) && !sync_error)
|| wallet.is_closing() || (sync_after_opening && !integrated_node)
}