wallets: fix wallet mutability, wallet connection change, optimize wallet lists for different chain types

This commit is contained in:
ardocrat 2023-08-11 17:29:25 +03:00
parent 3635b7abe6
commit d466cb1d9c
10 changed files with 133 additions and 60 deletions

View file

@ -14,6 +14,7 @@
use egui::{Align, Align2, Layout, Margin, RichText, Rounding, ScrollArea, TextStyle, Widget}; use egui::{Align, Align2, Layout, Margin, RichText, Rounding, ScrollArea, TextStyle, Widget};
use egui_extras::{Size, StripBuilder}; use egui_extras::{Size, StripBuilder};
use grin_core::global::ChainTypes;
use crate::AppConfig; use crate::AppConfig;
use crate::gui::Colors; use crate::gui::Colors;
@ -95,10 +96,8 @@ impl WalletsContent {
// Draw modal content for current ui container. // Draw modal content for current ui container.
self.current_modal_ui(ui, frame, cb); self.current_modal_ui(ui, frame, cb);
let wallets = self.wallets.list();
let empty_list = wallets.is_empty();
// Setup wallet content flags. // Setup wallet content flags.
let empty_list = self.wallets.is_current_list_empty();
let create_wallet = self.creation_content.can_go_back(); let create_wallet = self.creation_content.can_go_back();
let show_wallet = self.wallets.is_selected_open(); let show_wallet = self.wallets.is_selected_open();
@ -140,9 +139,15 @@ impl WalletsContent {
self.wallets.add(wallet); self.wallets.add(wallet);
}); });
} else { } else {
for mut wallet in wallets.clone() { 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() {
// Show content for selected wallet. // Show content for selected wallet.
if self.wallets.is_selected(wallet.config.id) { if self.wallets.selected_id == Some(wallet.config.id) {
// Setup wallet content width. // Setup wallet content width.
let mut rect = ui.available_rect_before_wrap(); let mut rect = ui.available_rect_before_wrap();
let mut width = ui.available_width(); let mut width = ui.available_width();
@ -152,7 +157,7 @@ impl WalletsContent {
rect.set_width(width); rect.set_width(width);
// Show wallet content. // Show wallet content.
ui.allocate_ui_at_rect(rect, |ui| { ui.allocate_ui_at_rect(rect, |ui| {
self.wallet_content.ui(ui, frame, &mut wallet, cb); self.wallet_content.ui(ui, frame, wallet, cb);
}); });
break; break;
} }
@ -201,7 +206,7 @@ impl WalletsContent {
// Show list of wallets. // Show list of wallets.
let scroll = let scroll =
self.wallet_list_ui(ui, wallets, dual_panel, show_creation_button, cb); self.wallet_list_ui(ui, dual_panel, show_creation_button, cb);
if show_creation_button { if show_creation_button {
// Setup right margin for button. // Setup right margin for button.
@ -296,7 +301,6 @@ impl WalletsContent {
/// Draw list of wallets. Returns `true` if scroller is showing. /// Draw list of wallets. Returns `true` if scroller is showing.
fn wallet_list_ui(&mut self, fn wallet_list_ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
wallets: Vec<Wallet>,
dual_panel: bool, dual_panel: bool,
show_creation_btn: bool, show_creation_btn: bool,
cb: &dyn PlatformCallbacks) -> bool { cb: &dyn PlatformCallbacks) -> bool {
@ -324,9 +328,10 @@ impl WalletsContent {
rect.set_width(width); rect.set_width(width);
ui.allocate_ui(rect.size(), |ui| { ui.allocate_ui(rect.size(), |ui| {
for mut wallet in wallets { let list = self.wallets.list().clone();
for wallet in &list {
// Draw wallet list item. // Draw wallet list item.
self.wallet_item_ui(ui, &mut wallet, cb); self.wallet_item_ui(ui, wallet, cb);
ui.add_space(5.0); ui.add_space(5.0);
} }
// Add space for wallet creation button. // Add space for wallet creation button.
@ -345,10 +350,10 @@ impl WalletsContent {
/// Draw wallet list item. /// Draw wallet list item.
fn wallet_item_ui(&mut self, fn wallet_item_ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
wallet: &mut Wallet, wallet: &Wallet,
cb: &dyn PlatformCallbacks) { cb: &dyn PlatformCallbacks) {
let id = wallet.config.id; let id = wallet.config.id;
let is_selected = self.wallets.is_selected(id); let is_selected = self.wallets.selected_id == Some(id);
let is_current = wallet.is_open() && is_selected; let is_current = wallet.is_open() && is_selected;
// Draw round background. // Draw round background.

View file

@ -20,7 +20,7 @@ use crate::gui::icons::{GLOBE, GLOBE_SIMPLE};
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::wallet::{ConnectionsConfig, ExternalConnection}; use crate::wallet::{ConnectionsConfig, ExternalConnection, Wallet};
use crate::wallet::types::ConnectionMethod; use crate::wallet::types::ConnectionMethod;
/// Wallet node connection method setup content. /// Wallet node connection method setup content.
@ -77,12 +77,51 @@ impl ModalContainer for ConnectionSetup {
} }
impl ConnectionSetup { impl ConnectionSetup {
//TODO: Setup for provided wallet /// Draw wallet creation setup content.
// pub fn new() -> Self { pub fn create_ui(&mut self,
// Self { method: ConnectionMethod::Integrated } ui: &mut egui::Ui,
// } frame: &mut eframe::Frame,
cb: &dyn PlatformCallbacks) {
self.ui(ui, frame, cb);
}
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) { /// Draw existing wallet connection setup content.
pub fn wallet_ui(&mut self,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
wallet: &mut Wallet,
cb: &dyn PlatformCallbacks) {
// Setup connection value from provided wallet.
match wallet.config.ext_conn_id {
None => self.method = ConnectionMethod::Integrated,
Some(id) => self.method = ConnectionMethod::External(id)
}
// Draw setup content.
self.ui(ui, frame, cb);
// Setup wallet connection value after change.
match self.method {
ConnectionMethod::Integrated => {
if wallet.config.ext_conn_id.is_some() {
wallet.config.ext_conn_id = None;
wallet.config.save();
}
}
ConnectionMethod::External(id) => {
if wallet.config.ext_conn_id != Some(id) {
wallet.config.ext_conn_id = Some(id);
wallet.config.save();
}
}
}
}
/// Draw connection setup content.
fn ui(&mut self,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
cb: &dyn PlatformCallbacks) {
// Draw modal content for current ui container. // Draw modal content for current ui container.
self.current_modal_ui(ui, frame, cb); self.current_modal_ui(ui, frame, cb);

View file

@ -60,11 +60,12 @@ impl WalletContent {
.show_inside(ui, |ui| { .show_inside(ui, |ui| {
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
// Setup tabs width. // Setup tabs width.
let mut rect = ui.available_rect_before_wrap(); let available_width = ui.available_width();
let mut width = f32::min(ui.available_width(), Root::SIDE_PANEL_WIDTH * 2.0); if available_width == 0.0 {
if width == 0.0 {
return; return;
} }
let mut rect = ui.available_rect_before_wrap();
let width = f32::min(available_width, Root::SIDE_PANEL_WIDTH * 2.0);
rect.set_width(width); rect.set_width(width);
// Draw wallet tabs. // Draw wallet tabs.
@ -90,11 +91,12 @@ impl WalletContent {
.show_inside(ui, |ui| { .show_inside(ui, |ui| {
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
// Setup tab content width. // Setup tab content width.
let mut rect = ui.available_rect_before_wrap(); let available_width = ui.available_width();
let mut width = f32::min(ui.available_width(), Root::SIDE_PANEL_WIDTH * 2.0); if available_width == 0.0 {
if width == 0.0 {
return; return;
} }
let mut rect = ui.available_rect_before_wrap();
let width = f32::min(available_width, Root::SIDE_PANEL_WIDTH * 2.0);
rect.set_width(width); rect.set_width(width);
// Draw current tab content. // Draw current tab content.

View file

@ -30,7 +30,7 @@ impl WalletTab for WalletInfo {
fn ui(&mut self, fn ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
wallet: &Wallet, wallet: &mut Wallet,
cb: &dyn PlatformCallbacks) { cb: &dyn PlatformCallbacks) {
WalletContent::loading_ui(ui, frame, wallet); WalletContent::loading_ui(ui, frame, wallet);
} }

View file

@ -25,6 +25,10 @@ impl WalletTab for WalletReceive {
WalletTabType::Receive WalletTabType::Receive
} }
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, wallet: &Wallet, cb: &dyn PlatformCallbacks) { fn ui(&mut self,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
wallet: &mut Wallet,
cb: &dyn PlatformCallbacks) {
} }
} }

View file

@ -25,6 +25,10 @@ impl WalletTab for WalletSend {
WalletTabType::Send WalletTabType::Send
} }
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, wallet: &Wallet, cb: &dyn PlatformCallbacks) { fn ui(&mut self,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
wallet: &mut Wallet,
cb: &dyn PlatformCallbacks) {
} }
} }

View file

@ -13,12 +13,16 @@
// limitations under the License. // limitations under the License.
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
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::wallet::Wallet;
/// Wallet settings tab content. /// Wallet settings tab content.
#[derive(Default)] #[derive(Default)]
pub struct WalletSettings; pub struct WalletSettings {
/// Connection setup content.
conn_setup: ConnectionSetup
}
impl WalletTab for WalletSettings { impl WalletTab for WalletSettings {
fn get_type(&self) -> WalletTabType { fn get_type(&self) -> WalletTabType {
@ -28,7 +32,8 @@ impl WalletTab for WalletSettings {
fn ui(&mut self, fn ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
wallet: &Wallet, wallet: &mut Wallet,
cb: &dyn PlatformCallbacks) { cb: &dyn PlatformCallbacks) {
self.conn_setup.wallet_ui(ui, frame, wallet, cb);
} }
} }

View file

@ -21,7 +21,7 @@ pub trait WalletTab {
fn ui(&mut self, fn ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
wallet: &Wallet, wallet: &mut Wallet,
cb: &dyn PlatformCallbacks); cb: &dyn PlatformCallbacks);
} }

View file

@ -109,7 +109,7 @@ impl WalletConfig {
} }
/// Save wallet config. /// Save wallet config.
fn save(&self) { pub fn save(&self) {
let config_path = Self::get_config_file_path(self.chain_type, self.id); let config_path = Self::get_config_file_path(self.chain_type, self.id);
Settings::write_to_file(self, config_path); Settings::write_to_file(self, config_path);
} }

View file

@ -20,56 +20,70 @@ use crate::wallet::{Wallet, WalletConfig};
/// Wrapper for [`Wallet`] list. /// Wrapper for [`Wallet`] list.
pub struct WalletList { pub struct WalletList {
/// List of wallets. /// List of wallets for [`ChainTypes::Mainnet`].
list: Vec<Wallet>, pub main_list: Vec<Wallet>,
/// List of wallets for [`ChainTypes::Testnet`].
pub test_list: Vec<Wallet>,
/// Selected [`Wallet`] identifier. /// Selected [`Wallet`] identifier.
selected_id: Option<i64>, pub selected_id: Option<i64>,
} }
impl Default for WalletList { impl Default for WalletList {
fn default() -> Self { fn default() -> Self {
Self { let (main_list, test_list) = Self::init();
list: Self::init(), Self { main_list, test_list, selected_id: None }
selected_id: None
}
} }
} }
impl WalletList { impl WalletList {
/// Initialize [`Wallet`] list from base directory. /// Initialize [`Wallet`] lists for [`ChainTypes::Mainnet`] and [`ChainTypes::Testnet`].
fn init() -> Vec<Wallet> { fn init() -> (Vec<Wallet>, Vec<Wallet>) {
let mut wallets = Vec::new(); let mut main_wallets = Vec::new();
let mut test_wallets = Vec::new();
let chain_types = vec![ChainTypes::Mainnet, ChainTypes::Testnet]; let chain_types = vec![ChainTypes::Mainnet, ChainTypes::Testnet];
for chain in chain_types { for chain in chain_types {
// initialize wallets from base directory.
let wallets_dir = WalletConfig::get_base_path(chain); let wallets_dir = WalletConfig::get_base_path(chain);
// Load wallets from base directory.
for dir in wallets_dir.read_dir().unwrap() { for dir in wallets_dir.read_dir().unwrap() {
let wallet_dir = dir.unwrap().path(); let wallet_dir = dir.unwrap().path();
if wallet_dir.is_dir() { if wallet_dir.is_dir() {
let wallet = Wallet::init(wallet_dir); let wallet = Wallet::init(wallet_dir);
if let Some(w) = wallet { if let Some(w) = wallet {
wallets.push(w); if chain == ChainTypes::Testnet {
test_wallets.push(w);
} else if chain == ChainTypes::Mainnet {
main_wallets.push(w);
}
} }
} }
} }
} }
// Sort wallets by id. // Sort wallets by id.
wallets.sort_by_key(|w| w.config.id); main_wallets.sort_by_key(|w| w.config.id);
wallets test_wallets.sort_by_key(|w| w.config.id);
(main_wallets, test_wallets)
} }
/// Get wallet list for current [`ChainTypes`]. /// Get [`Wallet`] list for current [`ChainTypes`].
pub fn list(&self) -> Vec<Wallet> { pub fn list(&self) -> &Vec<Wallet> {
let chain_type = AppConfig::chain_type(); let chain_type = AppConfig::chain_type();
self.list.iter().cloned() if chain_type == ChainTypes::Mainnet {
.filter(|w| w.config.chain_type == chain_type) &self.main_list
.collect::<Vec<Wallet>>() } else {
&self.test_list
}
} }
/// Add created [`Wallet`] to the list. /// Add created [`Wallet`] to the list.
pub fn add(&mut self, wallet: Wallet) { pub fn add(&mut self, wallet: Wallet) {
self.selected_id = Some(wallet.config.id); self.selected_id = Some(wallet.config.id);
self.list.insert(0, wallet); let chain_type = AppConfig::chain_type();
let list = if chain_type == ChainTypes::Mainnet {
&mut self.main_list
} else {
&mut self.test_list
};
list.insert(0, wallet);
} }
/// Select [`Wallet`] with provided identifier. /// Select [`Wallet`] with provided identifier.
@ -79,7 +93,7 @@ impl WalletList {
/// Get selected [`Wallet`] name. /// Get selected [`Wallet`] name.
pub fn selected_name(&self) -> String { pub fn selected_name(&self) -> String {
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 {
return w.config.name.to_owned() return w.config.name.to_owned()
} }
@ -87,14 +101,9 @@ impl WalletList {
t!("wallets.unlocked") t!("wallets.unlocked")
} }
/// Check if [`Wallet`] is selected for provided identifier.
pub fn is_selected(&self, id: i64) -> bool {
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 {
return w.is_open() return w.is_open()
} }
@ -102,9 +111,14 @@ impl WalletList {
false false
} }
/// Check if current list is empty.
pub fn is_current_list_empty(&self) -> bool {
self.list().is_empty()
}
/// Open selected [`Wallet`]. /// Open selected [`Wallet`].
pub fn open_selected(&mut self, password: String) -> Result<(), Error> { pub fn open_selected(&self, password: String) -> Result<(), Error> {
for w in self.list.iter_mut() { for w in self.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());
} }