wallet + ui: delete wallet, show recovery phrase, update translations
This commit is contained in:
parent
09d3835082
commit
48630fc6be
9 changed files with 294 additions and 140 deletions
|
@ -7,6 +7,7 @@ retry: Retry
|
|||
close: Close
|
||||
change: Change
|
||||
show: Show
|
||||
delete: Delete
|
||||
wallets:
|
||||
title: Wallets
|
||||
create_desc: Create or import existing wallet from saved recovery phrase.
|
||||
|
@ -51,7 +52,7 @@ wallets:
|
|||
repair_desc: Check a wallet, repairing and restoring missing outputs if required. This operation will take time.
|
||||
repair_unavailable: You need an active connection to the node and completed wallet synchronization.
|
||||
delete: Delete wallet
|
||||
delete_conf: 'Are you sure you want to remove the wallet? Enter password to confirm:'
|
||||
delete_conf: Are you sure you want to delete the wallet?
|
||||
delete_desc: Make sure you have saved your recovery phrase to access funds in the future.
|
||||
wallet_loading_err: 'An error occurred during synchronization of the wallet, you can retry or change connection settings by selecting %{settings} at the bottom of the screen.'
|
||||
wallet: Wallet
|
||||
|
|
|
@ -7,6 +7,7 @@ retry: Повторить
|
|||
close: Закрыть
|
||||
change: Изменить
|
||||
show: Показать
|
||||
delete: Удалить
|
||||
wallets:
|
||||
title: Кошельки
|
||||
create_desc: Создайте или импортируйте существующий кошелёк из сохранённой фразы восстановления.
|
||||
|
@ -51,7 +52,7 @@ wallets:
|
|||
repair_desc: Проверить кошелёк, исправляя и восстанавливая недостающие выходы, если это необходимо. Эта операция займёт время.
|
||||
repair_unavailable: Необходимо активное подключение к узлу и завершённая синхронизация кошелька.
|
||||
delete: Удалить кошелёк
|
||||
delete_conf: 'Вы уверены, что хотите удалить кошелек? Введите пароль для подтверждения:'
|
||||
delete_conf: Вы уверены, что хотите удалить кошелек?
|
||||
delete_desc: Убедитесь, что вы сохранили вашу фразу восстановления, чтобы получить доступ к средствам в будущем.
|
||||
wallet_loading_err: 'Во время синхронизации кошелька произошла ошибка, вы можете повторить попытку или изменить настройки подключения, выбрав %{settings} внизу экрана.'
|
||||
wallet: Кошелёк
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -66,26 +66,40 @@ impl WalletList {
|
|||
|
||||
/// Get [`Wallet`] list for current [`ChainTypes`].
|
||||
pub fn list(&self) -> &Vec<Wallet> {
|
||||
let chain_type = AppConfig::chain_type();
|
||||
if chain_type == ChainTypes::Mainnet {
|
||||
if AppConfig::chain_type() == ChainTypes::Mainnet {
|
||||
&self.main_list
|
||||
} else {
|
||||
&self.test_list
|
||||
}
|
||||
}
|
||||
|
||||
/// Add created [`Wallet`] to the list.
|
||||
pub fn add(&mut self, wallet: Wallet) {
|
||||
self.selected_id = Some(wallet.config.id);
|
||||
let chain_type = AppConfig::chain_type();
|
||||
let list = if chain_type == ChainTypes::Mainnet {
|
||||
/// Get mutable [`Wallet`] list for current [`ChainTypes`].
|
||||
pub fn mut_list(&mut self) -> &mut Vec<Wallet> {
|
||||
if AppConfig::chain_type() == ChainTypes::Mainnet {
|
||||
&mut self.main_list
|
||||
} else {
|
||||
&mut self.test_list
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Add created [`Wallet`] to the list.
|
||||
pub fn add(&mut self, wallet: Wallet) {
|
||||
self.selected_id = Some(wallet.config.id);
|
||||
let list = self.mut_list();
|
||||
list.insert(0, wallet);
|
||||
}
|
||||
|
||||
/// Remove [`Wallet`] with provided identifier.
|
||||
pub fn remove(&mut self, id: i64) {
|
||||
let list = self.mut_list();
|
||||
for (index, wallet) in list.iter().enumerate() {
|
||||
if wallet.config.id == id {
|
||||
list.remove(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Select [`Wallet`] with provided identifier.
|
||||
pub fn select(&mut self, id: Option<i64>) {
|
||||
self.selected_id = id;
|
||||
|
@ -118,14 +132,9 @@ impl WalletList {
|
|||
|
||||
/// Open selected [`Wallet`].
|
||||
pub fn open_selected(&mut self, password: String) -> Result<(), Error> {
|
||||
let chain_type = AppConfig::chain_type();
|
||||
let list = if chain_type == ChainTypes::Mainnet {
|
||||
&mut self.main_list
|
||||
} else {
|
||||
&mut self.test_list
|
||||
};
|
||||
for w in list {
|
||||
if Some(w.config.id) == self.selected_id {
|
||||
let selected_id = self.selected_id.clone();
|
||||
for w in self.mut_list() {
|
||||
if Some(w.config.id) == selected_id {
|
||||
return w.open(password.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{fs, thread};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, mpsc, RwLock};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||
use std::thread;
|
||||
use std::thread::Thread;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -53,6 +53,8 @@ pub struct Wallet {
|
|||
is_open: Arc<AtomicBool>,
|
||||
/// Flag to check if wallet is loading.
|
||||
closing: Arc<AtomicBool>,
|
||||
/// Flag to check if wallet was deleted to remove it from list.
|
||||
deleted: Arc<AtomicBool>,
|
||||
|
||||
/// Error on wallet loading.
|
||||
sync_error: Arc<AtomicBool>,
|
||||
|
@ -83,6 +85,7 @@ impl Wallet {
|
|||
reopen: Arc::new(AtomicBool::new(false)),
|
||||
is_open: Arc::from(AtomicBool::new(false)),
|
||||
closing: Arc::new(AtomicBool::new(false)),
|
||||
deleted: Arc::new(AtomicBool::new(false)),
|
||||
sync_error: Arc::from(AtomicBool::new(false)),
|
||||
info_sync_progress: Arc::from(AtomicU8::new(0)),
|
||||
txs_sync_progress: Arc::from(AtomicU8::new(0)),
|
||||
|
@ -183,8 +186,8 @@ impl Wallet {
|
|||
return Err(Error::GenericError("Already opened".to_string()));
|
||||
}
|
||||
|
||||
// Create new wallet instance if sync thread was stopped.
|
||||
if self.sync_thread.write().unwrap().is_none() {
|
||||
// Create new wallet instance if sync thread was stopped or instance was not created.
|
||||
if self.sync_thread.write().unwrap().is_none() || self.instance.is_none() {
|
||||
let new_instance = Self::create_wallet_instance(self.config.clone())?;
|
||||
self.instance = Some(new_instance);
|
||||
self.instance_ext_conn_id = self.config.ext_conn_id;
|
||||
|
@ -248,15 +251,11 @@ impl Wallet {
|
|||
self.closing.store(true, Ordering::Relaxed);
|
||||
|
||||
// Close wallet at separate thread.
|
||||
let mut wallet_close = self.clone();
|
||||
let wallet_close = self.clone();
|
||||
let instance = wallet_close.instance.clone().unwrap();
|
||||
thread::spawn(move || {
|
||||
// Close the wallet.
|
||||
{
|
||||
let mut wallet_lock = instance.lock();
|
||||
let lc = wallet_lock.lc_provider().unwrap();
|
||||
let _ = lc.close_wallet(None);
|
||||
}
|
||||
Self::close_wallet(&instance);
|
||||
|
||||
// Mark wallet as not opened.
|
||||
wallet_close.closing.store(false, Ordering::Relaxed);
|
||||
|
@ -270,6 +269,13 @@ impl Wallet {
|
|||
});
|
||||
}
|
||||
|
||||
/// Close wallet for provided [`WalletInstance`].
|
||||
fn close_wallet(instance: &WalletInstance) {
|
||||
let mut wallet_lock = instance.lock();
|
||||
let lc = wallet_lock.lc_provider().unwrap();
|
||||
let _ = lc.close_wallet(None);
|
||||
}
|
||||
|
||||
/// Set wallet reopen status.
|
||||
pub fn set_reopen(&self, reopen: bool) {
|
||||
self.reopen.store(reopen, Ordering::Relaxed);
|
||||
|
@ -356,8 +362,50 @@ impl Wallet {
|
|||
self.repair_progress.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn delete_wallet(&self) {
|
||||
/// Get recovery phrase.
|
||||
pub fn get_recovery(&self, password: String) -> Result<ZeroingString, Error> {
|
||||
let instance = self.instance.clone().unwrap();
|
||||
let mut wallet_lock = instance.lock();
|
||||
let lc = wallet_lock.lc_provider().unwrap();
|
||||
lc.get_mnemonic(None, ZeroingString::from(password))
|
||||
}
|
||||
|
||||
/// Close the wallet, delete its files and mark it as deleted.
|
||||
pub fn delete_wallet(&self) {
|
||||
if !self.is_open() || self.instance.is_none() {
|
||||
return;
|
||||
}
|
||||
self.closing.store(true, Ordering::Relaxed);
|
||||
|
||||
// Delete wallet at separate thread.
|
||||
let wallet_delete = self.clone();
|
||||
thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
if let Some(instance) = wallet_delete.instance {
|
||||
// Close the wallet.
|
||||
Self::close_wallet(&instance);
|
||||
// Remove wallet files.
|
||||
let mut wallet_lock = instance.lock();
|
||||
let _ = wallet_lock.lc_provider().unwrap();
|
||||
let _ = fs::remove_dir_all(wallet_delete.config.get_data_path());
|
||||
}
|
||||
|
||||
// Mark wallet as not opened and deleted.
|
||||
wallet_delete.closing.store(false, Ordering::Relaxed);
|
||||
wallet_delete.is_open.store(false, Ordering::Relaxed);
|
||||
wallet_delete.deleted.store(true, Ordering::Relaxed);
|
||||
|
||||
// Wake up wallet thread.
|
||||
let thread_r = wallet_delete.sync_thread.read().unwrap();
|
||||
if let Some(thread) = thread_r.as_ref() {
|
||||
thread.unpark();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Check if wallet was deleted to remove it from list.
|
||||
pub fn is_deleted(&self) -> bool {
|
||||
self.deleted.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue