ui: items rounding refactoring, external connections network content, exit modal title, update translations
This commit is contained in:
parent
4e42650160
commit
92c7ab62c2
16 changed files with 551 additions and 111 deletions
|
@ -38,6 +38,7 @@ wallets:
|
||||||
settings: Wallet settings
|
settings: Wallet settings
|
||||||
network:
|
network:
|
||||||
self: Network
|
self: Network
|
||||||
|
connections: Connections
|
||||||
node: Integrated node
|
node: Integrated node
|
||||||
metrics: Metrics
|
metrics: Metrics
|
||||||
mining: Mining
|
mining: Mining
|
||||||
|
|
|
@ -24,7 +24,7 @@ wallets:
|
||||||
add_node: Добавить узел
|
add_node: Добавить узел
|
||||||
node_url: 'URL узла:'
|
node_url: 'URL узла:'
|
||||||
node_secret: 'API токен (необязательно):'
|
node_secret: 'API токен (необязательно):'
|
||||||
invalid_url: Введенный URL-адрес недействителен
|
invalid_url: Введённый URL-адрес недействителен
|
||||||
open: Открыть кошелёк
|
open: Открыть кошелёк
|
||||||
wrong_pass: Введён неправильный пароль
|
wrong_pass: Введён неправильный пароль
|
||||||
locked: Заблокирован
|
locked: Заблокирован
|
||||||
|
@ -38,6 +38,7 @@ wallets:
|
||||||
settings: Настройки кошелька
|
settings: Настройки кошелька
|
||||||
network:
|
network:
|
||||||
self: Сеть
|
self: Сеть
|
||||||
|
connections: Подключения
|
||||||
node: Встроенный узел
|
node: Встроенный узел
|
||||||
metrics: Показатели
|
metrics: Показатели
|
||||||
mining: Майнинг
|
mining: Майнинг
|
||||||
|
|
343
src/gui/views/network/connections/content.rs
Normal file
343
src/gui/views/network/connections/content.rs
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use egui::{Align, Id, Layout, RichText, Rounding, TextStyle, Widget};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::AppConfig;
|
||||||
|
use crate::gui::Colors;
|
||||||
|
use crate::gui::icons::{CARET_RIGHT, CHECK_CIRCLE, COMPUTER_TOWER, DOTS_THREE_CIRCLE, GLOBE_SIMPLE, PENCIL, PLAY, STOP, TRASH, X_CIRCLE};
|
||||||
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
|
use crate::gui::views::{Modal, View};
|
||||||
|
use crate::gui::views::types::{ModalContainer, ModalPosition};
|
||||||
|
use crate::node::{Node, NodeConfig};
|
||||||
|
use crate::wallet::{ConnectionsConfig, ExternalConnection};
|
||||||
|
|
||||||
|
/// Network connections content.
|
||||||
|
pub struct ConnectionsContent {
|
||||||
|
/// Flag to check if modal was just opened.
|
||||||
|
first_modal_launch: bool,
|
||||||
|
/// External connection URL value for [`Modal`].
|
||||||
|
ext_node_url_edit: String,
|
||||||
|
/// External connection API secret value for [`Modal`].
|
||||||
|
ext_node_secret_edit: String,
|
||||||
|
/// Flag to show URL format error.
|
||||||
|
ext_node_url_error: bool,
|
||||||
|
/// Flag to check if existing connection is editing.
|
||||||
|
edit_ext_conn: Option<ExternalConnection>,
|
||||||
|
|
||||||
|
/// [`Modal`] identifiers allowed at this ui container.
|
||||||
|
modal_ids: Vec<&'static str>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ConnectionsContent {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
first_modal_launch: true,
|
||||||
|
ext_node_url_edit: "".to_string(),
|
||||||
|
ext_node_secret_edit: "".to_string(),
|
||||||
|
ext_node_url_error: false,
|
||||||
|
edit_ext_conn: None,
|
||||||
|
modal_ids: vec![
|
||||||
|
Self::NETWORK_EXT_CONNECTION_MODAL
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModalContainer for ConnectionsContent {
|
||||||
|
fn modal_ids(&self) -> &Vec<&'static str> {
|
||||||
|
&self.modal_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modal_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
_: &mut eframe::Frame,
|
||||||
|
modal: &Modal,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
match modal.id {
|
||||||
|
Self::NETWORK_EXT_CONNECTION_MODAL => self.ext_conn_modal_ui(ui, modal, cb),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectionsContent {
|
||||||
|
/// External connection [`Modal`] identifier.
|
||||||
|
pub const NETWORK_EXT_CONNECTION_MODAL: &'static str = "network_ext_connection_modal";
|
||||||
|
|
||||||
|
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) {
|
||||||
|
// Draw modal content for current ui container.
|
||||||
|
self.current_modal_ui(ui, frame, cb);
|
||||||
|
|
||||||
|
// Show integrated node info content.
|
||||||
|
Self::integrated_node_item_ui(ui);
|
||||||
|
|
||||||
|
ui.add_space(8.0);
|
||||||
|
ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::GRAY));
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
// Show external connections.
|
||||||
|
let ext_conn_list = ConnectionsConfig::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(), cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw integrated node connection item content.
|
||||||
|
fn integrated_node_item_ui(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);
|
||||||
|
let bg_color = Colors::FILL_DARK;
|
||||||
|
ui.painter().rect(rect, rounding, bg_color, View::HOVER_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 show integrated node.
|
||||||
|
View::item_button(ui, View::item_rounding(0, 1, true), CARET_RIGHT, || {
|
||||||
|
AppConfig::toggle_show_connections_network_panel();
|
||||||
|
});
|
||||||
|
|
||||||
|
if !Node::is_running() {
|
||||||
|
// Draw button to start integrated node.
|
||||||
|
View::item_button(ui, Rounding::none(), PLAY, || {
|
||||||
|
Node::start();
|
||||||
|
});
|
||||||
|
} else if !Node::is_starting() && !Node::is_stopping() && !Node::is_restarting() {
|
||||||
|
// Show button to open closed wallet.
|
||||||
|
View::item_button(ui, Rounding::none(), STOP, || {
|
||||||
|
Node::stop(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout_size = ui.available_size();
|
||||||
|
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);
|
||||||
|
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));
|
||||||
|
ui.add_space(4.0);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw external connection item content.
|
||||||
|
fn ext_conn_item_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
conn: &ExternalConnection,
|
||||||
|
index: usize,
|
||||||
|
len: usize,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
// Setup layout size.
|
||||||
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
|
rect.set_height(42.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 buttons for non-default connections.
|
||||||
|
if conn.url != ExternalConnection::DEFAULT_EXTERNAL_NODE_URL {
|
||||||
|
let button_rounding = View::item_rounding(index, len, true);
|
||||||
|
View::item_button(ui, button_rounding, TRASH, || {
|
||||||
|
ConnectionsConfig::remove_external_connection(conn);
|
||||||
|
});
|
||||||
|
View::item_button(ui, Rounding::none(), PENCIL, || {
|
||||||
|
// Setup values for Modal.
|
||||||
|
self.first_modal_launch = true;
|
||||||
|
self.ext_node_url_edit = conn.url.clone();
|
||||||
|
self.ext_node_secret_edit = conn.secret.clone().unwrap_or("".to_string());
|
||||||
|
self.ext_node_url_error = false;
|
||||||
|
self.edit_ext_conn = Some(conn.clone());
|
||||||
|
// Show modal.
|
||||||
|
Modal::new(Self::NETWORK_EXT_CONNECTION_MODAL)
|
||||||
|
.position(ModalPosition::CenterTop)
|
||||||
|
.title(t!("wallets.add_node"))
|
||||||
|
.show();
|
||||||
|
cb.show_keyboard();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
// Draw connections URL.
|
||||||
|
let conn_text = format!("{} {}", GLOBE_SIMPLE, conn.url);
|
||||||
|
ui.label(RichText::new(conn_text)
|
||||||
|
.color(Colors::TEXT_BUTTON)
|
||||||
|
.size(16.0));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show [`Modal`] to add external connection.
|
||||||
|
pub fn show_add_ext_conn_modal(&mut self, cb: &dyn PlatformCallbacks) {
|
||||||
|
// Setup values for Modal.
|
||||||
|
self.first_modal_launch = true;
|
||||||
|
self.ext_node_url_edit = "".to_string();
|
||||||
|
self.ext_node_secret_edit = "".to_string();
|
||||||
|
self.ext_node_url_error = false;
|
||||||
|
self.edit_ext_conn = None;
|
||||||
|
// Show modal.
|
||||||
|
Modal::new(Self::NETWORK_EXT_CONNECTION_MODAL)
|
||||||
|
.position(ModalPosition::CenterTop)
|
||||||
|
.title(t!("wallets.add_node"))
|
||||||
|
.show();
|
||||||
|
cb.show_keyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw external connection [`Modal`] content.
|
||||||
|
pub fn ext_conn_modal_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
modal: &Modal,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.label(RichText::new(t!("wallets.node_url"))
|
||||||
|
.size(17.0)
|
||||||
|
.color(Colors::GRAY));
|
||||||
|
ui.add_space(8.0);
|
||||||
|
|
||||||
|
// Draw node URL text edit.
|
||||||
|
let url_edit_resp = egui::TextEdit::singleline(&mut self.ext_node_url_edit)
|
||||||
|
.id(Id::from(modal.id).with("node_url_edit"))
|
||||||
|
.font(TextStyle::Heading)
|
||||||
|
.desired_width(ui.available_width())
|
||||||
|
.cursor_at_end(true)
|
||||||
|
.ui(ui);
|
||||||
|
ui.add_space(8.0);
|
||||||
|
if self.first_modal_launch {
|
||||||
|
self.first_modal_launch = false;
|
||||||
|
url_edit_resp.request_focus();
|
||||||
|
}
|
||||||
|
if url_edit_resp.clicked() {
|
||||||
|
cb.show_keyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.label(RichText::new(t!("wallets.node_secret"))
|
||||||
|
.size(17.0)
|
||||||
|
.color(Colors::GRAY));
|
||||||
|
ui.add_space(8.0);
|
||||||
|
|
||||||
|
// Draw node API secret text edit.
|
||||||
|
let secret_edit_resp = egui::TextEdit::singleline(&mut self.ext_node_secret_edit)
|
||||||
|
.id(Id::from(modal.id).with("node_secret_edit"))
|
||||||
|
.font(TextStyle::Heading)
|
||||||
|
.desired_width(ui.available_width())
|
||||||
|
.cursor_at_end(true)
|
||||||
|
.ui(ui);
|
||||||
|
ui.add_space(8.0);
|
||||||
|
if secret_edit_resp.clicked() {
|
||||||
|
cb.show_keyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show error when specified URL is not valid.
|
||||||
|
if self.ext_node_url_error {
|
||||||
|
ui.add_space(12.0);
|
||||||
|
ui.label(RichText::new(t!("wallets.invalid_url"))
|
||||||
|
.size(17.0)
|
||||||
|
.color(Colors::RED));
|
||||||
|
}
|
||||||
|
ui.add_space(12.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show modal buttons.
|
||||||
|
ui.scope(|ui| {
|
||||||
|
// Setup spacing between buttons.
|
||||||
|
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
|
||||||
|
|
||||||
|
ui.columns(2, |columns| {
|
||||||
|
columns[0].vertical_centered_justified(|ui| {
|
||||||
|
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
|
||||||
|
// Close modal.
|
||||||
|
cb.hide_keyboard();
|
||||||
|
modal.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
columns[1].vertical_centered_justified(|ui| {
|
||||||
|
// Add connection button callback.
|
||||||
|
let mut on_add = || {
|
||||||
|
let error = Url::parse(self.ext_node_url_edit.as_str()).is_err();
|
||||||
|
self.ext_node_url_error = error;
|
||||||
|
if !error {
|
||||||
|
// Save external connection.
|
||||||
|
let url = self.ext_node_url_edit.to_owned();
|
||||||
|
let secret = if self.ext_node_secret_edit.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.ext_node_secret_edit.to_owned())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update or create new connections.
|
||||||
|
let ext_conn = ExternalConnection::new(url.clone(), secret);
|
||||||
|
if let Some(edit_conn) = self.edit_ext_conn.clone() {
|
||||||
|
ConnectionsConfig::update_external_connection(edit_conn, ext_conn);
|
||||||
|
self.edit_ext_conn = None;
|
||||||
|
} else {
|
||||||
|
ConnectionsConfig::add_external_connection(ext_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close modal.
|
||||||
|
cb.hide_keyboard();
|
||||||
|
modal.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add connection on Enter button press.
|
||||||
|
View::on_enter_key(ui, || {
|
||||||
|
(on_add)();
|
||||||
|
});
|
||||||
|
|
||||||
|
View::button(ui, t!("modal.save"), Colors::WHITE, on_add);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ui.add_space(6.0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,21 +12,5 @@
|
||||||
// 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 crate::gui::platform::PlatformCallbacks;
|
mod content;
|
||||||
|
pub use content::ConnectionsContent;
|
||||||
/// Network connections content.
|
|
||||||
pub struct ConnectionsContent {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ConnectionsContent {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConnectionsContent {
|
|
||||||
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,14 +12,14 @@
|
||||||
// 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::RichText;
|
use egui::{RichText, ScrollArea};
|
||||||
use egui::style::Margin;
|
use egui::style::Margin;
|
||||||
|
|
||||||
use crate::AppConfig;
|
use crate::AppConfig;
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE, POWER};
|
use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE, PLUS_CIRCLE, POWER};
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::{NetworkMetrics, NetworkMining, NetworkNode, NetworkSettings, Root, TitlePanel, View};
|
use crate::gui::views::{ConnectionsContent, NetworkMetrics, NetworkMining, NetworkNode, NetworkSettings, Root, TitlePanel, View};
|
||||||
use crate::gui::views::network::types::{NetworkTab, NetworkTabType};
|
use crate::gui::views::network::types::{NetworkTab, NetworkTabType};
|
||||||
use crate::gui::views::types::TitleType;
|
use crate::gui::views::types::TitleType;
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
@ -28,38 +28,46 @@ use crate::node::Node;
|
||||||
pub struct NetworkContent {
|
pub struct NetworkContent {
|
||||||
/// Current tab content to show.
|
/// Current tab content to show.
|
||||||
current_tab: Box<dyn NetworkTab>,
|
current_tab: Box<dyn NetworkTab>,
|
||||||
|
|
||||||
|
/// Connections content.
|
||||||
|
connections: ConnectionsContent
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NetworkContent {
|
impl Default for NetworkContent {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
current_tab: Box::new(NetworkNode::default())
|
current_tab: Box::new(NetworkNode::default()),
|
||||||
|
connections: ConnectionsContent::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkContent {
|
impl NetworkContent {
|
||||||
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) {
|
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) {
|
||||||
|
// Flag to show connections or integrated node content.
|
||||||
|
let show_connections = AppConfig::show_connections_network_panel();
|
||||||
|
|
||||||
// Show title panel.
|
// Show title panel.
|
||||||
self.title_ui(ui, frame);
|
self.title_ui(ui, frame, show_connections, cb);
|
||||||
|
|
||||||
// Show bottom tabs.
|
// Show bottom tabs.
|
||||||
egui::TopBottomPanel::bottom("network_tabs")
|
if !show_connections {
|
||||||
.frame(egui::Frame {
|
egui::TopBottomPanel::bottom("network_tabs")
|
||||||
fill: Colors::FILL,
|
.frame(egui::Frame {
|
||||||
inner_margin: Margin {
|
fill: Colors::FILL,
|
||||||
left: View::get_left_inset() + 4.0,
|
inner_margin: Margin {
|
||||||
right: View::far_right_inset_margin(ui, frame) + 4.0,
|
left: View::get_left_inset() + 4.0,
|
||||||
top: 4.0,
|
right: View::far_right_inset_margin(ui, frame) + 4.0,
|
||||||
bottom: View::get_bottom_inset() + 4.0,
|
top: 4.0,
|
||||||
},
|
bottom: View::get_bottom_inset() + 4.0,
|
||||||
..Default::default()
|
},
|
||||||
})
|
..Default::default()
|
||||||
.show_inside(ui, |ui| {
|
})
|
||||||
self.tabs_ui(ui);
|
.show_inside(ui, |ui| {
|
||||||
});
|
self.tabs_ui(ui);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Show tab content.
|
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
stroke: View::DEFAULT_STROKE,
|
stroke: View::DEFAULT_STROKE,
|
||||||
|
@ -67,16 +75,48 @@ impl NetworkContent {
|
||||||
left: View::get_left_inset() + 4.0,
|
left: View::get_left_inset() + 4.0,
|
||||||
right: View::far_right_inset_margin(ui, frame) + 4.0,
|
right: View::far_right_inset_margin(ui, frame) + 4.0,
|
||||||
top: 3.0,
|
top: 3.0,
|
||||||
bottom: 4.0,
|
bottom: if show_connections {
|
||||||
|
View::get_bottom_inset() + 4.0
|
||||||
|
} else {
|
||||||
|
4.0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fill: if show_connections {
|
||||||
|
Colors::FILL
|
||||||
|
} else {
|
||||||
|
Colors::WHITE
|
||||||
},
|
},
|
||||||
fill: Colors::WHITE,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.show_inside(ui, |ui| {
|
.show_inside(ui, |ui| {
|
||||||
self.current_tab.ui(ui, frame, cb);
|
if show_connections {
|
||||||
|
ScrollArea::vertical()
|
||||||
|
.id_source("connections_content")
|
||||||
|
.auto_shrink([false; 2])
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.add_space(1.0);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
// Setup wallet list width.
|
||||||
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
|
let mut width = ui.available_width();
|
||||||
|
if !Root::is_dual_panel_mode(frame) {
|
||||||
|
width = f32::min(width, Root::SIDE_PANEL_WIDTH * 1.3)
|
||||||
|
}
|
||||||
|
rect.set_width(width);
|
||||||
|
|
||||||
|
ui.allocate_ui(rect.size(), |ui| {
|
||||||
|
// Show connections content.
|
||||||
|
self.connections.ui(ui, frame, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Show current tab content.
|
||||||
|
self.current_tab.ui(ui, frame, cb);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redraw content after delay if node is not syncing to update stats.
|
// Redraw after delay if node is not syncing to update stats.
|
||||||
if Node::not_syncing() {
|
if Node::not_syncing() {
|
||||||
ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY);
|
ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY);
|
||||||
}
|
}
|
||||||
|
@ -118,18 +158,32 @@ impl NetworkContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw title content.
|
/// Draw title content.
|
||||||
fn title_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
fn title_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
frame: &mut eframe::Frame,
|
||||||
|
show_connections: bool,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
// Setup values for title panel.
|
// Setup values for title panel.
|
||||||
let title_text = self.current_tab.get_type().title().to_uppercase();
|
let title_text = self.current_tab.get_type().title().to_uppercase();
|
||||||
let subtitle_text = Node::get_sync_status_text();
|
let subtitle_text = Node::get_sync_status_text();
|
||||||
let not_syncing = Node::not_syncing();
|
let not_syncing = Node::not_syncing();
|
||||||
let title_content = TitleType::WithSubTitle(title_text, subtitle_text, !not_syncing);
|
let title_content = if !show_connections {
|
||||||
|
TitleType::WithSubTitle(title_text, subtitle_text, !not_syncing)
|
||||||
|
} else {
|
||||||
|
TitleType::Single(t!("network.connections").to_uppercase())
|
||||||
|
};
|
||||||
|
|
||||||
// Draw title panel.
|
// Draw title panel.
|
||||||
TitlePanel::ui(title_content, |ui, _| {
|
TitlePanel::ui(title_content, |ui, _| {
|
||||||
View::title_button(ui, DOTS_THREE_OUTLINE_VERTICAL, || {
|
if !show_connections {
|
||||||
//TODO: Show connections
|
View::title_button(ui, DOTS_THREE_OUTLINE_VERTICAL, || {
|
||||||
});
|
AppConfig::toggle_show_connections_network_panel();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
View::title_button(ui, PLUS_CIRCLE, || {
|
||||||
|
self.connections.show_add_ext_conn_modal(cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
}, |ui, frame| {
|
}, |ui, frame| {
|
||||||
if !Root::is_dual_panel_mode(frame) {
|
if !Root::is_dual_panel_mode(frame) {
|
||||||
View::title_button(ui, CARDHOLDER, || {
|
View::title_button(ui, CARDHOLDER, || {
|
||||||
|
|
|
@ -131,7 +131,7 @@ impl NetworkTab for NetworkMetrics {
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
}
|
}
|
||||||
let db = stats.diff_stats.last_blocks.get(index).unwrap();
|
let db = stats.diff_stats.last_blocks.get(index).unwrap();
|
||||||
block_item_ui(ui, db, View::item_rounding(index, blocks_size))
|
block_item_ui(ui, db, View::item_rounding(index, blocks_size, false));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -177,7 +177,8 @@ impl NetworkTab for NetworkMining {
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
}
|
}
|
||||||
let worker = stratum_stats.worker_stats.get(index).unwrap();
|
let worker = stratum_stats.worker_stats.get(index).unwrap();
|
||||||
worker_item_ui(ui, worker, View::item_rounding(index, workers_size));
|
let item_rounding = View::item_rounding(index, workers_size, false);
|
||||||
|
worker_item_ui(ui, worker, item_rounding);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -164,7 +164,7 @@ impl NetworkTab for NetworkNode {
|
||||||
View::sub_title(ui, format!("{} {}", HANDSHAKE, t!("network_node.peers")));
|
View::sub_title(ui, format!("{} {}", HANDSHAKE, t!("network_node.peers")));
|
||||||
let peers = &stats.peer_stats;
|
let peers = &stats.peer_stats;
|
||||||
for (index, ps) in peers.iter().enumerate() {
|
for (index, ps) in peers.iter().enumerate() {
|
||||||
peer_item_ui(ui, ps, View::item_rounding(index, peers.len()));
|
peer_item_ui(ui, ps, View::item_rounding(index, peers.len(), false));
|
||||||
// Add space after the last item.
|
// Add space after the last item.
|
||||||
if index == peers.len() - 1 {
|
if index == peers.len() - 1 {
|
||||||
ui.add_space(5.0);
|
ui.add_space(5.0);
|
||||||
|
|
|
@ -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::{Align, Id, Layout, RichText, Rounding, TextStyle, Widget};
|
use egui::{Align, Id, Layout, RichText, TextStyle, Widget};
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
use grin_core::global::ChainTypes;
|
use grin_core::global::ChainTypes;
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ impl P2PSetup {
|
||||||
for (index, peer) in peers.iter().enumerate() {
|
for (index, peer) in peers.iter().enumerate() {
|
||||||
ui.horizontal_wrapped(|ui| {
|
ui.horizontal_wrapped(|ui| {
|
||||||
// Draw peer list item.
|
// Draw peer list item.
|
||||||
peer_item_ui(ui, peer, peer_type, View::item_rounding(index, peers.len()));
|
peer_item_ui(ui, peer, peer_type, index, peers.len());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,7 +889,11 @@ impl P2PSetup {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw peer list item.
|
/// Draw peer list item.
|
||||||
fn peer_item_ui(ui: &mut egui::Ui, peer_addr: &String, peer_type: &PeerType, rounding: Rounding) {
|
fn peer_item_ui(ui: &mut egui::Ui,
|
||||||
|
peer_addr: &String,
|
||||||
|
peer_type: &PeerType,
|
||||||
|
index: usize,
|
||||||
|
len: usize,) {
|
||||||
// Setup layout size.
|
// Setup layout size.
|
||||||
let mut rect = ui.available_rect_before_wrap();
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
rect.set_height(42.0);
|
rect.set_height(42.0);
|
||||||
|
@ -897,13 +901,14 @@ fn peer_item_ui(ui: &mut egui::Ui, peer_addr: &String, peer_type: &PeerType, rou
|
||||||
// Draw round background.
|
// Draw round background.
|
||||||
let mut bg_rect = rect.clone();
|
let mut bg_rect = rect.clone();
|
||||||
bg_rect.min += egui::emath::vec2(6.0, 0.0);
|
bg_rect.min += egui::emath::vec2(6.0, 0.0);
|
||||||
ui.painter().rect(bg_rect, rounding, Colors::WHITE, View::ITEM_STROKE);
|
let item_rounding = View::item_rounding(index, len, false);
|
||||||
|
ui.painter().rect(bg_rect, item_rounding, Colors::WHITE, View::ITEM_STROKE);
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
// Draw delete button for non-default seed peers.
|
// Draw delete button for non-default seed peers.
|
||||||
if peer_type != &PeerType::DefaultSeed {
|
if peer_type != &PeerType::DefaultSeed {
|
||||||
View::item_button(ui, [false, true], TRASH, || {
|
View::item_button(ui, View::item_rounding(index, len, true), TRASH, || {
|
||||||
match peer_type {
|
match peer_type {
|
||||||
PeerType::CustomSeed => {
|
PeerType::CustomSeed => {
|
||||||
NodeConfig::remove_custom_seed(peer_addr);
|
NodeConfig::remove_custom_seed(peer_addr);
|
||||||
|
|
|
@ -153,7 +153,7 @@ impl Root {
|
||||||
/// Show exit confirmation modal.
|
/// Show exit confirmation modal.
|
||||||
pub fn show_exit_modal() {
|
pub fn show_exit_modal() {
|
||||||
Modal::new(Self::EXIT_MODAL_ID)
|
Modal::new(Self::EXIT_MODAL_ID)
|
||||||
.title(t!("modal.confirmation"))
|
.title(t!("modal_exit.exit"))
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl View {
|
||||||
/// Stroke for items.
|
/// Stroke for items.
|
||||||
pub const ITEM_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_STROKE };
|
pub const ITEM_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_STROKE };
|
||||||
/// Stroke for hovered items and buttons.
|
/// Stroke for hovered items and buttons.
|
||||||
pub const ITEM_HOVER_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_HOVER };
|
pub const HOVER_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_HOVER };
|
||||||
|
|
||||||
/// Callback on Enter key press event.
|
/// Callback on Enter key press event.
|
||||||
pub fn on_enter_key(ui: &mut egui::Ui, cb: impl FnOnce()) {
|
pub fn on_enter_key(ui: &mut egui::Ui, cb: impl FnOnce()) {
|
||||||
|
@ -105,7 +105,7 @@ impl View {
|
||||||
pub fn title_button(ui: &mut egui::Ui, icon: &str, action: impl FnOnce()) {
|
pub fn title_button(ui: &mut egui::Ui, icon: &str, action: impl FnOnce()) {
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
// Setup stroke around title buttons on click.
|
// Setup stroke around title buttons on click.
|
||||||
ui.style_mut().visuals.widgets.hovered.bg_stroke = Self::ITEM_HOVER_STROKE;
|
ui.style_mut().visuals.widgets.hovered.bg_stroke = Self::HOVER_STROKE;
|
||||||
ui.style_mut().visuals.widgets.active.bg_stroke = Self::DEFAULT_STROKE;
|
ui.style_mut().visuals.widgets.active.bg_stroke = Self::DEFAULT_STROKE;
|
||||||
// Disable rounding.
|
// Disable rounding.
|
||||||
ui.style_mut().visuals.widgets.hovered.rounding = Rounding::none();
|
ui.style_mut().visuals.widgets.hovered.rounding = Rounding::none();
|
||||||
|
@ -120,6 +120,7 @@ impl View {
|
||||||
let br = Button::new(wt)
|
let br = Button::new(wt)
|
||||||
.fill(Colors::TRANSPARENT)
|
.fill(Colors::TRANSPARENT)
|
||||||
.ui(ui);
|
.ui(ui);
|
||||||
|
br.surrender_focus();
|
||||||
if Self::touched(ui, br) {
|
if Self::touched(ui, br) {
|
||||||
(action)();
|
(action)();
|
||||||
}
|
}
|
||||||
|
@ -146,13 +147,14 @@ impl View {
|
||||||
ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL;
|
ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL;
|
||||||
// Setup stroke colors.
|
// Setup stroke colors.
|
||||||
ui.visuals_mut().widgets.inactive.bg_stroke = Self::DEFAULT_STROKE;
|
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.hovered.bg_stroke = Self::HOVER_STROKE;
|
||||||
ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE;
|
ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE;
|
||||||
} else {
|
} else {
|
||||||
button = button.fill(Colors::FILL).stroke(Stroke::NONE);
|
button = button.fill(Colors::FILL).stroke(Stroke::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let br = button.ui(ui);
|
let br = button.ui(ui);
|
||||||
|
br.surrender_focus();
|
||||||
if Self::touched(ui, br) {
|
if Self::touched(ui, br) {
|
||||||
(action)();
|
(action)();
|
||||||
}
|
}
|
||||||
|
@ -172,9 +174,7 @@ impl View {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw list item [`Button`] with given vertical padding and rounding on left and right sides.
|
/// Draw list item [`Button`] with given vertical padding and rounding on left and right sides.
|
||||||
pub fn item_button(ui: &mut egui::Ui, r: [bool; 2], icon: &'static str, action: impl FnOnce()) {
|
pub fn item_button(ui: &mut egui::Ui, r: Rounding, icon: &'static str, action: impl FnOnce()) {
|
||||||
let rounding = Self::get_rounding([r[0], r[1], r[1], r[0]]);
|
|
||||||
|
|
||||||
// Setup button size.
|
// Setup button size.
|
||||||
let mut rect = ui.available_rect_before_wrap();
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
rect.set_width(32.0);
|
rect.set_width(32.0);
|
||||||
|
@ -190,14 +190,15 @@ impl View {
|
||||||
ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL;
|
ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL;
|
||||||
// Setup stroke colors.
|
// Setup stroke colors.
|
||||||
ui.visuals_mut().widgets.inactive.bg_stroke = Self::DEFAULT_STROKE;
|
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.hovered.bg_stroke = Self::HOVER_STROKE;
|
||||||
ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE;
|
ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE;
|
||||||
|
|
||||||
// Show button.
|
// Show button.
|
||||||
let br = Button::new(RichText::new(icon).size(20.0).color(Colors::ITEM_BUTTON))
|
let br = Button::new(RichText::new(icon).size(20.0).color(Colors::ITEM_BUTTON))
|
||||||
.rounding(rounding)
|
.rounding(r)
|
||||||
.min_size(button_size)
|
.min_size(button_size)
|
||||||
.ui(ui);
|
.ui(ui);
|
||||||
|
br.surrender_focus();
|
||||||
if Self::touched(ui, br) {
|
if Self::touched(ui, br) {
|
||||||
(action)();
|
(action)();
|
||||||
}
|
}
|
||||||
|
@ -243,8 +244,29 @@ impl View {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get rounding for provided corners clockwise.
|
/// Calculate item background/button rounding based on item index.
|
||||||
fn get_rounding(corners: [bool; 4]) -> Rounding {
|
pub fn item_rounding(index: usize, len: usize, is_button: bool) -> Rounding {
|
||||||
|
let corners = if is_button {
|
||||||
|
if len == 1 {
|
||||||
|
[false, true, true, false]
|
||||||
|
} else if index == 0 {
|
||||||
|
[false, true, false, false]
|
||||||
|
} else if index == len - 1 {
|
||||||
|
[false, false, true, false]
|
||||||
|
} else {
|
||||||
|
[false, false, false, false]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len == 1 {
|
||||||
|
[true, true, true, true]
|
||||||
|
} else if index == 0 {
|
||||||
|
[true, true, false, false]
|
||||||
|
} else if index == len - 1 {
|
||||||
|
[false, false, true, true]
|
||||||
|
} else {
|
||||||
|
[false, false, false, false]
|
||||||
|
}
|
||||||
|
};
|
||||||
Rounding {
|
Rounding {
|
||||||
nw: if corners[0] { 8.0 } else { 0.0 },
|
nw: if corners[0] { 8.0 } else { 0.0 },
|
||||||
ne: if corners[1] { 8.0 } else { 0.0 },
|
ne: if corners[1] { 8.0 } else { 0.0 },
|
||||||
|
@ -253,20 +275,6 @@ impl View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate list item rounding based on item index.
|
|
||||||
pub fn item_rounding(index: usize, len: usize) -> Rounding {
|
|
||||||
let rounding = if len == 1 {
|
|
||||||
[true, true, true, true]
|
|
||||||
} else if index == 0 {
|
|
||||||
[true, true, false, false]
|
|
||||||
} else if index == len - 1 {
|
|
||||||
[false, false, true, true]
|
|
||||||
} else {
|
|
||||||
[false, false, false, false]
|
|
||||||
};
|
|
||||||
Self::get_rounding(rounding)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draw rounded box with some value and label in the middle,
|
/// Draw rounded box with some value and label in the middle,
|
||||||
/// where is r = (top_left, top_right, bottom_left, bottom_right).
|
/// where is r = (top_left, top_right, bottom_left, bottom_right).
|
||||||
/// | VALUE |
|
/// | VALUE |
|
||||||
|
|
|
@ -351,10 +351,9 @@ impl WalletsContent {
|
||||||
// Draw round background.
|
// Draw round background.
|
||||||
let mut rect = ui.available_rect_before_wrap();
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
rect.set_height(78.0);
|
rect.set_height(78.0);
|
||||||
let rounding = View::item_rounding(0, 1);
|
let rounding = View::item_rounding(0, 1, false);
|
||||||
let bg_color = if is_current { Colors::ITEM_CURRENT } else { Colors::FILL };
|
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 };
|
ui.painter().rect(rect, rounding, bg_color, View::HOVER_STROKE);
|
||||||
ui.painter().rect(rect, rounding, bg_color, stroke);
|
|
||||||
|
|
||||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
// Setup padding for item buttons.
|
// Setup padding for item buttons.
|
||||||
|
@ -366,18 +365,17 @@ impl WalletsContent {
|
||||||
|
|
||||||
if !wallet.is_open() {
|
if !wallet.is_open() {
|
||||||
// Show button to open closed wallet.
|
// Show button to open closed wallet.
|
||||||
View::item_button(ui, [false, true], FOLDER_OPEN, || {
|
View::item_button(ui, View::item_rounding(0, 1, true), FOLDER_OPEN, || {
|
||||||
self.wallets.select(Some(id));
|
self.wallets.select(Some(id));
|
||||||
self.show_open_wallet_modal(cb);
|
self.show_open_wallet_modal(cb);
|
||||||
});
|
});
|
||||||
} else if !is_selected {
|
} else if !is_selected {
|
||||||
// Show button to select opened wallet.
|
// Show button to select opened wallet.
|
||||||
View::item_button(ui, [false, true], CARET_RIGHT, || {
|
View::item_button(ui, View::item_rounding(0, 1, true), CARET_RIGHT, || {
|
||||||
self.wallets.select(Some(id));
|
self.wallets.select(Some(id));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show button to close opened wallet.
|
// Show button to close opened wallet.
|
||||||
View::item_button(ui, [false, false], LOCK_KEY, || {
|
View::item_button(ui, Rounding::none(), LOCK_KEY, || {
|
||||||
let _ = wallet.close();
|
let _ = wallet.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub struct ConnectionSetup {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// External connection [`Modal`] identifier.
|
/// External connection [`Modal`] identifier.
|
||||||
pub const EXT_CONNECTION_MODAL: &'static str = "ext_connection_modal";
|
pub const ADD_EXT_CONNECTION_MODAL: &'static str = "add_ext_connection_modal";
|
||||||
|
|
||||||
impl Default for ConnectionSetup {
|
impl Default for ConnectionSetup {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -53,7 +53,7 @@ impl Default for ConnectionSetup {
|
||||||
ext_node_secret_edit: "".to_string(),
|
ext_node_secret_edit: "".to_string(),
|
||||||
ext_node_url_error: false,
|
ext_node_url_error: false,
|
||||||
modal_ids: vec![
|
modal_ids: vec![
|
||||||
EXT_CONNECTION_MODAL
|
ADD_EXT_CONNECTION_MODAL
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ impl ModalContainer for ConnectionSetup {
|
||||||
modal: &Modal,
|
modal: &Modal,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
match modal.id {
|
match modal.id {
|
||||||
EXT_CONNECTION_MODAL => self.ext_conn_modal_ui(ui, modal, cb),
|
ADD_EXT_CONNECTION_MODAL => self.add_ext_conn_modal_ui(ui, modal, cb),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,17 +117,7 @@ impl ConnectionSetup {
|
||||||
// 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, || {
|
||||||
// Setup values for Modal.
|
self.show_add_ext_conn_modal(cb);
|
||||||
self.first_modal_launch = true;
|
|
||||||
self.ext_node_url_edit = "".to_string();
|
|
||||||
self.ext_node_secret_edit = "".to_string();
|
|
||||||
self.ext_node_url_error = false;
|
|
||||||
// Show modal.
|
|
||||||
Modal::new(EXT_CONNECTION_MODAL)
|
|
||||||
.position(ModalPosition::CenterTop)
|
|
||||||
.title(t!("wallets.add_node"))
|
|
||||||
.show();
|
|
||||||
cb.show_keyboard();
|
|
||||||
});
|
});
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
|
|
||||||
|
@ -143,11 +133,26 @@ impl ConnectionSetup {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw external connection [`Modal`] content.
|
/// Show external connection adding [`Modal`].
|
||||||
pub fn ext_conn_modal_ui(&mut self,
|
fn show_add_ext_conn_modal(&mut self, cb: &dyn PlatformCallbacks) {
|
||||||
ui: &mut egui::Ui,
|
// Setup values for Modal.
|
||||||
modal: &Modal,
|
self.first_modal_launch = true;
|
||||||
cb: &dyn PlatformCallbacks) {
|
self.ext_node_url_edit = "".to_string();
|
||||||
|
self.ext_node_secret_edit = "".to_string();
|
||||||
|
self.ext_node_url_error = false;
|
||||||
|
// Show modal.
|
||||||
|
Modal::new(ADD_EXT_CONNECTION_MODAL)
|
||||||
|
.position(ModalPosition::CenterTop)
|
||||||
|
.title(t!("wallets.add_node"))
|
||||||
|
.show();
|
||||||
|
cb.show_keyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw external connection adding [`Modal`] content.
|
||||||
|
pub fn add_ext_conn_modal_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
modal: &Modal,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.label(RichText::new(t!("wallets.node_url"))
|
ui.label(RichText::new(t!("wallets.node_url"))
|
||||||
|
@ -217,7 +222,7 @@ impl ConnectionSetup {
|
||||||
let error = Url::parse(self.ext_node_url_edit.as_str()).is_err();
|
let error = Url::parse(self.ext_node_url_edit.as_str()).is_err();
|
||||||
self.ext_node_url_error = error;
|
self.ext_node_url_error = error;
|
||||||
if !error {
|
if !error {
|
||||||
// Save external connection.
|
// Add external connection.
|
||||||
let url = self.ext_node_url_edit.to_owned();
|
let url = self.ext_node_url_edit.to_owned();
|
||||||
let secret = if self.ext_node_secret_edit.is_empty() {
|
let secret = if self.ext_node_secret_edit.is_empty() {
|
||||||
None
|
None
|
||||||
|
|
|
@ -40,8 +40,11 @@ pub struct AppConfig {
|
||||||
pub auto_start_node: bool,
|
pub auto_start_node: bool,
|
||||||
/// Chain type for node and wallets.
|
/// Chain type for node and wallets.
|
||||||
chain_type: ChainTypes,
|
chain_type: ChainTypes,
|
||||||
/// Flag to show wallet list at dual panel wallets mode.
|
|
||||||
|
/// Flag to initially show wallet list at dual panel wallets mode.
|
||||||
show_wallets_at_dual_panel: bool,
|
show_wallets_at_dual_panel: bool,
|
||||||
|
/// Flag to initially show all connections at network panel.
|
||||||
|
show_connections_network_panel: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AppConfig {
|
impl Default for AppConfig {
|
||||||
|
@ -50,6 +53,7 @@ impl Default for AppConfig {
|
||||||
auto_start_node: false,
|
auto_start_node: false,
|
||||||
chain_type: ChainTypes::default(),
|
chain_type: ChainTypes::default(),
|
||||||
show_wallets_at_dual_panel: true,
|
show_wallets_at_dual_panel: true,
|
||||||
|
show_connections_network_panel: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +117,20 @@ impl AppConfig {
|
||||||
w_app_config.show_wallets_at_dual_panel = !show;
|
w_app_config.show_wallets_at_dual_panel = !show;
|
||||||
w_app_config.save();
|
w_app_config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggle flag to show all connections at network panel.
|
||||||
|
pub fn show_connections_network_panel() -> bool {
|
||||||
|
let r_config = Settings::app_config_to_read();
|
||||||
|
r_config.show_connections_network_panel
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggle flag to show all connections at network panel.
|
||||||
|
pub fn toggle_show_connections_network_panel() {
|
||||||
|
let show = Self::show_connections_network_panel();
|
||||||
|
let mut w_app_config = Settings::app_config_to_update();
|
||||||
|
w_app_config.show_connections_network_panel = !show;
|
||||||
|
w_app_config.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main application directory name.
|
/// Main application directory name.
|
||||||
|
|
|
@ -63,6 +63,10 @@ impl ConnectionsConfig {
|
||||||
|
|
||||||
/// Save external connection for the wallet in app config.
|
/// Save external connection for the wallet in app config.
|
||||||
pub fn add_external_connection(conn: ExternalConnection) {
|
pub fn add_external_connection(conn: ExternalConnection) {
|
||||||
|
// Do not update default connection.
|
||||||
|
if conn.url == ExternalConnection::DEFAULT_EXTERNAL_NODE_URL {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let mut w_config = CONNECTIONS_STATE.write().unwrap();
|
let mut w_config = CONNECTIONS_STATE.write().unwrap();
|
||||||
let mut exists = false;
|
let mut exists = false;
|
||||||
for mut c in w_config.external.iter_mut() {
|
for mut c in w_config.external.iter_mut() {
|
||||||
|
@ -75,7 +79,25 @@ impl ConnectionsConfig {
|
||||||
}
|
}
|
||||||
// Create new connection if URL not exists.
|
// Create new connection if URL not exists.
|
||||||
if !exists {
|
if !exists {
|
||||||
w_config.external.insert(0, conn);
|
w_config.external.push(conn);
|
||||||
|
}
|
||||||
|
w_config.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save external connection for the wallet in app config.
|
||||||
|
pub fn update_external_connection(conn: ExternalConnection, updated: ExternalConnection) {
|
||||||
|
// Do not update default connection.
|
||||||
|
if conn.url == ExternalConnection::DEFAULT_EXTERNAL_NODE_URL {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut w_config = CONNECTIONS_STATE.write().unwrap();
|
||||||
|
for mut c in w_config.external.iter_mut() {
|
||||||
|
// Update connection if URL exists.
|
||||||
|
if c.url == conn.url {
|
||||||
|
c.url = updated.url.clone();
|
||||||
|
c.secret = updated.secret.clone();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
w_config.save();
|
w_config.save();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub struct ExternalConnection {
|
||||||
|
|
||||||
impl ExternalConnection {
|
impl ExternalConnection {
|
||||||
/// Default external node URL.
|
/// Default external node URL.
|
||||||
const DEFAULT_EXTERNAL_NODE_URL: &'static str = "https://grinnnode.live:3413";
|
pub const DEFAULT_EXTERNAL_NODE_URL: &'static str = "https://grinnnode.live:3413";
|
||||||
|
|
||||||
pub fn new(url: String, secret: Option<String>) -> Self {
|
pub fn new(url: String, secret: Option<String>) -> Self {
|
||||||
Self { url, secret }
|
Self { url, secret }
|
||||||
|
|
Loading…
Reference in a new issue