diff --git a/src/gui/colors.rs b/src/gui/colors.rs index 1172b7e..7ccbeff 100644 --- a/src/gui/colors.rs +++ b/src/gui/colors.rs @@ -26,8 +26,8 @@ impl Colors { pub const GREEN: Color32 = Color32::from_rgb(0, 0x64, 0); pub const RED: Color32 = Color32::from_rgb(0x8B, 0, 0); pub const FILL: Color32 = Color32::from_gray(244); - pub const FILL_DARK: Color32 = Color32::from_gray(232); - pub const CHECKBOX: Color32 = Color32::from_gray(100); + pub const FILL_DARK: Color32 = Color32::from_gray(234); + pub const CHECKBOX: Color32 = Color32::from_gray(107); pub const TEXT: Color32 = Color32::from_gray(80); pub const TEXT_BUTTON: Color32 = Color32::from_gray(70); pub const TITLE: Color32 = Color32::from_gray(60); @@ -35,6 +35,7 @@ impl Colors { pub const GRAY: Color32 = Color32::from_gray(120); pub const STROKE: Color32 = Color32::from_gray(190); pub const INACTIVE_TEXT: Color32 = Color32::from_gray(150); + pub const ITEM_BUTTON: Color32 = Color32::from_gray(90); pub const ITEM_STROKE: Color32 = Color32::from_gray(220); pub const ITEM_HOVER: Color32 = Color32::from_gray(205); pub const ITEM_CURRENT: Color32 = Color32::from_gray(227); diff --git a/src/gui/views/modal.rs b/src/gui/views/modal.rs index 9f010fa..f2e1325 100644 --- a/src/gui/views/modal.rs +++ b/src/gui/views/modal.rs @@ -68,8 +68,8 @@ pub struct Modal { impl Modal { /// Margin from [`Modal`] window at top/left/right. const DEFAULT_MARGIN: f32 = 10.0; - /// Default width of the content. - const DEFAULT_WIDTH: f32 = Root::SIDE_PANEL_MIN_WIDTH - (2.0 * Self::DEFAULT_MARGIN); + /// Maximum width of the content. + const DEFAULT_WIDTH: f32 = Root::SIDE_PANEL_WIDTH - (2.0 * Self::DEFAULT_MARGIN); /// Create opened and closeable Modal with center position. pub fn new(id: &'static str) -> Self { diff --git a/src/gui/views/root.rs b/src/gui/views/root.rs index 4d09174..0582936 100644 --- a/src/gui/views/root.rs +++ b/src/gui/views/root.rs @@ -20,7 +20,7 @@ use lazy_static::lazy_static; use crate::gui::Colors; use crate::gui::platform::PlatformCallbacks; -use crate::gui::views::{WalletsContent, Modal, ModalContainer, Network, View}; +use crate::gui::views::{Modal, ModalContainer, Network, View, WalletsContent}; use crate::node::Node; lazy_static! { @@ -73,7 +73,7 @@ impl Root { pub const EXIT_MODAL_ID: &'static str = "exit_confirmation"; /// Default width of side panel at application UI. - pub const SIDE_PANEL_MIN_WIDTH: f32 = 400.0; + pub const SIDE_PANEL_WIDTH: f32 = 400.0; pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) { // Show opened exit confirmation modal content. @@ -110,7 +110,7 @@ impl Root { let dual_panel_mode = Self::is_dual_panel_mode(frame); let is_panel_open = dual_panel_mode || Self::is_network_panel_open(); let panel_width = if dual_panel_mode { - Self::SIDE_PANEL_MIN_WIDTH + View::get_left_inset() + Self::SIDE_PANEL_WIDTH + View::get_left_inset() } else { frame.info().window_info.size.x }; @@ -126,7 +126,7 @@ impl Root { // Dual panel mode is available when window is wide and its width is at least 2 times // greater than minimal width of the side panel plus display insets from both sides. let side_insets = View::get_left_inset() + View::get_right_inset(); - is_wide_screen && w >= (Self::SIDE_PANEL_MIN_WIDTH * 2.0) + side_insets + is_wide_screen && w >= (Self::SIDE_PANEL_WIDTH * 2.0) + side_insets } /// Toggle [`Network`] panel state. diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 64ecfc9..6beaefc 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -128,25 +128,35 @@ impl View { /// Tab button with white background fill color, contains only icon. pub fn tab_button(ui: &mut egui::Ui, icon: &str, active: bool, action: impl FnOnce()) { - let text_color = match active { - true => Colors::TITLE, - false => Colors::TEXT - }; - let stroke = match active { - true => Stroke::NONE, - false => Self::DEFAULT_STROKE - }; - let color = match active { - true => Colors::FILL, - false => Colors::WHITE - }; - let br = Button::new(RichText::new(icon.to_string()).size(22.0).color(text_color)) - .stroke(stroke) - .fill(color) - .ui(ui); - if Self::touched(ui, br) { - (action)(); - } + ui.scope(|ui| { + let text_color = match active { + true => Colors::TITLE, + false => Colors::TEXT + }; + + let mut button = Button::new(RichText::new(icon).size(22.0).color(text_color)); + + if !active { + // Disable expansion on click/hover. + ui.style_mut().visuals.widgets.hovered.expansion = 0.0; + ui.style_mut().visuals.widgets.active.expansion = 0.0; + // Setup fill colors. + ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::WHITE; + ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::BUTTON; + ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL; + // Setup stroke colors. + ui.visuals_mut().widgets.inactive.bg_stroke = Self::DEFAULT_STROKE; + ui.visuals_mut().widgets.hovered.bg_stroke = Self::ITEM_HOVER_STROKE; + ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE; + } else { + button = button.fill(Colors::FILL).stroke(Stroke::NONE); + } + + let br = button.ui(ui); + if Self::touched(ui, br) { + (action)(); + } + }); } /// Draw [`Button`] with specified background fill color. @@ -174,19 +184,17 @@ impl View { // Disable expansion on click/hover. ui.style_mut().visuals.widgets.hovered.expansion = 0.0; ui.style_mut().visuals.widgets.active.expansion = 0.0; - // Setup fill colors. ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::WHITE; ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::BUTTON; ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL; - // Setup stroke colors. ui.visuals_mut().widgets.inactive.bg_stroke = Self::DEFAULT_STROKE; ui.visuals_mut().widgets.hovered.bg_stroke = Self::ITEM_HOVER_STROKE; ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE; // Show button. - let br = Button::new(RichText::new(icon).size(20.0).color(Colors::CHECKBOX)) + let br = Button::new(RichText::new(icon).size(20.0).color(Colors::ITEM_BUTTON)) .rounding(rounding) .min_size(button_size) .ui(ui); diff --git a/src/gui/views/wallets/creation/mnemonic.rs b/src/gui/views/wallets/creation/mnemonic.rs index d1c7629..46db431 100644 --- a/src/gui/views/wallets/creation/mnemonic.rs +++ b/src/gui/views/wallets/creation/mnemonic.rs @@ -321,7 +321,7 @@ impl MnemonicSetup { /// Calculate word list columns count based on available ui width. fn list_columns_count(ui: &mut egui::Ui) -> usize { let w = ui.available_width(); - let min_panel_w = Root::SIDE_PANEL_MIN_WIDTH - 12.0; + let min_panel_w = Root::SIDE_PANEL_WIDTH - 12.0; let double_min_panel_w = min_panel_w * 2.0; if w >= min_panel_w * 1.5 && w < double_min_panel_w { 3 diff --git a/src/gui/views/wallets/wallets.rs b/src/gui/views/wallets/wallets.rs index 053b0da..fcec260 100644 --- a/src/gui/views/wallets/wallets.rs +++ b/src/gui/views/wallets/wallets.rs @@ -18,7 +18,7 @@ use egui::{Align, Align2, Layout, Margin, RichText, Rounding, ScrollArea, TextSt use egui_extras::{Size, StripBuilder}; use crate::gui::Colors; -use crate::gui::icons::{ARROW_LEFT, CARET_RIGHT, COMPUTER_TOWER, EYE, EYE_SLASH, FOLDER, FOLDER_LOCK, FOLDER_OPEN, GEAR, GLOBE, GLOBE_SIMPLE, PLUS}; +use crate::gui::icons::{ARROW_LEFT, CARET_RIGHT, COMPUTER_TOWER, EYE, EYE_SLASH, FOLDER_LOCK, FOLDER_OPEN, GEAR, GLOBE, GLOBE_SIMPLE, PLUS}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, ModalContainer, ModalPosition, Root, TitlePanel, TitleType, View}; use crate::gui::views::wallets::creation::{MnemonicSetup, WalletCreation}; @@ -229,14 +229,12 @@ impl WalletsContent { .auto_shrink([false; 2]) .show(ui, |ui| { ui.vertical_centered(|ui| { - // Calculate wallet list width. - let available_width = ui.available_width(); - let width = if dual_panel { - available_width - } else { - min(available_width as i64, (Root::SIDE_PANEL_MIN_WIDTH * 1.3) as i64) as f32 - }; + // Setup wallet list width. let mut rect = ui.available_rect_before_wrap(); + let mut width = ui.available_width(); + if !dual_panel { + width = min(width as i64, (Root::SIDE_PANEL_WIDTH * 1.3) as i64) as f32 + } rect.set_width(width); ui.allocate_ui(rect.size(), |ui| { @@ -274,7 +272,7 @@ impl WalletsContent { // Draw round background. let mut rect = ui.available_rect_before_wrap(); - rect.set_height(77.0); + rect.set_height(78.0); let rounding = View::item_rounding(0, 1); let bg_color = if is_current { Colors::ITEM_CURRENT } else { Colors::FILL }; let stroke = if is_current { View::ITEM_HOVER_STROKE } else { View::ITEM_HOVER_STROKE }; @@ -310,21 +308,20 @@ impl WalletsContent { ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| { ui.add_space(7.0); ui.vertical(|ui| { + ui.add_space(3.0); // Setup wallet name text. - let name_text = format!("{} {}", FOLDER, wallet.config.name); let name_color = if is_selected { Colors::BLACK } else { Colors::TITLE }; - ui.add_space(4.0); - View::ellipsize_text(ui, name_text, 18.0, name_color); - ui.add_space(-1.0); + View::ellipsize_text(ui, wallet.config.name.to_owned(), 18.0, name_color); // Setup wallet connection text. - let external_url = wallet.config.get_external_node_url(); + let external_url = &wallet.config.external_node_url; let conn_text = if let Some(url) = external_url { format!("{} {}", GLOBE_SIMPLE, url) } else { format!("{} {}", COMPUTER_TOWER, t!("network.node")) }; View::ellipsize_text(ui, conn_text, 15.0, Colors::TEXT); + ui.add_space(1.0); // Setup wallet status text. let status_text = if Wallets::is_open(id) { @@ -491,10 +488,10 @@ impl WalletsContent { let available_width = if is_list_empty || is_wallet_creation { ui.available_width() } else { - ui.available_width() - Root::SIDE_PANEL_MIN_WIDTH + ui.available_width() - Root::SIDE_PANEL_WIDTH }; if dual_panel { - let min_width = (Root::SIDE_PANEL_MIN_WIDTH + View::get_right_inset()) as i64; + let min_width = (Root::SIDE_PANEL_WIDTH + View::get_right_inset()) as i64; max(min_width, available_width as i64) as f32 } else { if is_wallet_showing { @@ -509,7 +506,7 @@ impl WalletsContent { fn is_dual_panel_mode(ui: &mut egui::Ui, frame: &mut eframe::Frame) -> bool { let dual_panel_root = Root::is_dual_panel_mode(frame); let max_width = ui.available_width(); - dual_panel_root && max_width >= (Root::SIDE_PANEL_MIN_WIDTH * 2.0) + View::get_right_inset() + dual_panel_root && max_width >= (Root::SIDE_PANEL_WIDTH * 2.0) + View::get_right_inset() } /// Handle Back key event. diff --git a/src/settings.rs b/src/settings.rs index 25fa93f..ae3417c 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -83,16 +83,19 @@ impl AppConfig { pub fn change_chain_type(chain_type: &ChainTypes) { let current_chain_type = Self::chain_type(); if current_chain_type != *chain_type { - let mut w_app_config = Settings::app_config_to_update(); - w_app_config.chain_type = *chain_type; - w_app_config.save(); - + // Save chain type at app config. + { + let mut w_app_config = Settings::app_config_to_update(); + w_app_config.chain_type = *chain_type; + w_app_config.save(); + } // Load node config for selected chain type. - let mut w_node_config = Settings::node_config_to_update(); - let node_config = NodeConfig::for_chain_type(chain_type); - w_node_config.node = node_config.node; - w_node_config.peers = node_config.peers; - + { + let mut w_node_config = Settings::node_config_to_update(); + let node_config = NodeConfig::for_chain_type(chain_type); + w_node_config.node = node_config.node; + w_node_config.peers = node_config.peers; + } // Reload wallets. Wallets::reload(chain_type); } diff --git a/src/wallet/config.rs b/src/wallet/config.rs index 5468d95..2913cdb 100644 --- a/src/wallet/config.rs +++ b/src/wallet/config.rs @@ -14,9 +14,10 @@ use std::fs; use std::path::PathBuf; -use grin_core::global::ChainTypes; +use grin_core::global::ChainTypes; use serde_derive::{Deserialize, Serialize}; + use crate::{AppConfig, Settings}; use crate::wallet::Wallets; @@ -24,13 +25,13 @@ use crate::wallet::Wallets; #[derive(Serialize, Deserialize, Clone)] pub struct WalletConfig { /// Chain type for current wallet. - chain_type: ChainTypes, + pub(crate) chain_type: ChainTypes, /// Identifier for a wallet. pub(crate) id: i64, /// Human-readable wallet name for ui. pub(crate) name: String, /// External node connection URL. - external_node_url: Option, + pub(crate) external_node_url: Option, } /// Wallet configuration file name. @@ -84,13 +85,8 @@ impl WalletConfig { Settings::write_to_file(self, config_path); } - /// Get external node connection URL. - pub fn get_external_node_url(&self) -> &Option { - &self.external_node_url - } - /// Set external node connection URL. - pub fn set_external_node_url(&mut self, url: Option) { + pub fn save_external_node_url(&mut self, url: Option) { self.external_node_url = url; self.save(); } diff --git a/src/wallet/wallets.rs b/src/wallet/wallets.rs index d53b1e9..38a1f6f 100644 --- a/src/wallet/wallets.rs +++ b/src/wallet/wallets.rs @@ -160,8 +160,11 @@ impl Wallets { /// Reload list of wallets for provided [`ChainTypes`]. pub fn reload(chain_type: &ChainTypes) { + let wallets = Self::load_wallets(chain_type); let mut w_state = WALLETS_STATE.write().unwrap(); - w_state.list = Self::load_wallets(chain_type); + w_state.selected_id = None; + w_state.opened_ids = BTreeSet::default(); + w_state.list = wallets; } } @@ -241,7 +244,7 @@ impl Wallet { /// Create wallet instance from provided config. fn create_wallet_instance(config: WalletConfig) -> Result { // Assume global chain type has already been initialized. - let chain_type = AppConfig::chain_type(); + let chain_type = config.chain_type; if !global::GLOBAL_CHAIN_TYPE.is_init() { global::init_global_chain_type(chain_type); } else { @@ -250,8 +253,8 @@ impl Wallet { } // Setup node client. - let (node_api_url, node_secret) = if let Some(url) = config.get_external_node_url() { - (url.to_string(), None) + let (node_api_url, node_secret) = if let Some(url) = &config.external_node_url { + (url.to_owned(), None) } else { (NodeConfig::get_api_address(), NodeConfig::get_api_secret()) };