wallet + ui: optimize loading, retry button for non-success loading, update translations

This commit is contained in:
ardocrat 2023-08-09 20:11:44 +03:00
parent 3c14f72c24
commit ab83d7c95c
6 changed files with 191 additions and 119 deletions

View file

@ -2,6 +2,9 @@ copy: Copy
paste: Paste paste: Paste
continue: Continue continue: Continue
complete: Complete complete: Complete
loading: Loading
loading_error: Loading error
retry: Retry
wallets: wallets:
title: Wallets title: Wallets
create_desc: Create or import existing wallet from saved recovery phrase. create_desc: Create or import existing wallet from saved recovery phrase.
@ -31,7 +34,7 @@ wallets:
unlocked: Unlocked unlocked: Unlocked
enable_node: 'Enable integrated node to use the wallet or change connection settings by selecting %{settings} at the bottom of the screen.' enable_node: 'Enable integrated node to use the wallet or change connection settings by selecting %{settings} at the bottom of the screen.'
wallet_loading: 'Wallet is loading' wallet_loading: 'Wallet is loading'
wallet_loading_err: 'An error occurred during loading the wallet, you can change connection settings by selecting %{settings} at the bottom of the screen.' wallet_loading_err: 'An error occurred during loading the wallet, you can retry or change connection settings by selecting %{settings} at the bottom of the screen.'
wallet: Wallet wallet: Wallet
send: Send send: Send
receive: Receive receive: Receive

View file

@ -2,6 +2,9 @@ copy: Копировать
paste: Вставить paste: Вставить
continue: Продолжить continue: Продолжить
complete: Завершить complete: Завершить
loading: Загружается
loading_error: Ошибка загрузки
retry: Повторить
wallets: wallets:
title: Кошельки title: Кошельки
create_desc: Создайте или импортируйте существующий кошелёк из сохранённой фразы восстановления. create_desc: Создайте или импортируйте существующий кошелёк из сохранённой фразы восстановления.
@ -31,7 +34,7 @@ wallets:
unlocked: Разблокирован unlocked: Разблокирован
enable_node: 'Чтобы использовать кошелёк, включите встроенный узел или измените настройки подключения, выбрав %{settings} внизу экрана.' enable_node: 'Чтобы использовать кошелёк, включите встроенный узел или измените настройки подключения, выбрав %{settings} внизу экрана.'
wallet_loading: 'Кошелёк загружается' wallet_loading: 'Кошелёк загружается'
wallet_loading_err: 'Во время загрузки кошелька произошла ошибка, вы можете изменить настройки подключения, выбрав %{settings} внизу экрана.' wallet_loading_err: 'Во время загрузки кошелька произошла ошибка, вы можете повторить попытку или изменить настройки подключения, выбрав %{settings} внизу экрана.'
wallet: Кошелёк wallet: Кошелёк
send: Отправить send: Отправить
receive: Получить receive: Получить

View file

@ -18,7 +18,7 @@ use grin_core::global::ChainTypes;
use crate::AppConfig; use crate::AppConfig;
use crate::gui::Colors; use crate::gui::Colors;
use crate::gui::icons::{ARROW_LEFT, CARET_RIGHT, COMPUTER_TOWER, EYE, EYE_SLASH, FOLDER_LOCK, FOLDER_OPEN, GEAR, GLOBE, GLOBE_SIMPLE, LOCK_KEY, PLUS, SIDEBAR_SIMPLE, SUITCASE}; use crate::gui::icons::{ARROW_LEFT, CARET_RIGHT, COMPUTER_TOWER, EYE, EYE_SLASH, FOLDER_LOCK, FOLDER_OPEN, GEAR, GLOBE, GLOBE_SIMPLE, LOCK_KEY, PLUS, SIDEBAR_SIMPLE, SPINNER, SUITCASE, WARNING_CIRCLE};
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, Root, TitlePanel, View}; use crate::gui::views::{Modal, Root, TitlePanel, View};
use crate::gui::views::types::{ModalContainer, ModalPosition, TitleType}; use crate::gui::views::types::{ModalContainer, ModalPosition, TitleType};
@ -408,7 +408,15 @@ impl WalletsContent {
// Setup wallet status text. // Setup wallet status text.
let status_text = if wallet.is_open() { let status_text = if wallet.is_open() {
format!("{} {}", FOLDER_OPEN, t!("wallets.unlocked")) if wallet.get_info().is_none() {
if wallet.loading_error() {
format!("{} {}", WARNING_CIRCLE, t!("loading_error"))
} else {
format!("{} {}", SPINNER, t!("loading"))
}
} else {
format!("{} {}", FOLDER_OPEN, t!("wallets.unlocked"))
}
} else { } else {
format!("{} {}", FOLDER_LOCK, t!("wallets.locked")) format!("{} {}", FOLDER_LOCK, t!("wallets.locked"))
}; };
@ -532,7 +540,7 @@ impl WalletsContent {
if self.pass_edit.is_empty() { if self.pass_edit.is_empty() {
return; return;
} }
match self.wallets.launch_selected(self.pass_edit.clone()) { match self.wallets.open_selected(self.pass_edit.clone()) {
Ok(_) => { Ok(_) => {
// Clear values. // Clear values.
self.pass_edit = "".to_string(); self.pass_edit = "".to_string();

View file

@ -15,9 +15,11 @@
use std::time::Duration; use std::time::Duration;
use egui::{Margin, RichText}; use egui::{Margin, RichText};
use grin_chain::SyncStatus;
use crate::AppConfig;
use crate::gui::Colors; use crate::gui::Colors;
use crate::gui::icons::{DOWNLOAD, GEAR_FINE, POWER, UPLOAD, WALLET}; use crate::gui::icons::{DOWNLOAD, GEAR_FINE, POWER, REPEAT, UPLOAD, WALLET};
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Root, View}; use crate::gui::views::{Root, View};
use crate::gui::views::wallets::{WalletInfo, WalletReceive, WalletSend, WalletSettings}; use crate::gui::views::wallets::{WalletInfo, WalletReceive, WalletSend, WalletSettings};
@ -119,48 +121,63 @@ impl WalletContent {
}); });
} }
/// Content to draw when wallet is loading. /// Content to draw when wallet is loading, returns `true` if wallet is not ready.
pub fn show_loading_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, wallet: &Wallet) -> bool { pub fn loading_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, wallet: &Wallet) -> bool {
if wallet.config.ext_conn_id.is_none() && !Node::is_running() { if wallet.config.ext_conn_id.is_none() {
let dual_panel_root = Root::is_dual_panel_mode(frame); if !Node::is_running() || Node::is_stopping() {
View::center_content(ui, if !dual_panel_root { 162.0 } else { 96.0 }, |ui| { let dual_panel_root = Root::is_dual_panel_mode(frame);
let text = t!("wallets.enable_node", "settings" => GEAR_FINE); View::center_content(ui, if !dual_panel_root { 162.0 } else { 96.0 }, |ui| {
ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT)); let text = t!("wallets.enable_node", "settings" => GEAR_FINE);
// Show button to enable integrated node at non-dual root panel mode. ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT));
if !dual_panel_root {
ui.add_space(8.0); ui.add_space(8.0);
let enable_node_text = format!("{} {}", POWER, t!("network.enable_node")); // Show button to enable integrated node at non-dual root panel mode
View::button(ui, enable_node_text, Colors::GOLD, || { // or when network connections are not showing and node is not stopping
Node::start(); if (!dual_panel_root || AppConfig::show_connections_network_panel())
}); && !Node::is_stopping() {
} let enable_node_text = format!("{} {}", POWER, t!("network.enable_node"));
}); View::button(ui, enable_node_text, Colors::GOLD, || {
return true; Node::start();
} else { });
if wallet.get_info().is_none() || wallet.loading_progress() < 100 { }
if wallet.loading_error() { });
View::center_content(ui, 96.0, |ui| { return true
let text = t!("wallets.wallet_loading_err", "settings" => GEAR_FINE); } else if wallet.get_info().is_none() {
ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT)); Self::progress_ui(ui, wallet);
});
} else {
View::center_content(ui, 162.0, |ui| {
View::big_loading_spinner(ui);
ui.add_space(18.0);
// Setup loading progress text.
let progress = wallet.loading_progress();
let text = if progress == 0 {
t!("wallets.wallet_loading")
} else {
format!("{}: {}%", t!("wallets.wallet_loading"), progress)
};
ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT));
});
}
return true; return true;
} else {
} }
} else if wallet.get_info().is_none() {
// Show error message with button to retry on wallet loading error or loading progress.
if wallet.loading_error() {
View::center_content(ui, 162.0, |ui| {
let text = t!("wallets.wallet_loading_err", "settings" => GEAR_FINE);
ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT));
ui.add_space(8.0);
let retry_text = format!("{} {}", REPEAT, t!("retry"));
View::button(ui, retry_text, Colors::GOLD, || {
wallet.set_loading_error(false);
});
});
} else {
Self::progress_ui(ui, wallet);
}
return true;
} }
false false
} }
/// Draw wallet loading progress.
fn progress_ui(ui: &mut egui::Ui, wallet: &Wallet) {
View::center_content(ui, 162.0, |ui| {
View::big_loading_spinner(ui);
ui.add_space(18.0);
// Setup loading progress text.
let progress = wallet.loading_progress();
let text = if progress == 0 {
t!("wallets.wallet_loading")
} else {
format!("{}: {}%", t!("wallets.wallet_loading"), progress)
};
ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT));
});
}
} }

View file

@ -32,6 +32,6 @@ impl WalletTab for WalletInfo {
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
wallet: &Wallet, wallet: &Wallet,
cb: &dyn PlatformCallbacks) { cb: &dyn PlatformCallbacks) {
WalletContent::show_loading_ui(ui, frame, wallet); WalletContent::loading_ui(ui, frame, wallet);
} }
} }

View file

@ -14,10 +14,11 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, mpsc, RwLock}; use std::sync::{Arc, mpsc, RwLock};
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU8, Ordering};
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use grin_chain::SyncStatus;
use grin_core::global; use grin_core::global;
use grin_core::global::ChainTypes; use grin_core::global::ChainTypes;
use grin_keychain::{ExtKeychain, Keychain}; use grin_keychain::{ExtKeychain, Keychain};
@ -29,7 +30,7 @@ use grin_wallet_libwallet::api_impl::owner::retrieve_summary_info;
use parking_lot::Mutex; use parking_lot::Mutex;
use crate::AppConfig; use crate::AppConfig;
use crate::node::NodeConfig; use crate::node::{Node, NodeConfig};
use crate::wallet::{ConnectionsConfig, ExternalConnection, WalletConfig}; use crate::wallet::{ConnectionsConfig, ExternalConnection, WalletConfig};
use crate::wallet::types::{ConnectionMethod, WalletInstance}; use crate::wallet::types::{ConnectionMethod, WalletInstance};
@ -51,7 +52,7 @@ impl Default for Wallets {
} }
impl Wallets { impl Wallets {
/// Initialize wallets from base directory for provided [`ChainType`]. /// Initialize [`Wallet`] list from base directory for provided [`ChainType`].
fn init(chain_type: ChainTypes) -> Vec<Wallet> { fn init(chain_type: ChainTypes) -> Vec<Wallet> {
let mut wallets = Vec::new(); let mut wallets = Vec::new();
let wallets_dir = WalletConfig::get_base_path(chain_type); let wallets_dir = WalletConfig::get_base_path(chain_type);
@ -68,7 +69,7 @@ impl Wallets {
wallets wallets
} }
/// Reinitialize wallets for provided [`ChainTypes`]. /// Reinitialize [`Wallet`] list for provided [`ChainTypes`].
pub fn reinit(&mut self, chain_type: ChainTypes) { pub fn reinit(&mut self, chain_type: ChainTypes) {
for w in self.list.iter_mut() { for w in self.list.iter_mut() {
let _ = w.close(); let _ = w.close();
@ -82,17 +83,17 @@ impl Wallets {
self.list.insert(0, wallet); self.list.insert(0, wallet);
} }
/// Select wallet with provided identifier. /// Select [`Wallet`] with provided identifier.
pub fn select(&mut self, id: Option<i64>) { pub fn select(&mut self, id: Option<i64>) {
self.selected_id = id; self.selected_id = id;
} }
/// Check if wallet is selected for provided identifier. /// Check if [`Wallet`] is selected for provided identifier.
pub fn is_selected(&self, id: i64) -> bool { pub fn is_selected(&self, id: i64) -> bool {
return Some(id) == self.selected_id; return Some(id) == self.selected_id;
} }
/// Check if selected wallet is open. /// Check if selected [`Wallet`] is open.
pub fn is_selected_open(&self) -> bool { pub fn is_selected_open(&self) -> bool {
for w in &self.list { for w in &self.list {
if Some(w.config.id) == self.selected_id { if Some(w.config.id) == self.selected_id {
@ -102,8 +103,8 @@ impl Wallets {
false false
} }
/// Open and load selected wallet. /// Open selected [`Wallet`].
pub fn launch_selected(&mut self, password: String) -> Result<(), Error> { pub fn open_selected(&mut self, password: String) -> Result<(), Error> {
for w in self.list.iter_mut() { for w in self.list.iter_mut() {
if Some(w.config.id) == self.selected_id { if Some(w.config.id) == self.selected_id {
return w.open(password.clone()); return w.open(password.clone());
@ -113,33 +114,36 @@ impl Wallets {
} }
} }
/// Contains wallet instance and config. /// Contains wallet instance and handles wallet commands.
#[derive(Clone)] #[derive(Clone)]
pub struct Wallet { pub struct Wallet {
/// Wallet instance. /// Wallet instance.
instance: WalletInstance, instance: WalletInstance,
/// Wallet configuration. /// Wallet configuration.
pub config: WalletConfig, pub config: WalletConfig,
/// Identifier for launched wallet thread.
thread_id: Arc<AtomicI64>,
/// Flag to check if wallet is open. /// Flag to check if wallet is open.
is_open: Arc<AtomicBool>, is_open: Arc<AtomicBool>,
/// Error on wallet loading. /// Error on wallet loading.
loading_error: Arc<AtomicBool>, loading_error: Arc<AtomicBool>,
/// Loading progress in percents /// Loading progress in percents
pub loading_progress: Arc<AtomicU8>, loading_progress: Arc<AtomicU8>,
/// Wallet balance information. /// Wallet balance information.
info: Arc<RwLock<Option<WalletInfo>>> info: Arc<RwLock<Option<WalletInfo>>>
} }
impl Wallet { impl Wallet {
/// Create wallet from provided instance and config. /// Instantiate [`Wallet`] from provided [`WalletInstance`] and [`WalletConfig`].
fn new(instance: WalletInstance, config: WalletConfig) -> Self { fn new(instance: WalletInstance, config: WalletConfig) -> Self {
Self { Self {
instance, instance,
config, config,
thread_id: Arc::new(AtomicI64::new(0)),
is_open: Arc::from(AtomicBool::new(false)), is_open: Arc::from(AtomicBool::new(false)),
loading_error: Arc::from(AtomicBool::new(false)), loading_error: Arc::from(AtomicBool::new(false)),
loading_progress: Arc::new(AtomicU8::new(0)), loading_progress: Arc::new(AtomicU8::new(0)),
@ -170,7 +174,7 @@ impl Wallet {
Ok(w) Ok(w)
} }
/// Initialize wallet from provided data path. /// Initialize [`Wallet`] from provided data path.
fn init(data_path: PathBuf) -> Option<Wallet> { fn init(data_path: PathBuf) -> Option<Wallet> {
let wallet_config = WalletConfig::load(data_path.clone()); let wallet_config = WalletConfig::load(data_path.clone());
if let Some(config) = wallet_config { if let Some(config) = wallet_config {
@ -181,14 +185,14 @@ impl Wallet {
None None
} }
/// Reinitialize wallet instance to apply new config e.g. on change connection settings. /// Reinitialize [`WalletInstance`] to apply new [`WalletConfig`].
pub fn reinit(&mut self) -> Result<(), Error> { pub fn reinit(&mut self) -> Result<(), Error> {
self.close()?; self.close()?;
self.instance = Self::create_wallet_instance(self.config.clone())?; self.instance = Self::create_wallet_instance(self.config.clone())?;
Ok(()) Ok(())
} }
/// Create wallet instance from provided config. /// Create [`WalletInstance`] from provided [`WalletConfig`].
fn create_wallet_instance(config: WalletConfig) -> Result<WalletInstance, Error> { fn create_wallet_instance(config: WalletConfig) -> Result<WalletInstance, Error> {
// Assume global chain type has already been initialized. // Assume global chain type has already been initialized.
let chain_type = config.chain_type; let chain_type = config.chain_type;
@ -222,7 +226,7 @@ impl Wallet {
Ok(wallet) Ok(wallet)
} }
/// Instantiate wallet from provided node client and config. /// Instantiate [`WalletInstance`] from provided node client and [`WalletConfig`].
fn inst_wallet<L, C, K>( fn inst_wallet<L, C, K>(
config: WalletConfig, config: WalletConfig,
node_client: C, node_client: C,
@ -250,7 +254,7 @@ impl Wallet {
match lc.open_wallet(None, ZeroingString::from(password), false, false) { match lc.open_wallet(None, ZeroingString::from(password), false, false) {
Ok(keychain) => { Ok(keychain) => {
self.is_open.store(true, Ordering::Relaxed); self.is_open.store(true, Ordering::Relaxed);
// Start commands handling and updating info. // Start info updating and commands handling.
start_wallet(self.clone(), keychain); start_wallet(self.clone(), keychain);
} }
Err(e) => return Err(e) Err(e) => return Err(e)
@ -258,7 +262,19 @@ impl Wallet {
Ok(()) Ok(())
} }
/// Get wallet loading progress. /// Get wallet thread identifier.
fn get_thread_id(&self) -> i64 {
self.thread_id.load(Ordering::Relaxed)
}
/// Refresh wallet thread identifier.
fn new_thread_id(&self) -> i64 {
let id = chrono::Utc::now().timestamp();
self.thread_id.store(id, Ordering::Relaxed);
id
}
/// Get wallet loading progress after opening.
pub fn loading_progress(&self) -> u8 { pub fn loading_progress(&self) -> u8 {
self.loading_progress.load(Ordering::Relaxed) self.loading_progress.load(Ordering::Relaxed)
} }
@ -268,23 +284,32 @@ impl Wallet {
self.loading_error.load(Ordering::Relaxed) self.loading_error.load(Ordering::Relaxed)
} }
/// Check if wallet is open. /// Set an error for wallet on loading.
pub fn set_loading_error(&self, error: bool) {
self.loading_error.store(error, Ordering::Relaxed);
}
/// Check if wallet was open.
pub fn is_open(&self) -> bool { pub fn is_open(&self) -> bool {
self.is_open.load(Ordering::Relaxed) self.is_open.load(Ordering::Relaxed)
} }
/// Close wallet. /// Close the wallet.
pub fn close(&mut self) -> Result<(), Error> { pub fn close(&mut self) -> Result<(), Error> {
if self.is_open() { if self.is_open() {
let mut wallet_lock = self.instance.lock(); let mut wallet_lock = self.instance.lock();
let lc = wallet_lock.lc_provider()?; let lc = wallet_lock.lc_provider()?;
lc.close_wallet(None)?; lc.close_wallet(None)?;
// Clear wallet info.
let mut w_info = self.info.write().unwrap();
*w_info = None;
// Mark wallet as not opened.
self.is_open.store(false, Ordering::Relaxed); self.is_open.store(false, Ordering::Relaxed);
} }
Ok(()) Ok(())
} }
/// Get wallet info. /// Get wallet balance info.
pub fn get_info(&self) -> Option<WalletInfo> { pub fn get_info(&self) -> Option<WalletInfo> {
let r_info = self.info.read().unwrap(); let r_info = self.info.read().unwrap();
r_info.clone() r_info.clone()
@ -294,71 +319,87 @@ impl Wallet {
/// Delay in seconds to update wallet info. /// Delay in seconds to update wallet info.
const INFO_UPDATE_DELAY: Duration = Duration::from_millis(20 * 1000); const INFO_UPDATE_DELAY: Duration = Duration::from_millis(20 * 1000);
/// Maximum number of attempts to load the wallet on start before stopping the loop. /// Launch thread for commands handling and info updating after [`INFO_UPDATE_DELAY`].
const MAX_LOADING_ATTEMPTS: i8 = 10; fn start_wallet(mut wallet: Wallet, keychain_mask: Option<SecretKey>) {
// Setup initial loading values.
wallet.loading_progress.store(0, Ordering::Relaxed);
wallet.set_loading_error(false);
/// Start wallet by launching separate thread to handle commands and updating info after delay.
fn start_wallet(wallet: Wallet, keychain_mask: Option<SecretKey>) {
// Launch loop at separate thread to update wallet info. // Launch loop at separate thread to update wallet info.
let mut loading_attempts = 1; let thread_id = wallet.new_thread_id();
thread::spawn(move || loop { thread::spawn(move || loop {
// Stop updating if wallet was closed. // Stop updating if wallet was closed or thread changed.
if !wallet.is_open() { if !wallet.is_open() || thread_id != wallet.get_thread_id() {
break; break;
} }
// Update progress at separate thread. // Setup error when required integrated node is not enabled or skip when it's not ready.
let wallet_scan = wallet.clone(); if wallet.config.ext_conn_id.is_none() {
let (tx, rx) = mpsc::channel::<StatusMessage>(); if !Node::is_running() {
thread::spawn(move || { wallet.set_loading_error(true);
while let Ok(m) = rx.recv() { } else if Node::get_sync_status() != Some(SyncStatus::NoSync) {
// Stop updating if wallet was closed or maximum. wallet.set_loading_error(false);
if !wallet_scan.is_open() || loading_attempts == MAX_LOADING_ATTEMPTS { thread::sleep(Duration::from_millis(1000));
return; continue;
}
println!("m: {}", serde_json::to_string::<StatusMessage>(&m.clone()).unwrap());
match m {
StatusMessage::UpdatingOutputs(_) => {}
StatusMessage::UpdatingTransactions(_) => {}
StatusMessage::FullScanWarn(_) => {}
StatusMessage::Scanning(_, progress) => {
wallet_scan.loading_progress.store(progress, Ordering::Relaxed);
}
StatusMessage::ScanningComplete(_) => {
wallet_scan.loading_progress.store(100, Ordering::Relaxed);
}
StatusMessage::UpdateWarning(_) => {}
}
} }
}); }
// Retrieve wallet info. // Update wallet info if it was no loading error after several attempts.
match retrieve_summary_info( if !wallet.loading_error() {
wallet.instance.clone(), let wallet_scan = wallet.clone();
keychain_mask.as_ref(), let (tx, rx) = mpsc::channel::<StatusMessage>();
&Some(tx), // Update loading progress at separate thread.
true, thread::spawn(move || {
wallet.config.min_confirmations while let Ok(m) = rx.recv() {
) { // Stop updating if wallet was closed or maximum.
Ok(info) => { if !wallet_scan.is_open() || wallet_scan.get_thread_id() != thread_id {
wallet.loading_error.store(false, Ordering::Relaxed); return;
let mut w_info = wallet.info.write().unwrap(); }
*w_info = Some(info.1); match m {
} StatusMessage::UpdatingOutputs(_) => {}
Err(e) => { StatusMessage::UpdatingTransactions(_) => {}
println!("Error!: {}", e); StatusMessage::FullScanWarn(_) => {}
loading_attempts += 1; StatusMessage::Scanning(_, progress) => {
wallet.loading_progress.store(0, Ordering::Relaxed); wallet_scan.loading_progress.store(progress, Ordering::Relaxed);
// Setup an error flag when maximum loading attempts were reached. }
if loading_attempts == MAX_LOADING_ATTEMPTS { StatusMessage::ScanningComplete(_) => {
wallet.loading_error.store(true, Ordering::Relaxed); wallet_scan.loading_progress.store(100, Ordering::Relaxed);
break; }
StatusMessage::UpdateWarning(_) => {}
}
}
});
// Retrieve wallet info.
match retrieve_summary_info(
wallet.instance.clone(),
keychain_mask.as_ref(),
&Some(tx),
true,
wallet.config.min_confirmations
) {
Ok(info) => {
if wallet.loading_progress() != 100 {
wallet.set_loading_error(true);
} else {
let mut w_info = wallet.info.write().unwrap();
*w_info = Some(info.1);
}
}
Err(_) => {
wallet.set_loading_error(true);
wallet.loading_progress.store(0, Ordering::Relaxed);
} }
} }
} }
// Stop updating if wallet was closed.
if !wallet.is_open() || wallet.get_thread_id() != thread_id {
break;
}
// Repeat after default delay or after 1 second if update was not complete. // Repeat after default delay or after 1 second if update was not complete.
let delay = if wallet.loading_progress() == 100 { let delay = if wallet.loading_progress() == 100 && !wallet.loading_error() {
INFO_UPDATE_DELAY INFO_UPDATE_DELAY
} else { } else {
Duration::from_millis(1000) Duration::from_millis(1000)