From 32f8bd11de59830ca47167d21eb06700b04785a5 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Wed, 29 May 2024 22:47:17 +0300 Subject: [PATCH] ui: dark theme support, setup by default from system, settings --- Cargo.lock | 97 ++++++- Cargo.toml | 1 + .../java/mw/gri/android/MainActivity.java | 6 + img/logo_light.png | Bin 0 -> 40733 bytes locales/en.yml | 3 + locales/ru.yml | 3 + locales/tr.yml | 69 ++--- src/gui/app.rs | 2 - src/gui/colors.rs | 253 ++++++++++++++++-- src/gui/platform/android/mod.rs | 9 +- src/gui/views/camera.rs | 4 +- src/gui/views/modal.rs | 18 +- src/gui/views/network/connections.rs | 32 +-- src/gui/views/network/content.rs | 32 +-- src/gui/views/network/metrics.rs | 8 +- src/gui/views/network/mining.rs | 26 +- src/gui/views/network/node.rs | 8 +- src/gui/views/network/settings.rs | 28 +- src/gui/views/network/setup/dandelion.rs | 58 ++-- src/gui/views/network/setup/node.rs | 66 ++--- src/gui/views/network/setup/p2p.rs | 98 +++---- src/gui/views/network/setup/pool.rs | 70 ++--- src/gui/views/network/setup/stratum.rs | 58 ++-- src/gui/views/qr.rs | 8 +- src/gui/views/root.rs | 109 +++++--- src/gui/views/title_panel.rs | 8 +- src/gui/views/views.rs | 105 ++++---- src/gui/views/wallets/content.rs | 49 ++-- src/gui/views/wallets/creation/creation.rs | 56 ++-- src/gui/views/wallets/creation/mnemonic.rs | 28 +- src/gui/views/wallets/setup/common.rs | 50 ++-- src/gui/views/wallets/setup/connection.rs | 36 +-- src/gui/views/wallets/setup/recovery.rs | 48 ++-- src/gui/views/wallets/wallet/content.rs | 70 ++--- src/gui/views/wallets/wallet/messages.rs | 73 +++-- src/gui/views/wallets/wallet/settings.rs | 4 +- src/gui/views/wallets/wallet/transport.rs | 72 ++--- src/gui/views/wallets/wallet/txs.rs | 88 +++--- src/lib.rs | 41 ++- src/main.rs | 16 +- src/settings/config.rs | 25 +- 41 files changed, 1131 insertions(+), 704 deletions(-) create mode 100644 img/logo_light.png diff --git a/Cargo.lock b/Cargo.lock index 88c91b0..c4ea356 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,6 +173,17 @@ dependencies = [ "sha2 0.9.9", ] +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.11" @@ -2030,6 +2041,22 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "dark-light" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a76fa97167fa740dcdbfe18e8895601e1bc36525f09b044e00916e717c03a3c" +dependencies = [ + "dconf_rs", + "detect-desktop-environment", + "dirs 4.0.0", + "objc", + "rust-ini", + "web-sys", + "winreg 0.10.1", + "zbus 4.2.2", +] + [[package]] name = "darling" version = "0.14.4" @@ -2125,6 +2152,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "dconf_rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" + [[package]] name = "der" version = "0.7.9" @@ -2256,6 +2289,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "detect-desktop-environment" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810" + [[package]] name = "digest" version = "0.8.1" @@ -2305,6 +2344,15 @@ dependencies = [ "dirs-sys 0.3.7", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys 0.3.7", +] + [[package]] name = "dirs" version = "5.0.1" @@ -2384,6 +2432,12 @@ dependencies = [ "libloading 0.8.3", ] +[[package]] +name = "dlv-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" + [[package]] name = "document-features" version = "0.2.8" @@ -2564,7 +2618,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "584c5d1bf9a67b25778a3323af222dbe1a1feb532190e103901187f92c7fe29a" dependencies = [ "accesskit", - "ahash", + "ahash 0.8.11", "epaint", "log", "nohash-hasher", @@ -2830,7 +2884,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b381f8b149657a4acf837095351839f32cd5c4aec1817fc4df84e18d76334176" dependencies = [ "ab_glyph", - "ahash", + "ahash 0.8.11", "bytemuck", "ecolor", "emath", @@ -3687,6 +3741,7 @@ dependencies = [ "built", "chrono", "curve25519-dalek 4.1.2", + "dark-light", "dirs 5.0.1", "ed25519-dalek 2.1.1", "eframe", @@ -4251,6 +4306,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] [[package]] name = "hashbrown" @@ -4258,7 +4316,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash", + "ahash 0.8.11", "allocator-api2", ] @@ -6356,6 +6414,16 @@ dependencies = [ "num-traits 0.2.19", ] +[[package]] +name = "ordered-multimap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +dependencies = [ + "dlv-list", + "hashbrown 0.12.3", +] + [[package]] name = "ordered-stream" version = "0.2.0" @@ -7407,7 +7475,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg", + "winreg 0.7.0", ] [[package]] @@ -7648,6 +7716,16 @@ dependencies = [ "toml 0.7.8", ] +[[package]] +name = "rust-ini" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +dependencies = [ + "cfg-if 1.0.0", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -11192,7 +11270,7 @@ version = "0.29.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" dependencies = [ - "ahash", + "ahash 0.8.11", "android-activity 0.5.2", "atomic-waker", "bitflags 2.5.0", @@ -11262,6 +11340,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 41db16f..ac09f18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ rqrr = "0.7.1" qrcodegen = "1.8.0" ur = "0.4.1" gif = "0.13.1" +dark-light = "1.1.1" ## tor arti-client = { version = "0.18.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client"] } diff --git a/android/app/src/main/java/mw/gri/android/MainActivity.java b/android/app/src/main/java/mw/gri/android/MainActivity.java index f57d3e2..980e74f 100644 --- a/android/app/src/main/java/mw/gri/android/MainActivity.java +++ b/android/app/src/main/java/mw/gri/android/MainActivity.java @@ -353,4 +353,10 @@ public class MainActivity extends GameActivity { intent.setType("image/*"); startActivity(Intent.createChooser(intent, "Share image")); } + + // Check if device is using dark theme. + public boolean useDarkTheme() { + int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + return currentNightMode == Configuration.UI_MODE_NIGHT_YES; + } } \ No newline at end of file diff --git a/img/logo_light.png b/img/logo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..d0a0ab08872c226978016896b0c7de1f831f71e7 GIT binary patch literal 40733 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 sN#|=Cb_&95aP0s4`+p;__V eframe::App for PlatformApp { // Show main content. egui::CentralPanel::default() .frame(egui::Frame { - fill: Colors::YELLOW, ..Default::default() }) .show(ctx, |ui| { diff --git a/src/gui/colors.rs b/src/gui/colors.rs index 3ab81d7..eab2b1d 100644 --- a/src/gui/colors.rs +++ b/src/gui/colors.rs @@ -14,29 +14,236 @@ use egui::Color32; +use crate::AppConfig; + +/// Provides colors values based on current theme. pub struct Colors; -impl Colors { - pub const WHITE: Color32 = Color32::from_gray(253); - pub const BLACK: Color32 = Color32::from_gray(12); - pub const TRANSPARENT: Color32 = Color32::from_rgba_premultiplied(0, 0, 0, 0); - pub const SEMI_TRANSPARENT: Color32 = Color32::from_black_alpha(100); - pub const YELLOW: Color32 = Color32::from_rgb(254, 241, 2); - pub const GOLD: Color32 = Color32::from_rgb(255, 215, 0); - pub const GREEN: Color32 = Color32::from_rgb(0, 0x64, 0); - pub const RED: Color32 = Color32::from_rgb(0x8B, 0, 0); - pub const FILL: Color32 = Color32::from_gray(244); - pub const FILL_DARK: Color32 = Color32::from_gray(238); - pub const CHECKBOX: Color32 = Color32::from_gray(100); - pub const TEXT: Color32 = Color32::from_gray(80); - pub const TEXT_BUTTON: Color32 = Color32::from_gray(70); - pub const TITLE: Color32 = Color32::from_gray(60); - pub const BUTTON: Color32 = Color32::from_gray(249); - pub const GRAY: Color32 = Color32::from_gray(120); - pub const STROKE: Color32 = Color32::from_gray(200); - pub const INACTIVE_TEXT: Color32 = Color32::from_gray(150); - pub const ITEM_BUTTON: Color32 = Color32::from_gray(90); - pub const ITEM_STROKE: Color32 = Color32::from_gray(220); - pub const ITEM_HOVER: Color32 = Color32::from_gray(205); - pub const ITEM_CURRENT: Color32 = Color32::from_gray(227); +const WHITE: Color32 = Color32::from_gray(253); +const BLACK: Color32 = Color32::from_gray(12); + +const SEMI_TRANSPARENT: Color32 = Color32::from_black_alpha(100); +const DARK_SEMI_TRANSPARENT: Color32 = Color32::from_black_alpha(170); + +const GOLD: Color32 = Color32::from_rgb(255, 215, 0); + +const YELLOW: Color32 = Color32::from_rgb(254, 241, 2); + +const GREEN: Color32 = Color32::from_rgb(0, 0x64, 0); + +const RED: Color32 = Color32::from_rgb(0x8B, 0, 0); + +const FILL: Color32 = Color32::from_gray(244); +const FILL_DEEP: Color32 = Color32::from_gray(238); + +const FILL_DARK: Color32 = Color32::from_gray(24); +const FILL_DEEP_DARK: Color32 = Color32::from_gray(18); + +const TEXT: Color32 = Color32::from_gray(80); +const TEXT_DARK: Color32 = Color32::from_gray(185); + +const CHECKBOX: Color32 = Color32::from_gray(100); +const CHECKBOX_DARK: Color32 = Color32::from_gray(175); + +const TEXT_BUTTON: Color32 = Color32::from_gray(70); +const TEXT_BUTTON_DARK: Color32 = Color32::from_gray(195); + +const TITLE: Color32 = Color32::from_gray(60); +const TITLE_DARK: Color32 = Color32::from_gray(205); + +const BUTTON: Color32 = Color32::from_gray(249); +const BUTTON_DARK: Color32 = Color32::from_gray(16); + +const GRAY: Color32 = Color32::from_gray(120); +const GRAY_DARK: Color32 = Color32::from_gray(145); + +const STROKE: Color32 = Color32::from_gray(200); +const STROKE_DARK: Color32 = Color32::from_gray(65); + +const INACTIVE_TEXT: Color32 = Color32::from_gray(150); +const INACTIVE_TEXT_DARK: Color32 = Color32::from_gray(115); + +const ITEM_BUTTON: Color32 = Color32::from_gray(90); +const ITEM_BUTTON_DARK: Color32 = Color32::from_gray(175); + +const ITEM_STROKE: Color32 = Color32::from_gray(220); +const ITEM_STROKE_DARK: Color32 = Color32::from_gray(45); + +const ITEM_HOVER: Color32 = Color32::from_gray(205); +const ITEM_HOVER_DARK: Color32 = Color32::from_gray(60); + +const ITEM_CURRENT: Color32 = Color32::from_gray(227); +const ITEM_CURRENT_DARK: Color32 = Color32::from_gray(38); + +/// Check if dark theme should be used. +fn use_dark() -> bool { + AppConfig::dark_theme().unwrap_or(false) } + +impl Colors { + pub const TRANSPARENT: Color32 = Color32::from_rgba_premultiplied(0, 0, 0, 0); + + pub fn white_or_black(black_in_white: bool) -> Color32 { + if use_dark() { + if black_in_white { + WHITE + } else { + BLACK + } + } else { + if black_in_white { + BLACK + } else { + WHITE + } + } + } + + pub fn semi_transparent() -> Color32 { + if use_dark() { + DARK_SEMI_TRANSPARENT + } else { + SEMI_TRANSPARENT + } + } + + pub fn gold() -> Color32 { + if use_dark() { + GOLD.linear_multiply(0.85) + } else { + GOLD + } + } + + pub fn yellow() -> Color32 { + YELLOW + } + + pub fn green() -> Color32 { + if use_dark() { + GREEN.linear_multiply(1.3) + } else { + GREEN + } + } + + pub fn red() -> Color32 { + if use_dark() { + RED.linear_multiply(1.3) + } else { + RED + } + } + + pub fn fill() -> Color32 { + if use_dark() { + FILL_DARK + } else { + FILL + } + } + + pub fn fill_deep() -> Color32 { + if use_dark() { + FILL_DEEP_DARK + } else { + FILL_DEEP + } + } + + pub fn checkbox() -> Color32 { + if use_dark() { + CHECKBOX_DARK + } else { + CHECKBOX + } + } + + pub fn text(always_light: bool) -> Color32 { + if use_dark() && !always_light { + TEXT_DARK + } else { + TEXT + } + } + + pub fn text_button() -> Color32 { + if use_dark() { + TEXT_BUTTON_DARK + } else { + TEXT_BUTTON + } + } + + pub fn title(always_light: bool) -> Color32 { + if use_dark() && !always_light { + TITLE_DARK + } else { + TITLE + } + } + + pub fn button() -> Color32 { + if use_dark() { + BUTTON_DARK + } else { + BUTTON + } + } + + pub fn gray() -> Color32 { + if use_dark() { + GRAY_DARK + } else { + GRAY + } + } + + pub fn stroke() -> Color32 { + if use_dark() { + STROKE_DARK + } else { + STROKE + } + } + + pub fn inactive_text() -> Color32 { + if use_dark() { + INACTIVE_TEXT_DARK + } else { + INACTIVE_TEXT + } + } + + pub fn item_button() -> Color32 { + if use_dark() { + ITEM_BUTTON_DARK + } else { + ITEM_BUTTON + } + } + + pub fn item_stroke() -> Color32 { + if use_dark() { + ITEM_STROKE_DARK + } else { + ITEM_STROKE + } + } + + pub fn item_hover() -> Color32 { + if use_dark() { + ITEM_HOVER_DARK + } else { + ITEM_HOVER + } + } + + pub fn item_current() -> Color32 { + if use_dark() { + ITEM_CURRENT_DARK + } else { + ITEM_CURRENT + } + } +} \ No newline at end of file diff --git a/src/gui/platform/android/mod.rs b/src/gui/platform/android/mod.rs index c2d25c1..553a669 100644 --- a/src/gui/platform/android/mod.rs +++ b/src/gui/platform/android/mod.rs @@ -27,25 +27,29 @@ use winit::platform::android::activity::AndroidApp; use crate::gui::platform::PlatformCallbacks; +/// Android platform implementation. #[derive(Clone)] pub struct Android { android_app: AndroidApp, } impl Android { + /// Create new Android platform instance from provided [`AndroidApp`]. pub fn new(app: AndroidApp) -> Self { Self { android_app: app, } } - fn call_java_method(&self, name: &str, sig: &str, args: &[JValue]) -> Option { + + /// Call Android Activity method with JNI. + pub fn call_java_method(&self, name: &str, sig: &str, args: &[JValue]) -> Option { let vm = unsafe { jni::JavaVM::from_raw(self.android_app.vm_as_ptr() as _) }.unwrap(); let mut env = vm.attach_current_thread().unwrap(); let activity = unsafe { JObject::from_raw(self.android_app.activity_as_ptr() as jni::sys::jobject) }; if let Ok(result) = env.call_method(activity, name, sig, args) { - return Some(result.as_jni().clone()); + return Some(result.as_jni().clone()); } None } @@ -142,6 +146,7 @@ impl PlatformCallbacks for Android { } lazy_static! { + /// Last image data from camera. static ref LAST_CAMERA_IMAGE: Arc, u32)>>> = Arc::new(RwLock::new(None)); } diff --git a/src/gui/views/camera.rs b/src/gui/views/camera.rs index 5ba0508..d7f4483 100644 --- a/src/gui/views/camera.rs +++ b/src/gui/views/camera.rs @@ -114,7 +114,7 @@ impl CameraContent { ui.vertical_centered(|ui| { ui.label(RichText::new(format!("{}%", ur_progress)) .size(16.0) - .color(Colors::YELLOW)); + .color(Colors::yellow())); }); } @@ -125,7 +125,7 @@ impl CameraContent { size.y = 48.0; ui.allocate_ui_with_layout(size, Layout::right_to_left(Align::Max), |ui| { ui.add_space(4.0); - View::button(ui, CAMERA_ROTATE.to_string(), Colors::WHITE, || { + View::button(ui, CAMERA_ROTATE.to_string(), Colors::white_or_black(false), || { cb.switch_camera(); }); }); diff --git a/src/gui/views/modal.rs b/src/gui/views/modal.rs index aaba144..f1c74a3 100644 --- a/src/gui/views/modal.rs +++ b/src/gui/views/modal.rs @@ -43,7 +43,7 @@ pub struct Modal { impl Modal { /// Margin from [`Modal`] window at top/left/right. - const DEFAULT_MARGIN: f32 = 10.0; + const DEFAULT_MARGIN: f32 = 6.0; /// Maximum width of the content. const DEFAULT_WIDTH: f32 = Root::SIDE_PANEL_WIDTH - (2.0 * Self::DEFAULT_MARGIN); @@ -167,7 +167,7 @@ impl Modal { .collapsible(false) .fixed_rect(rect) .frame(egui::Frame { - fill: Colors::SEMI_TRANSPARENT, + fill: Colors::semi_transparent(), ..Default::default() }) .show(ctx, |ui| { @@ -196,7 +196,7 @@ impl Modal { color: egui::Color32::from_black_alpha(32), }, rounding: Rounding::same(8.0), - fill: Colors::YELLOW, + fill: Colors::fill(), ..Default::default() }) .show(ctx, |ui| { @@ -246,7 +246,7 @@ impl Modal { let mut bg_shape = RectShape { rect, rounding, - fill: Colors::FILL, + fill: Colors::fill(), stroke: Stroke::NONE, fill_texture_id: Default::default(), uv: Rect::ZERO @@ -278,7 +278,7 @@ impl Modal { sw: 0.0, se: 0.0, }, - fill: Colors::YELLOW, + fill: Colors::yellow(), stroke: Stroke::NONE, fill_texture_id: Default::default(), uv: Rect::ZERO @@ -288,12 +288,12 @@ impl Modal { // Draw title content. let title_resp = ui.allocate_ui_at_rect(rect, |ui| { ui.vertical_centered_justified(|ui| { - ui.add_space(8.0); + ui.add_space(10.0); ui.label(RichText::new(self.title.as_ref().unwrap()) .size(19.0) - .color(Colors::TITLE) + .color(Colors::title(true)) ); - ui.add_space(8.0); + ui.add_space(10.0); }); }).response; @@ -302,6 +302,6 @@ impl Modal { ui.painter().set(bg_idx, bg_shape); // Draw line below title. - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); } } \ No newline at end of file diff --git a/src/gui/views/network/connections.rs b/src/gui/views/network/connections.rs index bc6a72d..ba0b003 100644 --- a/src/gui/views/network/connections.rs +++ b/src/gui/views/network/connections.rs @@ -101,12 +101,12 @@ impl ConnectionsContent { // Show external connections. ui.add_space(8.0); - ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::gray())); ui.add_space(6.0); // Show button to add new external node connection. let add_node_text = format!("{} {}", PLUS_CIRCLE, t!("wallets.add_node")); - View::button(ui, add_node_text, Colors::WHITE, || { + View::button(ui, add_node_text, Colors::white_or_black(false), || { self.show_add_ext_conn_modal(None, cb); }); @@ -130,7 +130,7 @@ impl ConnectionsContent { let mut rect = ui.available_rect_before_wrap(); rect.set_height(78.0); let rounding = View::item_rounding(0, 1, false); - ui.painter().rect(rect, rounding, Colors::FILL, View::ITEM_STROKE); + ui.painter().rect(rect, rounding, Colors::fill(), View::item_stroke()); ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { // Draw button to show integrated node info. @@ -140,12 +140,12 @@ impl ConnectionsContent { if !Node::is_running() { // Draw button to start integrated node. - View::item_button(ui, Rounding::default(), POWER, Some(Colors::GREEN), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::green()), || { Node::start(); }); } else if !Node::is_starting() && !Node::is_stopping() && !Node::is_restarting() { // Draw button to stop integrated node. - View::item_button(ui, Rounding::default(), POWER, Some(Colors::RED), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::red()), || { Node::stop(false); }); } @@ -157,12 +157,12 @@ impl ConnectionsContent { ui.add_space(3.0); ui.label(RichText::new(t!("network.node")) .size(18.0) - .color(Colors::TITLE)); + .color(Colors::title(false))); // 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.label(RichText::new(address_text).size(15.0).color(Colors::text(false))); ui.add_space(1.0); // Setup node status text. @@ -174,7 +174,7 @@ impl ConnectionsContent { 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.label(RichText::new(status_text).size(15.0).color(Colors::gray())); }) }); }); @@ -194,7 +194,7 @@ impl ConnectionsContent { // 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.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| { @@ -216,7 +216,7 @@ impl ConnectionsContent { // Draw connections URL. ui.add_space(4.0); let conn_text = format!("{} {}", GLOBE_SIMPLE, conn.url); - View::ellipsize_text(ui, conn_text, 15.0, Colors::TITLE); + View::ellipsize_text(ui, conn_text, 15.0, Colors::title(false)); ui.add_space(1.0); // Setup connection status text. @@ -229,7 +229,7 @@ impl ConnectionsContent { } else { format!("{} {}", DOTS_THREE_CIRCLE, t!("network.availability_check")) }; - ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY)); + ui.label(RichText::new(status_text).size(15.0).color(Colors::gray())); ui.add_space(3.0); }); }); @@ -270,7 +270,7 @@ impl ConnectionsContent { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.node_url")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw node URL text edit. @@ -285,7 +285,7 @@ impl ConnectionsContent { ui.label(RichText::new(t!("wallets.node_secret")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw node API secret text edit. @@ -298,7 +298,7 @@ impl ConnectionsContent { ui.add_space(12.0); ui.label(RichText::new(t!("wallets.invalid_url")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); }); @@ -310,7 +310,7 @@ impl ConnectionsContent { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -352,7 +352,7 @@ impl ConnectionsContent { (on_add)(); }); - View::button(ui, t!("modal.save"), Colors::WHITE, on_add); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_add); }); }); ui.add_space(6.0); diff --git a/src/gui/views/network/content.rs b/src/gui/views/network/content.rs index f065cd0..4179d51 100644 --- a/src/gui/views/network/content.rs +++ b/src/gui/views/network/content.rs @@ -54,8 +54,8 @@ impl NetworkContent { egui::TopBottomPanel::bottom("node_tabs_panel") .resizable(false) .frame(egui::Frame { - fill: Colors::FILL, - stroke: View::ITEM_STROKE, + fill: Colors::fill(), + stroke: View::item_stroke(), inner_margin: Margin { left: View::get_left_inset() + 4.0, right: View::far_right_inset_margin(ui) + 4.0, @@ -78,14 +78,14 @@ impl NetworkContent { .resizable(false) .exact_width(ui.available_width()) .frame(egui::Frame { - stroke: View::DEFAULT_STROKE, + stroke: View::default_stroke(), ..Default::default() }) .show_animated_inside(ui, !show_connections, |ui| { egui::CentralPanel::default() .frame(egui::Frame { - fill: Colors::WHITE, - stroke: View::DEFAULT_STROKE, + fill: Colors::white_or_black(false), + stroke: View::default_stroke(), inner_margin: Margin { left: View::get_left_inset() + 4.0, right: View::far_right_inset_margin(ui) + 4.0, @@ -104,7 +104,7 @@ impl NetworkContent { egui::CentralPanel::default() .frame(egui::Frame { stroke: if show_connections{ - View::DEFAULT_STROKE + View::default_stroke() } else { Stroke::NONE }, @@ -122,7 +122,7 @@ impl NetworkContent { top: 3.0, bottom: View::get_bottom_inset() + 4.0, }, - fill: Colors::BUTTON, + fill: Colors::button(), ..Default::default() }) .show_inside(ui, |ui| { @@ -230,10 +230,10 @@ impl NetworkContent { let text = t!("network.disabled_server", "dots" => DOTS_THREE_OUTLINE_VERTICAL); ui.label(RichText::new(text) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); ui.add_space(8.0); - View::button(ui, format!("{} {}", POWER, t!("network.enable_node")), Colors::GOLD, || { + View::action_button(ui, format!("{} {}", POWER, t!("network.enable_node")), || { Node::start(); }); ui.add_space(2.0); @@ -255,7 +255,7 @@ impl NetworkContent { ui.add_space(18.0); ui.label(RichText::new(t) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); }); } @@ -277,13 +277,13 @@ impl NetworkContent { View::center_content(ui, 156.0, |ui| { ui.label(RichText::new(t!("network_node.error_clean")) .size(16.0) - .color(Colors::RED) + .color(Colors::red()) ); ui.add_space(8.0); let btn_txt = format!("{} {}", ARROWS_COUNTER_CLOCKWISE, t!("network_node.resync")); - View::button(ui, btn_txt, Colors::GOLD, || { + View::action_button(ui, btn_txt, || { Node::clean_up_data(); Node::start(); }); @@ -304,7 +304,7 @@ impl NetworkContent { ); ui.label(RichText::new(text) .size(16.0) - .color(Colors::RED) + .color(Colors::red()) ); ui.add_space(2.0); }); @@ -314,7 +314,7 @@ impl NetworkContent { View::center_content(ui, 106.0, |ui| { ui.label(RichText::new(t!("network_node.error_config", "settings" => FADERS)) .size(16.0) - .color(Colors::RED) + .color(Colors::red()) ); ui.add_space(2.0); }); @@ -323,13 +323,13 @@ impl NetworkContent { View::center_content(ui, 156.0, |ui| { ui.label(RichText::new(t!("network_node.error_unknown", "settings" => FADERS)) .size(16.0) - .color(Colors::RED) + .color(Colors::red()) ); ui.add_space(8.0); let btn_txt = format!("{} {}", ARROWS_COUNTER_CLOCKWISE, t!("network_node.resync")); - View::button(ui, btn_txt, Colors::GOLD, || { + View::action_button(ui, btn_txt, || { Node::clean_up_data(); Node::start(); }); diff --git a/src/gui/views/network/metrics.rs b/src/gui/views/network/metrics.rs index 3bb37f2..23100ba 100644 --- a/src/gui/views/network/metrics.rs +++ b/src/gui/views/network/metrics.rs @@ -173,7 +173,7 @@ fn block_item_ui(ui: &mut egui::Ui, db: &DiffBlock, rounding: Rounding) { // Draw round background. rect.min += vec2(8.0, 0.0); rect.max -= vec2(8.0, 0.0); - ui.painter().rect(rect, rounding, Colors::WHITE, View::ITEM_STROKE); + ui.painter().rect(rect, rounding, Colors::white_or_black(false), View::item_stroke()); ui.add_space(2.0); @@ -181,7 +181,7 @@ fn block_item_ui(ui: &mut egui::Ui, db: &DiffBlock, rounding: Rounding) { ui.horizontal(|ui| { ui.add_space(5.0); ui.label(RichText::new(format!("{} {}", HASH, db.block_hash)) - .color(Colors::BLACK) + .color(Colors::white_or_black(true)) .size(17.0)); }); // Draw block difficulty and height. @@ -192,7 +192,7 @@ fn block_item_ui(ui: &mut egui::Ui, db: &DiffBlock, rounding: Rounding) { db.difficulty, AT, db.block_height); - ui.label(RichText::new(diff_text).color(Colors::TITLE).size(16.0)); + ui.label(RichText::new(diff_text).color(Colors::title(false)).size(16.0)); }); // Draw block date. ui.horizontal(|ui| { @@ -203,7 +203,7 @@ fn block_item_ui(ui: &mut egui::Ui, db: &DiffBlock, rounding: Rounding) { db.duration, HOURGLASS_LOW, block_time)) - .color(Colors::GRAY) + .color(Colors::gray()) .size(16.0)); }); diff --git a/src/gui/views/network/mining.rs b/src/gui/views/network/mining.rs index 36f884f..62b5eb7 100644 --- a/src/gui/views/network/mining.rs +++ b/src/gui/views/network/mining.rs @@ -175,7 +175,7 @@ impl NetworkTab for NetworkMining { let workers_size = stratum_stats.worker_stats.len(); if workers_size != 0 && stratum_stats.num_workers > 0 { ui.add_space(4.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(4.0); ScrollArea::vertical() .id_source("stratum_workers_scroll") @@ -201,7 +201,7 @@ impl NetworkTab for NetworkMining { View::center_content(ui, 142.0, |ui| { ui.label(RichText::new(t!("network_mining.info", "settings" => FADERS)) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); }); } @@ -218,7 +218,7 @@ fn worker_item_ui(ui: &mut egui::Ui, ws: &WorkerStats, rounding: Rounding) { // Draw round background. let mut rect = ui.available_rect_before_wrap(); rect.set_height(WORKER_ITEM_HEIGHT); - ui.painter().rect(rect, rounding, Colors::WHITE, View::ITEM_STROKE); + ui.painter().rect(rect, rounding, Colors::white_or_black(false), View::item_stroke()); ui.add_space(2.0); ui.horizontal(|ui| { @@ -226,8 +226,12 @@ fn worker_item_ui(ui: &mut egui::Ui, ws: &WorkerStats, rounding: Rounding) { // Draw worker connection status. let (status_text, status_icon, status_color) = match ws.is_connected { - true => (t!("network_mining.connected"), PLUGS_CONNECTED, Colors::BLACK), - false => (t!("network_mining.disconnected"), PLUGS, Colors::INACTIVE_TEXT) + true => ( + t!("network_mining.connected"), + PLUGS_CONNECTED, + Colors::white_or_black(true) + ), + false => (t!("network_mining.disconnected"), PLUGS, Colors::inactive_text()) }; let status_line_text = format!("{} {} {}", status_icon, ws.id, status_text); ui.heading(RichText::new(status_line_text) @@ -241,35 +245,35 @@ fn worker_item_ui(ui: &mut egui::Ui, ws: &WorkerStats, rounding: Rounding) { // Draw difficulty. let diff_text = format!("{} {}", BARBELL, ws.pow_difficulty); ui.heading(RichText::new(diff_text) - .color(Colors::TITLE) + .color(Colors::title(false)) .size(16.0)); ui.add_space(6.0); // Draw accepted shares. let accepted_text = format!("{} {}", FOLDER_SIMPLE_PLUS, ws.num_accepted); ui.heading(RichText::new(accepted_text) - .color(Colors::GREEN) + .color(Colors::green()) .size(16.0)); ui.add_space(6.0); // Draw rejected shares. let rejected_text = format!("{} {}", FOLDER_SIMPLE_MINUS, ws.num_rejected); ui.heading(RichText::new(rejected_text) - .color(Colors::RED) + .color(Colors::red()) .size(16.0)); ui.add_space(6.0); // Draw stale shares. let stale_text = format!("{} {}", FOLDER_DASHED, ws.num_stale); ui.heading(RichText::new(stale_text) - .color(Colors::GRAY) + .color(Colors::gray()) .size(16.0)); ui.add_space(6.0); // Draw blocks found. let blocks_found_text = format!("{} {}", CUBE, ws.num_blocks_found); ui.heading(RichText::new(blocks_found_text) - .color(Colors::TITLE) + .color(Colors::title(false)) .size(16.0)); }); ui.horizontal(|ui| { @@ -280,7 +284,7 @@ fn worker_item_ui(ui: &mut egui::Ui, ws: &WorkerStats, rounding: Rounding) { let seen_time = View::format_time(seen_ts as i64); let seen_text = format!("{} {}", CLOCK_AFTERNOON, seen_time); ui.heading(RichText::new(seen_text) - .color(Colors::GRAY) + .color(Colors::gray()) .size(16.0)); }); }); diff --git a/src/gui/views/network/node.rs b/src/gui/views/network/node.rs index 325cbc3..935d45a 100644 --- a/src/gui/views/network/node.rs +++ b/src/gui/views/network/node.rs @@ -205,7 +205,7 @@ fn peer_item_ui(ui: &mut egui::Ui, peer: &PeerStats, rounding: Rounding) { ui.allocate_ui_at_rect(rect, |ui| { ui.vertical(|ui| { // Draw round background. - ui.painter().rect(rect, rounding, Colors::WHITE, View::ITEM_STROKE); + ui.painter().rect(rect, rounding, Colors::white_or_black(false), View::item_stroke()); ui.add_space(2.0); @@ -213,7 +213,7 @@ fn peer_item_ui(ui: &mut egui::Ui, peer: &PeerStats, rounding: Rounding) { 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(17.0)); + ui.label(RichText::new(addr_text).color(Colors::white_or_black(true)).size(17.0)); }); // Draw peer difficulty and height ui.horizontal(|ui| { @@ -223,13 +223,13 @@ fn peer_item_ui(ui: &mut egui::Ui, peer: &PeerStats, rounding: Rounding) { peer.total_difficulty, AT, peer.height); - ui.label(RichText::new(diff_text).color(Colors::TITLE).size(16.0)); + ui.label(RichText::new(diff_text).color(Colors::title(false)).size(16.0)); }); // Draw peer user-agent ui.horizontal(|ui| { ui.add_space(6.0); let agent_text = format!("{} {}", DEVICES, &peer.user_agent); - ui.label(RichText::new(agent_text).color(Colors::GRAY).size(16.0)); + ui.label(RichText::new(agent_text).color(Colors::gray()).size(16.0)); }); ui.add_space(2.0); diff --git a/src/gui/views/network/settings.rs b/src/gui/views/network/settings.rs index ff6ca36..d8391e2 100644 --- a/src/gui/views/network/settings.rs +++ b/src/gui/views/network/settings.rs @@ -97,35 +97,35 @@ impl NetworkTab for NetworkSettings { self.node.ui(ui, frame, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(4.0); // Draw P2P server setup section. self.p2p.ui(ui, frame, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(4.0); // Draw Stratum server setup section. self.stratum.ui(ui, frame, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(4.0); // Draw pool setup section. self.pool.ui(ui, frame, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(4.0); // Draw Dandelion server setup section. self.dandelion.ui(ui, frame, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); // Draw reset settings content. @@ -143,7 +143,7 @@ impl NetworkSettings { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.restart_node_required")) .size(16.0) - .color(Colors::GREEN) + .color(Colors::green()) ); } } @@ -192,7 +192,7 @@ impl NetworkSettings { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network.no_ips")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); ui.add_space(6.0); }); @@ -204,12 +204,12 @@ fn reset_settings_ui(ui: &mut egui::Ui) { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.reset_settings_desc")) .size(16.0) - .color(Colors::TEXT)); + .color(Colors::text(false))); ui.add_space(8.0); let button_text = format!("{} {}", ARROW_COUNTER_CLOCKWISE, t!("network_settings.reset_settings")); - View::button(ui, button_text, Colors::GOLD, || { + View::action_button(ui, button_text, || { // Show modal to confirm settings reset. Modal::new(RESET_SETTINGS_MODAL) .position(ModalPosition::Center) @@ -222,7 +222,7 @@ fn reset_settings_ui(ui: &mut egui::Ui) { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.restart_node_required")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); } ui.add_space(12.0); @@ -237,24 +237,24 @@ fn reset_settings_confirmation_modal(ui: &mut egui::Ui, modal: &Modal) { let reset_text = format!("{}?", t!("network_settings.reset_settings_desc")); ui.label(RichText::new(reset_text) .size(17.0) - .color(Colors::TEXT)); + .color(Colors::text(false))); ui.add_space(8.0); }); // Show modal buttons. ui.scope(|ui| { // Setup spacing between buttons. - ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); + 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!("network_settings.reset"), Colors::WHITE, || { + View::button(ui, t!("network_settings.reset"), Colors::white_or_black(false), || { NodeConfig::reset_to_default(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { modal.close(); }); }); diff --git a/src/gui/views/network/setup/dandelion.rs b/src/gui/views/network/setup/dandelion.rs index 2cde589..2906c8f 100644 --- a/src/gui/views/network/setup/dandelion.rs +++ b/src/gui/views/network/setup/dandelion.rs @@ -92,7 +92,7 @@ impl DandelionSetup { self.current_modal_ui(ui, frame, cb); View::sub_title(ui, format!("{} {}", GRAPH, "Dandelion")); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { @@ -100,28 +100,28 @@ impl DandelionSetup { self.epoch_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show embargo expiration time setup. self.embargo_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show aggregation period setup. self.aggregation_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show Stem phase probability setup. self.stem_prob_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(8.0); // Show setup to always stem our txs. @@ -137,12 +137,12 @@ impl DandelionSetup { fn epoch_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.epoch_duration")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let epoch = NodeConfig::get_dandelion_epoch(); - View::button(ui, format!("{} {}", WATCH, epoch.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", WATCH, epoch.clone()), Colors::button(), || { // Setup values for modal. self.epoch_edit = epoch; // Show epoch setup modal. @@ -161,7 +161,7 @@ impl DandelionSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.epoch_duration")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw epoch text edit. @@ -173,7 +173,7 @@ impl DandelionSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -196,14 +196,14 @@ impl DandelionSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -214,12 +214,12 @@ impl DandelionSetup { fn embargo_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.embargo_timer")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let embargo = NodeConfig::get_dandelion_embargo(); - View::button(ui, format!("{} {}", TIMER, embargo.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", TIMER, embargo.clone()), Colors::button(), || { // Setup values for modal. self.embargo_edit = embargo; // Show embargo setup modal. @@ -238,7 +238,7 @@ impl DandelionSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.embargo_timer")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw embargo text edit. @@ -250,7 +250,7 @@ impl DandelionSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -273,14 +273,14 @@ impl DandelionSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -291,12 +291,12 @@ impl DandelionSetup { fn aggregation_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.aggregation_period")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let agg = NodeConfig::get_dandelion_aggregation(); - View::button(ui, format!("{} {}", CLOCK_COUNTDOWN, agg.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", CLOCK_COUNTDOWN, agg.clone()), Colors::button(), || { // Setup values for modal. self.aggregation_edit = agg; // Show aggregation setup modal. @@ -315,7 +315,7 @@ impl DandelionSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.aggregation_period")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw aggregation period text edit. @@ -327,7 +327,7 @@ impl DandelionSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -350,14 +350,14 @@ impl DandelionSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -368,12 +368,12 @@ impl DandelionSetup { fn stem_prob_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.stem_probability")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let stem_prob = NodeConfig::get_stem_probability(); - View::button(ui, format!("{}%", stem_prob.clone()), Colors::BUTTON, || { + View::button(ui, format!("{}%", stem_prob.clone()), Colors::button(), || { // Setup values for modal. self.stem_prob_edit = stem_prob; // Show stem probability setup modal. @@ -392,7 +392,7 @@ impl DandelionSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.stem_probability")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw stem phase probability text edit. @@ -404,7 +404,7 @@ impl DandelionSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -427,14 +427,14 @@ impl DandelionSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); diff --git a/src/gui/views/network/setup/node.rs b/src/gui/views/network/setup/node.rs index f24e0d5..61c5342 100644 --- a/src/gui/views/network/setup/node.rs +++ b/src/gui/views/network/setup/node.rs @@ -103,7 +103,7 @@ impl NodeSetup { self.current_modal_ui(ui, frame, cb); View::sub_title(ui, format!("{} {}", COMPUTER_TOWER, t!("network_settings.server"))); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); // Show chain type setup. @@ -126,12 +126,12 @@ impl NodeSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("network_settings.disable"), Colors::GOLD, || { + View::action_button(ui, t!("network_settings.disable"), || { Node::stop(false); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("network_settings.restart"), Colors::GOLD, || { + View::action_button(ui, t!("network_settings.restart"), || { Node::restart(); }); }); @@ -141,7 +141,7 @@ impl NodeSetup { ui.add_space(6.0); ui.vertical_centered(|ui| { let enable_text = format!("{} {}", POWER, t!("network_settings.enable")); - View::button(ui, enable_text, Colors::GOLD, || { + View::action_button(ui, enable_text, || { Node::start(); }); }); @@ -156,7 +156,7 @@ impl NodeSetup { ui.add_space(2.0); ui.label(RichText::new(t!("network_settings.restart_node_required")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); ui.add_space(4.0); } @@ -167,13 +167,13 @@ impl NodeSetup { // Show message when IP addresses are not available on the system. NetworkSettings::no_ip_address_ui(ui); } else { - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.api_ip")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); @@ -196,7 +196,7 @@ impl NodeSetup { } ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { @@ -204,14 +204,14 @@ impl NodeSetup { self.ftl_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Validation setup. self.validation_mode_ui(ui); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Archive mode setup. @@ -222,7 +222,7 @@ impl NodeSetup { /// Draw [`ChainTypes`] setup content. pub fn chain_type_ui(ui: &mut egui::Ui) { ui.vertical_centered(|ui| { - ui.label(RichText::new(t!("network.type")).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("network.type")).size(16.0).color(Colors::gray())); }); let saved_chain_type = AppConfig::chain_type(); @@ -251,11 +251,11 @@ impl NodeSetup { /// Draw API port setup content. fn api_port_setup_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { - ui.label(RichText::new(t!("network_settings.api_port")).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("network_settings.api_port")).size(16.0).color(Colors::gray())); ui.add_space(6.0); let (_, port) = NodeConfig::get_api_ip_port(); - View::button(ui, format!("{} {}", PLUG, port.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", PLUG, port.clone()), Colors::button(), || { // Setup values for modal. self.api_port_edit = port; self.api_port_available_edit = self.is_api_port_available; @@ -273,7 +273,7 @@ impl NodeSetup { // Show error when API server port is unavailable. ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(16.0) - .color(Colors::RED)); + .color(Colors::red())); ui.add_space(6.0); } ui.add_space(6.0); @@ -283,7 +283,7 @@ impl NodeSetup { fn api_port_modal(&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!("network_settings.api_port")).size(17.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("network_settings.api_port")).size(17.0).color(Colors::gray())); ui.add_space(6.0); // Draw API port text edit. @@ -295,7 +295,7 @@ impl NodeSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(16.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -330,13 +330,13 @@ impl NodeSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -351,7 +351,7 @@ impl NodeSetup { }; ui.label(RichText::new(secret_title) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); @@ -366,7 +366,7 @@ impl NodeSetup { format!("{} {}", SHIELD_SLASH, t!("network_settings.disabled")) }; - View::button(ui, secret_text, Colors::BUTTON, || { + View::button(ui, secret_text, Colors::button(), || { // Setup values for modal. self.secret_edit = secret_value.unwrap_or("".to_string()); // Show secret edit modal. @@ -386,7 +386,7 @@ impl NodeSetup { API_SECRET_MODAL => t!("network_settings.api_secret"), _ => t!("network_settings.foreign_api_secret") }; - ui.label(RichText::new(description).size(17.0).color(Colors::GRAY)); + ui.label(RichText::new(description).size(17.0).color(Colors::gray())); ui.add_space(8.0); // Draw API secret token value text edit. @@ -398,7 +398,7 @@ impl NodeSetup { if Node::is_running() { ui.label(RichText::new(t!("network_settings.restart_node_required")) .size(16.0) - .color(Colors::GREEN) + .color(Colors::green()) ); ui.add_space(6.0); } @@ -427,13 +427,13 @@ impl NodeSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -444,12 +444,12 @@ impl NodeSetup { fn ftl_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.ftl")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let ftl = NodeConfig::get_ftl(); - View::button(ui, format!("{} {}", CLOCK_CLOCKWISE, ftl.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", CLOCK_CLOCKWISE, ftl.clone()), Colors::button(), || { // Setup values for modal. self.ftl_edit = ftl; // Show ftl value setup modal. @@ -462,7 +462,7 @@ impl NodeSetup { ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.ftl_description")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); } @@ -472,7 +472,7 @@ impl NodeSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.ftl")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw ftl value text edit. @@ -484,7 +484,7 @@ impl NodeSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -507,14 +507,14 @@ impl NodeSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -530,7 +530,7 @@ impl NodeSetup { ui.add_space(4.0); ui.label(RichText::new(t!("network_settings.full_validation_description")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); } @@ -543,7 +543,7 @@ impl NodeSetup { ui.add_space(4.0); ui.label(RichText::new(t!("network_settings.archive_mode_desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); } } \ No newline at end of file diff --git a/src/gui/views/network/setup/p2p.rs b/src/gui/views/network/setup/p2p.rs index 6cefe9c..3c056c6 100644 --- a/src/gui/views/network/setup/p2p.rs +++ b/src/gui/views/network/setup/p2p.rs @@ -158,7 +158,7 @@ impl P2PSetup { self.current_modal_ui(ui, frame, cb); View::sub_title(ui, format!("{} {}", HANDSHAKE, t!("network_settings.p2p_server"))); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { @@ -166,62 +166,62 @@ impl P2PSetup { self.port_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show seeding type setup. self.seeding_type_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.allow_list")) .size(16.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(6.0); // Show allowed peers setup. self.peer_list_ui(ui, &PeerType::Allowed, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.deny_list")) .size(16.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(6.0); // Show denied peers setup. self.peer_list_ui(ui, &PeerType::Denied, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.favourites")) .size(16.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(6.0); // Show preferred peers setup. self.peer_list_ui(ui, &PeerType::Preferred, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show ban window setup. self.ban_window_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show maximum inbound peers value setup. self.max_inbound_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show maximum outbound peers value setup. @@ -229,7 +229,7 @@ impl P2PSetup { if !Node::is_restarting() && !self.peers_reset { ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show peers data reset content. @@ -242,12 +242,12 @@ impl P2PSetup { fn port_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.p2p_port")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let port = NodeConfig::get_p2p_port(); - View::button(ui, format!("{} {}", PLUG, port.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", PLUG, port.clone()), Colors::button(), || { // Setup values for modal. self.port_edit = port; self.port_available_edit = self.is_port_available; @@ -265,7 +265,7 @@ impl P2PSetup { ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(16.0) - .color(Colors::RED)); + .color(Colors::red())); ui.add_space(12.0); } } @@ -276,7 +276,7 @@ impl P2PSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.p2p_port")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw p2p port text edit. @@ -288,7 +288,7 @@ impl P2PSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); @@ -320,14 +320,14 @@ impl P2PSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -370,7 +370,7 @@ impl P2PSetup { }; ui.label(RichText::new(desc) .size(16.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); ui.add_space(12.0); } @@ -380,7 +380,7 @@ impl P2PSetup { format!("{} {}", PLUS_CIRCLE, t!("network_settings.add_peer")) }; - View::button(ui, add_text, Colors::BUTTON, || { + View::button(ui, add_text, Colors::button(), || { // Setup values for modal. self.is_correct_address_edit = true; self.peer_edit = "".to_string(); @@ -417,7 +417,7 @@ impl P2PSetup { CUSTOM_SEED_MODAL => t!("network_settings.seed_address"), &_ => t!("network_settings.peer_address") }; - ui.label(RichText::new(label_text).size(17.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. @@ -429,7 +429,7 @@ impl P2PSetup { ui.add_space(10.0); ui.label(RichText::new(t!("network_settings.peer_address_error")) .size(16.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); @@ -463,14 +463,14 @@ impl P2PSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -481,7 +481,7 @@ impl P2PSetup { /// Draw seeding type setup content. fn seeding_type_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { let title = Self::DNS_SEEDS_TITLE; - ui.label(RichText::new(title).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(title).size(16.0).color(Colors::gray())); ui.add_space(2.0); let default_seeding = NodeConfig::is_default_seeding_type(); @@ -502,12 +502,12 @@ impl P2PSetup { fn ban_window_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.ban_window")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let ban_window = NodeConfig::get_p2p_ban_window(); - View::button(ui, format!("{} {}", PROHIBIT_INSET, ban_window.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", PROHIBIT_INSET, ban_window.clone()), Colors::button(), || { // Setup values for modal. self.ban_window_edit = ban_window; // Show ban window period setup modal. @@ -520,7 +520,7 @@ impl P2PSetup { ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.ban_window_desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); ui.add_space(2.0); } @@ -531,7 +531,7 @@ impl P2PSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.ban_window")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw ban window text edit. @@ -543,7 +543,7 @@ impl P2PSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -566,14 +566,14 @@ impl P2PSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -584,13 +584,13 @@ impl P2PSetup { fn max_inbound_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.max_inbound_count")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let max_inbound = NodeConfig::get_max_inbound_peers(); let button_text = format!("{} {}", ARROW_FAT_LINES_DOWN, max_inbound.clone()); - View::button(ui, button_text, Colors::BUTTON, || { + View::button(ui, button_text, Colors::button(), || { // Setup values for modal. self.max_inbound_count = max_inbound; // Show maximum number of inbound peers setup modal. @@ -609,7 +609,7 @@ impl P2PSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_inbound_count")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw maximum number of inbound peers text edit. @@ -621,7 +621,7 @@ impl P2PSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -644,14 +644,14 @@ impl P2PSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -662,13 +662,13 @@ impl P2PSetup { fn max_outbound_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.max_outbound_count")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let max_outbound = NodeConfig::get_max_outbound_peers(); let button_text = format!("{} {}", ARROW_FAT_LINES_UP, max_outbound.clone()); - View::button(ui, button_text, Colors::BUTTON, || { + View::button(ui, button_text, Colors::button(), || { // Setup values for modal. self.max_outbound_count = max_outbound; // Show maximum number of outbound peers setup modal. @@ -687,7 +687,7 @@ impl P2PSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_outbound_count")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw maximum number of outbound peers text edit. @@ -699,7 +699,7 @@ impl P2PSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -722,14 +722,14 @@ impl P2PSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -741,14 +741,14 @@ impl P2PSetup { ui.add_space(4.0); let button_text = format!("{} {}", TRASH, t!("network_settings.reset_peers")); - View::colored_text_button(ui, button_text, Colors::RED, Colors::BUTTON, || { + View::colored_text_button(ui, button_text, Colors::red(), Colors::button(), || { Node::reset_peers(false); self.peers_reset = true; }); ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.reset_peers_desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); } } @@ -767,7 +767,7 @@ fn peer_item_ui(ui: &mut egui::Ui, let mut bg_rect = rect.clone(); bg_rect.min += egui::emath::vec2(6.0, 0.0); let item_rounding = View::item_rounding(index, len, false); - ui.painter().rect(bg_rect, item_rounding, Colors::WHITE, View::ITEM_STROKE); + ui.painter().rect(bg_rect, item_rounding, Colors::white_or_black(false), View::item_stroke()); ui.vertical(|ui| { ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { @@ -798,7 +798,7 @@ fn peer_item_ui(ui: &mut egui::Ui, // Draw peer address. let peer_text = format!("{} {}", GLOBE_SIMPLE, &peer_addr); ui.label(RichText::new(peer_text) - .color(Colors::TEXT_BUTTON) + .color(Colors::text_button()) .size(16.0)); }); }); diff --git a/src/gui/views/network/setup/pool.rs b/src/gui/views/network/setup/pool.rs index cbd79df..05e6a94 100644 --- a/src/gui/views/network/setup/pool.rs +++ b/src/gui/views/network/setup/pool.rs @@ -100,7 +100,7 @@ impl PoolSetup { self.current_modal_ui(ui, frame, cb); View::sub_title(ui, format!("{} {}", CHART_SCATTER, t!("network_settings.tx_pool"))); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { @@ -108,28 +108,28 @@ impl PoolSetup { self.fee_base_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show reorg cache retention period setup. self.reorg_period_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show pool size setup. self.pool_size_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show stem pool size setup. self.stem_size_ui(ui, cb); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show max weight of transactions setup. @@ -141,12 +141,12 @@ impl PoolSetup { fn fee_base_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.pool_fee")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let fee = NodeConfig::get_base_fee(); - View::button(ui, format!("{} {}", HAND_COINS, fee.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", HAND_COINS, fee.clone()), Colors::button(), || { // Setup values for modal. self.fee_base_edit = fee; // Show fee setup modal. @@ -165,7 +165,7 @@ impl PoolSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.pool_fee")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw fee base text edit. @@ -177,7 +177,7 @@ impl PoolSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -199,14 +199,14 @@ impl PoolSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -218,12 +218,12 @@ impl PoolSetup { fn reorg_period_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.reorg_period")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let period = NodeConfig::get_reorg_cache_period(); - View::button(ui, format!("{} {}", CLOCK_COUNTDOWN, period.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", CLOCK_COUNTDOWN, period.clone()), Colors::button(), || { // Setup values for modal. self.reorg_period_edit = period; // Show reorg period setup modal. @@ -242,7 +242,7 @@ impl PoolSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.reorg_period")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw reorg period text edit. @@ -254,7 +254,7 @@ impl PoolSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -276,14 +276,14 @@ impl PoolSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -295,12 +295,12 @@ impl PoolSetup { fn pool_size_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.max_tx_pool")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let size = NodeConfig::get_max_pool_size(); - View::button(ui, format!("{} {}", CIRCLES_THREE, size.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", CIRCLES_THREE, size.clone()), Colors::button(), || { // Setup values for modal. self.pool_size_edit = size; // Show pool size setup modal. @@ -319,7 +319,7 @@ impl PoolSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_tx_pool")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw pool size text edit. @@ -331,7 +331,7 @@ impl PoolSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -353,14 +353,14 @@ impl PoolSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -372,12 +372,12 @@ impl PoolSetup { fn stem_size_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.max_tx_stempool")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let size = NodeConfig::get_max_stempool_size(); - View::button(ui, format!("{} {}", BEZIER_CURVE, size.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", BEZIER_CURVE, size.clone()), Colors::button(), || { // Setup values for modal. self.stempool_size_edit = size; // Show stempool size setup modal. @@ -396,7 +396,7 @@ impl PoolSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_tx_stempool")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw stempool size text edit. @@ -408,7 +408,7 @@ impl PoolSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -430,14 +430,14 @@ impl PoolSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -449,12 +449,12 @@ impl PoolSetup { fn max_weight_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.max_tx_weight")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let weight = NodeConfig::get_mineable_max_weight(); - View::button(ui, format!("{} {}", BOUNDING_BOX, weight.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", BOUNDING_BOX, weight.clone()), Colors::button(), || { // Setup values for modal. self.max_weight_edit = weight; // Show total tx weight setup modal. @@ -473,7 +473,7 @@ impl PoolSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.max_tx_weight")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw tx weight text edit. @@ -485,7 +485,7 @@ impl PoolSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { NetworkSettings::node_restart_required_ui(ui); } @@ -507,14 +507,14 @@ impl PoolSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); diff --git a/src/gui/views/network/setup/stratum.rs b/src/gui/views/network/setup/stratum.rs index 7ba1612..aaf4db3 100644 --- a/src/gui/views/network/setup/stratum.rs +++ b/src/gui/views/network/setup/stratum.rs @@ -97,7 +97,7 @@ impl StratumSetup { self.current_modal_ui(ui, frame, cb); View::sub_title(ui, format!("{} {}", HARD_DRIVES, t!("network_mining.server"))); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { @@ -112,14 +112,14 @@ impl StratumSetup { } else if Node::get_stratum_stats().is_running { ui.add_space(6.0); let disable_text = format!("{} {}", POWER, t!("network_settings.disable")); - View::button(ui, disable_text, Colors::GOLD, || { + View::action_button(ui, disable_text, || { Node::stop_stratum(); }); ui.add_space(6.0); } else { ui.add_space(6.0); let enable_text = format!("{} {}", POWER, t!("network_settings.enable")); - View::button(ui, enable_text, Colors::GOLD, || { + View::action_button(ui, enable_text, || { Node::start_stratum(); }); ui.add_space(6.0); @@ -137,13 +137,13 @@ impl StratumSetup { ui.add_space(2.0); ui.label(RichText::new(t!("network_mining.restart_server_required")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); } ui.add_space(8.0); }); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show message when IP addresses are not available on the system. @@ -155,7 +155,7 @@ impl StratumSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.stratum_ip")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); // Show stratum IP addresses to select. @@ -168,13 +168,13 @@ impl StratumSetup { // Show stratum port setup. self.port_setup_ui(ui, cb); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show attempt time setup. self.attempt_time_ui(ui, cb); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show minimum acceptable share difficulty setup. @@ -186,12 +186,12 @@ impl StratumSetup { fn port_setup_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.stratum_port")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let (_, port) = NodeConfig::get_stratum_address(); - View::button(ui, format!("{} {}", PLUG, port.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", PLUG, port.clone()), Colors::button(), || { // Setup values for modal. self.stratum_port_edit = port; self.stratum_port_available_edit = self.is_port_available; @@ -209,7 +209,7 @@ impl StratumSetup { ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(16.0) - .color(Colors::RED)); + .color(Colors::red())); ui.add_space(12.0); } } @@ -220,7 +220,7 @@ impl StratumSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.stratum_port")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw stratum port text edit. @@ -232,7 +232,7 @@ impl StratumSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { server_restart_required_ui(ui); } @@ -266,14 +266,14 @@ impl StratumSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -285,12 +285,12 @@ impl StratumSetup { fn attempt_time_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.attempt_time")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let time = NodeConfig::get_stratum_attempt_time(); - View::button(ui, format!("{} {}", TIMER, time.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", TIMER, time.clone()), Colors::button(), || { // Setup values for modal. self.attempt_time_edit = time; @@ -304,7 +304,7 @@ impl StratumSetup { ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.attempt_time_desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT) + .color(Colors::inactive_text()) ); ui.add_space(6.0); } @@ -315,7 +315,7 @@ impl StratumSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.attempt_time")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw attempt time text edit. @@ -327,7 +327,7 @@ impl StratumSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { server_restart_required_ui(ui); } @@ -350,14 +350,14 @@ impl StratumSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -368,12 +368,12 @@ impl StratumSetup { fn min_diff_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("network_settings.min_share_diff")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(6.0); let diff = NodeConfig::get_stratum_min_share_diff(); - View::button(ui, format!("{} {}", BARBELL, diff.clone()), Colors::BUTTON, || { + View::button(ui, format!("{} {}", BARBELL, diff.clone()), Colors::button(), || { // Setup values for modal. self.min_share_diff_edit = diff; @@ -393,7 +393,7 @@ impl StratumSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network_settings.min_share_diff")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw share difficulty text edit. @@ -405,7 +405,7 @@ impl StratumSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { server_restart_required_ui(ui); } @@ -428,14 +428,14 @@ impl StratumSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -449,7 +449,7 @@ pub fn server_restart_required_ui(ui: &mut egui::Ui) { ui.add_space(12.0); ui.label(RichText::new(t!("network_mining.restart_server_required")) .size(16.0) - .color(Colors::GREEN) + .color(Colors::green()) ); } } \ No newline at end of file diff --git a/src/gui/views/qr.rs b/src/gui/views/qr.rs index ab36455..5512421 100644 --- a/src/gui/views/qr.rs +++ b/src/gui/views/qr.rs @@ -131,8 +131,8 @@ impl QrCodeContent { }; if !sharing { // Show button to share QR. - let share_text = format!("{} {}", IMAGES_SQUARE, t!("share")); - View::button(ui, share_text, Colors::GOLD, || { + let share_txt = format!("{} {}", IMAGES_SQUARE, t!("share")); + View::action_button(ui, share_txt, || { { let mut w_state = self.qr_image_state.write(); w_state.exporting = true; @@ -211,13 +211,13 @@ impl QrCodeContent { ui.add_space(6.0); // Show QR code text. - View::ellipsize_text(ui, text.clone(), 16.0, Colors::INACTIVE_TEXT); + View::ellipsize_text(ui, text.clone(), 16.0, Colors::inactive_text()); ui.add_space(6.0); // Show button to share QR. ui.vertical_centered(|ui| { let share_text = format!("{} {}", IMAGES_SQUARE, t!("share")); - View::button(ui, share_text, Colors::GOLD, || { + View::action_button(ui, share_text, || { if let Ok(qr) = QrCode::encode_text(text.as_str(), qrcodegen::QrCodeEcc::Low) { if let Some(data) = Self::qr_to_image_data(qr, DEFAULT_QR_SIZE as usize) { let mut png = vec![]; diff --git a/src/gui/views/root.rs b/src/gui/views/root.rs index e6c39e3..7dea4bc 100644 --- a/src/gui/views/root.rs +++ b/src/gui/views/root.rs @@ -110,7 +110,7 @@ impl Root { .resizable(false) .exact_width(panel_width) .frame(egui::Frame { - fill: Colors::WHITE, + fill: Colors::white_or_black(false), ..Default::default() }) .show_animated_inside(ui, is_panel_open, |ui| { @@ -126,7 +126,7 @@ impl Root { // Show wallets content. egui::CentralPanel::default() .frame(egui::Frame { - fill: Colors::FILL_DARK, + fill: Colors::fill_deep(), ..Default::default() }) .show_inside(ui, |ui| { @@ -208,7 +208,7 @@ impl Root { ui.add_space(12.0); ui.label(RichText::new(t!("sync_status.shutdown")) .size(17.0) - .color(Colors::TEXT)); + .color(Colors::text(false))); }); ui.add_space(10.0); } else { @@ -216,38 +216,35 @@ impl Root { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("modal_exit.description")) .size(17.0) - .color(Colors::TEXT)); + .color(Colors::text(false))); }); ui.add_space(10.0); - // Show modal buttons. - ui.scope(|ui| { - // Setup spacing between buttons. - ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); + // Setup spacing between buttons. + ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); - ui.columns(2, |columns| { - columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { - modal.close(); - }); - }); - columns[1].vertical_centered_justified(|ui| { - View::button_ui(ui, t!("modal_exit.exit"), Colors::WHITE, |ui| { - if !Node::is_running() { - self.exit_allowed = true; - ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); - modal.close(); - } else { - Node::stop(true); - modal.disable_closing(); - Modal::set_title(t!("modal_exit.exit")); - self.show_exit_progress = true; - } - }); + ui.columns(2, |columns| { + columns[0].vertical_centered_justified(|ui| { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { + modal.close(); + }); + }); + columns[1].vertical_centered_justified(|ui| { + View::button_ui(ui, t!("modal_exit.exit"), Colors::white_or_black(false), |ui| { + if !Node::is_running() { + self.exit_allowed = true; + ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); + modal.close(); + } else { + Node::stop(true); + modal.disable_closing(); + Modal::set_title(t!("modal_exit.exit")); + self.show_exit_progress = true; + } }); }); - ui.add_space(6.0); }); + ui.add_space(6.0); } } @@ -268,16 +265,23 @@ impl Root { NodeSetup::chain_type_ui(ui); ui.add_space(8.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); + ui.add_space(8.0); + + // Draw theme selection. + Self::theme_selection_ui(ui); + + ui.add_space(8.0); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(format!("{}:", t!("language"))) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); }); - ui.add_space(6.0); + ui.add_space(8.0); // Draw available list of languages to select. let locales = rust_i18n::available_locales!(); @@ -289,13 +293,39 @@ impl Root { // Show button to close modal. ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { modal.close(); }); }); ui.add_space(6.0); } + /// Draw theme selection content. + fn theme_selection_ui(ui: &mut egui::Ui) { + ui.vertical_centered(|ui| { + ui.label(RichText::new(t!("theme")).size(16.0).color(Colors::gray())); + }); + + let saved_use_dark = AppConfig::dark_theme().unwrap_or(false); + let mut selected_use_dark = saved_use_dark; + + ui.add_space(8.0); + ui.columns(2, |columns| { + columns[0].vertical_centered(|ui| { + View::radio_value(ui, &mut selected_use_dark, false, t!("light")); + }); + columns[1].vertical_centered(|ui| { + View::radio_value(ui, &mut selected_use_dark, true, t!("dark")); + }) + }); + ui.add_space(8.0); + + if saved_use_dark != selected_use_dark { + AppConfig::set_dark_theme(selected_use_dark); + crate::setup_visuals(ui.ctx()); + } + } + /// Draw language selection item content. fn language_item_ui(locale: &str, ui: &mut egui::Ui, index: usize, len: usize, modal: &Modal) { // Setup layout size. @@ -305,7 +335,7 @@ impl Root { // 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.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| { @@ -323,7 +353,7 @@ impl Root { }); } else { ui.add_space(14.0); - ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::GREEN)); + ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::green())); ui.add_space(14.0); } @@ -333,9 +363,14 @@ impl Root { ui.vertical(|ui| { // Draw language name. ui.add_space(12.0); + let color = if is_current { + Colors::title(false) + } else { + Colors::gray() + }; ui.label(RichText::new(t!("lang_name", locale = locale)) .size(17.0) - .color(Colors::TEXT)); + .color(color)); ui.add_space(3.0); }); }); @@ -349,11 +384,11 @@ impl Root { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("network.android_warning")) .size(15.0) - .color(Colors::TEXT)); + .color(Colors::text(false))); }); ui.add_space(8.0); ui.vertical_centered_justified(|ui| { - View::button(ui, t!("continue"), Colors::WHITE, || { + View::button(ui, t!("continue"), Colors::white_or_black(false), || { AppConfig::show_android_integrated_node_warning(); modal.close(); }); diff --git a/src/gui/views/title_panel.rs b/src/gui/views/title_panel.rs index 9bc47a8..ae3a549 100644 --- a/src/gui/views/title_panel.rs +++ b/src/gui/views/title_panel.rs @@ -59,7 +59,7 @@ impl TitlePanel { .exact_height(Self::DEFAULT_HEIGHT) .frame(egui::Frame { inner_margin: Self::inner_margin(ui), - fill: Colors::YELLOW, + fill: Colors::yellow(), ..Default::default() }) .show_inside(ui, |ui| { @@ -118,7 +118,7 @@ impl TitlePanel { strip.cell(|ui| { ui.add_space(2.0); ui.centered_and_justified(|ui| { - View::ellipsize_text(ui, text, 19.0, Colors::TITLE); + View::ellipsize_text(ui, text, 19.0, Colors::title(true)); }); }); } @@ -149,12 +149,12 @@ impl TitlePanel { strip.cell(|ui| { ui.add_space(4.0); ui.centered_and_justified(|ui| { - View::ellipsize_text(ui, title, 18.0, Colors::TITLE); + View::ellipsize_text(ui, title, 18.0, Colors::title(true)); }); }); strip.cell(|ui| { ui.centered_and_justified(|ui| { - View::animate_text(ui, subtitle, 15.0, Colors::TEXT, animate_sub); + View::animate_text(ui, subtitle, 15.0, Colors::text(true), animate_sub); }); }); }); diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index eab2a76..f62b563 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -33,12 +33,20 @@ use crate::gui::views::types::TextEditOptions; pub struct View; impl View { - /// Default stroke around views. - pub const DEFAULT_STROKE: Stroke = Stroke { width: 1.0, color: Colors::STROKE }; - /// Stroke for items. - pub const ITEM_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_STROKE }; - /// Stroke for hovered items and buttons. - pub const HOVER_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_HOVER }; + /// Get default stroke around views. + pub fn default_stroke() -> Stroke { + Stroke { width: 1.0, color: Colors::stroke() } + } + + /// Get default stroke around item buttons. + pub fn item_stroke() -> Stroke { + Stroke { width: 1.0, color: Colors::item_stroke() } + } + + /// Get stroke for hovered items and buttons. + pub fn hover_stroke() -> Stroke { + Stroke { width: 1.0, color: Colors::item_hover() } + } /// Draw content with maximum width value. pub fn max_width_ui(ui: &mut egui::Ui, @@ -149,7 +157,7 @@ impl View { /// Draw horizontally centered sub-title with space below. pub fn sub_title(ui: &mut egui::Ui, text: String) { ui.vertical_centered_justified(|ui| { - ui.label(RichText::new(text.to_uppercase()).size(16.0).color(Colors::TEXT)); + ui.label(RichText::new(text.to_uppercase()).size(16.0).color(Colors::text(false))); }); ui.add_space(4.0); } @@ -170,20 +178,15 @@ impl View { /// Title button with transparent background fill color, contains only icon. pub fn title_button(ui: &mut egui::Ui, icon: &str, action: impl FnOnce()) { ui.scope(|ui| { - // Disable stroke when inactive. + // Disable strokes. ui.style_mut().visuals.widgets.inactive.bg_stroke = Stroke::NONE; - // Setup stroke around title buttons on click. - ui.style_mut().visuals.widgets.hovered.bg_stroke = Self::HOVER_STROKE; - ui.style_mut().visuals.widgets.active.bg_stroke = Self::DEFAULT_STROKE; - // Disable rounding. - ui.style_mut().visuals.widgets.hovered.rounding = Rounding::default(); + ui.style_mut().visuals.widgets.hovered.bg_stroke = Stroke::NONE; + ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE; ui.style_mut().visuals.widgets.active.rounding = Rounding::default(); - // Disable expansion. - ui.style_mut().visuals.widgets.hovered.expansion = 0.0; ui.style_mut().visuals.widgets.active.expansion = 0.0; // Setup text. - let wt = RichText::new(icon.to_string()).size(22.0).color(Colors::TITLE); + let wt = RichText::new(icon.to_string()).size(22.0).color(Colors::title(true)); // Draw button. let br = Button::new(wt) .fill(Colors::TRANSPARENT) @@ -200,8 +203,8 @@ impl View { pub fn tab_button(ui: &mut egui::Ui, icon: &str, active: bool, action: impl FnOnce()) { ui.scope(|ui| { let text_color = match active { - true => Colors::TITLE, - false => Colors::TEXT + true => Colors::title(false), + false => Colors::text(false) }; let mut button = Button::new(RichText::new(icon).size(22.0).color(text_color)); @@ -211,15 +214,15 @@ impl View { ui.style_mut().visuals.widgets.hovered.expansion = 0.0; ui.style_mut().visuals.widgets.active.expansion = 0.0; // Setup fill colors. - ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::WHITE; - ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::BUTTON; - ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL; + ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::white_or_black(false); + ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::button(); + ui.visuals_mut().widgets.active.weak_bg_fill = Colors::fill(); // Setup stroke colors. - ui.visuals_mut().widgets.inactive.bg_stroke = Self::DEFAULT_STROKE; - ui.visuals_mut().widgets.hovered.bg_stroke = Self::HOVER_STROKE; - ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE; + ui.visuals_mut().widgets.inactive.bg_stroke = Self::default_stroke(); + ui.visuals_mut().widgets.hovered.bg_stroke = Self::hover_stroke(); + ui.visuals_mut().widgets.active.bg_stroke = Self::item_stroke(); } else { - button = button.fill(Colors::FILL).stroke(Stroke::NONE); + button = button.fill(Colors::fill()).stroke(Stroke::NONE); } let br = button.ui(ui).on_hover_cursor(CursorIcon::PointingHand); @@ -234,7 +237,7 @@ impl View { fn button_resp(ui: &mut egui::Ui, text: String, text_color: Color32, bg: Color32) -> Response { let button_text = Self::ellipsize(text.to_uppercase(), 17.0, text_color); Button::new(button_text) - .stroke(Self::DEFAULT_STROKE) + .stroke(Self::default_stroke()) .fill(bg) .ui(ui) .on_hover_cursor(CursorIcon::PointingHand) @@ -242,7 +245,7 @@ impl View { /// Draw [`Button`] with specified background fill color and default text color. pub fn button(ui: &mut egui::Ui, text: String, fill: Color32, action: impl FnOnce()) { - let br = Self::button_resp(ui, text, Colors::TEXT_BUTTON, fill); + let br = Self::button_resp(ui, text, Colors::text_button(), fill); if Self::touched(ui, br) { (action)(); } @@ -260,14 +263,20 @@ impl View { } } + /// Draw gold action [`Button`]. + pub fn action_button(ui: &mut egui::Ui, + text: String, action: impl FnOnce()) { + Self::colored_text_button(ui, text, Colors::title(true), Colors::gold(), action); + } + /// Draw [`Button`] with specified background fill color and ui at callback. pub fn button_ui(ui: &mut egui::Ui, text: String, fill: Color32, action: impl FnOnce(&mut egui::Ui)) { - let button_text = Self::ellipsize(text.to_uppercase(), 17.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) + .stroke(Self::default_stroke()) .fill(fill) .ui(ui) .on_hover_cursor(CursorIcon::PointingHand); @@ -294,16 +303,16 @@ impl View { ui.style_mut().visuals.widgets.hovered.expansion = 0.0; ui.style_mut().visuals.widgets.active.expansion = 0.0; // Setup fill colors. - ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::WHITE; - ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::BUTTON; - ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL; + ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::white_or_black(false); + ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::button(); + ui.visuals_mut().widgets.active.weak_bg_fill = Colors::fill(); // Setup stroke colors. - ui.visuals_mut().widgets.inactive.bg_stroke = Self::DEFAULT_STROKE; - ui.visuals_mut().widgets.hovered.bg_stroke = Self::HOVER_STROKE; - ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE; + ui.visuals_mut().widgets.inactive.bg_stroke = Self::default_stroke(); + ui.visuals_mut().widgets.hovered.bg_stroke = Self::hover_stroke(); + ui.visuals_mut().widgets.active.bg_stroke = Self::item_stroke(); // Setup button text color. - let text_color = if let Some(c) = color { c } else { Colors::ITEM_BUTTON }; + let text_color = if let Some(c) = color { c } else { Colors::item_button() }; // Show button. let br = Button::new(RichText::new(text).size(20.0).color(text_color)) @@ -340,7 +349,7 @@ impl View { // Draw button to show/hide current password. let eye_icon = if show_pass { EYE } else { EYE_SLASH }; let mut changed = false; - View::button(ui, eye_icon.to_string(), Colors::WHITE, || { + View::button(ui, eye_icon.to_string(), Colors::white_or_black(false), || { show_pass = !show_pass; changed = true; }); @@ -356,7 +365,7 @@ impl View { // Setup copy button. if options.copy { let copy_icon = COPY.to_string(); - View::button(ui, copy_icon, Colors::WHITE, || { + View::button(ui, copy_icon, Colors::white_or_black(false), || { cb.copy_string_to_buffer(value.clone()); }); ui.add_space(8.0); @@ -365,7 +374,7 @@ impl View { // Setup paste button. if options.paste { let paste_icon = CLIPBOARD_TEXT.to_string(); - View::button(ui, paste_icon, Colors::WHITE, || { + View::button(ui, paste_icon, Colors::white_or_black(false), || { *value = cb.get_string_from_buffer(); }); ui.add_space(8.0); @@ -374,7 +383,7 @@ impl View { // Setup scan QR code button. if options.scan_qr { let scan_icon = SCAN.to_string(); - View::button(ui, scan_icon, Colors::WHITE, || { + View::button(ui, scan_icon, Colors::white_or_black(false), || { cb.start_camera(); options.scan_pressed = true; }); @@ -500,7 +509,7 @@ impl View { se: if r[3] { 8.0 } else { 0.0 }, }, fill: Colors::TRANSPARENT, - stroke: Self::ITEM_STROKE, + stroke: Self::item_stroke(), fill_texture_id: Default::default(), uv: Rect::ZERO }; @@ -518,7 +527,7 @@ impl View { // Draw box value. let mut job = LayoutJob::single_section(value, TextFormat { font_id: FontId::proportional(17.0), - color: Colors::BLACK, + color: Colors::white_or_black(true), ..Default::default() }); job.wrap = TextWrapping { @@ -530,7 +539,7 @@ impl View { ui.label(job); // Draw box label. - ui.label(RichText::new(label).color(Colors::GRAY).size(15.0)); + ui.label(RichText::new(label).color(Colors::gray()).size(15.0)); }); ui.add_space(2.0); @@ -560,19 +569,19 @@ impl View { /// Draw big gold loading spinner. pub fn big_loading_spinner(ui: &mut egui::Ui) { - Spinner::new().size(Self::BIG_SPINNER_SIZE).color(Colors::GOLD).ui(ui); + Spinner::new().size(Self::BIG_SPINNER_SIZE).color(Colors::gold()).ui(ui); } /// Draw small gold loading spinner. pub fn small_loading_spinner(ui: &mut egui::Ui) { - Spinner::new().size(38.0).color(Colors::GOLD).ui(ui); + Spinner::new().size(38.0).color(Colors::gold()).ui(ui); } /// Draw the button that looks like checkbox with callback on check. pub fn checkbox(ui: &mut egui::Ui, checked: bool, text: String, callback: impl FnOnce()) { let (text_value, color) = match checked { - true => (format!("{} {}", CHECK_SQUARE, text), Colors::TEXT_BUTTON), - false => (format!("{} {}", SQUARE, text), Colors::CHECKBOX) + true => (format!("{} {}", CHECK_SQUARE, text), Colors::text_button()), + false => (format!("{} {}", SQUARE, text), Colors::checkbox()) }; let br = Button::new(RichText::new(text_value).size(17.0).color(color)) @@ -591,7 +600,7 @@ impl View { pub fn radio_value(ui: &mut egui::Ui, current: &mut T, value: T, text: String) { ui.scope(|ui| { // Setup background color. - ui.visuals_mut().widgets.inactive.bg_fill = Colors::FILL_DARK; + ui.visuals_mut().widgets.inactive.bg_fill = Colors::fill_deep(); // Draw radio button. let mut response = ui.radio(*current == value, text) .on_hover_cursor(CursorIcon::PointingHand); diff --git a/src/gui/views/wallets/content.rs b/src/gui/views/wallets/content.rs index 29f67fd..98ba88a 100644 --- a/src/gui/views/wallets/content.rs +++ b/src/gui/views/wallets/content.rs @@ -115,12 +115,12 @@ impl WalletsContent { .frame(egui::Frame { fill: if empty_list && !create_wallet || (dual_panel && show_wallet && !self.show_wallets_at_dual_panel) { - Colors::FILL_DARK + Colors::fill_deep() } else { if create_wallet { - Colors::WHITE + Colors::white_or_black(true) } else { - Colors::BUTTON + Colors::button() } }, ..Default::default() @@ -175,8 +175,8 @@ impl WalletsContent { // Show wallets bottom panel. egui::TopBottomPanel::bottom("wallets_bottom_panel") .frame(egui::Frame { - stroke: View::ITEM_STROKE, - fill: Colors::FILL, + stroke: View::item_stroke(), + fill: Colors::fill(), inner_margin: Margin { left: View::get_left_inset() + 4.0, right: View::far_right_inset_margin(ui) + 4.0, @@ -202,8 +202,8 @@ impl WalletsContent { // Show wallet list panel. egui::CentralPanel::default() .frame(egui::Frame { - stroke: View::DEFAULT_STROKE, - fill: Colors::FILL_DARK, + stroke: View::default_stroke(), + fill: Colors::fill_deep(), inner_margin: Margin { left: if list_hidden { 0.0 @@ -337,11 +337,6 @@ impl WalletsContent { dual_panel: bool, cb: &dyn PlatformCallbacks) { ui.scope(|ui| { - // Setup scroll bar color. - ui.style_mut().visuals.widgets.inactive.bg_fill = Colors::ITEM_HOVER; - ui.style_mut().visuals.widgets.hovered.bg_fill = Colors::STROKE; - - // Draw list of wallets. ScrollArea::vertical() .id_source("wallet_list") .scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden) @@ -389,11 +384,15 @@ impl WalletsContent { rect.set_height(78.0); let rounding = View::item_rounding(0, 1, false); let bg = if current { - egui::Color32::from_gray(234) + if AppConfig::dark_theme().unwrap_or(false) { + egui::Color32::from_gray(32) + } else { + egui::Color32::from_gray(233) + } } else { - Colors::FILL + Colors::fill() }; - ui.painter().rect(rect, rounding, bg, View::HOVER_STROKE); + ui.painter().rect(rect, rounding, bg, View::hover_stroke()); ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { // Setup padding for item buttons. @@ -434,7 +433,11 @@ impl WalletsContent { ui.vertical(|ui| { ui.add_space(3.0); // Setup wallet name text. - let name_color = if is_selected { Colors::BLACK } else { Colors::TITLE }; + let name_color = if is_selected { + Colors::white_or_black(true) + } else { + Colors::title(false) + }; View::ellipsize_text(ui, config.name, 18.0, name_color); // Setup wallet connection text. @@ -443,7 +446,7 @@ impl WalletsContent { } else { format!("{} {}", COMPUTER_TOWER, t!("network.node")) }; - View::ellipsize_text(ui, conn_text, 15.0, Colors::TEXT); + View::ellipsize_text(ui, conn_text, 15.0, Colors::text(false)); ui.add_space(1.0); // Setup wallet status text. @@ -490,7 +493,7 @@ impl WalletsContent { } else { format!("{} {}", FOLDER_LOCK, t!("wallets.locked")) }; - ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY)); + ui.label(RichText::new(status_text).size(15.0).color(Colors::gray())); ui.add_space(4.0); }) }); @@ -519,7 +522,7 @@ impl WalletsContent { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.pass")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Show password input. @@ -532,12 +535,12 @@ impl WalletsContent { ui.add_space(10.0); ui.label(RichText::new(t!("wallets.pass_empty")) .size(17.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); } else if self.wrong_pass { ui.add_space(10.0); ui.label(RichText::new(t!("wallets.wrong_pass")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); }); @@ -549,7 +552,7 @@ impl WalletsContent { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -581,7 +584,7 @@ impl WalletsContent { (on_continue)(); }); - View::button(ui, t!("continue"), Colors::WHITE, on_continue); + View::button(ui, t!("continue"), Colors::white_or_black(false), on_continue); }); }); ui.add_space(6.0); diff --git a/src/gui/views/wallets/creation/creation.rs b/src/gui/views/wallets/creation/creation.rs index b53e691..1570f91 100644 --- a/src/gui/views/wallets/creation/creation.rs +++ b/src/gui/views/wallets/creation/creation.rs @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, Margin, RichText, ScrollArea, vec2}; +use egui::{Id, Margin, RichText, ScrollArea, vec2, Widget}; use egui::scroll_area::ScrollBarVisibility; use grin_util::ZeroingString; -use crate::built_info; +use crate::{AppConfig, built_info}; use crate::gui::Colors; use crate::gui::icons::{CHECK, CLIPBOARD_TEXT, COPY, FOLDER_PLUS, SCAN, SHARE_FAT}; use crate::gui::platform::PlatformCallbacks; @@ -74,8 +74,8 @@ impl WalletCreation { if self.step.is_some() { egui::TopBottomPanel::bottom("wallet_creation_step_panel") .frame(egui::Frame { - stroke: View::DEFAULT_STROKE, - fill: Colors::FILL, + fill: Colors::fill(), + stroke: View::default_stroke(), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 8.0, right: View::get_right_inset() + 8.0, @@ -99,7 +99,8 @@ impl WalletCreation { // Show wallet creation step content panel. egui::CentralPanel::default() .frame(egui::Frame { - stroke: View::DEFAULT_STROKE, + fill: Colors::fill(), + stroke: View::default_stroke(), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 4.0, right: View::get_right_inset() + 4.0, @@ -168,14 +169,14 @@ impl WalletCreation { }; // Show step description. ui.add_space(2.0); - ui.label(RichText::new(step_text).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(step_text).size(16.0).color(Colors::gray())); ui.add_space(2.0); // Show error if entered phrase is not valid. if !self.mnemonic_setup.valid_phrase { step_available = false; ui.label(RichText::new(t!("wallets.not_valid_phrase")) .size(16.0) - .color(Colors::RED)); + .color(Colors::red())); ui.add_space(2.0); } if step == Step::EnterMnemonic { @@ -197,7 +198,7 @@ impl WalletCreation { } else { // Show QR code scan button. let scan_text = format!("{} {}", SCAN, t!("scan").to_uppercase()); - View::button(ui, scan_text, Colors::WHITE, || { + View::button(ui, scan_text, Colors::white_or_black(false), || { self.mnemonic_setup.show_qr_scan_modal(cb); }); } @@ -221,14 +222,14 @@ impl WalletCreation { PhraseMode::Generate => { // Show copy button. let c_t = format!("{} {}", COPY, t!("copy").to_uppercase()); - View::button(ui, c_t.to_uppercase(), Colors::WHITE, || { + View::button(ui, c_t.to_uppercase(), Colors::white_or_black(false), || { cb.copy_string_to_buffer(self.mnemonic_setup.mnemonic.get_phrase()); }); } PhraseMode::Import => { // Show paste button. let p_t = format!("{} {}", CLIPBOARD_TEXT, t!("paste").to_uppercase()); - View::button(ui, p_t, Colors::WHITE, || { + View::button(ui, p_t, Colors::white_or_black(false), || { let data = ZeroingString::from(cb.get_string_from_buffer().trim()); self.mnemonic_setup.mnemonic.import_text(&data); }); @@ -242,15 +243,15 @@ impl WalletCreation { step: Step, on_create: impl FnOnce(Wallet)) { // Setup button text. - let (next_text, color) = if step == Step::SetupConnection { - (format!("{} {}", CHECK, t!("complete")), Colors::GOLD) + let (next_text, text_color, bg_color) = if step == Step::SetupConnection { + (format!("{} {}", CHECK, t!("complete")), Colors::title(true), Colors::gold()) } else { let text = format!("{} {}", SHARE_FAT, t!("continue")); - (text, Colors::WHITE) + (text, Colors::text_button(), Colors::white_or_black(false)) }; // Show next step button. - View::button(ui, next_text.to_uppercase(), color, || { + View::colored_text_button(ui, next_text.to_uppercase(), text_color, bg_color, || { self.step = if let Some(step) = &self.step { match step { Step::EnterMnemonic => { @@ -310,28 +311,31 @@ impl WalletCreation { None => { // Show wallet creation message if step is empty. View::center_content(ui, 350.0 + View::get_bottom_inset(), |ui| { - ui.add( - egui::Image::new(egui::include_image!("../../../../../img/logo.png")) - .fit_to_exact_size(vec2(180.0, 180.0)) - ); + let logo = if AppConfig::dark_theme().unwrap_or(false) { + egui::include_image!("../../../../../img/logo_light.png") + } else { + egui::include_image!("../../../../../img/logo.png") + }; + // Show app logo. + egui::Image::new(logo).fit_to_exact_size(vec2(180.0, 180.0)).ui(ui); ui.add_space(-15.0); ui.label(RichText::new("GRIM") .size(24.0) - .color(Colors::BLACK) + .color(Colors::white_or_black(true)) ); ui.label(RichText::new(built_info::PKG_VERSION) .size(16.0) - .color(Colors::BLACK) + .color(Colors::white_or_black(true)) ); ui.add_space(4.0); let text = t!("wallets.create_desc"); ui.label(RichText::new(text) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); ui.add_space(8.0); let add_text = format!("{} {}", FOLDER_PLUS, t!("wallets.add")); - View::button(ui, add_text, Colors::WHITE, || { + View::button(ui, add_text, Colors::white_or_black(false), || { self.show_name_pass_modal(cb); }); }); @@ -399,7 +403,7 @@ impl WalletCreation { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.name")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Show wallet name text edit. @@ -414,7 +418,7 @@ impl WalletCreation { ui.label(RichText::new(t!("wallets.pass")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw wallet password text edit. @@ -432,7 +436,7 @@ impl WalletCreation { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -454,7 +458,7 @@ impl WalletCreation { (on_next)(); }); - View::button(ui, t!("continue"), Colors::WHITE, on_next); + View::button(ui, t!("continue"), Colors::white_or_black(false), on_next); }); }); ui.add_space(6.0); diff --git a/src/gui/views/wallets/creation/mnemonic.rs b/src/gui/views/wallets/creation/mnemonic.rs index b2e51e2..1604776 100644 --- a/src/gui/views/wallets/creation/mnemonic.rs +++ b/src/gui/views/wallets/creation/mnemonic.rs @@ -100,7 +100,7 @@ impl MnemonicSetup { self.mode_type_ui(ui); ui.add_space(12.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show words setup. @@ -118,7 +118,7 @@ impl MnemonicSetup { ui.add_space(4.0); ui.vertical_centered(|ui| { let text = format!("{}:", t!("wallets.recovery_phrase")); - ui.label(RichText::new(text).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(text).size(16.0).color(Colors::gray())); }); ui.add_space(4.0); self.word_list_ui(ui, true, cb); @@ -148,7 +148,7 @@ impl MnemonicSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.words_count")) .size(16.0) - .color(Colors::GRAY) + .color(Colors::gray()) ); }); ui.add_space(6.0); @@ -240,7 +240,7 @@ impl MnemonicSetup { cb: &dyn PlatformCallbacks) { if edit { ui.add_space(6.0); - View::button(ui, PENCIL.to_string(), Colors::BUTTON, || { + View::button(ui, PENCIL.to_string(), Colors::button(), || { // Setup modal values. self.word_num_edit = num; self.word_edit = word.clone(); @@ -254,11 +254,11 @@ impl MnemonicSetup { }); ui.label(RichText::new(format!("#{} {}", num, word)) .size(17.0) - .color(Colors::BLACK)); + .color(Colors::white_or_black(true))); } else { ui.add_space(12.0); let text = format!("#{} {}", num, word); - ui.label(RichText::new(text).size(17.0).color(Colors::BLACK)); + ui.label(RichText::new(text).size(17.0).color(Colors::white_or_black(true))); } } @@ -273,7 +273,7 @@ impl MnemonicSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.enter_word", "number" => self.word_num_edit)) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw word value text edit. @@ -287,7 +287,7 @@ impl MnemonicSetup { ui.add_space(12.0); ui.label(RichText::new(t!("wallets.not_valid_word")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); }); @@ -299,7 +299,7 @@ impl MnemonicSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -346,7 +346,7 @@ impl MnemonicSetup { (save)(); }); // Show save button. - View::button(ui, t!("continue"), Colors::WHITE, save); + View::button(ui, t!("continue"), Colors::white_or_black(false), save); }); }); ui.add_space(6.0); @@ -376,7 +376,7 @@ impl MnemonicSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.rec_phrase_not_found")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); }); ui.add_space(6.0); } else if let Some(result) = self.camera_content.qr_scan_result() { @@ -408,13 +408,13 @@ impl MnemonicSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.scan_phrase_not_found = None; modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("repeat"), Colors::WHITE, || { + View::button(ui, t!("repeat"), Colors::white_or_black(false), || { Modal::set_title(t!("scan_qr")); self.scan_phrase_not_found = None; cb.start_camera(); @@ -423,7 +423,7 @@ impl MnemonicSetup { }); } else { ui.vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { cb.stop_camera(); modal.close(); }); diff --git a/src/gui/views/wallets/setup/common.rs b/src/gui/views/wallets/setup/common.rs index 2cbcb06..6b2765c 100644 --- a/src/gui/views/wallets/setup/common.rs +++ b/src/gui/views/wallets/setup/common.rs @@ -72,14 +72,18 @@ impl CommonSetup { let wallet_name = wallet.get_config().name; // Show wallet name. ui.add_space(2.0); - ui.label(RichText::new(t!("wallets.name")).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("wallets.name")) + .size(16.0) + .color(Colors::gray())); ui.add_space(2.0); - ui.label(RichText::new(wallet_name.clone()).size(16.0).color(Colors::BLACK)); + ui.label(RichText::new(wallet_name.clone()) + .size(16.0) + .color(Colors::white_or_black(true))); ui.add_space(8.0); // Show wallet name setup. let name_text = format!("{} {}", PENCIL, t!("change")); - View::button(ui, name_text, Colors::BUTTON, || { + View::button(ui, name_text, Colors::button(), || { self.name_edit = wallet_name; // Show wallet name modal. Modal::new(NAME_EDIT_MODAL) @@ -90,14 +94,14 @@ impl CommonSetup { }); ui.add_space(12.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); - ui.label(RichText::new(t!("wallets.pass")).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("wallets.pass")).size(16.0).color(Colors::gray())); ui.add_space(6.0); // Show wallet password setup. let pass_text = format!("{} {}", PASSWORD, t!("change")); - View::button(ui, pass_text, Colors::BUTTON, || { + View::button(ui, pass_text, Colors::button(), || { // Setup modal values. self.first_edit_pass_opening = true; self.old_pass_edit = "".to_string(); @@ -112,15 +116,15 @@ impl CommonSetup { }); ui.add_space(12.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); - ui.label(RichText::new(t!("wallets.min_tx_conf_count")).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("wallets.min_tx_conf_count")).size(16.0).color(Colors::gray())); ui.add_space(6.0); // Show minimum amount of confirmations value setup. let min_confirmations = wallet.get_config().min_confirmations; let min_conf_text = format!("{} {}", CLOCK_COUNTDOWN, min_confirmations); - View::button(ui, min_conf_text, Colors::BUTTON, || { + View::button(ui, min_conf_text, Colors::button(), || { self.min_confirmations_edit = min_confirmations.to_string(); // Show minimum amount of confirmations value modal. Modal::new(MIN_CONFIRMATIONS_EDIT_MODAL) @@ -131,7 +135,7 @@ impl CommonSetup { }); ui.add_space(12.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(4.0); }); } @@ -176,7 +180,7 @@ impl CommonSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.name")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Show wallet name text edit. @@ -193,7 +197,7 @@ impl CommonSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -213,7 +217,7 @@ impl CommonSetup { (on_save)(); }); - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); @@ -232,7 +236,7 @@ impl CommonSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.current_pass")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw old password text edit. @@ -247,7 +251,7 @@ impl CommonSetup { ui.label(RichText::new(t!("wallets.new_pass")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw new password text edit. @@ -262,12 +266,12 @@ impl CommonSetup { ui.add_space(10.0); ui.label(RichText::new(t!("wallets.pass_empty")) .size(17.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); } else if self.wrong_pass { ui.add_space(10.0); ui.label(RichText::new(t!("wallets.wrong_pass")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); }); @@ -279,7 +283,7 @@ impl CommonSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -311,7 +315,7 @@ impl CommonSetup { (on_continue)(); }); - View::button(ui, t!("change"), Colors::WHITE, on_continue); + View::button(ui, t!("change"), Colors::white_or_black(false), on_continue); }); }); ui.add_space(6.0); @@ -328,7 +332,7 @@ impl CommonSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.min_tx_conf_count")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Minimum amount of confirmations text edit. @@ -340,7 +344,7 @@ impl CommonSetup { ui.add_space(12.0); ui.label(RichText::new(t!("network_settings.not_valid_value")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); }); @@ -352,7 +356,7 @@ impl CommonSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -372,7 +376,7 @@ impl CommonSetup { (on_save)(); }); - View::button(ui, t!("modal.save"), Colors::WHITE, on_save); + View::button(ui, t!("modal.save"), Colors::white_or_black(false), on_save); }); }); ui.add_space(6.0); diff --git a/src/gui/views/wallets/setup/connection.rs b/src/gui/views/wallets/setup/connection.rs index b0e42ce..59701bd 100644 --- a/src/gui/views/wallets/setup/connection.rs +++ b/src/gui/views/wallets/setup/connection.rs @@ -143,7 +143,7 @@ impl ConnectionSetup { ui.add_space(2.0); View::sub_title(ui, format!("{} {}", GLOBE, t!("wallets.conn_method"))); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); ui.vertical_centered(|ui| { @@ -153,12 +153,12 @@ impl ConnectionSetup { // Show external connections. ui.add_space(8.0); - ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::gray())); ui.add_space(6.0); // Show button to add new external node connection. let add_node_text = format!("{} {}", PLUS_CIRCLE, t!("wallets.add_node")); - View::button(ui, add_node_text, Colors::WHITE, || { + View::button(ui, add_node_text, Colors::white_or_black(false), || { self.show_add_ext_conn_modal(cb); }); ui.add_space(4.0); @@ -196,7 +196,7 @@ impl ConnectionSetup { let mut rect = ui.available_rect_before_wrap(); rect.set_height(78.0); let rounding = View::item_rounding(0, 1, false); - ui.painter().rect(rect, rounding, Colors::FILL, View::ITEM_STROKE); + ui.painter().rect(rect, rounding, Colors::fill(), View::item_stroke()); ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { // Setup padding for item buttons. @@ -210,13 +210,13 @@ impl ConnectionSetup { }); } else { ui.add_space(14.0); - ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::GREEN)); + ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::green())); ui.add_space(14.0); } if !Node::is_running() { // Draw button to start integrated node. - View::item_button(ui, Rounding::default(), POWER, Some(Colors::GREEN), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::green()), || { Node::start(); }); } @@ -228,12 +228,12 @@ impl ConnectionSetup { ui.add_space(3.0); ui.label(RichText::new(t!("network.node")) .size(18.0) - .color(Colors::TITLE)); + .color(Colors::title(false))); // 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.label(RichText::new(address_text).size(15.0).color(Colors::text(false))); ui.add_space(1.0); // Setup node status text. @@ -245,7 +245,7 @@ impl ConnectionSetup { 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.label(RichText::new(status_text).size(15.0).color(Colors::gray())); }) }); }); @@ -265,7 +265,7 @@ impl ConnectionSetup { // 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.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| { @@ -286,7 +286,7 @@ impl ConnectionSetup { }); } else { ui.add_space(12.0); - ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::GREEN)); + ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::green())); } let layout_size = ui.available_size(); @@ -296,7 +296,7 @@ impl ConnectionSetup { // Draw connections URL. ui.add_space(4.0); let conn_text = format!("{} {}", GLOBE_SIMPLE, conn.url); - View::ellipsize_text(ui, conn_text, 15.0, Colors::TITLE); + View::ellipsize_text(ui, conn_text, 15.0, Colors::title(false)); ui.add_space(1.0); // Setup connection status text. let status_text = if let Some(available) = conn.available { @@ -308,7 +308,7 @@ impl ConnectionSetup { } else { format!("{} {}", DOTS_THREE_CIRCLE, t!("network.availability_check")) }; - ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY)); + ui.label(RichText::new(status_text).size(15.0).color(Colors::gray())); ui.add_space(3.0); }); }); @@ -340,7 +340,7 @@ impl ConnectionSetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.node_url")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw node URL text edit. @@ -355,7 +355,7 @@ impl ConnectionSetup { ui.label(RichText::new(t!("wallets.node_secret")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw node API secret text edit. @@ -368,7 +368,7 @@ impl ConnectionSetup { ui.add_space(10.0); ui.label(RichText::new(t!("wallets.invalid_url")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(10.0); }); @@ -380,7 +380,7 @@ impl ConnectionSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -418,7 +418,7 @@ impl ConnectionSetup { (on_add)(); }); - View::button(ui, t!("modal.add"), Colors::WHITE, on_add); + View::button(ui, t!("modal.add"), Colors::white_or_black(false), on_add); }); }); ui.add_space(6.0); diff --git a/src/gui/views/wallets/setup/recovery.rs b/src/gui/views/wallets/setup/recovery.rs index 0dcb263..c3cc9a8 100644 --- a/src/gui/views/wallets/setup/recovery.rs +++ b/src/gui/views/wallets/setup/recovery.rs @@ -60,10 +60,10 @@ impl RecoverySetup { self.modal_content_ui(ui, wallet, cb); ui.add_space(10.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); View::sub_title(ui, format!("{} {}", WRENCH, t!("wallets.recovery"))); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(4.0); ui.vertical_centered(|ui| { @@ -73,60 +73,60 @@ impl RecoverySetup { ui.add_space(6.0); ui.label(RichText::new(t!("wallets.repair_unavailable")) .size(16.0) - .color(Colors::RED)); + .color(Colors::red())); } else if !wallet.is_repairing() { ui.add_space(6.0); // Draw button to repair the wallet. let repair_text = format!("{} {}", STETHOSCOPE, t!("wallets.repair_wallet")); - View::button(ui, repair_text, Colors::GOLD, || { + View::action_button(ui, repair_text, || { wallet.repair(); }); ui.add_space(6.0); ui.label(RichText::new(t!("wallets.repair_desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); } ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Draw button to restore the wallet. let recover_text = format!("{} {}", LIFEBUOY, t!("wallets.recover")); ui.add_space(4.0); - View::colored_text_button(ui, recover_text, Colors::GREEN, Colors::BUTTON, || { + View::colored_text_button(ui, recover_text, Colors::green(), Colors::button(), || { wallet.delete_db(true); }); ui.add_space(6.0); ui.label(RichText::new(t!("wallets.restore_wallet_desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); let recovery_text = format!("{}:", t!("wallets.recovery_phrase")); - ui.label(RichText::new(recovery_text).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(recovery_text).size(16.0).color(Colors::gray())); ui.add_space(6.0); // Draw button to show recovery phrase. let show_text = format!("{} {}", EYE, t!("show")); - View::button(ui, show_text, Colors::BUTTON, || { + View::button(ui, show_text, Colors::button(), || { self.show_recovery_phrase_modal(cb); }); ui.add_space(12.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); - ui.label(RichText::new(t!("wallets.delete_desc")).size(16.0).color(Colors::RED)); + ui.label(RichText::new(t!("wallets.delete_desc")).size(16.0).color(Colors::red())); ui.add_space(6.0); // Draw button to delete the wallet. let delete_text = format!("{} {}", TRASH, t!("wallets.delete")); - View::colored_text_button(ui, delete_text, Colors::RED, Colors::BUTTON, || { + View::colored_text_button(ui, delete_text, Colors::red(), Colors::button(), || { Modal::new(DELETE_CONFIRMATION_MODAL) .position(ModalPosition::Center) .title(t!("modal.confirmation")) @@ -186,11 +186,11 @@ impl RecoverySetup { ui.vertical_centered(|ui| { ui.label(RichText::new(self.recovery_phrase.clone().unwrap().to_string()) .size(17.0) - .color(Colors::BLACK)); + .color(Colors::white_or_black(true))); }); ui.add_space(10.0); ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.recovery_phrase = None; modal.close(); }); @@ -199,7 +199,7 @@ impl RecoverySetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.pass")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw current wallet password text edit. @@ -212,12 +212,12 @@ impl RecoverySetup { ui.add_space(12.0); ui.label(RichText::new(t!("wallets.pass_empty")) .size(17.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); } else if self.wrong_pass { ui.add_space(12.0); ui.label(RichText::new(t!("wallets.wrong_pass")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } }); ui.add_space(12.0); @@ -229,13 +229,13 @@ impl RecoverySetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { self.recovery_phrase = None; modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, "OK".to_owned(), Colors::WHITE, || { + View::button(ui, "OK".to_owned(), Colors::white_or_black(false), || { match wallet.get_recovery(self.pass_edit.clone()) { Ok(phrase) => { self.wrong_pass = false; @@ -263,7 +263,7 @@ impl RecoverySetup { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.delete_conf")) .size(17.0) - .color(Colors::TEXT)); + .color(Colors::text(false))); }); ui.add_space(12.0); @@ -274,12 +274,12 @@ impl RecoverySetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("delete"), Colors::WHITE, || { + View::button(ui, t!("delete"), Colors::white_or_black(false), || { wallet.delete_wallet(); modal.close(); }); diff --git a/src/gui/views/wallets/wallet/content.rs b/src/gui/views/wallets/wallet/content.rs index 726cf0f..627c10d 100644 --- a/src/gui/views/wallets/wallet/content.rs +++ b/src/gui/views/wallets/wallet/content.rs @@ -90,8 +90,8 @@ impl WalletContent { && !wallet.sync_error() && !wallet.is_repairing(); egui::TopBottomPanel::top(Id::from("wallet_balance").with(wallet.identifier())) .frame(egui::Frame { - fill: Colors::FILL, - stroke: View::DEFAULT_STROKE, + fill: Colors::fill(), + stroke: View::default_stroke(), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 4.0, right: View::get_right_inset() + 4.0, @@ -118,8 +118,8 @@ impl WalletContent { // Show wallet tabs panel. egui::TopBottomPanel::bottom("wallet_tabs") .frame(egui::Frame { - stroke: View::ITEM_STROKE, - fill: Colors::FILL, + stroke: View::item_stroke(), + fill: Colors::fill(), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 4.0, right: View::get_right_inset() + 4.0, @@ -140,8 +140,8 @@ impl WalletContent { // Show tab content panel. egui::CentralPanel::default() .frame(egui::Frame { - fill: Colors::WHITE, - stroke: View::DEFAULT_STROKE, + fill: Colors::white_or_black(false), + stroke: View::default_stroke(), ..Default::default() }) .show_inside(ui, |ui| { @@ -191,7 +191,7 @@ impl WalletContent { rect.set_height(75.0); // Draw round background. let rounding = View::item_rounding(0, 2, false); - ui.painter().rect(rect, rounding, Colors::BUTTON, View::HOVER_STROKE); + ui.painter().rect(rect, rounding, Colors::button(), View::hover_stroke()); ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { // Draw button to scan QR code. @@ -228,7 +228,9 @@ impl WalletContent { // Show spendable amount. let amount = amount_to_hr_string(data.info.amount_currently_spendable, true); let amount_text = format!("{} {}", amount, GRIN); - ui.label(RichText::new(amount_text).size(18.0).color(Colors::BLACK)); + ui.label(RichText::new(amount_text) + .size(18.0) + .color(Colors::white_or_black(true))); ui.add_space(-2.0); // Show account label. @@ -240,11 +242,11 @@ impl WalletContent { account.to_owned() }; let acc_text = format!("{} {}", FOLDER_USER, acc_label); - View::ellipsize_text(ui, acc_text, 15.0, Colors::TEXT); + View::ellipsize_text(ui, acc_text, 15.0, Colors::text(false)); // Show confirmed height. let height_text = format!("{} {}", PACKAGE, data.info.last_confirmed_height); - View::animate_text(ui, height_text, 15.0, Colors::GRAY, wallet.syncing()); + View::animate_text(ui, height_text, 15.0, Colors::gray(), wallet.syncing()); }) }); }); @@ -261,7 +263,7 @@ impl WalletContent { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.new_account_desc")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); ui.add_space(8.0); // Draw account name edit. @@ -274,7 +276,7 @@ impl WalletContent { ui.add_space(12.0); ui.label(RichText::new(t!("error")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } ui.add_space(12.0); }); @@ -285,7 +287,7 @@ impl WalletContent { // Show modal buttons. ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. cb.hide_keyboard(); modal.close(); @@ -311,7 +313,7 @@ impl WalletContent { (on_create)(); }); - View::button(ui, t!("create"), Colors::WHITE, on_create); + View::button(ui, t!("create"), Colors::white_or_black(false), on_create); }); }); ui.add_space(6.0); @@ -340,7 +342,7 @@ impl WalletContent { }); ui.add_space(2.0); - View::horizontal_line(ui, Colors::STROKE); + View::horizontal_line(ui, Colors::stroke()); ui.add_space(6.0); // Setup spacing between buttons. @@ -349,12 +351,12 @@ impl WalletContent { // Show modal buttons. ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("create"), Colors::WHITE, || { + View::button(ui, t!("create"), Colors::white_or_black(false), || { self.account_creating = true; cb.show_keyboard(); }); @@ -373,7 +375,7 @@ impl WalletContent { // Show scan result if exists or show camera content while scanning. if let Some(result) = &self.qr_scan_result { let mut result_text = result.text(); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(3.0); ScrollArea::vertical() .id_source(Id::from("qr_scan_result_input").with(wallet.get_config().id)) @@ -391,20 +393,20 @@ impl WalletContent { ui.add_space(6.0); }); ui.add_space(2.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show copy button. ui.vertical_centered(|ui| { let copy_text = format!("{} {}", COPY, t!("copy")); - View::button(ui, copy_text, Colors::BUTTON, || { + View::button(ui, copy_text, Colors::button(), || { cb.copy_string_to_buffer(result_text.to_string()); self.qr_scan_result = None; modal.close(); }); }); ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); } else if let Some(result) = self.camera_content.qr_scan_result() { cb.stop_camera(); @@ -448,13 +450,13 @@ impl WalletContent { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.qr_scan_result = None; modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("repeat"), Colors::WHITE, || { + View::button(ui, t!("repeat"), Colors::white_or_black(false), || { Modal::set_title(t!("scan_qr")); self.qr_scan_result = None; cb.start_camera(); @@ -463,7 +465,7 @@ impl WalletContent { }); } else { ui.vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { cb.stop_camera(); modal.close(); }); @@ -524,7 +526,7 @@ impl WalletContent { View::center_content(ui, 108.0, |ui| { View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.5, |ui| { let text = t!("wallets.enable_node", "settings" => GEAR_FINE); - ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT)); + ui.label(RichText::new(text).size(16.0).color(Colors::inactive_text())); ui.add_space(8.0); // Show button to enable integrated node at non-dual root panel mode // or when network connections are not showing and node is not stopping @@ -532,7 +534,7 @@ impl WalletContent { if (!dual_panel_root || AppConfig::show_connections_network_panel()) && !Node::is_stopping() { let enable_text = format!("{} {}", POWER, t!("network.enable_node")); - View::button(ui, enable_text, Colors::GOLD, || { + View::action_button(ui, enable_text, || { Node::start(); }); } @@ -561,10 +563,10 @@ impl WalletContent { fn sync_error_ui(ui: &mut egui::Ui, wallet: &Wallet) { View::center_content(ui, 108.0, |ui| { let text = t!("wallets.wallet_loading_err", "settings" => GEAR_FINE); - ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT)); + ui.label(RichText::new(text).size(16.0).color(Colors::inactive_text())); ui.add_space(8.0); let retry_text = format!("{} {}", ARROWS_CLOCKWISE, t!("retry")); - View::button(ui, retry_text, Colors::GOLD, || { + View::action_button(ui, retry_text, || { wallet.set_sync_error(false); }); }); @@ -620,7 +622,7 @@ impl WalletContent { } } }; - ui.label(RichText::new(text).size(16.0).color(Colors::INACTIVE_TEXT)); + ui.label(RichText::new(text).size(16.0).color(Colors::inactive_text())); }); }); } @@ -642,7 +644,7 @@ fn account_item_ui(ui: &mut egui::Ui, // Draw round background. let bg_rect = rect.clone(); let item_rounding = View::item_rounding(index, size, false); - ui.painter().rect(bg_rect, item_rounding, Colors::FILL, View::ITEM_STROKE); + 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| { @@ -656,7 +658,7 @@ fn account_item_ui(ui: &mut egui::Ui, }); } else { ui.add_space(12.0); - ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::GREEN)); + ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::green())); } let layout_size = ui.available_size(); @@ -667,7 +669,7 @@ fn account_item_ui(ui: &mut egui::Ui, // Show spendable amount. let amount = amount_to_hr_string(acc.spendable_amount, true); let amount_text = format!("{} {}", amount, GRIN); - ui.label(RichText::new(amount_text).size(18.0).color(Colors::BLACK)); + ui.label(RichText::new(amount_text).size(18.0).color(Colors::white_or_black(true))); ui.add_space(-2.0); // Show account name. @@ -678,11 +680,11 @@ fn account_item_ui(ui: &mut egui::Ui, acc.label.to_owned() }; let acc_name = format!("{} {}", FOLDER_USER, acc_label); - View::ellipsize_text(ui, acc_name, 15.0, Colors::TEXT); + View::ellipsize_text(ui, acc_name, 15.0, Colors::text(false)); // Show account BIP32 derivation path. let acc_path = format!("{} {}", PATH, acc.path); - ui.label(RichText::new(acc_path).size(15.0).color(Colors::GRAY)); + ui.label(RichText::new(acc_path).size(15.0).color(Colors::gray())); ui.add_space(3.0); }); }); diff --git a/src/gui/views/wallets/wallet/messages.rs b/src/gui/views/wallets/wallet/messages.rs index df13c05..e9b7141 100644 --- a/src/gui/views/wallets/wallet/messages.rs +++ b/src/gui/views/wallets/wallet/messages.rs @@ -127,11 +127,10 @@ impl WalletTab for WalletMessages { // Show modal content for this ui container. self.modal_content_ui(ui, wallet, cb); - // Show manual wallet content panel. egui::CentralPanel::default() .frame(egui::Frame { - stroke: View::ITEM_STROKE, - fill: Colors::WHITE, + stroke: View::item_stroke(), + fill: Colors::white_or_black(false), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 4.0, right: View::get_right_inset() + 4.0, @@ -194,7 +193,7 @@ impl WalletMessages { self.request_ui(ui, wallet, cb); ui.add_space(12.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show Slatepack message input field. @@ -240,7 +239,7 @@ impl WalletMessages { cb: &dyn PlatformCallbacks) { ui.label(RichText::new(t!("wallets.create_request_desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); ui.add_space(7.0); // Show send button only if balance is not empty. @@ -253,7 +252,7 @@ impl WalletMessages { columns[0].vertical_centered_justified(|ui| { // Draw sending request creation button. let send_text = format!("{} {}", UPLOAD_SIMPLE, t!("wallets.send")); - View::colored_text_button(ui, send_text, Colors::RED, Colors::BUTTON, || { + View::colored_text_button(ui, send_text, Colors::red(), Colors::button(), || { self.show_request_modal(false, cb); }); }); @@ -271,7 +270,7 @@ impl WalletMessages { /// Draw invoice request creation button. fn receive_button_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { let receive_text = format!("{} {}", DOWNLOAD_SIMPLE, t!("wallets.receive")); - View::colored_text_button(ui, receive_text, Colors::GREEN, Colors::BUTTON, || { + View::colored_text_button(ui, receive_text, Colors::green(), Colors::button(), || { self.show_request_modal(true, cb); }); } @@ -358,7 +357,7 @@ impl WalletMessages { }; ui.label(RichText::new(enter_text) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); }); ui.add_space(8.0); @@ -412,7 +411,7 @@ impl WalletMessages { ui.vertical_centered(|ui| { ui.label(RichText::new(self.request_error.clone().unwrap().text()) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); }); } @@ -423,7 +422,7 @@ impl WalletMessages { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { self.request_amount_edit = "".to_string(); self.request_error = None; cb.hide_keyboard(); @@ -432,7 +431,7 @@ impl WalletMessages { }); columns[1].vertical_centered_justified(|ui| { // Button to create Slatepack message request. - View::button(ui, t!("continue"), Colors::WHITE, || { + View::button(ui, t!("continue"), Colors::white_or_black(false), || { if self.request_amount_edit.is_empty() { return; } @@ -472,7 +471,7 @@ impl WalletMessages { } else { t!("wallets.send_request_desc","amount" => amount_format) }; - ui.label(RichText::new(desc_text).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(desc_text).size(16.0).color(Colors::gray())); }); ui.add_space(6.0); @@ -488,7 +487,7 @@ impl WalletMessages { // Show button to close modal. ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.request_qr_content.clear_state(); self.request_qr = false; modal.close(); @@ -498,7 +497,7 @@ impl WalletMessages { return; } - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(3.0); // Draw request Slatepack message text. @@ -526,7 +525,7 @@ impl WalletMessages { ui.add_space(6.0); }); ui.add_space(2.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(10.0); @@ -538,14 +537,14 @@ impl WalletMessages { columns[0].vertical_centered_justified(|ui| { // Draw button to show request as QR code. let qr_text = format!("{} {}", QR_CODE, t!("qr_code")); - View::button(ui, qr_text, Colors::BUTTON, || { + View::button(ui, qr_text, Colors::button(), || { self.request_qr = true; }); }); columns[1].vertical_centered_justified(|ui| { // Draw button to copy request to clipboard. let copy_text = format!("{} {}", COPY, t!("copy")); - View::button(ui, copy_text, Colors::BUTTON, || { + View::button(ui, copy_text, Colors::button(), || { cb.copy_string_to_buffer(self.request_edit.clone()); self.request_amount_edit = "".to_string(); self.request_edit = "".to_string(); @@ -560,7 +559,7 @@ impl WalletMessages { columns[0].vertical_centered_justified(|ui| { // Draw button to cancel transaction. let cancel = t!("modal.cancel"); - View::colored_text_button(ui, cancel, Colors::RED, Colors::BUTTON, || { + View::colored_text_button(ui, cancel, Colors::red(), Colors::button(), || { if let Ok(slate) = wallet.parse_slatepack(&self.request_edit) { if let Some(tx) = wallet.tx_by_slate(&slate) { wallet.cancel(tx.data.id); @@ -574,7 +573,7 @@ impl WalletMessages { }); columns[1].vertical_centered_justified(|ui| { // Draw button to close modal. - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.request_amount_edit = "".to_string(); self.request_edit = "".to_string(); modal.close(); @@ -595,7 +594,7 @@ impl WalletMessages { let empty_fields = self.message_edit.is_empty() && self.request_edit.is_empty(); let response_empty = self.response_edit.is_empty(); if let Some(err) = &self.message_error { - ui.label(RichText::new(err.text()).size(16.0).color(Colors::RED)); + ui.label(RichText::new(err.text()).size(16.0).color(Colors::red())); } else { let desc_text = if self.message_slate.is_none() || empty_fields { t!("wallets.input_slatepack_desc") @@ -626,7 +625,7 @@ impl WalletMessages { } } }; - ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT)); + ui.label(RichText::new(desc_text).size(16.0).color(Colors::inactive_text())); } ui.add_space(6.0); @@ -640,7 +639,7 @@ impl WalletMessages { // Save message to check for changes. let message_before = message.clone(); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(3.0); let scroll_id = Id::from( if response_empty { @@ -676,7 +675,7 @@ impl WalletMessages { ui.add_space(6.0); }); ui.add_space(2.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(10.0); // Parse Slatepack message if input field was changed, resetting message error. @@ -697,7 +696,7 @@ impl WalletMessages { if self.response_edit.is_empty() { // Draw button to clear message input. let clear_text = format!("{} {}", BROOM, t!("clear")); - View::button(ui, clear_text, Colors::BUTTON, || { + View::button(ui, clear_text, Colors::button(), || { self.message_edit.clear(); self.response_edit.clear(); self.message_error = None; @@ -706,7 +705,7 @@ impl WalletMessages { } else { // Draw button to show Slatepack message as QR code. let qr_text = format!("{} {}", QR_CODE, t!("qr_code")); - View::button(ui, qr_text, Colors::BUTTON, || { + View::button(ui, qr_text, Colors::button(), || { let text = self.response_edit.clone(); self.message_edit.clear(); self.response_edit.clear(); @@ -721,7 +720,7 @@ impl WalletMessages { } else { // Draw button to scan Slatepack message QR code. let scan_text = format!("{} {}", SCAN, t!("scan")); - View::button(ui, scan_text, Colors::BUTTON, || { + View::button(ui, scan_text, Colors::button(), || { self.message_edit.clear(); self.message_error = None; self.show_qr_message_scan_modal(cb); @@ -738,7 +737,7 @@ impl WalletMessages { if !self.response_edit.is_empty() { // Draw button to copy response to clipboard. let copy_text = format!("{} {}", COPY, t!("copy")); - View::button(ui, copy_text, Colors::BUTTON, || { + View::button(ui, copy_text, Colors::button(), || { cb.copy_string_to_buffer(self.response_edit.clone()); self.message_edit.clear(); self.response_edit.clear(); @@ -747,7 +746,7 @@ impl WalletMessages { } else { show_dandelion = true; // Draw button to finalize or repost transaction. - View::button(ui, t!("wallets.finalize"), Colors::GOLD, || { + View::action_button(ui, t!("wallets.finalize"), || { let slate = self.message_slate.clone().unwrap(); self.message_slate = None; let dandelion = self.dandelion; @@ -779,7 +778,7 @@ impl WalletMessages { } else { // Draw button to paste text from clipboard. let paste = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); - View::button(ui, paste, Colors::BUTTON, || { + View::button(ui, paste, Colors::button(), || { let buf = cb.get_string_from_buffer(); let previous = self.message_edit.clone(); self.message_edit = buf.clone().trim().to_string(); @@ -800,7 +799,7 @@ impl WalletMessages { if self.message_slate.is_none() && !self.message_edit.is_empty() { // Draw button to clear message input. let clear_text = format!("{} {}", BROOM, t!("clear")); - View::button(ui, clear_text, Colors::BUTTON, || { + View::button(ui, clear_text, Colors::button(), || { self.message_edit.clear(); self.response_edit.clear(); self.message_error = None; @@ -809,7 +808,7 @@ impl WalletMessages { } else if !self.response_edit.is_empty() && self.message_slate.is_some() { // Draw cancel button. let cancel = format!("{} {}", PROHIBIT, t!("modal.cancel")); - View::colored_text_button(ui, cancel, Colors::RED, Colors::BUTTON, || { + View::colored_text_button(ui, cancel, Colors::red(), Colors::button(), || { let slate = self.message_slate.clone().unwrap(); if let Some(tx) = wallet.tx_by_slate(&slate) { wallet.cancel(tx.data.id); @@ -861,7 +860,7 @@ impl WalletMessages { } else { t!("wallets.parse_i1_slatepack_desc","amount" => amount) }; - ui.label(RichText::new(title).size(16.0).color(Colors::INACTIVE_TEXT)); + ui.label(RichText::new(title).size(16.0).color(Colors::inactive_text())); }); ui.add_space(6.0); @@ -871,7 +870,7 @@ impl WalletMessages { ui.add_space(6.0); ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.qr_message_text = None; self.qr_message_content.clear_state(); self.response_edit.clear(); @@ -906,7 +905,7 @@ impl WalletMessages { let err_text = format!("{}", t!("wallets.parse_slatepack_err")).replace(":", "."); ui.label(RichText::new(err_text) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); }); ui.add_space(12.0); @@ -915,13 +914,13 @@ impl WalletMessages { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.message_scan_error = false; modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("repeat"), Colors::WHITE, || { + View::button(ui, t!("repeat"), Colors::white_or_black(false), || { Modal::set_title(t!("scan_qr")); self.message_scan_error = false; cb.start_camera(); @@ -950,7 +949,7 @@ impl WalletMessages { } ui.vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { cb.stop_camera(); modal.close(); }); diff --git a/src/gui/views/wallets/wallet/settings.rs b/src/gui/views/wallets/wallet/settings.rs index cddf7d1..c4db907 100644 --- a/src/gui/views/wallets/wallet/settings.rs +++ b/src/gui/views/wallets/wallet/settings.rs @@ -64,8 +64,8 @@ impl WalletTab for WalletSettings { // Show settings content panel. egui::CentralPanel::default() .frame(egui::Frame { - stroke: View::DEFAULT_STROKE, - fill: Colors::WHITE, + stroke: View::default_stroke(), + fill: Colors::white_or_black(false), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 4.0, right: View::get_right_inset() + 4.0, diff --git a/src/gui/views/wallets/wallet/transport.rs b/src/gui/views/wallets/wallet/transport.rs index d748fc6..c205df5 100644 --- a/src/gui/views/wallets/wallet/transport.rs +++ b/src/gui/views/wallets/wallet/transport.rs @@ -90,8 +90,8 @@ impl WalletTab for WalletTransport { // Show transport content panel. egui::CentralPanel::default() .frame(egui::Frame { - stroke: View::ITEM_STROKE, - fill: Colors::WHITE, + stroke: View::item_stroke(), + fill: Colors::white_or_black(false), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 4.0, right: View::get_right_inset() + 4.0, @@ -159,7 +159,7 @@ impl WalletTransport { ui.add_space(3.0); ui.label(RichText::new(t!("transport.desc")) .size(16.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); ui.add_space(7.0); // Draw Tor content. @@ -223,7 +223,7 @@ impl WalletTransport { // Draw round background. let bg_rect = rect.clone(); let item_rounding = View::item_rounding(0, 2, false); - ui.painter().rect(bg_rect, item_rounding, Colors::BUTTON, View::ITEM_STROKE); + ui.painter().rect(bg_rect, item_rounding, Colors::button(), View::item_stroke()); ui.vertical(|ui| { ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { @@ -237,14 +237,14 @@ impl WalletTransport { let service_id = &wallet.identifier(); if !Tor::is_service_starting(service_id) && wallet.foreign_api_port().is_some() { if !Tor::is_service_running(service_id) { - View::item_button(ui, Rounding::default(), POWER, Some(Colors::GREEN), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::green()), || { if let Ok(key) = wallet.secret_key() { let api_port = wallet.foreign_api_port().unwrap(); Tor::start_service(api_port, key, service_id); } }); } else { - View::item_button(ui, Rounding::default(), POWER, Some(Colors::RED), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::red()), || { Tor::stop_service(service_id); }); } @@ -257,7 +257,7 @@ impl WalletTransport { ui.add_space(3.0); ui.label(RichText::new(t!("transport.tor_network")) .size(18.0) - .color(Colors::TITLE)); + .color(Colors::title(false))); // Setup bridges status text. let bridge = TorConfig::get_bridge(); @@ -272,7 +272,7 @@ impl WalletTransport { t!("transport.bridge_name", "b" = name)) } }; - ui.label(RichText::new(bridges_text).size(15.0).color(Colors::TEXT)); + ui.label(RichText::new(bridges_text).size(15.0).color(Colors::text(false))); ui.add_space(1.0); // Setup Tor status text. @@ -291,7 +291,7 @@ impl WalletTransport { (X_CIRCLE, t!("transport.disconnected")) }; let status_text = format!("{} {}", icon, text); - ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY)); + ui.label(RichText::new(status_text).size(15.0).color(Colors::gray())); }); }); }); @@ -340,13 +340,13 @@ impl WalletTransport { // Show buttons to close modal or come back to sending input. ui.columns(2, |cols| { cols[0].vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { on_stop(&mut self.bridge_qr_scan_content); modal.close(); }); }); cols[1].vertical_centered_justified(|ui| { - View::button(ui, t!("back"), Colors::WHITE, || { + View::button(ui, t!("back"), Colors::white_or_black(false), || { on_stop(&mut self.bridge_qr_scan_content); }); }); @@ -364,7 +364,7 @@ impl WalletTransport { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("transport.bridges_desc")) .size(17.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); // Draw checkbox to enable/disable bridges. View::checkbox(ui, bridge.is_some(), t!("transport.bridges"), || { @@ -423,7 +423,7 @@ impl WalletTransport { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("transport.bin_file")) .size(17.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); ui.add_space(6.0); View::text_edit(ui, cb, &mut self.bridge_bin_path_edit, &mut bin_edit_opts); ui.add_space(6.0); @@ -441,7 +441,7 @@ impl WalletTransport { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("transport.conn_line")) .size(17.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); ui.add_space(6.0); View::text_edit(ui, cb, &mut self.bridge_conn_line_edit, &mut conn_edit_opts); // Check if scan button was pressed. @@ -474,14 +474,14 @@ impl WalletTransport { } ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); } ui.vertical_centered(|ui| { ui.label(RichText::new(t!("transport.tor_autorun_desc")) .size(17.0) - .color(Colors::INACTIVE_TEXT)); + .color(Colors::inactive_text())); // Show Tor service autorun checkbox. let autorun = wallet.auto_start_tor_listener(); @@ -491,7 +491,7 @@ impl WalletTransport { }); ui.add_space(6.0); ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { if self.tor_settings_changed { self.tor_settings_changed = false; // Restart running service or rebuild client. @@ -532,7 +532,7 @@ impl WalletTransport { } else { View::item_rounding(1, 2, false) }; - ui.painter().rect(bg_rect, item_rounding, Colors::BUTTON, View::ITEM_STROKE); + ui.painter().rect(bg_rect, item_rounding, Colors::button(), View::item_stroke()); ui.vertical(|ui| { ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { @@ -565,18 +565,18 @@ impl WalletTransport { // Show wallet Slatepack address. let address_color = if Tor::is_service_starting(service_id) || wallet.foreign_api_port().is_none() { - Colors::INACTIVE_TEXT + Colors::inactive_text() } else if Tor::is_service_running(service_id) { - Colors::GREEN + Colors::green() } else { - Colors::RED + Colors::red() }; View::ellipsize_text(ui, slatepack_addr, 15.0, address_color); let address_label = format!("{} {}", GLOBE_SIMPLE, t!("network_mining.address")); - ui.label(RichText::new(address_label).size(15.0).color(Colors::GRAY)); + ui.label(RichText::new(address_label).size(15.0).color(Colors::gray())); }); }); }); @@ -593,7 +593,7 @@ impl WalletTransport { ui.add_space(10.0); ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.qr_address_content.clear_state(); m.close(); }); @@ -610,14 +610,14 @@ impl WalletTransport { // Draw round background. let bg_rect = rect.clone(); let item_rounding = View::item_rounding(1, 2, false); - ui.painter().rect(bg_rect, item_rounding, Colors::FILL, View::ITEM_STROKE); + ui.painter().rect(bg_rect, item_rounding, Colors::fill(), View::item_stroke()); ui.vertical(|ui| { ui.allocate_ui_with_layout(rect.size(), Layout::top_down(Align::Center), |ui| { ui.add_space(7.0); // Draw button to open sending modal. let send_text = format!("{} {}", EXPORT, t!("wallets.send")); - View::button(ui, send_text, Colors::WHITE, || { + View::button(ui, send_text, Colors::white_or_black(false), || { self.show_send_tor_modal(cb, None); }); }); @@ -699,13 +699,13 @@ impl WalletTransport { // Show buttons to close modal or come back to sending input. ui.columns(2, |cols| { cols[0].vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { on_stop(&mut self.address_scan_content); modal.close(); }); }); cols[1].vertical_centered_justified(|ui| { - View::button(ui, t!("back"), Colors::WHITE, || { + View::button(ui, t!("back"), Colors::white_or_black(false), || { self.modal_just_opened = true; on_stop(&mut self.address_scan_content); cb.show_keyboard(); @@ -723,7 +723,7 @@ impl WalletTransport { let enter_text = t!("wallets.enter_amount_send","amount" => amount); ui.label(RichText::new(enter_text) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); }); ui.add_space(8.0); @@ -778,11 +778,11 @@ impl WalletTransport { if self.address_error { ui.label(RichText::new(t!("transport.incorrect_addr_err")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); } else { ui.label(RichText::new(t!("transport.receiver_address")) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); } }); ui.add_space(6.0); @@ -814,7 +814,7 @@ impl WalletTransport { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { self.amount_edit = "".to_string(); self.address_edit = "".to_string(); cb.hide_keyboard(); @@ -822,7 +822,7 @@ impl WalletTransport { }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("continue"), Colors::WHITE, || { + View::button(ui, t!("continue"), Colors::white_or_black(false), || { if self.amount_edit.is_empty() { return; } @@ -869,7 +869,7 @@ impl WalletTransport { ui.vertical_centered(|ui| { ui.label(RichText::new(t!("transport.tor_send_error")) .size(17.0) - .color(Colors::RED)); + .color(Colors::red())); }); ui.add_space(12.0); @@ -878,7 +878,7 @@ impl WalletTransport { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { self.amount_edit = "".to_string(); self.address_edit = "".to_string(); cb.hide_keyboard(); @@ -886,7 +886,7 @@ impl WalletTransport { }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("repeat"), Colors::WHITE, || { + View::button(ui, t!("repeat"), Colors::white_or_black(false), || { // Parse amount and send over Tor. if let Ok(a) = amount_from_hr_string(self.amount_edit.as_str()) { let mut w_send_error = self.tor_send_error.write(); @@ -929,7 +929,7 @@ impl WalletTransport { ui.add_space(12.0); ui.label(RichText::new(t!("transport.tor_sending", "amount" => self.amount_edit)) .size(17.0) - .color(Colors::GRAY)); + .color(Colors::gray())); }); ui.add_space(10.0); diff --git a/src/gui/views/wallets/wallet/txs.rs b/src/gui/views/wallets/wallet/txs.rs index 8b5e5a6..289f48c 100644 --- a/src/gui/views/wallets/wallet/txs.rs +++ b/src/gui/views/wallets/wallet/txs.rs @@ -109,8 +109,8 @@ impl WalletTab for WalletTransactions { // Show wallet transactions panel. egui::CentralPanel::default() .frame(egui::Frame { - stroke: View::ITEM_STROKE, - fill: Colors::BUTTON, + stroke: View::item_stroke(), + fill: Colors::button(), inner_margin: Margin { left: View::far_left_inset_margin(ui) + 4.0, right: View::get_right_inset() + 4.0, @@ -196,7 +196,7 @@ impl WalletTransactions { "transport" => BRIDGE, "settings" => GEAR_FINE ); - ui.label(RichText::new(empty_text).size(16.0).color(Colors::INACTIVE_TEXT)); + ui.label(RichText::new(empty_text).size(16.0).color(Colors::inactive_text())); }); return; } @@ -302,11 +302,11 @@ impl WalletTransactions { // Draw round background. let bg_rect = rect.clone(); let color = if can_show_info { - Colors::BUTTON + Colors::button() } else { - Colors::FILL + Colors::fill() }; - ui.painter().rect(bg_rect, rounding, color, View::ITEM_STROKE); + ui.painter().rect(bg_rect, rounding, color, View::item_stroke()); ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { // Draw button to show transaction info. @@ -326,7 +326,7 @@ impl WalletTransactions { let (icon, color) = if !can_show_info && self.tx_info_finalize { (FILE_TEXT, None) } else { - (CHECK, Some(Colors::GREEN)) + (CHECK, Some(Colors::green())) }; let final_rounding = if can_show_info { Rounding::default() @@ -352,7 +352,7 @@ impl WalletTransactions { let wallet_loaded = wallet.foreign_api_port().is_some(); if ((!can_show_info && !self.tx_info_finalizing) || can_show_info) && (tx.can_repost(data) || tx.can_cancel()) && wallet_loaded { - View::item_button(ui, Rounding::default(), PROHIBIT, Some(Colors::RED), || { + View::item_button(ui, Rounding::default(), PROHIBIT, Some(Colors::red()), || { if can_show_info { self.confirm_cancel_tx_id = Some(tx.data.id); // Show transaction cancellation confirmation modal. @@ -376,7 +376,7 @@ impl WalletTransactions { rounding.sw = 0.0; rounding }; - View::item_button(ui, repost_rounding, ARROW_CLOCKWISE, Some(Colors::GREEN), || { + View::item_button(ui, repost_rounding, ARROW_CLOCKWISE, Some(Colors::green()), || { // Post tx after getting slate from slatepack file. if let Some((s, _)) = wallet.read_slate_by_tx(tx) { let _ = wallet.post(&s, wallet.can_use_dandelion()); @@ -407,12 +407,12 @@ impl WalletTransactions { // Setup amount color. let amount_color = match tx.data.tx_type { - TxLogEntryType::ConfirmedCoinbase => Colors::BLACK, - TxLogEntryType::TxReceived => Colors::BLACK, - TxLogEntryType::TxSent => Colors::BLACK, - TxLogEntryType::TxReceivedCancelled => Colors::TEXT, - TxLogEntryType::TxSentCancelled => Colors::TEXT, - TxLogEntryType::TxReverted => Colors::TEXT + TxLogEntryType::ConfirmedCoinbase => Colors::white_or_black(true), + TxLogEntryType::TxReceived => Colors::white_or_black(true), + TxLogEntryType::TxSent => Colors::white_or_black(true), + TxLogEntryType::TxReceivedCancelled => Colors::text(false), + TxLogEntryType::TxSentCancelled => Colors::text(false), + TxLogEntryType::TxReverted => Colors::text(false) }; View::ellipsize_text(ui, amount_text, 18.0, amount_color); ui.add_space(-2.0); @@ -484,27 +484,27 @@ impl WalletTransactions { // Setup status text color. let status_color = match tx.data.tx_type { - TxLogEntryType::ConfirmedCoinbase => Colors::TEXT, + TxLogEntryType::ConfirmedCoinbase => Colors::text(false), TxLogEntryType::TxReceived => if tx.data.confirmed { - Colors::GREEN + Colors::green() } else { - Colors::TEXT + Colors::text(false) }, TxLogEntryType::TxSent => if tx.data.confirmed { - Colors::RED + Colors::red() } else { - Colors::TEXT + Colors::text(false) }, - TxLogEntryType::TxReceivedCancelled => Colors::INACTIVE_TEXT, - TxLogEntryType::TxSentCancelled => Colors::INACTIVE_TEXT, - TxLogEntryType::TxReverted => Colors::INACTIVE_TEXT, + TxLogEntryType::TxReceivedCancelled => Colors::inactive_text(), + TxLogEntryType::TxSentCancelled => Colors::inactive_text(), + TxLogEntryType::TxReverted => Colors::inactive_text(), }; ui.label(RichText::new(status_text).size(15.0).color(status_color)); // Setup transaction time. let tx_time = View::format_time(tx.data.creation_ts.timestamp()); let tx_time_text = format!("{} {}", CALENDAR_CHECK, tx_time); - ui.label(RichText::new(tx_time_text).size(15.0).color(Colors::GRAY)); + ui.label(RichText::new(tx_time_text).size(15.0).color(Colors::gray())); ui.add_space(3.0); }); }); @@ -570,14 +570,14 @@ impl WalletTransactions { // Show buttons to close modal or come back to text request content. ui.columns(2, |cols| { cols[0].vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.tx_info_qr_code_content.clear_state(); self.tx_info_show_qr = false; modal.close(); }); }); cols[1].vertical_centered_justified(|ui| { - View::button(ui, t!("back"), Colors::WHITE, || { + View::button(ui, t!("back"), Colors::white_or_black(false), || { self.tx_info_qr_code_content.clear_state(); self.tx_info_show_qr = false; }); @@ -587,14 +587,14 @@ impl WalletTransactions { // Show buttons to close modal or scanner. ui.columns(2, |cols| { cols[0].vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { cb.stop_camera(); self.tx_info_show_scanner = false; modal.close(); }); }); cols[1].vertical_centered_justified(|ui| { - View::button(ui, t!("back"), Colors::WHITE, || { + View::button(ui, t!("back"), Colors::white_or_black(false), || { cb.stop_camera(); self.tx_info_show_scanner = false; modal.enable_closing(); @@ -604,7 +604,7 @@ impl WalletTransactions { } else { // Show button to close modal. ui.vertical_centered_justified(|ui| { - View::button(ui, t!("close"), Colors::WHITE, || { + View::button(ui, t!("close"), Colors::white_or_black(false), || { self.tx_info_id = None; self.tx_info_finalize = false; cb.hide_keyboard(); @@ -660,7 +660,7 @@ impl WalletTransactions { let bg_rect = rect.clone(); let mut rounding = View::item_rounding(1, 3, false); - ui.painter().rect(bg_rect, rounding, Colors::FILL, View::ITEM_STROKE); + ui.painter().rect(bg_rect, rounding, Colors::fill(), View::item_stroke()); ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { // Draw button to copy transaction info value. @@ -678,8 +678,8 @@ impl WalletTransactions { ui.add_space(6.0); ui.vertical(|ui| { ui.add_space(3.0); - View::ellipsize_text(ui, value, 15.0, Colors::TITLE); - ui.label(RichText::new(label).size(15.0).color(Colors::GRAY)); + View::ellipsize_text(ui, value, 15.0, Colors::title(false)); + ui.label(RichText::new(label).size(15.0).color(Colors::gray())); ui.add_space(3.0); }); }); @@ -734,9 +734,9 @@ impl WalletTransactions { } }; let desc_color = if self.tx_info_finalize_error { - Colors::RED + Colors::red() } else { - Colors::GRAY + Colors::gray() }; ui.label(RichText::new(desc_text).size(16.0).color(desc_color)); } else { @@ -753,7 +753,7 @@ impl WalletTransactions { t!("wallets.parse_s1_slatepack_desc", "amount" => amount) } }; - ui.label(RichText::new(desc_text).size(16.0).color(Colors::GRAY)); + ui.label(RichText::new(desc_text).size(16.0).color(Colors::gray())); } }); ui.add_space(6.0); @@ -785,7 +785,7 @@ impl WalletTransactions { } else { Id::from("tx_info_message_request") }.with(slate.id).with(tx.data.id); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(3.0); ScrollArea::vertical() .id_source(input_id) @@ -806,7 +806,7 @@ impl WalletTransactions { }); ui.add_space(2.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); + View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(8.0); // Do not show buttons on finalization. @@ -822,7 +822,7 @@ impl WalletTransactions { columns[0].vertical_centered_justified(|ui| { // Draw button to scan Slatepack message QR code. let qr_text = format!("{} {}", SCAN, t!("scan")); - View::button(ui, qr_text, Colors::BUTTON, || { + View::button(ui, qr_text, Colors::button(), || { cb.hide_keyboard(); modal.disable_closing(); cb.start_camera(); @@ -832,7 +832,7 @@ impl WalletTransactions { columns[1].vertical_centered_justified(|ui| { // Draw button to paste data from clipboard. let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); - View::button(ui, paste_text, Colors::BUTTON, || { + View::button(ui, paste_text, Colors::button(), || { self.tx_info_finalize_edit = cb.get_string_from_buffer(); }); // Callback on finalization message input change. @@ -846,7 +846,7 @@ impl WalletTransactions { columns[0].vertical_centered_justified(|ui| { // Draw button to show Slatepack message as QR code. let qr_text = format!("{} {}", QR_CODE, t!("qr_code")); - View::button(ui, qr_text, Colors::BUTTON, || { + View::button(ui, qr_text, Colors::button(), || { cb.hide_keyboard(); self.tx_info_show_qr = true; }); @@ -854,7 +854,7 @@ impl WalletTransactions { columns[1].vertical_centered_justified(|ui| { // Draw copy button. let copy_text = format!("{} {}", COPY, t!("copy")); - View::button(ui, copy_text, Colors::BUTTON, || { + View::button(ui, copy_text, Colors::button(), || { cb.copy_string_to_buffer(self.tx_info_response_edit.clone()); self.tx_info_finalize_edit = "".to_string(); if tx.can_finalize { @@ -932,7 +932,7 @@ impl WalletTransactions { }; ui.label(RichText::new(text) .size(17.0) - .color(Colors::TEXT)); + .color(Colors::text(false))); ui.add_space(8.0); }); @@ -943,13 +943,13 @@ impl WalletTransactions { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { self.confirm_cancel_tx_id = None; modal.close(); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, "OK".to_string(), Colors::WHITE, || { + View::button(ui, "OK".to_string(), Colors::white_or_black(false), || { wallet.cancel(self.confirm_cancel_tx_id.unwrap()); self.confirm_cancel_tx_id = None; modal.close(); diff --git a/src/lib.rs b/src/lib.rs index 02c05e7..6640af8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,10 +41,10 @@ pub mod built_info { include!(concat!(env!("OUT_DIR"), "/built.rs")); } +/// Android platform entry point. #[allow(dead_code)] #[cfg(target_os = "android")] #[no_mangle] -/// Android platform entry point. fn android_main(app: AndroidApp) { #[cfg(debug_assertions)] { @@ -59,6 +59,12 @@ fn android_main(app: AndroidApp) { let platform = Android::new(app.clone()); use winit::platform::android::EventLoopBuilderExtAndroid; + // Setup system theme if not set. + if let None = AppConfig::dark_theme() { + let use_dark = system_dark_theme(&platform); + AppConfig::set_dark_theme(use_dark); + } + let width = app.config().screen_width_dp().unwrap() as f32; let height = app.config().screen_height_dp().unwrap() as f32; let size = egui::emath::vec2(width, height); @@ -82,7 +88,16 @@ fn android_main(app: AndroidApp) { builder.with_android_app(app); })); - start(options, app_creator(PlatformApp::new(platform))); + let app = PlatformApp::new(platform); + start(options, app_creator(app)); +} + +/// Check if system is using dark theme. +#[allow(dead_code)] +#[cfg(target_os = "android")] +fn system_dark_theme(platform: &gui::platform::Android) -> bool { + let res = platform.call_java_method("useDarkTheme", "()Z", &[]).unwrap(); + unsafe { res.z != 0 } } /// [`PlatformApp`] setup for [`eframe`]. @@ -132,17 +147,27 @@ pub fn setup_visuals(ctx: &Context) { // Setup style ctx.set_style(style); - let mut visuals = egui::Visuals::light(); + // Setup visuals based on app color theme. + let use_dark = AppConfig::dark_theme().unwrap_or(false); + let mut visuals = if use_dark { + egui::Visuals::dark() + } else { + egui::Visuals::light() + }; // Setup selection color. - visuals.selection.stroke = Stroke { width: 1.0, color: Colors::TEXT }; - visuals.selection.bg_fill = Colors::GOLD; + visuals.selection.stroke = Stroke { width: 1.0, color: Colors::text(false) }; + visuals.selection.bg_fill = Colors::gold(); // Disable stroke around panels by default. visuals.widgets.noninteractive.bg_stroke = Stroke::NONE; // Setup stroke around inactive widgets. - visuals.widgets.inactive.bg_stroke = View::DEFAULT_STROKE; + visuals.widgets.inactive.bg_stroke = View::default_stroke(); // Setup background and foreground stroke color for widgets like pull-to-refresher. - visuals.widgets.inactive.bg_fill = Colors::YELLOW; - visuals.widgets.inactive.fg_stroke.color = Colors::ITEM_BUTTON; + visuals.widgets.inactive.bg_fill = if use_dark { + Colors::white_or_black(false) + } else { + Colors::yellow() + }; + visuals.widgets.inactive.fg_stroke.color = Colors::item_button(); // Setup visuals ctx.set_visuals(visuals); } diff --git a/src/main.rs b/src/main.rs index 6dab82b..1bc200a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use dark_light::Mode; + pub fn main() { #[allow(dead_code)] #[cfg(not(target_os = "android"))] @@ -36,7 +38,17 @@ fn real_main() { let platform = Desktop::default(); - // Desktop window size. + // Setup system theme if not set. + if let None = AppConfig::dark_theme() { + let dark = match dark_light::detect() { + Mode::Dark => true, + Mode::Light => false, + Mode::Default => false + }; + AppConfig::set_dark_theme(dark); + } + + // Setup window size. let (width, height) = AppConfig::window_size(); let mut viewport = egui::ViewportBuilder::default() @@ -53,7 +65,7 @@ fn real_main() { })); } - // Desktop window position. + // Setup window position. if let Some((x, y)) = AppConfig::window_pos() { viewport = viewport.with_position(pos2(x, y)); } diff --git a/src/settings/config.rs b/src/settings/config.rs index 04d1e4c..fee82ce 100644 --- a/src/settings/config.rs +++ b/src/settings/config.rs @@ -44,7 +44,10 @@ pub struct AppConfig { x: Option, y: Option, /// Locale code for i18n. - lang: Option + lang: Option, + + /// Flag to check if dark theme should be used, use system settings if not set. + use_dark_theme: Option, } impl Default for AppConfig { @@ -60,6 +63,7 @@ impl Default for AppConfig { x: None, y: None, lang: None, + use_dark_theme: None, } } } @@ -213,8 +217,21 @@ impl AppConfig { /// Mark integrated node warning for Android as shown. pub fn show_android_integrated_node_warning() { - let mut w_app_config = Settings::app_config_to_update(); - w_app_config.android_integrated_node_warning = Some(false); - w_app_config.save(); + let mut w_config = Settings::app_config_to_update(); + w_config.android_integrated_node_warning = Some(false); + w_config.save(); + } + + /// Check if dark theme should be used. + pub fn dark_theme() -> Option { + let r_config = Settings::app_config_to_read(); + r_config.use_dark_theme.clone() + } + + /// Setup flag to use dark theme. + pub fn set_dark_theme(use_dark: bool) { + let mut w_config = Settings::app_config_to_update(); + w_config.use_dark_theme = Some(use_dark); + w_config.save(); } } \ No newline at end of file