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

View file

@ -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

View file

@ -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: Кошелёк

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,

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,

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);
});
}
}

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);
});
}
}

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)
}

View file

@ -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());
}
}

View file

@ -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)
}
}