ui + wallets: wallet connection settings, reopen wallet on connection change, recreate wallet instance on opening, update translations, wallet instance refactoring
This commit is contained in:
parent
f5d213bb4c
commit
e86cba50ca
18 changed files with 509 additions and 193 deletions
|
@ -43,6 +43,7 @@ wallets:
|
||||||
send: Send
|
send: Send
|
||||||
receive: Receive
|
receive: Receive
|
||||||
settings: Wallet settings
|
settings: Wallet settings
|
||||||
|
change_server_confirmation: To apply change of connection settings, it is necessary to reopen the wallet. Reopen it now?
|
||||||
network:
|
network:
|
||||||
self: Network
|
self: Network
|
||||||
type: 'Network type:'
|
type: 'Network type:'
|
||||||
|
|
|
@ -43,6 +43,7 @@ wallets:
|
||||||
send: Отправить
|
send: Отправить
|
||||||
receive: Получить
|
receive: Получить
|
||||||
settings: Настройки кошелька
|
settings: Настройки кошелька
|
||||||
|
change_server_confirmation: Чтобы применить изменение настроек соединения, необходимо переоткрыть кошелёк. Переоткрыть его сейчас?
|
||||||
network:
|
network:
|
||||||
self: Сеть
|
self: Сеть
|
||||||
type: 'Тип сети:'
|
type: 'Тип сети:'
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::gui::views::Modal;
|
||||||
|
|
||||||
/// Title content type, can be single title or with animated subtitle.
|
/// Title content type, can be single title or with animated subtitle.
|
||||||
pub enum TitleType {
|
pub enum TitleType {
|
||||||
/// Single text with possibility to align text at left side at default panel size width.
|
/// Single text with possibility to align text at left side for default panel size width.
|
||||||
Single(String, bool),
|
Single(String, bool),
|
||||||
/// With animated subtitle text.
|
/// With animated subtitle text.
|
||||||
WithSubTitle(String, String, bool)
|
WithSubTitle(String, String, bool)
|
||||||
|
|
|
@ -333,6 +333,13 @@ impl WalletsContent {
|
||||||
ui.allocate_ui(rect.size(), |ui| {
|
ui.allocate_ui(rect.size(), |ui| {
|
||||||
let list = self.wallets.list().clone();
|
let list = self.wallets.list().clone();
|
||||||
for wallet in &list {
|
for wallet in &list {
|
||||||
|
// Check if wallet reopen is needed.
|
||||||
|
if !wallet.is_open() && wallet.reopen_needed() {
|
||||||
|
wallet.set_reopen(false);
|
||||||
|
self.wallets.select(Some(wallet.config.id));
|
||||||
|
self.show_open_wallet_modal(cb);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw wallet list item.
|
// Draw wallet list item.
|
||||||
self.wallet_item_ui(ui, wallet, cb);
|
self.wallet_item_ui(ui, wallet, cb);
|
||||||
ui.add_space(5.0);
|
ui.add_space(5.0);
|
||||||
|
@ -430,7 +437,7 @@ impl WalletsContent {
|
||||||
if wallet.is_closing() {
|
if wallet.is_closing() {
|
||||||
format!("{} {}", SPINNER, t!("wallets.wallet_closing"))
|
format!("{} {}", SPINNER, t!("wallets.wallet_closing"))
|
||||||
} else if wallet.get_data().is_none() {
|
} else if wallet.get_data().is_none() {
|
||||||
if wallet.loading_error() {
|
if wallet.load_error() {
|
||||||
format!("{} {}", WARNING_CIRCLE, t!("loading_error"))
|
format!("{} {}", WARNING_CIRCLE, t!("loading_error"))
|
||||||
} else {
|
} else {
|
||||||
format!("{} {}", SPINNER, t!("loading"))
|
format!("{} {}", SPINNER, t!("loading"))
|
||||||
|
|
|
@ -24,8 +24,8 @@ use crate::gui::views::types::ModalPosition;
|
||||||
use crate::gui::views::wallets::creation::MnemonicSetup;
|
use crate::gui::views::wallets::creation::MnemonicSetup;
|
||||||
use crate::gui::views::wallets::creation::types::Step;
|
use crate::gui::views::wallets::creation::types::Step;
|
||||||
use crate::gui::views::wallets::setup::ConnectionSetup;
|
use crate::gui::views::wallets::setup::ConnectionSetup;
|
||||||
|
use crate::wallet::{ExternalConnection, Wallet};
|
||||||
use crate::wallet::types::PhraseMode;
|
use crate::wallet::types::PhraseMode;
|
||||||
use crate::wallet::Wallet;
|
|
||||||
|
|
||||||
/// Wallet creation content.
|
/// Wallet creation content.
|
||||||
pub struct WalletCreation {
|
pub struct WalletCreation {
|
||||||
|
@ -304,14 +304,19 @@ impl WalletCreation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Step::ConfirmMnemonic => Some(Step::SetupConnection),
|
Step::ConfirmMnemonic => {
|
||||||
|
// Check external connections availability on connection setup.
|
||||||
|
ExternalConnection::start_ext_conn_availability_check();
|
||||||
|
Some(Step::SetupConnection)
|
||||||
|
},
|
||||||
Step::SetupConnection => {
|
Step::SetupConnection => {
|
||||||
// Create wallet at last step.
|
// Create wallet at last step.
|
||||||
let name = self.name_edit.clone();
|
let name = self.name_edit.clone();
|
||||||
let pass = self.pass_edit.clone();
|
let pass = self.pass_edit.clone();
|
||||||
let phrase = self.mnemonic_setup.mnemonic.get_phrase();
|
let phrase = self.mnemonic_setup.mnemonic.get_phrase();
|
||||||
let conn_method = &self.network_setup.method;
|
let conn_method = &self.network_setup.method;
|
||||||
let wallet = Wallet::create(name, pass.clone(), phrase, conn_method).unwrap();
|
let mut wallet
|
||||||
|
= Wallet::create(name, pass.clone(), phrase, conn_method).unwrap();
|
||||||
// Open created wallet.
|
// Open created wallet.
|
||||||
wallet.open(pass).unwrap();
|
wallet.open(pass).unwrap();
|
||||||
// Pass created wallet to callback.
|
// Pass created wallet to callback.
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use egui::{Id, RichText, ScrollArea, TextStyle, Widget};
|
use egui::{Id, RichText, TextStyle, Widget};
|
||||||
|
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
use crate::gui::icons::PENCIL;
|
use crate::gui::icons::PENCIL;
|
||||||
|
|
|
@ -12,18 +12,19 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use egui::{Id, RichText, ScrollArea, TextStyle, Widget};
|
use egui::{Align, Id, Layout, RichText, Rounding, TextStyle, Widget};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
use crate::gui::icons::{GLOBE, GLOBE_SIMPLE};
|
use crate::gui::icons::{CHECK, CHECK_CIRCLE, CHECK_FAT, COMPUTER_TOWER, DOTS_THREE_CIRCLE, GLOBE, GLOBE_SIMPLE, POWER, X_CIRCLE};
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::{Modal, View};
|
use crate::gui::views::{Modal, View};
|
||||||
use crate::gui::views::types::{ModalContainer, ModalPosition};
|
use crate::gui::views::types::{ModalContainer, ModalPosition};
|
||||||
|
use crate::node::{Node, NodeConfig};
|
||||||
use crate::wallet::{ConnectionsConfig, ExternalConnection, Wallet};
|
use crate::wallet::{ConnectionsConfig, ExternalConnection, Wallet};
|
||||||
use crate::wallet::types::ConnectionMethod;
|
use crate::wallet::types::ConnectionMethod;
|
||||||
|
|
||||||
/// Wallet node connection method setup content.
|
/// Wallet connection setup content.
|
||||||
pub struct ConnectionSetup {
|
pub struct ConnectionSetup {
|
||||||
/// Selected connection method.
|
/// Selected connection method.
|
||||||
pub method: ConnectionMethod,
|
pub method: ConnectionMethod,
|
||||||
|
@ -37,13 +38,19 @@ pub struct ConnectionSetup {
|
||||||
/// Flag to show URL format error.
|
/// Flag to show URL format error.
|
||||||
ext_node_url_error: bool,
|
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`] identifiers allowed at this ui container.
|
||||||
modal_ids: Vec<&'static str>
|
modal_ids: Vec<&'static str>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// External connection [`Modal`] identifier.
|
/// Identifier for [`Modal`] to add external connection.
|
||||||
pub const ADD_EXT_CONNECTION_MODAL: &'static str = "add_ext_connection_modal";
|
pub const ADD_EXT_CONNECTION_MODAL: &'static str = "add_ext_connection_modal";
|
||||||
|
|
||||||
|
/// Identifier for [`Modal`] to confirm wallet reopening after connection change.
|
||||||
|
pub const REOPEN_WALLET_CONFIRMATION_MODAL: &'static str = "change_conn_reopen_wallet_modal";
|
||||||
|
|
||||||
impl Default for ConnectionSetup {
|
impl Default for ConnectionSetup {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -52,6 +59,7 @@ impl Default for ConnectionSetup {
|
||||||
ext_node_url_edit: "".to_string(),
|
ext_node_url_edit: "".to_string(),
|
||||||
ext_node_secret_edit: "".to_string(),
|
ext_node_secret_edit: "".to_string(),
|
||||||
ext_node_url_error: false,
|
ext_node_url_error: false,
|
||||||
|
show_closing_progress: false,
|
||||||
modal_ids: vec![
|
modal_ids: vec![
|
||||||
ADD_EXT_CONNECTION_MODAL
|
ADD_EXT_CONNECTION_MODAL
|
||||||
]
|
]
|
||||||
|
@ -91,6 +99,13 @@ impl ConnectionSetup {
|
||||||
frame: &mut eframe::Frame,
|
frame: &mut eframe::Frame,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
// Show modal content to reopen the wallet.
|
||||||
|
if Modal::opened() == Some(REOPEN_WALLET_CONFIRMATION_MODAL) {
|
||||||
|
Modal::ui(ui.ctx(), |ui, modal| {
|
||||||
|
self.reopen_modal_content(ui, wallet, modal, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Setup connection value from provided wallet.
|
// Setup connection value from provided wallet.
|
||||||
match wallet.config.ext_conn_id {
|
match wallet.config.ext_conn_id {
|
||||||
None => self.method = ConnectionMethod::Integrated,
|
None => self.method = ConnectionMethod::Integrated,
|
||||||
|
@ -101,19 +116,26 @@ impl ConnectionSetup {
|
||||||
self.ui(ui, frame, cb);
|
self.ui(ui, frame, cb);
|
||||||
|
|
||||||
// Setup wallet connection value after change.
|
// Setup wallet connection value after change.
|
||||||
match self.method {
|
let changed = match self.method {
|
||||||
ConnectionMethod::Integrated => {
|
ConnectionMethod::Integrated => {
|
||||||
if wallet.config.ext_conn_id.is_some() {
|
let changed = wallet.config.ext_conn_id.is_some();
|
||||||
|
if changed {
|
||||||
wallet.config.ext_conn_id = None;
|
wallet.config.ext_conn_id = None;
|
||||||
wallet.config.save();
|
|
||||||
}
|
}
|
||||||
|
changed
|
||||||
}
|
}
|
||||||
ConnectionMethod::External(id) => {
|
ConnectionMethod::External(id) => {
|
||||||
if wallet.config.ext_conn_id != Some(id) {
|
let changed = wallet.config.ext_conn_id != Some(id);
|
||||||
|
if changed {
|
||||||
wallet.config.ext_conn_id = Some(id);
|
wallet.config.ext_conn_id = Some(id);
|
||||||
wallet.config.save();
|
|
||||||
}
|
}
|
||||||
|
changed
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
wallet.config.save();
|
||||||
|
self.show_reopen_confirmation_modal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,33 +155,155 @@ impl ConnectionSetup {
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
// Show integrated node selection.
|
// Show integrated node selection.
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
View::radio_value(ui,
|
self.integrated_node_item_ui(ui);
|
||||||
&mut self.method,
|
|
||||||
ConnectionMethod::Integrated,
|
|
||||||
t!("network.node"));
|
|
||||||
|
|
||||||
ui.add_space(10.0);
|
let ext_conn_list = ConnectionsConfig::ext_conn_list();
|
||||||
ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::GRAY));
|
if !ext_conn_list.is_empty() {
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
|
ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::GRAY));
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
// Show button to add new external node connection.
|
// Show button to add new external node connection.
|
||||||
let add_node_text = format!("{} {}", GLOBE_SIMPLE, t!("wallets.add_node"));
|
let add_node_text = format!("{} {}", GLOBE_SIMPLE, t!("wallets.add_node"));
|
||||||
View::button(ui, add_node_text, Colors::GOLD, || {
|
View::button(ui, add_node_text, Colors::GOLD, || {
|
||||||
self.show_add_ext_conn_modal(cb);
|
self.show_add_ext_conn_modal(cb);
|
||||||
});
|
});
|
||||||
ui.add_space(12.0);
|
|
||||||
|
|
||||||
// Show external nodes URLs selection.
|
|
||||||
for conn in ConnectionsConfig::ext_conn_list() {
|
|
||||||
View::radio_value(ui,
|
|
||||||
&mut self.method,
|
|
||||||
ConnectionMethod::External(conn.id),
|
|
||||||
conn.url);
|
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
|
|
||||||
|
// Show external connections.
|
||||||
|
for (index, conn) in ext_conn_list.iter().enumerate() {
|
||||||
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
// Draw connection list item.
|
||||||
|
self.ext_conn_item_ui(ui, conn, index, ext_conn_list.len());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw integrated node connection item content.
|
||||||
|
fn integrated_node_item_ui(&mut self, ui: &mut egui::Ui) {
|
||||||
|
// Draw round background.
|
||||||
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
|
rect.set_height(78.0);
|
||||||
|
let rounding = View::item_rounding(0, 1, false);
|
||||||
|
ui.painter().rect(rect, rounding, Colors::FILL, View::ITEM_STROKE);
|
||||||
|
|
||||||
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
|
// Setup padding for item buttons.
|
||||||
|
ui.style_mut().spacing.button_padding = egui::vec2(14.0, 0.0);
|
||||||
|
// Setup rounding for item buttons.
|
||||||
|
ui.style_mut().visuals.widgets.inactive.rounding = Rounding::same(8.0);
|
||||||
|
ui.style_mut().visuals.widgets.hovered.rounding = Rounding::same(8.0);
|
||||||
|
ui.style_mut().visuals.widgets.active.rounding = Rounding::same(8.0);
|
||||||
|
|
||||||
|
// Draw button to select integrated node if it was not selected.
|
||||||
|
let is_current_method = self.method == ConnectionMethod::Integrated;
|
||||||
|
if !is_current_method {
|
||||||
|
View::item_button(ui, View::item_rounding(0, 1, true), CHECK, None, || {
|
||||||
|
self.method = ConnectionMethod::Integrated;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !Node::is_running() {
|
||||||
|
// Draw button to start integrated node.
|
||||||
|
let rounding = if is_current_method {
|
||||||
|
View::item_rounding(0, 1, true)
|
||||||
|
} else {
|
||||||
|
Rounding::none()
|
||||||
|
};
|
||||||
|
View::item_button(ui, rounding, POWER, Some(Colors::GREEN), || {
|
||||||
|
Node::start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout_size = ui.available_size();
|
||||||
|
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.add_space(3.0);
|
||||||
|
ui.label(RichText::new(t!("network.node"))
|
||||||
|
.size(18.0)
|
||||||
|
.color(Colors::TITLE));
|
||||||
|
|
||||||
|
// Setup node API address text.
|
||||||
|
let api_address = NodeConfig::get_api_address();
|
||||||
|
let address_text = format!("{} http://{}", COMPUTER_TOWER, api_address);
|
||||||
|
ui.label(RichText::new(address_text).size(15.0).color(Colors::TEXT));
|
||||||
|
ui.add_space(1.0);
|
||||||
|
|
||||||
|
// Setup node status text.
|
||||||
|
let status_icon = if !Node::is_running() {
|
||||||
|
X_CIRCLE
|
||||||
|
} else if Node::not_syncing() {
|
||||||
|
CHECK_CIRCLE
|
||||||
|
} else {
|
||||||
|
DOTS_THREE_CIRCLE
|
||||||
|
};
|
||||||
|
let status_text = format!("{} {}", status_icon, Node::get_sync_status_text());
|
||||||
|
ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw external connection item content.
|
||||||
|
fn ext_conn_item_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
conn: &ExternalConnection,
|
||||||
|
index: usize,
|
||||||
|
len: usize) {
|
||||||
|
// Setup layout size.
|
||||||
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
|
rect.set_height(52.0);
|
||||||
|
|
||||||
|
// Draw round background.
|
||||||
|
let bg_rect = rect.clone();
|
||||||
|
let item_rounding = View::item_rounding(index, len, false);
|
||||||
|
ui.painter().rect(bg_rect, item_rounding, Colors::FILL, View::ITEM_STROKE);
|
||||||
|
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
|
// Draw button to select connection.
|
||||||
|
let is_current_method = self.method == ConnectionMethod::External(conn.id);
|
||||||
|
if !is_current_method {
|
||||||
|
let button_rounding = View::item_rounding(index, len, true);
|
||||||
|
View::item_button(ui, button_rounding, CHECK, None, || {
|
||||||
|
self.method = ConnectionMethod::External(conn.id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ui.add_space(12.0);
|
||||||
|
ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::TITLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout_size = ui.available_size();
|
||||||
|
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
// Draw connections URL.
|
||||||
|
ui.add_space(4.0);
|
||||||
|
let conn_text = format!("{} {}", COMPUTER_TOWER, conn.url);
|
||||||
|
View::ellipsize_text(ui, conn_text, 15.0, Colors::TITLE);
|
||||||
|
ui.add_space(1.0);
|
||||||
|
|
||||||
|
// Setup connection status text.
|
||||||
|
let status_text = if let Some(available) = conn.available {
|
||||||
|
if available {
|
||||||
|
format!("{} {}", CHECK_CIRCLE, t!("network.available"))
|
||||||
|
} else {
|
||||||
|
format!("{} {}", X_CIRCLE, t!("network.not_available"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format!("{} {}", DOTS_THREE_CIRCLE, t!("network.availability_check"))
|
||||||
|
};
|
||||||
|
ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY));
|
||||||
|
ui.add_space(3.0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Show external connection adding [`Modal`].
|
/// Show external connection adding [`Modal`].
|
||||||
fn show_add_ext_conn_modal(&mut self, cb: &dyn PlatformCallbacks) {
|
fn show_add_ext_conn_modal(&mut self, cb: &dyn PlatformCallbacks) {
|
||||||
// Setup values for Modal.
|
// Setup values for Modal.
|
||||||
|
@ -257,6 +401,7 @@ impl ConnectionSetup {
|
||||||
Some(self.ext_node_secret_edit.to_owned())
|
Some(self.ext_node_secret_edit.to_owned())
|
||||||
};
|
};
|
||||||
let ext_conn = ExternalConnection::new(url.clone(), secret);
|
let ext_conn = ExternalConnection::new(url.clone(), secret);
|
||||||
|
ext_conn.check_conn_availability();
|
||||||
ConnectionsConfig::add_ext_conn(ext_conn.clone());
|
ConnectionsConfig::add_ext_conn(ext_conn.clone());
|
||||||
|
|
||||||
// Set added connection as current.
|
// Set added connection as current.
|
||||||
|
@ -279,4 +424,67 @@ impl ConnectionSetup {
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
// 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.add_space(6.0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
18
src/gui/views/wallets/setup/main.rs
Normal file
18
src/gui/views/wallets/setup/main.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2023 The Grim Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/// Main wallet setup content.
|
||||||
|
pub struct MainSetup {
|
||||||
|
|
||||||
|
}
|
|
@ -13,4 +13,10 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
mod connection;
|
mod connection;
|
||||||
pub use connection::ConnectionSetup;
|
pub use connection::ConnectionSetup;
|
||||||
|
|
||||||
|
mod main;
|
||||||
|
pub use main::MainSetup;
|
||||||
|
|
||||||
|
mod recovery;
|
||||||
|
pub use recovery::RecoverySetup;
|
18
src/gui/views/wallets/setup/recovery.rs
Normal file
18
src/gui/views/wallets/setup/recovery.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2023 The Grim Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/// Wallet recovery setup content.
|
||||||
|
pub struct RecoverySetup {
|
||||||
|
|
||||||
|
}
|
|
@ -46,6 +46,8 @@ impl WalletContent {
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
// Show wallet tabs panel.
|
// Show wallet tabs panel.
|
||||||
|
let not_show_tabs =
|
||||||
|
wallet.is_closing() || (wallet.get_data().is_none() && !wallet.load_error());
|
||||||
egui::TopBottomPanel::bottom("wallet_tabs")
|
egui::TopBottomPanel::bottom("wallet_tabs")
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
fill: Colors::FILL,
|
fill: Colors::FILL,
|
||||||
|
@ -57,7 +59,7 @@ impl WalletContent {
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.show_inside(ui, |ui| {
|
.show_animated_inside(ui, !not_show_tabs, |ui| {
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
// Setup tabs width.
|
// Setup tabs width.
|
||||||
let available_width = ui.available_width();
|
let available_width = ui.available_width();
|
||||||
|
@ -172,7 +174,7 @@ impl WalletContent {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true
|
return true
|
||||||
} else if wallet.loading_error()
|
} else if wallet.load_error()
|
||||||
&& Node::get_sync_status() == Some(SyncStatus::NoSync) {
|
&& Node::get_sync_status() == Some(SyncStatus::NoSync) {
|
||||||
Self::loading_error_ui(ui, wallet);
|
Self::loading_error_ui(ui, wallet);
|
||||||
return true;
|
return true;
|
||||||
|
@ -181,7 +183,7 @@ impl WalletContent {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if wallet.get_data().is_none() {
|
} else if wallet.get_data().is_none() {
|
||||||
if wallet.loading_error() {
|
if wallet.load_error() {
|
||||||
Self::loading_error_ui(ui, wallet);
|
Self::loading_error_ui(ui, wallet);
|
||||||
} else {
|
} else {
|
||||||
Self::loading_progress_ui(ui, wallet);
|
Self::loading_progress_ui(ui, wallet);
|
||||||
|
@ -199,7 +201,7 @@ impl WalletContent {
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
let retry_text = format!("{} {}", REPEAT, t!("retry"));
|
let retry_text = format!("{} {}", REPEAT, t!("retry"));
|
||||||
View::button(ui, retry_text, Colors::GOLD, || {
|
View::button(ui, retry_text, Colors::GOLD, || {
|
||||||
wallet.set_loading_error(false);
|
wallet.set_load_error(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -211,7 +213,7 @@ impl WalletContent {
|
||||||
ui.add_space(18.0);
|
ui.add_space(18.0);
|
||||||
// Setup loading progress text.
|
// Setup loading progress text.
|
||||||
let text = {
|
let text = {
|
||||||
let info_progress = wallet.info_loading_progress();
|
let info_progress = wallet.info_load_progress();
|
||||||
if wallet.is_closing() {
|
if wallet.is_closing() {
|
||||||
t!("wallets.wallet_closing")
|
t!("wallets.wallet_closing")
|
||||||
} else if info_progress != 100 {
|
} else if info_progress != 100 {
|
||||||
|
@ -221,7 +223,7 @@ impl WalletContent {
|
||||||
format!("{}: {}%", t!("wallets.wallet_loading"), info_progress)
|
format!("{}: {}%", t!("wallets.wallet_loading"), info_progress)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let tx_progress = wallet.txs_loading_progress();
|
let tx_progress = wallet.txs_load_progress();
|
||||||
if tx_progress == 0 {
|
if tx_progress == 0 {
|
||||||
t!("wallets.tx_loading")
|
t!("wallets.tx_loading")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -32,6 +32,8 @@ impl WalletTab for WalletInfo {
|
||||||
frame: &mut eframe::Frame,
|
frame: &mut eframe::Frame,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
WalletContent::loading_ui(ui, frame, wallet);
|
if WalletContent::loading_ui(ui, frame, wallet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::wallets::wallet::types::{WalletTab, WalletTabType};
|
use crate::gui::views::wallets::wallet::types::{WalletTab, WalletTabType};
|
||||||
|
use crate::gui::views::wallets::wallet::WalletContent;
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
|
|
||||||
/// Receive funds tab content.
|
/// Receive funds tab content.
|
||||||
|
@ -30,5 +31,8 @@ impl WalletTab for WalletReceive {
|
||||||
frame: &mut eframe::Frame,
|
frame: &mut eframe::Frame,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
if WalletContent::loading_ui(ui, frame, wallet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::wallets::wallet::types::{WalletTab, WalletTabType};
|
use crate::gui::views::wallets::wallet::types::{WalletTab, WalletTabType};
|
||||||
|
use crate::gui::views::wallets::wallet::WalletContent;
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
|
|
||||||
/// Send funds tab content.
|
/// Send funds tab content.
|
||||||
|
@ -30,5 +31,8 @@ impl WalletTab for WalletSend {
|
||||||
frame: &mut eframe::Frame,
|
frame: &mut eframe::Frame,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
if WalletContent::loading_ui(ui, frame, wallet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,15 +15,25 @@
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::wallets::setup::ConnectionSetup;
|
use crate::gui::views::wallets::setup::ConnectionSetup;
|
||||||
use crate::gui::views::wallets::wallet::types::{WalletTab, WalletTabType};
|
use crate::gui::views::wallets::wallet::types::{WalletTab, WalletTabType};
|
||||||
use crate::wallet::Wallet;
|
use crate::gui::views::wallets::wallet::WalletContent;
|
||||||
|
use crate::wallet::{ExternalConnection, Wallet};
|
||||||
|
|
||||||
/// Wallet settings tab content.
|
/// Wallet settings tab content.
|
||||||
#[derive(Default)]
|
|
||||||
pub struct WalletSettings {
|
pub struct WalletSettings {
|
||||||
/// Connection setup content.
|
/// Connection setup content.
|
||||||
conn_setup: ConnectionSetup
|
conn_setup: ConnectionSetup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for WalletSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
// Check external connections availability on first tab opening.
|
||||||
|
ExternalConnection::start_ext_conn_availability_check();
|
||||||
|
Self {
|
||||||
|
conn_setup: ConnectionSetup::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WalletTab for WalletSettings {
|
impl WalletTab for WalletSettings {
|
||||||
fn get_type(&self) -> WalletTabType {
|
fn get_type(&self) -> WalletTabType {
|
||||||
WalletTabType::Settings
|
WalletTabType::Settings
|
||||||
|
@ -34,6 +44,12 @@ impl WalletTab for WalletSettings {
|
||||||
frame: &mut eframe::Frame,
|
frame: &mut eframe::Frame,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
// Show progress if wallet is loading after opening without an error.
|
||||||
|
if wallet.is_closing() || (wallet.get_data().is_none() && !wallet.load_error()) {
|
||||||
|
WalletContent::loading_progress_ui(ui, wallet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.conn_setup.wallet_ui(ui, frame, wallet, cb);
|
self.conn_setup.wallet_ui(ui, frame, wallet, cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -78,12 +78,6 @@ impl ExternalConnection {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let chain_type = AppConfig::chain_type();
|
let chain_type = AppConfig::chain_type();
|
||||||
loop {
|
loop {
|
||||||
// Stop checking if connections are not showing or network type was changed.
|
|
||||||
if !AppConfig::show_connections_network_panel()
|
|
||||||
|| chain_type != AppConfig::chain_type() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check external connections URLs availability.
|
// Check external connections URLs availability.
|
||||||
let conn_list = ConnectionsConfig::ext_conn_list();
|
let conn_list = ConnectionsConfig::ext_conn_list();
|
||||||
for conn in conn_list {
|
for conn in conn_list {
|
||||||
|
@ -91,6 +85,12 @@ impl ExternalConnection {
|
||||||
conn.check_conn_availability();
|
conn.check_conn_availability();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop checking if connections are not showing or network type was changed.
|
||||||
|
if !AppConfig::show_connections_network_panel()
|
||||||
|
|| chain_type != AppConfig::chain_type() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Pause checking for delay value.
|
// Pause checking for delay value.
|
||||||
std::thread::sleep(Self::AV_CHECK_DELAY);
|
std::thread::sleep(Self::AV_CHECK_DELAY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,8 +117,14 @@ impl WalletList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open selected [`Wallet`].
|
/// Open selected [`Wallet`].
|
||||||
pub fn open_selected(&self, password: String) -> Result<(), Error> {
|
pub fn open_selected(&mut self, password: String) -> Result<(), Error> {
|
||||||
for w in self.list() {
|
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 {
|
if Some(w.config.id) == self.selected_id {
|
||||||
return w.open(password.clone());
|
return w.open(password.clone());
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,25 +36,27 @@ use crate::wallet::types::{ConnectionMethod, WalletData, WalletInstance};
|
||||||
/// Contains wallet instance, configuration and state, handles wallet commands.
|
/// Contains wallet instance, configuration and state, handles wallet commands.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Wallet {
|
pub struct Wallet {
|
||||||
/// Wallet instance.
|
/// Wallet instance, initializing on wallet opening and clearing on wallet closing.
|
||||||
instance: WalletInstance,
|
instance: Option<WalletInstance>,
|
||||||
/// Wallet configuration.
|
/// Wallet configuration.
|
||||||
pub config: WalletConfig,
|
pub config: WalletConfig,
|
||||||
|
|
||||||
/// Wallet updating thread.
|
/// Wallet updating thread.
|
||||||
thread: Arc<RwLock<Option<Thread>>>,
|
thread: Arc<RwLock<Option<Thread>>>,
|
||||||
|
|
||||||
|
/// Flag to check if wallet reopening is needed.
|
||||||
|
reopen: Arc<AtomicBool>,
|
||||||
/// Flag to check if wallet is open.
|
/// Flag to check if wallet is open.
|
||||||
is_open: Arc<AtomicBool>,
|
is_open: Arc<AtomicBool>,
|
||||||
/// Flag to check if wallet is loading.
|
/// Flag to check if wallet is loading.
|
||||||
closing: Arc<AtomicBool>,
|
closing: Arc<AtomicBool>,
|
||||||
|
|
||||||
/// Error on wallet loading.
|
/// Error on wallet loading.
|
||||||
loading_error: Arc<AtomicBool>,
|
load_error: Arc<AtomicBool>,
|
||||||
/// Info loading progress in percents
|
/// Info loading progress in percents
|
||||||
info_loading_progress: Arc<AtomicU8>,
|
info_load_progress: Arc<AtomicU8>,
|
||||||
/// Transactions loading progress in percents
|
/// Transactions loading progress in percents
|
||||||
txs_loading_progress: Arc<AtomicU8>,
|
txs_load_progress: Arc<AtomicU8>,
|
||||||
|
|
||||||
/// Wallet data.
|
/// Wallet data.
|
||||||
data: Arc<RwLock<Option<WalletData>>>,
|
data: Arc<RwLock<Option<WalletData>>>,
|
||||||
|
@ -63,17 +65,18 @@ pub struct Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wallet {
|
impl Wallet {
|
||||||
/// Instantiate [`Wallet`] from provided [`WalletInstance`] and [`WalletConfig`].
|
/// Create new [`Wallet`] instance with provided [`WalletConfig`].
|
||||||
fn new(instance: WalletInstance, config: WalletConfig) -> Self {
|
fn new(config: WalletConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
instance,
|
instance: None,
|
||||||
config,
|
config,
|
||||||
thread: Arc::from(RwLock::new(None)),
|
thread: Arc::from(RwLock::new(None)),
|
||||||
|
reopen: Arc::new(AtomicBool::new(false)),
|
||||||
is_open: Arc::from(AtomicBool::new(false)),
|
is_open: Arc::from(AtomicBool::new(false)),
|
||||||
closing: Arc::new(AtomicBool::new(false)),
|
closing: Arc::new(AtomicBool::new(false)),
|
||||||
loading_error: Arc::from(AtomicBool::new(false)),
|
load_error: Arc::from(AtomicBool::new(false)),
|
||||||
info_loading_progress: Arc::from(AtomicU8::new(0)),
|
info_load_progress: Arc::from(AtomicU8::new(0)),
|
||||||
txs_loading_progress: Arc::from(AtomicU8::new(0)),
|
txs_load_progress: Arc::from(AtomicU8::new(0)),
|
||||||
data: Arc::from(RwLock::new(None)),
|
data: Arc::from(RwLock::new(None)),
|
||||||
data_update_attempts: Arc::new(AtomicU8::new(0))
|
data_update_attempts: Arc::new(AtomicU8::new(0))
|
||||||
}
|
}
|
||||||
|
@ -87,10 +90,10 @@ impl Wallet {
|
||||||
conn_method: &ConnectionMethod
|
conn_method: &ConnectionMethod
|
||||||
) -> Result<Wallet, Error> {
|
) -> Result<Wallet, Error> {
|
||||||
let config = WalletConfig::create(name, conn_method);
|
let config = WalletConfig::create(name, conn_method);
|
||||||
let instance = Self::create_wallet_instance(config.clone())?;
|
let w = Wallet::new(config.clone());
|
||||||
let w = Wallet::new(instance, config);
|
|
||||||
{
|
{
|
||||||
let mut w_lock = w.instance.lock();
|
let instance = Self::create_wallet_instance(config)?;
|
||||||
|
let mut w_lock = instance.lock();
|
||||||
let p = w_lock.lc_provider()?;
|
let p = w_lock.lc_provider()?;
|
||||||
p.create_wallet(None,
|
p.create_wallet(None,
|
||||||
Some(ZeroingString::from(mnemonic.clone())),
|
Some(ZeroingString::from(mnemonic.clone())),
|
||||||
|
@ -106,18 +109,11 @@ impl Wallet {
|
||||||
pub fn init(data_path: PathBuf) -> Option<Wallet> {
|
pub 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 {
|
||||||
if let Ok(instance) = Self::create_wallet_instance(config.clone()) {
|
return Some(Wallet::new(config));
|
||||||
return Some(Wallet::new(instance, config));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reinitialize [`WalletInstance`] to apply new [`WalletConfig`].
|
|
||||||
pub fn reinit(&self) {
|
|
||||||
//TODO: Reinit wallet.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create [`WalletInstance`] from provided [`WalletConfig`].
|
/// 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.
|
||||||
|
@ -171,10 +167,18 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open the wallet and start update the data at separate thread.
|
/// Open the wallet and start update the data at separate thread.
|
||||||
pub fn open(&self, password: String) -> Result<(), Error> {
|
pub fn open(&mut self, password: String) -> Result<(), Error> {
|
||||||
let mut wallet_lock = self.instance.lock();
|
if self.is_open() {
|
||||||
let lc = wallet_lock.lc_provider()?;
|
return Err(Error::GenericError("Already opened".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new wallet instance.
|
||||||
|
let instance = Self::create_wallet_instance(self.config.clone())?;
|
||||||
|
self.instance = Some(instance.clone());
|
||||||
|
|
||||||
// Open the wallet.
|
// Open the wallet.
|
||||||
|
let mut wallet_lock = instance.lock();
|
||||||
|
let lc = wallet_lock.lc_provider()?;
|
||||||
match lc.open_wallet(None, ZeroingString::from(password), false, false) {
|
match lc.open_wallet(None, ZeroingString::from(password), false, false) {
|
||||||
Ok(keychain) => {
|
Ok(keychain) => {
|
||||||
// Start data updating if thread was not launched.
|
// Start data updating if thread was not launched.
|
||||||
|
@ -189,29 +193,42 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
self.is_open.store(true, Ordering::Relaxed);
|
self.is_open.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e)
|
Err(e) => {
|
||||||
|
self.instance = None;
|
||||||
|
return Err(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set wallet reopen status.
|
||||||
|
pub fn set_reopen(&self, reopen: bool) {
|
||||||
|
self.reopen.store(reopen, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if wallet reopen is needed.
|
||||||
|
pub fn reopen_needed(&self) -> bool {
|
||||||
|
self.reopen.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get wallet transactions loading progress.
|
/// Get wallet transactions loading progress.
|
||||||
pub fn txs_loading_progress(&self) -> u8 {
|
pub fn txs_load_progress(&self) -> u8 {
|
||||||
self.txs_loading_progress.load(Ordering::Relaxed)
|
self.txs_load_progress.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get wallet info loading progress.
|
/// Get wallet info loading progress.
|
||||||
pub fn info_loading_progress(&self) -> u8 {
|
pub fn info_load_progress(&self) -> u8 {
|
||||||
self.info_loading_progress.load(Ordering::Relaxed)
|
self.info_load_progress.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if wallet had an error on loading.
|
/// Check if wallet had an error on loading.
|
||||||
pub fn loading_error(&self) -> bool {
|
pub fn load_error(&self) -> bool {
|
||||||
self.loading_error.load(Ordering::Relaxed)
|
self.load_error.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set an error for wallet on loading.
|
/// Set an error for wallet on loading.
|
||||||
pub fn set_loading_error(&self, error: bool) {
|
pub fn set_load_error(&self, error: bool) {
|
||||||
self.loading_error.store(error, Ordering::Relaxed);
|
self.load_error.store(error, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get wallet data update attempts.
|
/// Get wallet data update attempts.
|
||||||
|
@ -243,25 +260,29 @@ impl Wallet {
|
||||||
|
|
||||||
/// Close the wallet.
|
/// Close the wallet.
|
||||||
pub fn close(&self) {
|
pub fn close(&self) {
|
||||||
if !self.is_open() {
|
if !self.is_open() || self.instance.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.closing.store(true, Ordering::Relaxed);
|
self.closing.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
// Close wallet at separate thread.
|
// Close wallet at separate thread.
|
||||||
let wallet_close = self.clone();
|
let mut wallet_close = self.clone();
|
||||||
|
let instance = wallet_close.instance.clone().unwrap();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
// Close the wallet.
|
// Close the wallet.
|
||||||
let _ = Self::close_wallet(&wallet_close.instance);
|
let mut wallet_lock = instance.lock();
|
||||||
|
let lc = wallet_lock.lc_provider().unwrap();
|
||||||
|
let _ = lc.close_wallet(None);
|
||||||
|
wallet_close.instance = None;
|
||||||
|
|
||||||
// Clear wallet info.
|
// Clear wallet info.
|
||||||
let mut w_data = wallet_close.data.write().unwrap();
|
let mut w_data = wallet_close.data.write().unwrap();
|
||||||
*w_data = None;
|
*w_data = None;
|
||||||
|
|
||||||
// Reset wallet loading values.
|
// Reset wallet loading values.
|
||||||
wallet_close.info_loading_progress.store(0, Ordering::Relaxed);
|
wallet_close.info_load_progress.store(0, Ordering::Relaxed);
|
||||||
wallet_close.txs_loading_progress.store(0, Ordering::Relaxed);
|
wallet_close.txs_load_progress.store(0, Ordering::Relaxed);
|
||||||
wallet_close.set_loading_error(false);
|
wallet_close.set_load_error(false);
|
||||||
wallet_close.reset_data_update_attempts();
|
wallet_close.reset_data_update_attempts();
|
||||||
|
|
||||||
// Mark wallet as not opened.
|
// Mark wallet as not opened.
|
||||||
|
@ -276,13 +297,6 @@ impl Wallet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Close provided [`WalletInstance`].
|
|
||||||
fn close_wallet(instance: &WalletInstance) -> Result<(), Error> {
|
|
||||||
let mut wallet_lock = instance.lock();
|
|
||||||
let lc = wallet_lock.lc_provider()?;
|
|
||||||
lc.close_wallet(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get wallet data.
|
/// Get wallet data.
|
||||||
pub fn get_data(&self) -> Option<WalletData> {
|
pub fn get_data(&self) -> Option<WalletData> {
|
||||||
let r_data = self.data.read().unwrap();
|
let r_data = self.data.read().unwrap();
|
||||||
|
@ -313,7 +327,7 @@ fn start_wallet(wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
||||||
// Set an error when required integrated node is not enabled and
|
// Set an error when required integrated node is not enabled and
|
||||||
// skip next cycle of update when node sync is not finished.
|
// skip next cycle of update when node sync is not finished.
|
||||||
if wallet_update.config.ext_conn_id.is_none() {
|
if wallet_update.config.ext_conn_id.is_none() {
|
||||||
wallet_update.set_loading_error(!Node::is_running() || Node::is_stopping());
|
wallet_update.set_load_error(!Node::is_running() || Node::is_stopping());
|
||||||
if !Node::is_running() || Node::get_sync_status() != Some(SyncStatus::NoSync) {
|
if !Node::is_running() || Node::get_sync_status() != Some(SyncStatus::NoSync) {
|
||||||
println!("integrated node wait");
|
println!("integrated node wait");
|
||||||
thread::park_timeout(Duration::from_millis(1000));
|
thread::park_timeout(Duration::from_millis(1000));
|
||||||
|
@ -322,7 +336,7 @@ fn start_wallet(wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update wallet data if there is no error.
|
// Update wallet data if there is no error.
|
||||||
if !wallet_update.loading_error() {
|
if !wallet_update.load_error() {
|
||||||
update_wallet_data(&wallet_update, keychain.clone());
|
update_wallet_data(&wallet_update, keychain.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +350,7 @@ fn start_wallet(wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat after default delay or after 1 second if update was not success.
|
// Repeat after default delay or after 1 second if update was not success.
|
||||||
let delay = if wallet_update.loading_error()
|
let delay = if wallet_update.load_error()
|
||||||
|| wallet_update.get_data_update_attempts() != 0 {
|
|| wallet_update.get_data_update_attempts() != 0 {
|
||||||
Duration::from_millis(1000)
|
Duration::from_millis(1000)
|
||||||
} else {
|
} else {
|
||||||
|
@ -348,7 +362,7 @@ fn start_wallet(wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle [`WalletCommand::UpdateData`] command to update [`WalletData`].
|
/// Handle [`WalletCommand::UpdateData`] command to update [`WalletData`].
|
||||||
fn update_wallet_data(wallet: &Wallet, key: Option<SecretKey>) {
|
fn update_wallet_data(wallet: &Wallet, keychain: Option<SecretKey>) {
|
||||||
println!("UPDATE start, attempts: {}", wallet.get_data_update_attempts());
|
println!("UPDATE start, attempts: {}", wallet.get_data_update_attempts());
|
||||||
|
|
||||||
let wallet_scan = wallet.clone();
|
let wallet_scan = wallet.clone();
|
||||||
|
@ -362,10 +376,10 @@ fn update_wallet_data(wallet: &Wallet, key: Option<SecretKey>) {
|
||||||
StatusMessage::UpdatingTransactions(_) => {}
|
StatusMessage::UpdatingTransactions(_) => {}
|
||||||
StatusMessage::FullScanWarn(_) => {}
|
StatusMessage::FullScanWarn(_) => {}
|
||||||
StatusMessage::Scanning(_, progress) => {
|
StatusMessage::Scanning(_, progress) => {
|
||||||
wallet_scan.info_loading_progress.store(progress, Ordering::Relaxed);
|
wallet_scan.info_load_progress.store(progress, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
StatusMessage::ScanningComplete(_) => {
|
StatusMessage::ScanningComplete(_) => {
|
||||||
wallet_scan.info_loading_progress.store(100, Ordering::Relaxed);
|
wallet_scan.info_load_progress.store(100, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
StatusMessage::UpdateWarning(_) => {}
|
StatusMessage::UpdateWarning(_) => {}
|
||||||
}
|
}
|
||||||
|
@ -373,108 +387,112 @@ fn update_wallet_data(wallet: &Wallet, key: Option<SecretKey>) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieve wallet info.
|
// Retrieve wallet info.
|
||||||
match retrieve_summary_info(
|
if let Some(instance) = &wallet.instance {
|
||||||
wallet.instance.clone(),
|
match retrieve_summary_info(
|
||||||
key.as_ref(),
|
instance.clone(),
|
||||||
&Some(info_tx),
|
keychain.as_ref(),
|
||||||
true,
|
&Some(info_tx),
|
||||||
wallet.config.min_confirmations
|
true,
|
||||||
) {
|
wallet.config.min_confirmations
|
||||||
Ok(info) => {
|
) {
|
||||||
// Do not retrieve txs if wallet was closed.
|
Ok(info) => {
|
||||||
if !wallet.is_open() {
|
// Do not retrieve txs if wallet was closed.
|
||||||
println!("UPDATE stop at retrieve_summary_info");
|
if !wallet.is_open() {
|
||||||
return;
|
println!("UPDATE stop at retrieve_summary_info");
|
||||||
}
|
return;
|
||||||
|
|
||||||
// Add attempt if scanning was not complete
|
|
||||||
// or set an error on initial request.
|
|
||||||
if wallet.info_loading_progress() != 100 {
|
|
||||||
println!("UPDATE retrieve_summary_info was not completed");
|
|
||||||
if wallet.get_data().is_none() {
|
|
||||||
wallet.set_loading_error(true);
|
|
||||||
} else {
|
|
||||||
wallet.increment_data_update_attempts();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
println!("UPDATE before retrieve_txs");
|
|
||||||
|
|
||||||
let wallet_txs = wallet.clone();
|
// Add attempt if scanning was not complete
|
||||||
let (txs_tx, txs_rx) = mpsc::channel::<StatusMessage>();
|
// or set an error on initial request.
|
||||||
// Update txs loading progress at separate thread.
|
if wallet.info_load_progress() != 100 {
|
||||||
thread::spawn(move || {
|
println!("UPDATE retrieve_summary_info was not completed");
|
||||||
while let Ok(m) = txs_rx.recv() {
|
if wallet.get_data().is_none() {
|
||||||
println!("UPDATE TXS MESSAGE");
|
wallet.set_load_error(true);
|
||||||
match m {
|
} else {
|
||||||
StatusMessage::UpdatingOutputs(_) => {}
|
|
||||||
StatusMessage::UpdatingTransactions(_) => {}
|
|
||||||
StatusMessage::FullScanWarn(_) => {}
|
|
||||||
StatusMessage::Scanning(_, progress) => {
|
|
||||||
wallet_txs.txs_loading_progress.store(progress, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
StatusMessage::ScanningComplete(_) => {
|
|
||||||
wallet_txs.txs_loading_progress.store(100, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
StatusMessage::UpdateWarning(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Retrieve txs.
|
|
||||||
match retrieve_txs(
|
|
||||||
wallet.instance.clone(),
|
|
||||||
key.as_ref(),
|
|
||||||
&Some(txs_tx),
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None
|
|
||||||
) {
|
|
||||||
Ok(txs) => {
|
|
||||||
// Do not update data if wallet was closed.
|
|
||||||
if !wallet.is_open() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add attempt if retrieving was not complete
|
|
||||||
// or set an error on initial request.
|
|
||||||
if wallet.txs_loading_progress() != 100 {
|
|
||||||
if wallet.get_data().is_none() {
|
|
||||||
wallet.set_loading_error(true);
|
|
||||||
} else {
|
|
||||||
wallet.increment_data_update_attempts();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Set wallet data.
|
|
||||||
let mut w_data = wallet.data.write().unwrap();
|
|
||||||
*w_data = Some(WalletData { info: info.1, txs: txs.1 });
|
|
||||||
|
|
||||||
// Reset attempts.
|
|
||||||
wallet.reset_data_update_attempts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
// Increment attempts value in case of error.
|
|
||||||
wallet.increment_data_update_attempts();
|
wallet.increment_data_update_attempts();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
println!("UPDATE before retrieve_txs");
|
||||||
|
|
||||||
|
let wallet_txs = wallet.clone();
|
||||||
|
let (txs_tx, txs_rx) = mpsc::channel::<StatusMessage>();
|
||||||
|
// Update txs loading progress at separate thread.
|
||||||
|
thread::spawn(move || {
|
||||||
|
while let Ok(m) = txs_rx.recv() {
|
||||||
|
println!("UPDATE TXS MESSAGE");
|
||||||
|
match m {
|
||||||
|
StatusMessage::UpdatingOutputs(_) => {}
|
||||||
|
StatusMessage::UpdatingTransactions(_) => {}
|
||||||
|
StatusMessage::FullScanWarn(_) => {}
|
||||||
|
StatusMessage::Scanning(_, progress) => {
|
||||||
|
wallet_txs.txs_load_progress.store(progress, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
StatusMessage::ScanningComplete(_) => {
|
||||||
|
wallet_txs.txs_load_progress.store(100, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
StatusMessage::UpdateWarning(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Retrieve txs.
|
||||||
|
match retrieve_txs(
|
||||||
|
instance.clone(),
|
||||||
|
keychain.as_ref(),
|
||||||
|
&Some(txs_tx),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None
|
||||||
|
) {
|
||||||
|
Ok(txs) => {
|
||||||
|
// Do not update data if wallet was closed.
|
||||||
|
if !wallet.is_open() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add attempt if retrieving was not complete
|
||||||
|
// or set an error on initial request.
|
||||||
|
if wallet.txs_load_progress() != 100 {
|
||||||
|
if wallet.get_data().is_none() {
|
||||||
|
wallet.set_load_error(true);
|
||||||
|
} else {
|
||||||
|
wallet.increment_data_update_attempts();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Set wallet data.
|
||||||
|
let mut w_data = wallet.data.write().unwrap();
|
||||||
|
*w_data = Some(WalletData { info: info.1, txs: txs.1 });
|
||||||
|
|
||||||
|
// Reset attempts.
|
||||||
|
wallet.reset_data_update_attempts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("error on retrieve_txs {}", e);
|
||||||
|
// Increment attempts value in case of error.
|
||||||
|
wallet.increment_data_update_attempts();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Err(e) => {
|
||||||
Err(_) => {
|
println!("error on retrieve_summary_info {}", e);
|
||||||
// Increment attempts value in case of error.
|
// Increment attempts value in case of error.
|
||||||
wallet.increment_data_update_attempts();
|
wallet.increment_data_update_attempts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset progress values.
|
// Reset progress values.
|
||||||
wallet.info_loading_progress.store(0, Ordering::Relaxed);
|
wallet.info_load_progress.store(0, Ordering::Relaxed);
|
||||||
wallet.txs_loading_progress.store(0, Ordering::Relaxed);
|
wallet.txs_load_progress.store(0, Ordering::Relaxed);
|
||||||
|
|
||||||
println!("UPDATE finish, attempts: {}", wallet.get_data_update_attempts());
|
println!("UPDATE finish, attempts: {}", wallet.get_data_update_attempts());
|
||||||
|
|
||||||
// Set an error if maximum number of attempts was reached.
|
// Set an error if maximum number of attempts was reached.
|
||||||
if wallet.get_data_update_attempts() >= DATA_UPDATE_ATTEMPTS {
|
if wallet.get_data_update_attempts() >= DATA_UPDATE_ATTEMPTS {
|
||||||
wallet.reset_data_update_attempts();
|
wallet.reset_data_update_attempts();
|
||||||
wallet.set_loading_error(true);
|
wallet.set_load_error(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue