ui: add checkbox view, move spinners creation to views, autorun option when server is disabled, refactor network tabs to hold only current instance
This commit is contained in:
parent
b91bc2f7e7
commit
d34889a801
14 changed files with 173 additions and 100 deletions
|
@ -8,6 +8,7 @@ network:
|
||||||
enable: Enable
|
enable: Enable
|
||||||
disable: Disable
|
disable: Disable
|
||||||
restart: Restart
|
restart: Restart
|
||||||
|
autorun: Autorun
|
||||||
disabled_server: 'Enable server or choose another connection method by pressing %{dots} on top left corner of the screen.'
|
disabled_server: 'Enable server or choose another connection method by pressing %{dots} on top left corner of the screen.'
|
||||||
sync_status:
|
sync_status:
|
||||||
server_restarting: Server is restarting
|
server_restarting: Server is restarting
|
||||||
|
@ -27,7 +28,7 @@ sync_status:
|
||||||
tx_hashset_range_proofs_validation: 'Validating state (range proofs): %{percent}%'
|
tx_hashset_range_proofs_validation: 'Validating state (range proofs): %{percent}%'
|
||||||
tx_hashset_kernels_validation: 'Validating state (kernels): %{percent}%'
|
tx_hashset_kernels_validation: 'Validating state (kernels): %{percent}%'
|
||||||
tx_hashset_save: Finalizing chain state
|
tx_hashset_save: Finalizing chain state
|
||||||
body_sync: Downloading blockchain
|
body_sync: Downloading blocks
|
||||||
body_sync_percent: 'Downloading blocks: %{percent}%'
|
body_sync_percent: 'Downloading blocks: %{percent}%'
|
||||||
shutdown: Server is shutting down
|
shutdown: Server is shutting down
|
||||||
network_node:
|
network_node:
|
||||||
|
|
|
@ -8,6 +8,7 @@ network:
|
||||||
enable: Включить
|
enable: Включить
|
||||||
disable: Выключить
|
disable: Выключить
|
||||||
restart: Перезапустить
|
restart: Перезапустить
|
||||||
|
autorun: Автозапуск
|
||||||
disabled_server: 'Включите сервер или выберите другой способ подключения, нажав %{dots} в левом верхнем углу экрана.'
|
disabled_server: 'Включите сервер или выберите другой способ подключения, нажав %{dots} в левом верхнем углу экрана.'
|
||||||
sync_status:
|
sync_status:
|
||||||
server_restarting: Сервер перезапускается
|
server_restarting: Сервер перезапускается
|
||||||
|
@ -27,7 +28,7 @@ sync_status:
|
||||||
tx_hashset_range_proofs_validation: 'Проверка доказательств: %{percent}%'
|
tx_hashset_range_proofs_validation: 'Проверка доказательств: %{percent}%'
|
||||||
tx_hashset_kernels_validation: 'Проверка ядер: %{percent}%'
|
tx_hashset_kernels_validation: 'Проверка ядер: %{percent}%'
|
||||||
tx_hashset_save: Сохранение состояния цепи
|
tx_hashset_save: Сохранение состояния цепи
|
||||||
body_sync: Загрузка блокчейна
|
body_sync: Загрузка блоков
|
||||||
body_sync_percent: 'Загрузка блоков: %{percent}%'
|
body_sync_percent: 'Загрузка блоков: %{percent}%'
|
||||||
shutdown: Выключение сервера
|
shutdown: Выключение сервера
|
||||||
network_node:
|
network_node:
|
||||||
|
|
|
@ -72,6 +72,10 @@ impl App {
|
||||||
style.spacing.scroll_bar_width = 4.0;
|
style.spacing.scroll_bar_width = 4.0;
|
||||||
// Disable spacing between items.
|
// Disable spacing between items.
|
||||||
style.spacing.item_spacing = egui::vec2(0.0, 0.0);
|
style.spacing.item_spacing = egui::vec2(0.0, 0.0);
|
||||||
|
// Setup radio button/checkbox size and spacing.
|
||||||
|
style.spacing.icon_width = 24.0;
|
||||||
|
style.spacing.icon_width_inner = 14.0;
|
||||||
|
style.spacing.icon_spacing = 10.0;
|
||||||
|
|
||||||
ctx.set_style(style);
|
ctx.set_style(style);
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::gui::screens::ScreenId;
|
||||||
use crate::gui::views::{Modal, ModalId, ModalLocation};
|
use crate::gui::views::{Modal, ModalId, ModalLocation};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Static [Navigator] state to be accessible from anywhere.
|
/// Static [`Navigator`] state to be accessible from anywhere.
|
||||||
static ref NAVIGATOR_STATE: RwLock<Navigator> = RwLock::new(Navigator::default());
|
static ref NAVIGATOR_STATE: RwLock<Navigator> = RwLock::new(Navigator::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,20 +53,20 @@ impl Default for Navigator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Navigator {
|
impl Navigator {
|
||||||
/// Initialize navigation from provided [ScreenId].
|
/// Initialize navigation from provided [`ScreenId`].
|
||||||
pub fn init(from: ScreenId) {
|
pub fn init(from: ScreenId) {
|
||||||
let mut w_nav = NAVIGATOR_STATE.write().unwrap();
|
let mut w_nav = NAVIGATOR_STATE.write().unwrap();
|
||||||
w_nav.screen_stack.clear();
|
w_nav.screen_stack.clear();
|
||||||
w_nav.screen_stack.insert(from);
|
w_nav.screen_stack.insert(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if provided [ScreenId] is current.
|
/// Check if provided [`ScreenId`] is current.
|
||||||
pub fn is_current(id: &ScreenId) -> bool {
|
pub fn is_current(id: &ScreenId) -> bool {
|
||||||
let r_nav = NAVIGATOR_STATE.read().unwrap();
|
let r_nav = NAVIGATOR_STATE.read().unwrap();
|
||||||
r_nav.screen_stack.last().unwrap() == id
|
r_nav.screen_stack.last().unwrap() == id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Navigate to screen with provided [ScreenId].
|
/// Navigate to screen with provided [`ScreenId`].
|
||||||
pub fn to(id: ScreenId) {
|
pub fn to(id: ScreenId) {
|
||||||
NAVIGATOR_STATE.write().unwrap().screen_stack.insert(id);
|
NAVIGATOR_STATE.write().unwrap().screen_stack.insert(id);
|
||||||
}
|
}
|
||||||
|
@ -110,19 +110,19 @@ impl Navigator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open exit confirmation [Modal].
|
/// Open exit confirmation [`Modal`].
|
||||||
pub fn open_exit_modal() {
|
pub fn open_exit_modal() {
|
||||||
let w_nav = NAVIGATOR_STATE.write().unwrap();
|
let w_nav = NAVIGATOR_STATE.write().unwrap();
|
||||||
Self::open_exit_modal_nav(w_nav);
|
Self::open_exit_modal_nav(w_nav);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open exit confirmation [Modal] with provided [NAVIGATOR_STATE] lock.
|
/// Open exit confirmation [`Modal`] with provided [NAVIGATOR_STATE] lock.
|
||||||
fn open_exit_modal_nav(mut w_nav: RwLockWriteGuard<Navigator>) {
|
fn open_exit_modal_nav(mut w_nav: RwLockWriteGuard<Navigator>) {
|
||||||
let m = Modal::new(ModalId::Exit, ModalLocation::Global).title(t!("modal_exit.exit"));
|
let m = Modal::new(ModalId::Exit, ModalLocation::Global).title(t!("modal_exit.exit"));
|
||||||
w_nav.global_modal = Some(m);
|
w_nav.global_modal = Some(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open [Modal] at specified location.
|
/// Open [`Modal`] at specified location.
|
||||||
pub fn open_modal(modal: Modal) {
|
pub fn open_modal(modal: Modal) {
|
||||||
let mut w_nav = NAVIGATOR_STATE.write().unwrap();
|
let mut w_nav = NAVIGATOR_STATE.write().unwrap();
|
||||||
match modal.location {
|
match modal.location {
|
||||||
|
@ -138,7 +138,7 @@ impl Navigator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [Modal] is open at specified location and remove it from [Navigator] if closed.
|
/// Check if [`Modal`] is open at specified location and remove it from [`Navigator`] otherwise.
|
||||||
pub fn is_modal_open(location: ModalLocation) -> bool {
|
pub fn is_modal_open(location: ModalLocation) -> bool {
|
||||||
// Check if Modal is showing.
|
// Check if Modal is showing.
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@ impl Navigator {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show [Modal] with provided location at app UI.
|
/// Show [`Modal`] with provided location at app UI.
|
||||||
pub fn modal_ui(ui: &mut egui::Ui,
|
pub fn modal_ui(ui: &mut egui::Ui,
|
||||||
location: ModalLocation,
|
location: ModalLocation,
|
||||||
add_content: impl FnOnce(&mut egui::Ui, &Modal)) {
|
add_content: impl FnOnce(&mut egui::Ui, &Modal)) {
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
use egui::{Spinner, Widget};
|
|
||||||
|
|
||||||
use crate::gui::{App, Colors, Navigator};
|
use crate::gui::{App, Colors, Navigator};
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::screens::{Account, Accounts, Screen, ScreenId};
|
use crate::gui::screens::{Account, Accounts, Screen, ScreenId};
|
||||||
|
@ -80,7 +78,7 @@ impl Root {
|
||||||
}
|
}
|
||||||
ui.add_space(16.0);
|
ui.add_space(16.0);
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
Spinner::new().size(48.0).color(Colors::GOLD).ui(ui);
|
View::small_loading_spinner(ui);
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
ui.label(t!("sync_status.shutdown"));
|
ui.label(t!("sync_status.shutdown"));
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,14 +22,9 @@ mod modal;
|
||||||
pub use modal::*;
|
pub use modal::*;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
pub use network::Network;
|
pub use network::*;
|
||||||
|
|
||||||
mod network_node;
|
mod network_node;
|
||||||
mod network_settings;
|
mod network_settings;
|
||||||
mod network_metrics;
|
mod network_metrics;
|
||||||
mod network_mining;
|
mod network_mining;
|
||||||
|
|
||||||
pub trait NetworkTab {
|
|
||||||
fn name(&self) -> String;
|
|
||||||
fn ui(&mut self, ui: &mut egui::Ui);
|
|
||||||
}
|
|
|
@ -133,7 +133,7 @@ impl Modal {
|
||||||
ui.set_min_size(ui.available_size());
|
ui.set_min_size(ui.available_size());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show main content Window at give position
|
// Show main content Window at given position
|
||||||
let layer_id = egui::Window::new(self.window_id(false))
|
let layer_id = egui::Window::new(self.window_id(false))
|
||||||
.title_bar(false)
|
.title_bar(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
|
|
|
@ -22,35 +22,36 @@ use grin_chain::SyncStatus;
|
||||||
use crate::gui::{Colors, Navigator};
|
use crate::gui::{Colors, Navigator};
|
||||||
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, POWER};
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::{NetworkTab, View};
|
|
||||||
use crate::gui::views::network_metrics::NetworkMetrics;
|
use crate::gui::views::network_metrics::NetworkMetrics;
|
||||||
use crate::gui::views::network_mining::NetworkMining;
|
use crate::gui::views::network_mining::NetworkMining;
|
||||||
use crate::gui::views::network_node::NetworkNode;
|
use crate::gui::views::network_node::NetworkNode;
|
||||||
|
use crate::gui::views::network_settings::NetworkSettings;
|
||||||
|
use crate::gui::views::View;
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
use crate::Settings;
|
||||||
|
|
||||||
|
pub trait NetworkTab {
|
||||||
|
fn get_type(&self) -> NetworkTabType;
|
||||||
|
fn name(&self) -> String;
|
||||||
|
fn ui(&mut self, ui: &mut egui::Ui);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum Mode {
|
pub enum NetworkTabType {
|
||||||
Node,
|
Node,
|
||||||
Metrics,
|
Metrics,
|
||||||
Mining,
|
Mining,
|
||||||
Tuning
|
Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Network {
|
pub struct Network {
|
||||||
current_mode: Mode,
|
current_tab: Box<dyn NetworkTab>,
|
||||||
|
|
||||||
node_view: NetworkNode,
|
|
||||||
metrics_view: NetworkMetrics,
|
|
||||||
mining_view: NetworkMining,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Network {
|
impl Default for Network {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
current_mode: Mode::Node,
|
current_tab: Box::new(NetworkNode::default()),
|
||||||
node_view: NetworkNode::default(),
|
|
||||||
metrics_view: NetworkMetrics::default(),
|
|
||||||
mining_view: NetworkMining::default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +88,7 @@ impl Network {
|
||||||
.. Default::default()
|
.. Default::default()
|
||||||
})
|
})
|
||||||
.show_inside(ui, |ui| {
|
.show_inside(ui, |ui| {
|
||||||
self.draw_tab_content(ui);
|
self.current_tab.ui(ui);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,44 +101,33 @@ impl Network {
|
||||||
|
|
||||||
ui.columns(4, |columns| {
|
ui.columns(4, |columns| {
|
||||||
columns[0].vertical_centered_justified(|ui| {
|
columns[0].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, DATABASE, self.current_mode == Mode::Node, || {
|
View::tab_button(ui, DATABASE,
|
||||||
self.current_mode = Mode::Node;
|
self.current_tab.get_type() == NetworkTabType::Node, || {
|
||||||
});
|
self.current_tab = Box::new(NetworkNode::default());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
columns[1].vertical_centered_justified(|ui| {
|
columns[1].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, GAUGE, self.current_mode == Mode::Metrics, || {
|
View::tab_button(ui, GAUGE,
|
||||||
self.current_mode = Mode::Metrics;
|
self.current_tab.get_type() == NetworkTabType::Metrics, || {
|
||||||
});
|
self.current_tab = Box::new(NetworkMetrics::default());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
columns[2].vertical_centered_justified(|ui| {
|
columns[2].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, FACTORY, self.current_mode == Mode::Mining, || {
|
View::tab_button(ui, FACTORY,
|
||||||
self.current_mode = Mode::Mining;
|
self.current_tab.get_type() == NetworkTabType::Mining, || {
|
||||||
});
|
self.current_tab = Box::new(NetworkMining::default());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
columns[3].vertical_centered_justified(|ui| {
|
columns[3].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, FADERS, self.current_mode == Mode::Tuning, || {
|
View::tab_button(ui, FADERS,
|
||||||
self.current_mode = Mode::Tuning;
|
self.current_tab.get_type() == NetworkTabType::Settings, || {
|
||||||
});
|
self.current_tab = Box::new(NetworkSettings::default());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_tab_content(&mut self, ui: &mut egui::Ui) {
|
|
||||||
match self.current_mode {
|
|
||||||
Mode::Node => {
|
|
||||||
self.node_view.ui(ui);
|
|
||||||
}
|
|
||||||
Mode::Metrics => {
|
|
||||||
self.metrics_view.ui(ui);
|
|
||||||
}
|
|
||||||
Mode::Tuning => {
|
|
||||||
self.node_view.ui(ui);
|
|
||||||
}
|
|
||||||
Mode::Mining => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_title(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
fn draw_title(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||||
StripBuilder::new(ui)
|
StripBuilder::new(ui)
|
||||||
.size(Size::exact(52.0))
|
.size(Size::exact(52.0))
|
||||||
|
@ -173,21 +163,6 @@ impl Network {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_title_text(&self, builder: StripBuilder) {
|
fn draw_title_text(&self, builder: StripBuilder) {
|
||||||
let title_text = match &self.current_mode {
|
|
||||||
Mode::Node => {
|
|
||||||
self.node_view.name()
|
|
||||||
}
|
|
||||||
Mode::Metrics => {
|
|
||||||
self.metrics_view.name()
|
|
||||||
}
|
|
||||||
Mode::Mining => {
|
|
||||||
self.mining_view.name()
|
|
||||||
}
|
|
||||||
Mode::Tuning => {
|
|
||||||
self.node_view.name()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.size(Size::remainder())
|
.size(Size::remainder())
|
||||||
.size(Size::exact(32.0))
|
.size(Size::exact(32.0))
|
||||||
|
@ -195,7 +170,7 @@ impl Network {
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.add_space(2.0);
|
ui.add_space(2.0);
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.label(RichText::new(title_text.to_uppercase())
|
ui.label(RichText::new(self.current_tab.name().to_uppercase())
|
||||||
.size(18.0)
|
.size(18.0)
|
||||||
.color(Colors::TITLE));
|
.color(Colors::TITLE));
|
||||||
});
|
});
|
||||||
|
@ -233,7 +208,7 @@ impl Network {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disabled_server_content(ui: &mut egui::Ui) {
|
pub fn disabled_server_content(ui: &mut egui::Ui) {
|
||||||
View::center_content(ui, 142.0, |ui| {
|
View::center_content(ui, 162.0, |ui| {
|
||||||
let text = t!("network.disabled_server", "dots" => DOTS_THREE_OUTLINE_VERTICAL);
|
let text = t!("network.disabled_server", "dots" => DOTS_THREE_OUTLINE_VERTICAL);
|
||||||
ui.label(RichText::new(text)
|
ui.label(RichText::new(text)
|
||||||
.size(16.0)
|
.size(16.0)
|
||||||
|
@ -245,6 +220,15 @@ impl Network {
|
||||||
View::button(ui, format!("{} {}", POWER, t!("network.enable")), Colors::GOLD, || {
|
View::button(ui, format!("{} {}", POWER, t!("network.enable")), Colors::GOLD, || {
|
||||||
Node::start();
|
Node::start();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ui.add_space(4.0);
|
||||||
|
|
||||||
|
let autostart: bool = Settings::get_app_config().auto_start_node;
|
||||||
|
View::checkbox(ui, autostart, t!("network.autorun"), || {
|
||||||
|
let mut w_app_config = Settings::get_app_config_to_update();
|
||||||
|
w_app_config.auto_start_node = !autostart;
|
||||||
|
w_app_config.save();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,12 @@
|
||||||
|
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use eframe::epaint::{Color32, Rounding, Stroke};
|
use eframe::epaint::{Color32, Rounding, Stroke};
|
||||||
use egui::{RichText, ScrollArea, Spinner, Widget};
|
use egui::{RichText, ScrollArea};
|
||||||
use grin_servers::DiffBlock;
|
use grin_servers::DiffBlock;
|
||||||
|
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
use crate::gui::icons::{AT, COINS, CUBE_TRANSPARENT, HASH, HOURGLASS_LOW, HOURGLASS_MEDIUM, TIMER};
|
use crate::gui::icons::{AT, COINS, CUBE_TRANSPARENT, HASH, HOURGLASS_LOW, HOURGLASS_MEDIUM, TIMER};
|
||||||
use crate::gui::views::{Network, NetworkTab, View};
|
use crate::gui::views::{Network, NetworkTab, NetworkTabType, View};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -30,18 +30,23 @@ const BLOCK_REWARD: f64 = 60.0;
|
||||||
const YEARLY_SUPPLY: f64 = ((60 * 60 * 24 * 365) + 6 * 60 * 60) as f64;
|
const YEARLY_SUPPLY: f64 = ((60 * 60 * 24 * 365) + 6 * 60 * 60) as f64;
|
||||||
|
|
||||||
impl NetworkTab for NetworkMetrics {
|
impl NetworkTab for NetworkMetrics {
|
||||||
|
fn get_type(&self) -> NetworkTabType {
|
||||||
|
NetworkTabType::Metrics
|
||||||
|
}
|
||||||
|
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
t!("network.metrics")
|
t!("network.metrics")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
let server_stats = Node::get_stats();
|
let server_stats = Node::get_stats();
|
||||||
|
// Show loading spinner when stats are not available or message when server is not enabled.
|
||||||
if server_stats.is_none() || server_stats.as_ref().unwrap().diff_stats.height == 0 {
|
if server_stats.is_none() || server_stats.as_ref().unwrap().diff_stats.height == 0 {
|
||||||
if !Node::is_running() {
|
if !Node::is_running() {
|
||||||
Network::disabled_server_content(ui);
|
Network::disabled_server_content(ui);
|
||||||
} else {
|
} else {
|
||||||
View::center_content(ui, 160.0, |ui| {
|
View::center_content(ui, 160.0, |ui| {
|
||||||
Spinner::new().size(104.0).color(Colors::GOLD).ui(ui);
|
View::big_loading_spinner(ui);
|
||||||
ui.add_space(18.0);
|
ui.add_space(18.0);
|
||||||
ui.label(RichText::new(t!("network_metrics.loading"))
|
ui.label(RichText::new(t!("network_metrics.loading"))
|
||||||
.size(16.0)
|
.size(16.0)
|
||||||
|
@ -54,7 +59,7 @@ impl NetworkTab for NetworkMetrics {
|
||||||
|
|
||||||
let stats = server_stats.as_ref().unwrap();
|
let stats = server_stats.as_ref().unwrap();
|
||||||
|
|
||||||
// Show emission info
|
// Show emission info.
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
View::sub_header(ui, format!("{} {}", COINS, t!("network_metrics.emission")));
|
View::sub_header(ui, format!("{} {}", COINS, t!("network_metrics.emission")));
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,19 +12,37 @@
|
||||||
// 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::Ui;
|
use crate::gui::Colors;
|
||||||
use crate::gui::views::NetworkTab;
|
use crate::gui::views::{Network, NetworkTab, NetworkTabType, View};
|
||||||
|
use crate::node::Node;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct NetworkMining;
|
pub struct NetworkMining;
|
||||||
|
|
||||||
impl NetworkTab for NetworkMining {
|
impl NetworkTab for NetworkMining {
|
||||||
|
fn get_type(&self) -> NetworkTabType {
|
||||||
|
NetworkTabType::Mining
|
||||||
|
}
|
||||||
|
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
t!("network.mining")
|
t!("network.mining")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui(&mut self, ui: &mut Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
|
let server_stats = Node::get_stats();
|
||||||
|
// Show loading spinner when stats are not available or message when server is not enabled.
|
||||||
|
if !server_stats.is_some() {
|
||||||
|
if !Node::is_running() {
|
||||||
|
Network::disabled_server_content(ui);
|
||||||
|
} else {
|
||||||
|
ui.centered_and_justified(|ui| {
|
||||||
|
View::big_loading_spinner(ui);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stats = server_stats.as_ref().unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,30 +13,35 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use eframe::epaint::Stroke;
|
use eframe::epaint::Stroke;
|
||||||
use egui::{Color32, RichText, Rounding, ScrollArea, Spinner, Widget};
|
use egui::{Color32, RichText, Rounding, ScrollArea};
|
||||||
use grin_servers::PeerStats;
|
use grin_servers::PeerStats;
|
||||||
|
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
use crate::gui::icons::{AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS_CONNECTED, SHARE_NETWORK};
|
use crate::gui::icons::{AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS_CONNECTED, SHARE_NETWORK};
|
||||||
use crate::gui::views::{Network, NetworkTab, View};
|
use crate::gui::views::{Network, NetworkTab, NetworkTabType, View};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct NetworkNode;
|
pub struct NetworkNode;
|
||||||
|
|
||||||
impl NetworkTab for NetworkNode {
|
impl NetworkTab for NetworkNode {
|
||||||
|
fn get_type(&self) -> NetworkTabType {
|
||||||
|
NetworkTabType::Metrics
|
||||||
|
}
|
||||||
|
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
t!("network.node")
|
t!("network.node")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
let server_stats = Node::get_stats();
|
let server_stats = Node::get_stats();
|
||||||
|
// Show loading spinner when stats are not available or message when server is not enabled.
|
||||||
if !server_stats.is_some() {
|
if !server_stats.is_some() {
|
||||||
if !Node::is_running() {
|
if !Node::is_running() {
|
||||||
Network::disabled_server_content(ui);
|
Network::disabled_server_content(ui);
|
||||||
} else {
|
} else {
|
||||||
ui.centered_and_justified(|ui| {
|
ui.centered_and_justified(|ui| {
|
||||||
Spinner::new().size(104.0).color(Colors::GOLD).ui(ui);
|
View::big_loading_spinner(ui);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -83,7 +88,7 @@ impl NetworkTab for NetworkNode {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show block stats
|
// Show block stats
|
||||||
ui.add_space(6.0);
|
ui.add_space(4.0);
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
View::sub_header(ui, format!("{} {}", CUBE, t!("network_node.block")));
|
View::sub_header(ui, format!("{} {}", CUBE, t!("network_node.block")));
|
||||||
});
|
});
|
||||||
|
@ -119,7 +124,7 @@ impl NetworkTab for NetworkNode {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show data stats
|
// Show data stats
|
||||||
ui.add_space(6.0);
|
ui.add_space(4.0);
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
View::sub_header(ui, format!("{} {}", SHARE_NETWORK, t!("network_node.data")));
|
View::sub_header(ui, format!("{} {}", SHARE_NETWORK, t!("network_node.data")));
|
||||||
});
|
});
|
||||||
|
@ -167,7 +172,7 @@ impl NetworkTab for NetworkNode {
|
||||||
|
|
||||||
// Show peers stats when available
|
// Show peers stats when available
|
||||||
if stats.peer_count > 0 {
|
if stats.peer_count > 0 {
|
||||||
ui.add_space(6.0);
|
ui.add_space(4.0);
|
||||||
ui.vertical_centered_justified(|ui| {
|
ui.vertical_centered_justified(|ui| {
|
||||||
View::sub_header(ui, format!("{} {}", HANDSHAKE, t!("network_node.peers")));
|
View::sub_header(ui, format!("{} {}", HANDSHAKE, t!("network_node.peers")));
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,3 +11,22 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// 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::views::{NetworkTab, NetworkTabType};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NetworkSettings;
|
||||||
|
|
||||||
|
impl NetworkTab for NetworkSettings {
|
||||||
|
fn get_type(&self) -> NetworkTabType {
|
||||||
|
NetworkTabType::Settings
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> String {
|
||||||
|
t!("network.settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,12 +12,13 @@
|
||||||
// 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::{Button, PointerState, Response, RichText, Sense, Widget};
|
use egui::{Button, PointerState, Response, RichText, Sense, Spinner, Widget};
|
||||||
use egui::epaint::{Color32, FontId, RectShape, Rounding, Stroke};
|
use egui::epaint::{Color32, FontId, RectShape, Rounding, Stroke};
|
||||||
use egui::epaint::text::TextWrapping;
|
use egui::epaint::text::TextWrapping;
|
||||||
use egui::text::{LayoutJob, TextFormat};
|
use egui::text::{LayoutJob, TextFormat};
|
||||||
|
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
|
use crate::gui::icons::{CHECK_SQUARE, SQUARE};
|
||||||
|
|
||||||
pub struct View;
|
pub struct View;
|
||||||
|
|
||||||
|
@ -184,4 +185,38 @@ impl View {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw big gold loading spinner.
|
||||||
|
pub fn big_loading_spinner(ui: &mut egui::Ui) {
|
||||||
|
Spinner::new().size(104.0).color(Colors::GOLD).ui(ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw small gold loading spinner.
|
||||||
|
pub fn small_loading_spinner(ui: &mut egui::Ui) {
|
||||||
|
Spinner::new().size(48.0).color(Colors::GOLD).ui(ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
// let wt = RichText::new(text.to_uppercase()).size(18.0).color(Colors::BUTTON);
|
||||||
|
// let br = Button::new(wt)
|
||||||
|
// .stroke(Self::DEFAULT_STROKE)
|
||||||
|
// .fill(fill_color)
|
||||||
|
// .ui(ui).interact(Sense::click_and_drag());
|
||||||
|
//
|
||||||
|
// Self::on_button_click(ui, br, action);
|
||||||
|
|
||||||
|
/// Draw button that looks like checkbox with callback to change value.
|
||||||
|
pub fn checkbox(ui: &mut egui::Ui, value: bool, text: String, cb: impl FnOnce()) {
|
||||||
|
let text_value = match value {
|
||||||
|
true => { format!("{} {}", CHECK_SQUARE, text)}
|
||||||
|
false => { format!("{} {}", SQUARE, text)}
|
||||||
|
};
|
||||||
|
let wt = RichText::new(text_value).size(18.0).color(Colors::BUTTON);
|
||||||
|
let br = Button::new(wt)
|
||||||
|
.frame(false)
|
||||||
|
.stroke(Stroke::NONE)
|
||||||
|
.fill(Colors::TRANSPARENT)
|
||||||
|
.ui(ui).interact(Sense::click_and_drag());
|
||||||
|
|
||||||
|
Self::on_button_click(ui, br, cb);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
|
|
||||||
use grin_config::ConfigError;
|
use grin_config::ConfigError;
|
||||||
use grin_core::global::ChainTypes;
|
use grin_core::global::ChainTypes;
|
||||||
|
@ -38,14 +38,14 @@ pub struct AppConfig {
|
||||||
/// Run node server on startup.
|
/// Run node server on startup.
|
||||||
pub auto_start_node: bool,
|
pub auto_start_node: bool,
|
||||||
/// Chain type for node server.
|
/// Chain type for node server.
|
||||||
pub chain_type: ChainTypes
|
pub node_chain_type: ChainTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AppConfig {
|
impl Default for AppConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
auto_start_node: false,
|
auto_start_node: false,
|
||||||
chain_type: ChainTypes::default(),
|
node_chain_type: ChainTypes::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,12 +57,16 @@ impl AppConfig {
|
||||||
let parsed = Settings::read_from_file::<AppConfig>(config_path.clone());
|
let parsed = Settings::read_from_file::<AppConfig>(config_path.clone());
|
||||||
if !config_path.exists() || parsed.is_err() {
|
if !config_path.exists() || parsed.is_err() {
|
||||||
let default_config = AppConfig::default();
|
let default_config = AppConfig::default();
|
||||||
Settings::write_to_file(&default_config, config_path.to_str().unwrap());
|
Settings::write_to_file(&default_config, config_path);
|
||||||
default_config
|
default_config
|
||||||
} else {
|
} else {
|
||||||
parsed.unwrap()
|
parsed.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn save(&self) {
|
||||||
|
Settings::write_to_file(self, Settings::get_config_path(APP_CONFIG_FILE_NAME, None));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
|
@ -74,7 +78,7 @@ impl Settings {
|
||||||
/// Initialize settings with app and node configs from the disk.
|
/// Initialize settings with app and node configs from the disk.
|
||||||
fn init() -> Self {
|
fn init() -> Self {
|
||||||
let app_config = AppConfig::init();
|
let app_config = AppConfig::init();
|
||||||
let chain_type = app_config.chain_type;
|
let chain_type = app_config.node_chain_type;
|
||||||
Self {
|
Self {
|
||||||
app_config: Arc::new(RwLock::new(app_config)),
|
app_config: Arc::new(RwLock::new(app_config)),
|
||||||
node_config: Arc::new(RwLock::new(NodeConfig::init(&chain_type)))
|
node_config: Arc::new(RwLock::new(NodeConfig::init(&chain_type)))
|
||||||
|
@ -89,6 +93,10 @@ impl Settings {
|
||||||
SETTINGS_STATE.app_config.read().unwrap()
|
SETTINGS_STATE.app_config.read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_app_config_to_update() -> RwLockWriteGuard<'static, AppConfig> {
|
||||||
|
SETTINGS_STATE.app_config.write().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get working directory path for application.
|
/// Get working directory path for application.
|
||||||
pub fn get_working_path(chain_type: Option<&ChainTypes>) -> PathBuf {
|
pub fn get_working_path(chain_type: Option<&ChainTypes>) -> PathBuf {
|
||||||
// Check if dir exists
|
// Check if dir exists
|
||||||
|
@ -131,9 +139,9 @@ impl Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write config to a file
|
/// Write config to a file
|
||||||
pub fn write_to_file<T: Serialize>(config: &T, name: &str) {
|
pub fn write_to_file<T: Serialize>(config: &T, path: PathBuf) {
|
||||||
let conf_out = toml::to_string(config).unwrap();
|
let conf_out = toml::to_string(config).unwrap();
|
||||||
let mut file = File::create(name).unwrap();
|
let mut file = File::create(path.to_str().unwrap()).unwrap();
|
||||||
file.write_all(conf_out.as_bytes()).unwrap();
|
file.write_all(conf_out.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue