diff --git a/build_run_android.sh b/build_run_android.sh index 02e7f13..1b8036d 100755 --- a/build_run_android.sh +++ b/build_run_android.sh @@ -37,8 +37,11 @@ then yes | cp -f target/${platform_path}/${type}/libgrim.so app/src/main/jniLibs/${platform_param} ./gradlew clean ./gradlew build - #./gradlew installDebug - adb install app/build/outputs/apk/debug/app-debug.apk - sleep 1s - adb shell am start -n mw.gri.android/.MainActivity + # Install on several devices + for SERIAL in $(adb devices | grep -v List | cut -f 1); + do + adb -s $SERIAL install app/build/outputs/apk/debug/app-debug.apk + sleep 1s + adb -s $SERIAL shell am start -n mw.gri.android/.MainActivity; + done fi \ No newline at end of file diff --git a/locales/en.yml b/locales/en.yml index 0d15bfa..4ee0641 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -9,8 +9,6 @@ network: mining: Mining settings: Node settings enable_node: Enable node - disable: Disable - restart: Restart autorun: Autorun disabled_server: 'Enable integrated node or add another connection method by pressing %{dots} in the top-left corner of the screen.' no_ips: There are no available IP addresses on your system, server cannot be started, check your network connectivity. diff --git a/locales/ru.yml b/locales/ru.yml index 5c7e1c0..82ca9f5 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -9,8 +9,6 @@ network: mining: Майнинг settings: Настройки узла enable_node: Включить узел - disable: Выключить - restart: Перезапустить autorun: Автозапуск disabled_server: 'Включите встроенный узел или добавьте другой способ подключения, нажав %{dots} в левом-верхнем углу экрана.' no_ips: В вашей системе отсутствуют доступные IP адреса, запуск сервера невозможен, проверьте ваше подключение к сети. @@ -79,7 +77,7 @@ network_settings: restart_node_required: Для применения изменений требуется перезапуск узла. enable: Включить disable: Выключить - restart: Перезапустить + restart: Перезапуск server: Сервер api_ip: API IP Адрес api_port: API Порт diff --git a/src/gui/app.rs b/src/gui/app.rs index 26ec926..8ea6a06 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -43,7 +43,7 @@ impl eframe::App for PlatformApp { // Show main content. egui::CentralPanel::default() .frame(egui::Frame { - fill: Colors::FILL, + fill: Colors::YELLOW, ..Default::default() }) .show(ctx, |ui| { diff --git a/src/gui/platform/desktop/mod.rs b/src/gui/platform/desktop/mod.rs index 534ab58..6eab0c0 100644 --- a/src/gui/platform/desktop/mod.rs +++ b/src/gui/platform/desktop/mod.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::gui::{App, PlatformApp}; +use crate::gui::PlatformApp; use crate::gui::platform::PlatformCallbacks; #[derive(Default)] diff --git a/src/gui/views/accounts/accounts.rs b/src/gui/views/accounts/accounts.rs index 112a0f4..622280a 100644 --- a/src/gui/views/accounts/accounts.rs +++ b/src/gui/views/accounts/accounts.rs @@ -15,7 +15,7 @@ use crate::gui::Colors; use crate::gui::icons::{GLOBE, PLUS}; use crate::gui::platform::PlatformCallbacks; -use crate::gui::views::{Root, TitleAction, TitlePanel, View}; +use crate::gui::views::{Root, TitleAction, TitleType, TitlePanel, View}; /// Accounts content. pub struct Accounts { @@ -33,7 +33,8 @@ impl Default for Accounts { impl Accounts { pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) { - TitlePanel::ui(t!("accounts.title"), if !Root::is_dual_panel_mode(frame) { + let title_content = TitleType::Single(t!("accounts.title").to_uppercase()); + TitlePanel::ui(title_content, if !Root::is_dual_panel_mode(frame) { TitleAction::new(GLOBE, || { Root::toggle_side_panel(); }) diff --git a/src/gui/views/modal.rs b/src/gui/views/modal.rs index 2b6e0df..88a9e44 100644 --- a/src/gui/views/modal.rs +++ b/src/gui/views/modal.rs @@ -291,7 +291,7 @@ impl Modal { ui.vertical_centered_justified(|ui| { ui.add_space(8.0); ui.label(RichText::new(self.title.as_ref().unwrap()) - .size(20.0) + .size(19.0) .color(Colors::TITLE) ); ui.add_space(8.0); diff --git a/src/gui/views/network/metrics.rs b/src/gui/views/network/metrics.rs index 5210f29..f73da44 100644 --- a/src/gui/views/network/metrics.rs +++ b/src/gui/views/network/metrics.rs @@ -187,7 +187,7 @@ fn block_item_ui(ui: &mut egui::Ui, db: &DiffBlock, rounding: [bool; 2]) { // Draw block hash. ui.heading(RichText::new(format!("{} {}", HASH, db.block_hash)) .color(Colors::BLACK) - .size(18.0)); + .size(17.0)); }); ui.horizontal(|ui| { ui.add_space(6.0); diff --git a/src/gui/views/network/mining.rs b/src/gui/views/network/mining.rs index 68ad511..b36a298 100644 --- a/src/gui/views/network/mining.rs +++ b/src/gui/views/network/mining.rs @@ -246,7 +246,7 @@ fn worker_item_ui(ui: &mut egui::Ui, ws: &WorkerStats, rounding: [bool; 2]) { let status_line_text = format!("{} {} {}", status_icon, ws.id, status_text); ui.heading(RichText::new(status_line_text) .color(status_color) - .size(18.0)); + .size(17.0)); ui.add_space(2.0); }); ui.horizontal(|ui| { diff --git a/src/gui/views/network/network.rs b/src/gui/views/network/network.rs index 33bb76e..d5d2e1f 100644 --- a/src/gui/views/network/network.rs +++ b/src/gui/views/network/network.rs @@ -21,7 +21,7 @@ use crate::AppConfig; use crate::gui::Colors; use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE, POWER}; use crate::gui::platform::PlatformCallbacks; -use crate::gui::views::{Modal, ModalContainer, NetworkMetrics, NetworkMining, NetworkNode, NetworkSettings, Root, TitleAction, TitleContent, TitlePanel, View}; +use crate::gui::views::{Modal, ModalContainer, NetworkMetrics, NetworkMining, NetworkNode, NetworkSettings, Root, TitleAction, TitleType, TitlePanel, View}; use crate::gui::views::network::setup::{DandelionSetup, NodeSetup, P2PSetup, PoolSetup, StratumSetup}; use crate::node::Node; @@ -155,6 +155,11 @@ impl Network { .show_inside(ui, |ui| { self.current_tab.ui(ui, cb); }); + + // Redraw content after delay if node is not syncing to update stats. + if Node::not_syncing() { + ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY); + } } /// Draw tab buttons in the bottom of the screen. @@ -194,9 +199,13 @@ impl Network { /// Draw title content. fn title_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) { - let title_content = TitleContent::Custom("network_title".to_string(), Box::new(|ui| { - })); - TitlePanel::test_ui(title_content, TitleAction::new(DOTS_THREE_OUTLINE_VERTICAL, || { + // Setup values for title panel. + let title_text = self.current_tab.get_type().title().to_uppercase(); + let subtitle_text = Node::get_sync_status_text(); + let not_syncing = Node::not_syncing(); + let title_content = TitleType::WithSubTitle(title_text, subtitle_text, !not_syncing); + // Draw title panel. + TitlePanel::ui(title_content, TitleAction::new(DOTS_THREE_OUTLINE_VERTICAL, || { //TODO: Show connections }), if !Root::is_dual_panel_mode(frame) { TitleAction::new(CARDHOLDER, || { @@ -205,78 +214,6 @@ impl Network { } else { None }, ui); - - // StripBuilder::new(ui) - // .size(Size::exact(52.0)) - // .size(Size::remainder()) - // .size(Size::exact(52.0)) - // .horizontal(|mut strip| { - // strip.cell(|ui| { - // ui.centered_and_justified(|ui| { - // View::title_button(ui, DOTS_THREE_OUTLINE_VERTICAL, || { - // //TODO: Show connections - // }); - // }); - // }); - // strip.strip(|builder| { - // self.title_text_ui(builder); - // }); - // strip.cell(|ui| { - // if !Root::is_dual_panel_mode(frame) { - // ui.centered_and_justified(|ui| { - // View::title_button(ui, CARDHOLDER, || { - // Root::toggle_side_panel(); - // }); - // }); - // } - // }); - // }); - } - - /// Draw title text. - fn title_text_ui(&self, builder: StripBuilder) { - builder - .size(Size::remainder()) - .size(Size::exact(28.0)) - .vertical(|mut strip| { - strip.cell(|ui| { - ui.add_space(4.0); - ui.vertical_centered(|ui| { - ui.label(RichText::new(self.current_tab.get_type().title().to_uppercase()) - .size(19.0) - .color(Colors::TITLE)); - }); - }); - strip.cell(|ui| { - ui.centered_and_justified(|ui| { - let sync_status = Node::get_sync_status(); - - // Setup text color animation based on sync status - let idle = match sync_status { - None => !Node::is_starting(), - Some(ss) => ss == SyncStatus::NoSync - }; - let (dark, bright) = (0.3, 1.0); - let color_factor = if !idle { - lerp(dark..=bright, ui.input(|i| i.time).cos().abs()) as f32 - } else { - bright as f32 - }; - - // Draw sync status text. - let status_color_rgba = Rgba::from(Colors::TEXT) * color_factor; - let status_color = Color32::from(status_color_rgba); - View::ellipsize_text(ui, Node::get_sync_status_text(), 15.0, status_color); - - // Repaint delay based on sync status. - if idle { - ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY); - } else { - ui.ctx().request_repaint(); - } - }); - }); - }); } /// Content to draw when node is disabled. diff --git a/src/gui/views/network/node.rs b/src/gui/views/network/node.rs index f4ffc78..13e077b 100644 --- a/src/gui/views/network/node.rs +++ b/src/gui/views/network/node.rs @@ -210,7 +210,7 @@ fn peer_item_ui(ui: &mut egui::Ui, peer: &PeerStats, rounding: [bool; 2]) { ui.horizontal(|ui| { ui.add_space(5.0); let addr_text = format!("{} {}", PLUGS_CONNECTED, &peer.addr); - ui.label(RichText::new(addr_text).color(Colors::BLACK).size(18.0)); + ui.label(RichText::new(addr_text).color(Colors::BLACK).size(17.0)); }); // Draw peer difficulty and height ui.horizontal(|ui| { diff --git a/src/gui/views/network/settings.rs b/src/gui/views/network/settings.rs index 676b827..ff9d314 100644 --- a/src/gui/views/network/settings.rs +++ b/src/gui/views/network/settings.rs @@ -158,7 +158,7 @@ impl NetworkSettings { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.reset_settings_desc")) - .size(18.0) + .size(17.0) .color(Colors::TEXT)); ui.add_space(8.0); }); @@ -212,7 +212,7 @@ impl NetworkSettings { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.restart_node_required")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); }); diff --git a/src/gui/views/network/setup/dandelion.rs b/src/gui/views/network/setup/dandelion.rs index 34a6f29..266f1f7 100644 --- a/src/gui/views/network/setup/dandelion.rs +++ b/src/gui/views/network/setup/dandelion.rs @@ -127,7 +127,7 @@ impl DandelionSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.epoch_duration")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -147,7 +147,7 @@ impl DandelionSetup { if self.epoch_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -212,7 +212,7 @@ impl DandelionSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.embargo_timer")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -232,7 +232,7 @@ impl DandelionSetup { if self.embargo_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -297,7 +297,7 @@ impl DandelionSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.aggregation_period")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -317,7 +317,7 @@ impl DandelionSetup { if self.aggregation_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -382,7 +382,7 @@ impl DandelionSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.stem_probability")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -402,7 +402,7 @@ impl DandelionSetup { if self.stem_prob_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); diff --git a/src/gui/views/network/setup/node.rs b/src/gui/views/network/setup/node.rs index 8078011..7867eda 100644 --- a/src/gui/views/network/setup/node.rs +++ b/src/gui/views/network/setup/node.rs @@ -245,7 +245,7 @@ impl NodeSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.api_port")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(6.0); @@ -353,7 +353,7 @@ impl NodeSetup { _ => t!("network_settings.foreign_api_secret") }; ui.label(RichText::new(description) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(6.0); @@ -376,19 +376,17 @@ impl NodeSetup { ui.spacing_mut().item_spacing = egui::Vec2::new(12.0, 0.0); let mut buttons_rect = ui.available_rect_before_wrap(); - buttons_rect.set_height(46.0); + buttons_rect.set_height(42.0); ui.allocate_ui_at_rect(buttons_rect, |ui| { ui.columns(2, |columns| { columns[0].with_layout(Layout::right_to_left(Align::Center), |ui| { - let copy_title = format!("{} {}", COPY, t!("copy")); - View::button(ui, copy_title, Colors::WHITE, || { + View::button(ui, COPY.to_string(), Colors::WHITE, || { cb.copy_string_to_buffer(self.secret_edit.clone()); }); }); columns[1].with_layout(Layout::left_to_right(Align::Center), |ui| { - let paste_title = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); - View::button(ui, paste_title, Colors::WHITE, || { + View::button(ui, CLIPBOARD_TEXT.to_string(), Colors::WHITE, || { self.secret_edit = cb.get_string_from_buffer(); }); }); @@ -469,7 +467,7 @@ impl NodeSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.ftl")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -489,7 +487,7 @@ impl NodeSetup { if self.ftl_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); diff --git a/src/gui/views/network/setup/p2p.rs b/src/gui/views/network/setup/p2p.rs index 061b8ca..9eecb6a 100644 --- a/src/gui/views/network/setup/p2p.rs +++ b/src/gui/views/network/setup/p2p.rs @@ -235,7 +235,7 @@ impl P2PSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.p2p_port")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -255,7 +255,7 @@ impl P2PSetup { if !self.port_available_edit { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.port_unavailable")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } @@ -389,7 +389,7 @@ impl P2PSetup { Self::CUSTOM_SEED_MODAL => t!("network_settings.add_seed"), &_ => t!("network_settings.add_peer") }; - ui.label(RichText::new(label_text).size(18.0).color(Colors::GRAY)); + ui.label(RichText::new(label_text).size(17.0).color(Colors::GRAY)); ui.add_space(8.0); // Draw peer address text edit. @@ -577,7 +577,7 @@ impl P2PSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.ban_window")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -597,7 +597,7 @@ impl P2PSetup { if self.ban_window_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -663,7 +663,7 @@ impl P2PSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_inbound_count")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -683,7 +683,7 @@ impl P2PSetup { if self.max_inbound_count.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -749,7 +749,7 @@ impl P2PSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_outbound_count")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -769,7 +769,7 @@ impl P2PSetup { if self.max_outbound_count.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -840,7 +840,7 @@ impl P2PSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.min_outbound_count")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -860,7 +860,7 @@ impl P2PSetup { if self.min_outbound_count.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); diff --git a/src/gui/views/network/setup/pool.rs b/src/gui/views/network/setup/pool.rs index 568de3c..fe54c8e 100644 --- a/src/gui/views/network/setup/pool.rs +++ b/src/gui/views/network/setup/pool.rs @@ -129,7 +129,7 @@ impl PoolSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.pool_fee")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -149,7 +149,7 @@ impl PoolSetup { if self.fee_base_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -214,7 +214,7 @@ impl PoolSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.reorg_period")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -233,8 +233,8 @@ impl PoolSetup { // Show error when specified value is not valid or reminder to restart enabled node. if self.reorg_period_edit.parse::().is_err() { ui.add_space(12.0); - ui.label(RichText::new(t!("network_settings.reorg_period")) - .size(18.0) + ui.label(RichText::new(t!("network_settings.not_valid_value")) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -299,7 +299,7 @@ impl PoolSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_tx_pool")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -319,7 +319,7 @@ impl PoolSetup { if self.pool_size_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -384,7 +384,7 @@ impl PoolSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_tx_stempool")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -404,7 +404,7 @@ impl PoolSetup { if self.stempool_size_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); @@ -469,7 +469,7 @@ impl PoolSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_tx_weight")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -489,7 +489,7 @@ impl PoolSetup { if self.max_weight_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { NetworkSettings::node_restart_required_ui(ui); diff --git a/src/gui/views/network/setup/stratum.rs b/src/gui/views/network/setup/stratum.rs index 8198b3a..1c46af0 100644 --- a/src/gui/views/network/setup/stratum.rs +++ b/src/gui/views/network/setup/stratum.rs @@ -186,7 +186,7 @@ impl StratumSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.stratum_port")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -206,7 +206,7 @@ impl StratumSetup { if !self.stratum_port_available_edit { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.port_unavailable")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { server_restart_required_ui(ui); @@ -284,7 +284,7 @@ impl StratumSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.attempt_time")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -304,7 +304,7 @@ impl StratumSetup { if self.attempt_time_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { server_restart_required_ui(ui); @@ -370,7 +370,7 @@ impl StratumSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.min_share_diff")) - .size(18.0) + .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); @@ -390,7 +390,7 @@ impl StratumSetup { if self.min_share_diff_edit.parse::().is_err() { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) - .size(18.0) + .size(17.0) .color(Colors::RED)); } else { server_restart_required_ui(ui); diff --git a/src/gui/views/root.rs b/src/gui/views/root.rs index 52b4e17..66e753b 100644 --- a/src/gui/views/root.rs +++ b/src/gui/views/root.rs @@ -140,7 +140,7 @@ impl Root { /// Show exit confirmation modal. pub fn show_exit_modal() { - let exit_modal = Modal::new(Self::EXIT_MODAL_ID).title(t!("modal_exit.exit")); + let exit_modal = Modal::new(Self::EXIT_MODAL_ID).title(t!("modal.confirmation")); Modal::show(exit_modal); } @@ -160,7 +160,7 @@ impl Root { View::small_loading_spinner(ui); ui.add_space(12.0); ui.label(RichText::new(t!("sync_status.shutdown")) - .size(18.0) + .size(17.0) .color(Colors::TEXT)); }); ui.add_space(10.0); @@ -168,7 +168,7 @@ impl Root { ui.add_space(8.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("modal_exit.description")) - .size(18.0) + .size(17.0) .color(Colors::TEXT)); }); ui.add_space(10.0); diff --git a/src/gui/views/title_panel.rs b/src/gui/views/title_panel.rs index 64f6a91..84d8355 100644 --- a/src/gui/views/title_panel.rs +++ b/src/gui/views/title_panel.rs @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::Id; +use egui::{Color32, Id, lerp, Rgba, RichText}; use egui::style::Margin; use egui_extras::{Size, StripBuilder}; use crate::gui::Colors; use crate::gui::views::View; +/// Title action button. pub struct TitleAction { pub(crate) icon: Box<&'static str>, pub(crate) on_click: Box, @@ -30,22 +31,22 @@ impl TitleAction { } } -/// Represents title content, can be text or callback to draw custom title. -pub enum TitleContent { - Text(String), - /// First argument is identifier for panel. - Custom(String, Box) +/// Represents title content, can be single title or with animated sub-title. +pub enum TitleType { + Single(String), + WithSubTitle(String, String, bool) } +/// Title panel with left/right action buttons and text in the middle. pub struct TitlePanel; impl TitlePanel { pub const DEFAULT_HEIGHT: f32 = 52.0; - pub fn test_ui(title: TitleContent, l: Option, r: Option, ui: &mut egui::Ui) { + pub fn ui(title: TitleType, l: Option, r: Option, ui: &mut egui::Ui) { let id = match &title { - TitleContent::Text(text) => Id::from(text.clone()), - TitleContent::Custom(text, _) => Id::from(text.clone()) + TitleType::Single(text) => Id::from(text.clone()), + TitleType::WithSubTitle(text, _, _) => Id::from(text.clone()) }; egui::TopBottomPanel::top(id) .resizable(false) @@ -64,44 +65,21 @@ impl TitlePanel { strip.cell(|ui| { Self::draw_action(ui, l); }); - strip.cell(|ui| { - match title { - TitleContent::Text(text) => { - Self::draw_title(ui, text); - } - TitleContent::Custom(_, cb) => { - (cb)(ui); - } + match title { + TitleType::Single(text) => { + strip.cell(|ui| { + ui.add_space(2.0); + ui.centered_and_justified(|ui| { + View::ellipsize_text(ui, text, 19.0, Colors::TITLE); + }); + }); } - }); - strip.cell(|ui| { - Self::draw_action(ui, r); - }); - }); - }); - } - - pub fn ui(title: String, l: Option, r: Option, ui: &mut egui::Ui) { - egui::TopBottomPanel::top(Id::from(title.clone())) - .resizable(false) - .exact_height(Self::DEFAULT_HEIGHT) - .frame(egui::Frame { - outer_margin: Margin::same(-1.0), - fill: Colors::YELLOW, - ..Default::default() - }) - .show_inside(ui, |ui| { - StripBuilder::new(ui) - .size(Size::exact(Self::DEFAULT_HEIGHT)) - .size(Size::remainder()) - .size(Size::exact(Self::DEFAULT_HEIGHT)) - .horizontal(|mut strip| { - strip.cell(|ui| { - Self::draw_action(ui, l); - }); - strip.cell(|ui| { - Self::draw_title(ui, title); - }); + TitleType::WithSubTitle(text, subtitle_text, animate_sub) => { + strip.strip(|builder| { + Self::with_sub_title(builder, text, subtitle_text, animate_sub); + }); + } + } strip.cell(|ui| { Self::draw_action(ui, r); }); @@ -109,6 +87,7 @@ impl TitlePanel { }); } + /// Draw panel [`TitleAction`]. fn draw_action(ui: &mut egui::Ui, action: Option) { if action.is_some() { let action = action.unwrap(); @@ -120,10 +99,45 @@ impl TitlePanel { } } - fn draw_title(ui: &mut egui::Ui, title: String) { - ui.add_space(2.0); - ui.centered_and_justified(|ui| { - View::ellipsize_text(ui, title.to_uppercase(), 20.0, Colors::TITLE); - }); + /// Draw title text for [`TitleType::Single`] type. + fn single(ui: &mut egui::Ui, title: String) { + + } + + /// Draw title text for [`TitleType::WithSubTitle`] type. + fn with_sub_title(builder: StripBuilder, title: String, subtitle: String, animate_sub: bool) { + builder + .size(Size::remainder()) + .size(Size::exact(30.0)) + .vertical(|mut strip| { + strip.cell(|ui| { + ui.add_space(4.0); + ui.centered_and_justified(|ui| { + View::ellipsize_text(ui, title, 18.0, Colors::TITLE); + }); + }); + strip.cell(|ui| { + ui.centered_and_justified(|ui| { + // Setup text color animation if needed. + let (dark, bright) = (0.3, 1.0); + let color_factor = if animate_sub { + lerp(dark..=bright, ui.input(|i| i.time).cos().abs()) as f32 + } else { + bright as f32 + }; + + // Draw subtitle text. + let sub_color_rgba = Rgba::from(Colors::TEXT) * color_factor; + let sub_color = Color32::from(sub_color_rgba); + View::ellipsize_text(ui, subtitle, 15.0, sub_color); + + // Repaint delay based on animation status. + if animate_sub { + ui.ctx().request_repaint(); + } + }); + ui.add_space(2.0); + }); + }); } } diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 6a1f3ab..93d84e8 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -76,7 +76,7 @@ impl View { // Disable stroke color on hover. ui.style_mut().visuals.widgets.hovered.bg_stroke = Self::DEFAULT_STROKE; // Setup text. - let wt = RichText::new(icon.to_string()).size(24.0).color(Colors::TITLE); + let wt = RichText::new(icon.to_string()).size(22.0).color(Colors::TITLE); // Draw button. let br = Button::new(wt) .fill(Colors::TRANSPARENT) @@ -101,7 +101,7 @@ impl View { true => Colors::FILL, false => Colors::WHITE }; - let br = Button::new(RichText::new(icon.to_string()).size(24.0).color(text_color)) + let br = Button::new(RichText::new(icon.to_string()).size(22.0).color(text_color)) .stroke(stroke) .fill(color) .ui(ui); @@ -112,7 +112,7 @@ impl View { /// Draw [`Button`] with specified background fill color. pub fn button(ui: &mut egui::Ui, text: String, fill_color: Color32, action: impl FnOnce()) { - let button_text = Self::ellipsize(text.to_uppercase(), 18.0, Colors::TEXT_BUTTON); + let button_text = Self::ellipsize(text.to_uppercase(), 17.0, Colors::TEXT_BUTTON); let br = Button::new(button_text) .stroke(Self::DEFAULT_STROKE) .fill(fill_color) @@ -154,7 +154,7 @@ impl View { // Draw box value. let mut job = LayoutJob::single_section(value, TextFormat { - font_id: FontId::proportional(18.0), + font_id: FontId::proportional(17.0), color: Colors::BLACK, ..Default::default() }); @@ -209,7 +209,7 @@ impl View { false => (format!("{} {}", SQUARE, text), Colors::CHECKBOX) }; - let br = Button::new(RichText::new(text_value).size(18.0).color(color)) + let br = Button::new(RichText::new(text_value).size(17.0).color(color)) .frame(false) .stroke(Stroke::NONE) .fill(Colors::TRANSPARENT) diff --git a/src/lib.rs b/src/lib.rs index a345c74..0ffa410 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -173,10 +173,10 @@ pub fn setup_fonts(ctx: &Context) { let mut style = (*ctx.style()).clone(); style.text_styles = [ - (Heading, FontId::new(20.0, Proportional)), + (Heading, FontId::new(19.0, Proportional)), (Body, FontId::new(16.0, Proportional)), - (Button, FontId::new(18.0, Proportional)), - (Small, FontId::new(12.0, Proportional)), + (Button, FontId::new(17.0, Proportional)), + (Small, FontId::new(15.0, Proportional)), (Monospace, FontId::new(16.0, Proportional)), ].into(); diff --git a/src/node/node.rs b/src/node/node.rs index 5fd7a8d..2f3684a 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -29,31 +29,31 @@ use crate::node::NodeConfig; use crate::node::stratum::{StratumStopState, StratumServer}; lazy_static! { - /// Static thread-aware state of [`Node`] to be updated from another thread. + /// Static thread-aware state of [`Node`] to be updated from separate thread. static ref NODE_STATE: Arc = Arc::new(Node::default()); } /// Provides [`Server`] control, holds current status and statistics. pub struct Node { - /// The node [`Server`] statistics for UI. + /// Node [`Server`] statistics for UI. stats: Arc>>, - /// Stratum server statistics. + /// [`StratumServer`] statistics. stratum_stats: Arc>, - /// Stratum server statistics. + /// State to stop [`StratumServer`] from outside. stratum_stop_state: Arc, - /// Running API server address. + /// Running API [`Server`] address. api_addr: Arc>>, - /// Running P2P server port. + /// Running P2P [`grin_p2p::Server`] port. p2p_port: Arc>>, - /// Indicator if server is starting. + /// Indicator if node [`Server`] is starting. starting: AtomicBool, - /// Thread flag to stop the server and start it again. + /// Thread flag to stop the [`Server`] and start it again. restart_needed: AtomicBool, - /// Thread flag to stop the server. + /// Thread flag to stop the [`Server`]. stop_needed: AtomicBool, - /// Flag to check if app exit is needed after server stop. + /// Flag to check if app exit is needed after [`Server`] stop. exit_after_stop: AtomicBool, - /// Thread flag to start stratum server. + /// Thread flag to start [`StratumServer`]. start_stratum_needed: AtomicBool, /// Error on [`Server`] start. init_error: Option @@ -78,7 +78,7 @@ impl Default for Node { } impl Node { - /// Delay for server thread to update the stats. + /// Delay for thread to update the stats. pub const STATS_UPDATE_DELAY: Duration = Duration::from_millis(250); /// Stop the [`Server`] and setup exit flag after if needed. @@ -87,14 +87,14 @@ impl Node { NODE_STATE.exit_after_stop.store(exit_after_stop, Ordering::Relaxed); } - /// Start the node. + /// Request to start the [`Node`]. pub fn start() { if !Self::is_running() { Self::start_server_thread(); } } - /// Restart the node. + /// Request to restart the [`Node`]. pub fn restart() { if Self::is_running() { NODE_STATE.restart_needed.store(true, Ordering::Relaxed); @@ -103,7 +103,7 @@ impl Node { } } - /// Get API server address if node is running. + /// Get API [`Server`] address if [`Node`] is running. pub fn get_api_addr() -> Option { let r_api_addr = NODE_STATE.api_addr.read().unwrap(); if r_api_addr.is_some() { @@ -113,7 +113,7 @@ impl Node { } } - /// Get P2P server port if node is running. + /// Get P2P [`grin_p2p::Server`] port if node is running. pub fn get_p2p_port() -> Option { let r_p2p_port = NODE_STATE.p2p_port.read().unwrap(); if r_p2p_port.is_some() { @@ -123,47 +123,47 @@ impl Node { } } - /// Request to start stratum server. + /// Request to start [`StratumServer`]. pub fn start_stratum() { NODE_STATE.start_stratum_needed.store(true, Ordering::Relaxed); } - /// Check if stratum server is starting. + /// Check if [`StratumServer`] is starting. pub fn is_stratum_starting() -> bool { NODE_STATE.start_stratum_needed.load(Ordering::Relaxed) } - /// Get stratum server statistics. + /// Get [`StratumServer`] statistics. pub fn get_stratum_stats() -> grin_util::RwLockReadGuard<'static, StratumStats> { NODE_STATE.stratum_stats.read() } - /// Stop stratum server. + /// Stop [`StratumServer`]. pub fn stop_stratum() { NODE_STATE.stratum_stop_state.stop() } - /// Check if stratum server is stopping. + /// Check if [`StratumServer`] is stopping. pub fn is_stratum_stopping() -> bool { NODE_STATE.stratum_stop_state.is_stopped() } - /// Check if node is starting. + /// Check if [`Node`] is starting. pub fn is_starting() -> bool { NODE_STATE.starting.load(Ordering::Relaxed) } - /// Check if node is running. + /// Check if [`Node`] is running. pub fn is_running() -> bool { Self::get_sync_status().is_some() } - /// Check if node is stopping. + /// Check if [`Node`] is stopping. pub fn is_stopping() -> bool { NODE_STATE.stop_needed.load(Ordering::Relaxed) } - /// Check if node is restarting. + /// Check if [`Node`] is restarting. pub fn is_restarting() -> bool { NODE_STATE.restart_needed.load(Ordering::Relaxed) } @@ -173,6 +173,14 @@ impl Node { NODE_STATE.stats.read().unwrap() } + /// Check if [`Server`] is not syncing (disabled or just running after synchronization). + pub fn not_syncing() -> bool { + return match Node::get_sync_status() { + None => true, + Some(ss) => ss == SyncStatus::NoSync + }; + } + /// Get synchronization status, empty when [`Server`] is not running. pub fn get_sync_status() -> Option { // Return Shutdown status when node is stopping. diff --git a/src/node/stratum.rs b/src/node/stratum.rs index 6c48a30..e5732ab 100644 --- a/src/node/stratum.rs +++ b/src/node/stratum.rs @@ -205,7 +205,7 @@ impl State { } } -/// Stratum server stop state shared between to stop stratum from node thread. +/// Stratum server stop state to stop it from node thread. pub struct StratumStopState { stopping: AtomicBool, }