node: handle statuses, added base ui

This commit is contained in:
ardocrat 2023-05-04 20:09:26 +03:00
parent b24a204d59
commit ba5cd82f4b
19 changed files with 751 additions and 454 deletions

282
Cargo.lock generated
View file

@ -320,12 +320,6 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.6.0" version = "1.6.0"
@ -678,12 +672,6 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]] [[package]]
name = "combine" name = "combine"
version = "4.6.6" version = "4.6.6"
@ -946,15 +934,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "data-url"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193"
dependencies = [
"matches",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.9.0" version = "0.9.0"
@ -1151,10 +1130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1975cd88ff7430f93b29e6b9868b648a8ff6a43b08b9ff8474ee0a648bd8f9a6" checksum = "1975cd88ff7430f93b29e6b9868b648a8ff6a43b08b9ff8474ee0a648bd8f9a6"
dependencies = [ dependencies = [
"egui", "egui",
"resvg",
"serde", "serde",
"tiny-skia 0.6.6",
"usvg",
] ]
[[package]] [[package]]
@ -1371,39 +1347,12 @@ dependencies = [
"miniz_oxide 0.6.2", "miniz_oxide 0.6.2",
] ]
[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fontconfig-parser"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ab2e12762761366dcb876ab8b6e0cfa4797ddcd890575919f008b5ba655672a"
dependencies = [
"roxmltree 0.18.0",
]
[[package]]
name = "fontdb"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52186a39c335aa6f79fc0bf1c3cf854870b6ad4e50a7bb8a59b4ba1331f478a"
dependencies = [
"fontconfig-parser",
"log",
"memmap2",
"ttf-parser 0.17.1",
]
[[package]] [[package]]
name = "foreign-types" name = "foreign-types"
version = "0.3.2" version = "0.3.2"
@ -1650,16 +1599,6 @@ dependencies = [
"wasi 0.11.0+wasi-snapshot-preview1", "wasi 0.11.0+wasi-snapshot-preview1",
] ]
[[package]]
name = "gif"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
dependencies = [
"color_quant",
"weezl",
]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.27.2" version = "0.27.2"
@ -1818,12 +1757,15 @@ version = "0.1.0"
dependencies = [ dependencies = [
"android_logger", "android_logger",
"built", "built",
"chrono",
"dirs 2.0.2",
"eframe", "eframe",
"egui", "egui",
"egui_demo_lib", "egui_demo_lib",
"egui_extras", "egui_extras",
"env_logger 0.10.0", "env_logger 0.10.0",
"futures 0.3.28", "futures 0.3.28",
"grin_chain",
"grin_config", "grin_config",
"grin_core", "grin_core",
"grin_servers", "grin_servers",
@ -2441,12 +2383,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "jpeg-decoder"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.61" version = "0.3.61"
@ -2678,12 +2614,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "matches"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.5.0"
@ -3201,7 +3131,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228" checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228"
dependencies = [ dependencies = [
"ttf-parser 0.18.1", "ttf-parser",
] ]
[[package]] [[package]]
@ -3293,12 +3223,6 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pico-args"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.0.12" version = "1.0.12"
@ -3572,12 +3496,6 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "rctree"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ae028b272a6e99d9f8260ceefa3caa09300a8d6c8d2b2001316474bc52122e9"
[[package]] [[package]]
name = "rdrand" name = "rdrand"
version = "0.4.0" version = "0.4.0"
@ -3645,33 +3563,6 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
[[package]]
name = "resvg"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34489194784b86c03c3d688258e2ba73f3c82700ba4673ee2ecad5ae540b9438"
dependencies = [
"gif",
"jpeg-decoder",
"log",
"pico-args",
"png",
"rgb",
"svgfilters",
"svgtypes",
"tiny-skia 0.6.6",
"usvg",
]
[[package]]
name = "rgb"
version = "0.8.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59"
dependencies = [
"bytemuck",
]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.16.20" version = "0.16.20"
@ -3698,24 +3589,6 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "roxmltree"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
dependencies = [
"xmlparser",
]
[[package]]
name = "roxmltree"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8f595a457b6b8c6cda66a48503e92ee8d19342f905948f29c383200ec9eb1d8"
dependencies = [
"xmlparser",
]
[[package]] [[package]]
name = "rust-i18n" name = "rust-i18n"
version = "1.1.4" version = "1.1.4"
@ -3842,22 +3715,6 @@ dependencies = [
"security-framework", "security-framework",
] ]
[[package]]
name = "rustybuzz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a617c811f5c9a7060fe511d35d13bf5b9f0463ce36d63ce666d05779df2b4eba"
dependencies = [
"bitflags 1.3.2",
"bytemuck",
"smallvec",
"ttf-parser 0.15.2",
"unicode-bidi-mirroring",
"unicode-ccc",
"unicode-general-category",
"unicode-script",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.13" version = "1.0.13"
@ -3928,7 +3785,7 @@ dependencies = [
"crossfont", "crossfont",
"log", "log",
"smithay-client-toolkit", "smithay-client-toolkit",
"tiny-skia 0.7.0", "tiny-skia",
] ]
[[package]] [[package]]
@ -4071,15 +3928,6 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
[[package]]
name = "simplecss"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d"
dependencies = [
"log",
]
[[package]] [[package]]
name = "siphasher" name = "siphasher"
version = "0.3.10" version = "0.3.10"
@ -4196,25 +4044,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63" checksum = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63"
[[package]]
name = "svgfilters"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "639abcebc15fdc2df179f37d6f5463d660c1c79cd552c12343a4600827a04bce"
dependencies = [
"float-cmp",
"rgb",
]
[[package]]
name = "svgtypes"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22975e8a2bac6a76bb54f898a6b18764633b00e780330f0b689f65afb3975564"
dependencies = [
"siphasher",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.15.44" version = "0.15.44"
@ -4353,20 +4182,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "tiny-skia"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d049bfef0eaa2521e75d9ffb5ce86ad54480932ae19b85f78bec6f52c4d30d78"
dependencies = [
"arrayref",
"arrayvec 0.5.2",
"bytemuck",
"cfg-if 1.0.0",
"png",
"safe_arch",
]
[[package]] [[package]]
name = "tiny-skia" name = "tiny-skia"
version = "0.7.0" version = "0.7.0"
@ -4567,18 +4382,6 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "ttf-parser"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
[[package]]
name = "ttf-parser"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
[[package]] [[package]]
name = "ttf-parser" name = "ttf-parser"
version = "0.18.1" version = "0.18.1"
@ -4615,24 +4418,6 @@ version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-bidi-mirroring"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694"
[[package]]
name = "unicode-ccc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
[[package]]
name = "unicode-general-category"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.8" version = "1.0.8"
@ -4648,24 +4433,12 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "unicode-script"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d817255e1bed6dfd4ca47258685d14d2bdcfbc64fdc9e3819bd5848057b8ecc"
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.10.1" version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-vo"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.10" version = "0.1.10"
@ -4716,33 +4489,6 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "usvg"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a82565b5c96dcbb58c9bdbb6aa3642abd395a6a6b480658532c6f74c3c4b7a"
dependencies = [
"base64 0.13.1",
"data-url",
"flate2",
"float-cmp",
"fontdb",
"kurbo",
"log",
"pico-args",
"rctree",
"roxmltree 0.14.1",
"rustybuzz",
"simplecss",
"siphasher",
"svgtypes",
"ttf-parser 0.15.2",
"unicode-bidi",
"unicode-script",
"unicode-vo",
"xmlwriter",
]
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@ -4981,12 +4727,6 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "weezl"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
[[package]] [[package]]
name = "wgpu" name = "wgpu"
version = "0.14.2" version = "0.14.2"
@ -5476,18 +5216,6 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[package]]
name = "xmlparser"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
[[package]]
name = "xmlwriter"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
[[package]] [[package]]
name = "yaml-rust" name = "yaml-rust"
version = "0.4.5" version = "0.4.5"

View file

@ -14,7 +14,7 @@ build = "src/build/build.rs"
log = "0.4" log = "0.4"
#android-activity = { version = "0.4", features = ["game-activity"] } #android-activity = { version = "0.4", features = ["game-activity"] }
#grin_api = "5.1.2" #grin_api = "5.1.2"
#grin_chain = "5.1.2" grin_chain = "5.1.2"
grin_config = "5.1.2" grin_config = "5.1.2"
grin_core = "5.1.2" grin_core = "5.1.2"
#grin_keychain = "5.1.2" #grin_keychain = "5.1.2"
@ -33,17 +33,19 @@ openssl-sys = { version = "0.9.82", features = ["vendored"] }
pollster = "0.3.0" pollster = "0.3.0"
wgpu = "0.14.0" wgpu = "0.14.0"
egui = "0.20.1" egui = "0.20.1"
egui_extras = { version = "0.20.0", features = [ "svg" ] } egui_extras = { version = "0.20.0" }
eframe = { version = "0.20.1", features = [ "wgpu" ] } eframe = { version = "0.20.1", features = [ "wgpu" ] }
egui_demo_lib = "0.20.0" egui_demo_lib = "0.20.0"
## grin_servers ## grin_servers
futures = "0.3" futures = "0.3"
dirs = "2.0"
## other ## other
once_cell = "1.10.0" once_cell = "1.10.0"
rust-i18n = "1.1.4" rust-i18n = "1.1.4"
sys-locale = "0.3.0" sys-locale = "0.3.0"
chrono = "0.4.11"
[patch.crates-io] [patch.crates-io]
winit = { git = "https://github.com/rib/winit", branch = "android-activity" } winit = { git = "https://github.com/rib/winit", branch = "android-activity" }

View file

@ -1 +1,4 @@
accounts: Accounts accounts: Accounts
node: Node
metrics: Metrics
settings: Settings

View file

@ -56,3 +56,11 @@ impl App {
} }
} }
pub fn is_dual_panel_mode(frame: &mut Frame) -> bool {
is_landscape(frame) && frame.info().window_info.size.x > 400.0
}
pub fn is_landscape(frame: &mut Frame) -> bool {
return frame.info().window_info.size.x > frame.info().window_info.size.y
}

View file

@ -27,9 +27,10 @@ pub const COLOR_LIGHT: egui::Color32 = egui::Color32::from_gray(240);
pub const COLOR_DARK: egui::Color32 = egui::Color32::from_gray(60); pub const COLOR_DARK: egui::Color32 = egui::Color32::from_gray(60);
// Material icons chars // Material icons chars
pub const SYM_ARROW_BACK: &str = "";//""; pub const SYM_ARROW_BACK: &str = "";
pub const SYM_ADD: &str = "";
pub const SYM_ACCOUNTS: &str = ""; pub const SYM_ACCOUNTS: &str = "";
pub const SYM_NETWORK: &str = ""; pub const SYM_NETWORK: &str = "";
pub const SYM_SETTINGS: &str = "";//""; pub const SYM_SETTINGS: &str = "";
pub const SYM_TUNING: &str = "";
pub const SYM_METRICS: &str = "";

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use egui::Context; use eframe::epaint::Stroke;
use winit::platform::android::activity::AndroidApp; use winit::platform::android::activity::AndroidApp;
use crate::gui::{App, PlatformApp}; use crate::gui::{App, PlatformApp};
@ -85,7 +85,10 @@ impl PlatformApp<Android> {
} }
fn setup_visuals(ctx: &egui::Context) { fn setup_visuals(ctx: &egui::Context) {
ctx.set_visuals(egui::Visuals::light()); let mut visuals = egui::Visuals::light();
// Disable stroke around panels by default
visuals.widgets.noninteractive.bg_stroke = Stroke::NONE;
ctx.set_visuals(visuals);
} }
fn setup_fonts(ctx: &egui::Context) { fn setup_fonts(ctx: &egui::Context) {
@ -106,16 +109,6 @@ impl PlatformApp<Android> {
// }, // },
// }); // });
// fonts.font_data.insert(
// "material".to_owned(),
// egui::FontData::from_static(include_bytes!(
// "../../../../fonts/material-light.ttf"
// )).tweak(egui::FontTweak {
// scale: 1.0,
// y_offset_factor: 0.06,
// y_offset: 0.0
// }),
// );
fonts.font_data.insert( fonts.font_data.insert(
"material".to_owned(), "material".to_owned(),
egui::FontData::from_static(include_bytes!( egui::FontData::from_static(include_bytes!(
@ -160,7 +153,7 @@ impl PlatformApp<Android> {
(Heading, FontId::new(20.0, Proportional)), (Heading, FontId::new(20.0, Proportional)),
(Name("icon".into()), FontId::new(24.0, Proportional)), (Name("icon".into()), FontId::new(24.0, Proportional)),
(Body, FontId::new(16.0, Proportional)), (Body, FontId::new(16.0, Proportional)),
(Button, FontId::new(20.0, Proportional)), (Button, FontId::new(18.0, Proportional)),
(Small, FontId::new(12.0, Proportional)), (Small, FontId::new(12.0, Proportional)),
(Monospace, FontId::new(16.0, Proportional)), (Monospace, FontId::new(16.0, Proportional)),
].into(); ].into();

View file

@ -32,11 +32,11 @@ impl super::Screen for Account {
ScreenId::Account ScreenId::Account
} }
fn show(&mut self, fn ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
nav: &mut Navigator, nav: &mut Navigator,
cb: &dyn PlatformCallbacks) { cb: &dyn PlatformCallbacks) {
} }
} }

View file

@ -13,13 +13,15 @@
// limitations under the License. // limitations under the License.
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use egui::Widget; use eframe::epaint::{Color32, Stroke};
use egui::{Frame, Widget};
use crate::gui::{SYM_ARROW_BACK, SYM_NETWORK, SYM_SETTINGS};
use crate::gui::app::is_dual_panel_mode;
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::screens::{Navigator, Screen, ScreenId}; use crate::gui::screens::{Navigator, Screen, ScreenId};
use crate::gui::{SYM_ACCOUNTS, SYM_ARROW_BACK, SYM_NETWORK, SYM_SETTINGS}; use crate::gui::views::{TitlePanel, TitlePanelAction};
use crate::gui::screens::root::dual_panel_mode;
use crate::gui::views::title_panel::{PanelAction, TitlePanel};
use crate::gui::views::View;
pub struct Accounts { pub struct Accounts {
title: String, title: String,
@ -38,42 +40,43 @@ impl Screen for Accounts {
ScreenId::Accounts ScreenId::Accounts
} }
fn show(&mut self, fn ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
nav: &mut Navigator, nav: &mut Navigator,
cb: &dyn PlatformCallbacks) { cb: &dyn PlatformCallbacks) {
let Self { title } = self; let Self { title } = self;
let mut panel: TitlePanel = TitlePanel::default() let mut panel: TitlePanel = TitlePanel::default()
.title(title) .title(title)
.right_action(PanelAction { .right_action(TitlePanelAction {
icon: SYM_SETTINGS.into(), icon: SYM_SETTINGS.into(),
on_click: Box::new(on_settings_click), on_click: Box::new(|nav| {
//TODO: open settings
}),
}) })
.with_navigator(nav); .with_navigator(nav);
if !dual_panel_mode(frame) { if !is_dual_panel_mode(frame) {
panel = panel.left_action(PanelAction { panel = panel.left_action(TitlePanelAction {
icon: SYM_NETWORK.into(), icon: SYM_NETWORK.into(),
on_click: Box::new(on_network_click), on_click: Box::new(|nav|{
nav.as_mut().unwrap().toggle_left_panel();
}),
}); });
} }
panel.ui(ui); panel.ui(ui);
ui.label(format!("{}Here we go 10000 ツ", SYM_ARROW_BACK)); egui::CentralPanel::default().frame(Frame {
if ui.button("TEST").clicked() { stroke: Stroke::new(1.0, Color32::from_gray(190)),
nav.to(ScreenId::Account) .. Default::default()
}; }).show_inside(ui, |ui| {
if ui.button(format!("{}BACK ", SYM_ARROW_BACK)).clicked() { ui.label(format!("{}Here we go 10000 ツ", SYM_ARROW_BACK));
nav.to(ScreenId::Account) if ui.button("TEST").clicked() {
}; nav.to(ScreenId::Account)
};
if ui.button(format!("{}BACK ", SYM_ARROW_BACK)).clicked() {
nav.to(ScreenId::Account)
};
});
} }
} }
fn on_network_click(nav: &mut Option<&mut Navigator>) {
nav.as_mut().unwrap().toggle_left_panel();
}
fn on_settings_click(nav: &mut Option<&mut Navigator>) {
//TODO: Open settings
}

View file

@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub use account::Account;
pub use accounts::Accounts;
pub use navigator::Navigator; pub use navigator::Navigator;
pub use root::Root; pub use root::Root;
pub use accounts::Accounts;
pub use account::Account;
use crate::gui::App; use crate::gui::App;
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::title_panel::PanelAction; use crate::gui::views::TitlePanelAction;
mod navigator; mod navigator;
mod root; mod root;
@ -30,14 +30,14 @@ mod account;
pub enum ScreenId { pub enum ScreenId {
Root, Root,
Accounts, Accounts,
Account Account,
} }
pub trait Screen { pub trait Screen {
fn id(&self) -> ScreenId; fn id(&self) -> ScreenId;
fn show(&mut self, fn ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
navigator: &mut Navigator, navigator: &mut Navigator,
cb: &dyn PlatformCallbacks); cb: &dyn PlatformCallbacks);
} }

View file

@ -17,7 +17,7 @@ use std::collections::BTreeSet;
use crate::gui::screens::ScreenId; use crate::gui::screens::ScreenId;
pub struct Navigator { pub struct Navigator {
pub(crate) stack: BTreeSet<ScreenId>, stack: BTreeSet<ScreenId>,
pub(crate) left_panel_open: bool, pub(crate) left_panel_open: bool,
} }
@ -33,6 +33,10 @@ impl Default for Navigator {
} }
impl Navigator { impl Navigator {
pub fn current(&mut self) -> &ScreenId {
self.stack.last().unwrap()
}
pub fn to(&mut self, id: ScreenId) { pub fn to(&mut self, id: ScreenId) {
self.stack.insert(id); self.stack.insert(id);
} }

View file

@ -13,17 +13,20 @@
// limitations under the License. // limitations under the License.
use std::cmp::min; use std::cmp::min;
use eframe::epaint::{Shadow, Stroke};
use eframe::Frame; use eframe::epaint::{Color32, Shadow, Stroke};
use egui::style::Margin; use egui::style::Margin;
use egui::Ui;
use crate::gui::{App, COLOR_YELLOW}; use crate::gui::{App, COLOR_YELLOW};
use crate::gui::app::is_dual_panel_mode;
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::screens::{Account, Accounts, Navigator, Screen, ScreenId}; use crate::gui::screens::{Account, Accounts, Navigator, Screen, ScreenId};
use crate::gui::views::Network;
pub struct Root { pub struct Root {
navigator: Navigator, navigator: Navigator,
screens: Vec<Box<dyn Screen>>, screens: Vec<Box<dyn Screen>>,
network: Network
} }
impl Default for Root { impl Default for Root {
@ -34,6 +37,7 @@ impl Default for Root {
Box::new(Accounts::default()), Box::new(Accounts::default()),
Box::new(Account::default()) Box::new(Account::default())
]), ]),
network: Network::default()
} }
} }
} }
@ -43,32 +47,24 @@ impl Root {
ScreenId::Root ScreenId::Root
} }
pub fn ui(&mut self, ui: &mut Ui, frame: &mut Frame, cb: &dyn PlatformCallbacks) { pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) {
let is_network_panel_open = self.navigator.left_panel_open || dual_panel_mode(frame); let is_network_panel_open = self.navigator.left_panel_open || is_dual_panel_mode(frame);
egui::SidePanel::left("network_panel") egui::SidePanel::left("network_panel")
.resizable(false) .resizable(false)
.exact_width(if dual_panel_mode(frame) { .exact_width(if is_dual_panel_mode(frame) {
min(frame.info().window_info.size.x as i64, 400) as f32 min(frame.info().window_info.size.x as i64, 400) as f32
} else { } else {
frame.info().window_info.size.x frame.info().window_info.size.x
}) })
.frame(egui::Frame { .frame(egui::Frame {
inner_margin: Margin::same(0.0),
outer_margin: Margin::same(0.0),
fill: COLOR_YELLOW,
.. Default::default() .. Default::default()
}) })
.show_animated_inside(ui, is_network_panel_open, |ui| { .show_animated_inside(ui, is_network_panel_open, |ui| {
//TODO: Network content self.network.ui(ui, frame, &mut self.navigator, cb);
ui.vertical_centered(|ui| {
ui.heading("🖧 Node");
});
ui.separator();
}); });
egui::CentralPanel::default().frame(egui::containers::Frame { egui::CentralPanel::default().frame(egui::Frame {
..Default::default() ..Default::default()
}).show_inside(ui, |ui| { }).show_inside(ui, |ui| {
self.show_current_screen(ui, frame, cb); self.show_current_screen(ui, frame, cb);
@ -76,22 +72,17 @@ impl Root {
} }
pub fn show_current_screen(&mut self, ui: &mut Ui, frame: &mut Frame, cb: &dyn PlatformCallbacks) { pub fn show_current_screen(&mut self,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
cb: &dyn PlatformCallbacks) {
let Self { navigator, screens, .. } = self; let Self { navigator, screens, .. } = self;
let current = navigator.stack.last().unwrap(); let current = navigator.current();
for screen in screens.iter_mut() { for screen in screens.iter_mut() {
if screen.id() == *current { if screen.id() == *current {
screen.show(ui, frame, navigator, cb); screen.ui(ui, frame, navigator, cb);
break; break;
} }
} }
} }
} }
pub fn dual_panel_mode(frame: &mut Frame) -> bool {
is_landscape(frame) && frame.info().window_info.size.x > 400.0
}
pub fn is_landscape(frame: &mut Frame) -> bool {
return frame.info().window_info.size.x > frame.info().window_info.size.y
}

View file

@ -13,8 +13,18 @@
// limitations under the License. // limitations under the License.
pub mod buttons; pub mod buttons;
pub mod title_panel;
pub trait View { mod title_panel;
fn ui(&mut self, ui: &mut egui::Ui); pub use crate::gui::views::title_panel::{TitlePanel, TitlePanelAction, TitlePanelActions};
mod network;
pub use crate::gui::views::network::Network;
mod network_node;
mod network_tuning;
mod network_metrics;
pub trait NetworkTab {
fn ui(&mut self, ui: &mut egui::Ui, node: &mut crate::node::Node);
fn title(&self) -> &String;
} }

288
src/gui/views/network.rs Normal file
View file

@ -0,0 +1,288 @@
// Copyright 2023 The Grim Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::borrow::Cow;
use std::collections::hash_map::DefaultHasher;
use std::time::Duration;
use eframe::epaint::{Color32, FontId, Stroke};
use eframe::epaint::text::{LayoutJob, TextFormat, TextWrapping};
use egui::{Response, RichText, Sense, Spinner, Widget};
use egui::style::Margin;
use egui_extras::{Size, StripBuilder};
use grin_chain::SyncStatus;
use grin_core::global::ChainTypes;
use grin_servers::ServerStats;
use crate::gui::app::is_dual_panel_mode;
use crate::gui::platform::PlatformCallbacks;
use crate::gui::screens::Navigator;
use crate::gui::{COLOR_DARK, COLOR_LIGHT, COLOR_YELLOW, SYM_ACCOUNTS, SYM_METRICS, SYM_NETWORK};
use crate::gui::views::{NetworkTab, TitlePanel, TitlePanelAction};
use crate::gui::views::network_node::NetworkNode;
use crate::node;
use crate::node::Node;
enum Mode {
Node,
// Miner,
Metrics,
Tuning
}
pub struct Network {
current_mode: Mode,
node: Node,
node_view: NetworkNode,
}
impl Default for Network {
fn default() -> Self {
let node = Node::new(ChainTypes::Mainnet, true);
Self {
node,
current_mode: Mode::Node,
node_view: NetworkNode::default()
}
}
}
impl Network {
pub fn ui(&mut self,
ui: &mut egui::Ui,
frame: &mut eframe::Frame,
nav: &mut Navigator,
cb: &dyn PlatformCallbacks) {
egui::TopBottomPanel::top("network_title")
.resizable(false)
.frame(egui::Frame {
fill: COLOR_YELLOW,
inner_margin: Margin::same(0.0),
outer_margin: Margin::same(0.0),
stroke: Stroke::NONE,
..Default::default()
})
.show_inside(ui, |ui| {
self.draw_title(ui, frame, nav);
});
egui::CentralPanel::default().frame(egui::Frame {
stroke: Stroke::new(1.0, Color32::from_gray(190)),
fill: Color32::WHITE,
.. Default::default()
}).show_inside(ui, |ui| {
self.draw_tab_content(ui);
});
egui::TopBottomPanel::bottom("network_tabs")
.frame(egui::Frame {
stroke: Stroke::new(1.0, Color32::from_gray(190)),
.. Default::default()
})
.resizable(false)
.show_inside(ui, |ui| {
self.draw_tabs(ui);
});
ui.ctx().request_repaint_after(Duration::from_millis(500));
}
fn draw_tabs(&self, ui: &mut egui::Ui) {
ui.vertical_centered(|ui| {
ui.columns(3, |columns| {
columns[0].horizontal_wrapped(|ui| {
});
columns[1].vertical_centered(|ui| {
});
columns[2].horizontal_wrapped(|ui| {
});
});
});
}
fn draw_tab_content(&mut self, ui: &mut egui::Ui) {
match self.current_mode {
Mode::Node => {
self.node_view.ui(ui, &mut self.node);
}
Mode::Metrics => {}
Mode::Tuning => {}
}
}
fn draw_title(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, nav: &mut Navigator) {
// Disable stroke around title buttons on hover
ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE;
StripBuilder::new(ui)
.size(Size::exact(52.0))
.vertical(|mut strip| {
strip.strip(|builder| {
builder
.size(Size::exact(52.0))
.size(Size::remainder())
.size(Size::exact(52.0))
.horizontal(|mut strip| {
strip.empty();
strip.strip(|builder| {
self.draw_title_text(builder);
});
strip.cell(|ui| {
if !is_dual_panel_mode(frame) {
ui.centered_and_justified(|ui| {
let b = egui::widgets::Button::new(
RichText::new(SYM_ACCOUNTS)
.size(24.0)
.color(COLOR_DARK)
).fill(Color32::TRANSPARENT)
.ui(ui).interact(Sense::click_and_drag());
if b.drag_released() || b.clicked() {
nav.toggle_left_panel();
};
});
}
});
});
});
});
}
fn draw_title_text(&self, mut builder: StripBuilder) {
let title_text = match &self.current_mode {
Mode::Node => {
self.node_view.title()
}
Mode::Metrics => {
self.node_view.title()
}
Mode::Tuning => {
self.node_view.title()
}
};
let state = self.node.acquire_state();
let syncing = state.stats.is_some() &&
state.stats.as_ref().unwrap().sync_status != SyncStatus::NoSync;
let mut b = builder.size(Size::remainder());
if syncing {
b = b.size(Size::remainder());
}
b.vertical(|mut strip| {
strip.cell(|ui| {
ui.centered_and_justified(|ui| {
ui.heading(title_text.to_uppercase());
});
});
if syncing {
let stats = state.stats.as_ref().unwrap();
strip.cell(|ui| {
ui.centered_and_justified(|ui| {
let status_text = if state.is_stopping() {
get_sync_status(SyncStatus::Shutdown).to_string()
} else if state.is_restarting() {
"Restarting".to_string()
} else {
get_sync_status(stats.sync_status).to_string()
};
let mut job = LayoutJob::single_section(status_text, TextFormat {
font_id: FontId::proportional(15.0),
color: COLOR_DARK,
.. Default::default()
});
job.wrap = TextWrapping {
max_rows: 1,
break_anywhere: false,
overflow_character: Option::from('…'),
..Default::default()
};
ui.label(job);
});
});
}
});
}
}
fn get_sync_status(sync_status: SyncStatus) -> Cow<'static, str> {
match sync_status {
SyncStatus::Initial => Cow::Borrowed("Initializing"),
SyncStatus::NoSync => Cow::Borrowed("Running"),
SyncStatus::AwaitingPeers(_) => Cow::Borrowed("Waiting for peers"),
SyncStatus::HeaderSync {
sync_head,
highest_height,
..
} => {
if highest_height == 0 {
Cow::Borrowed("Downloading headers data")
} else {
let percent = sync_head.height * 100 / highest_height;
Cow::Owned(format!("Downloading headers: {}%", percent))
}
}
SyncStatus::TxHashsetDownload(stat) => {
Cow::Borrowed("Downloading chain state")
}
SyncStatus::TxHashsetSetup => {
Cow::Borrowed("Preparing chain state for validation")
}
SyncStatus::TxHashsetRangeProofsValidation {
rproofs,
rproofs_total,
} => {
let r_percent = if rproofs_total > 0 {
(rproofs * 100) / rproofs_total
} else {
0
};
Cow::Owned(format!("Validating state - range proofs: {}%", r_percent))
}
SyncStatus::TxHashsetKernelsValidation {
kernels,
kernels_total,
} => {
let k_percent = if kernels_total > 0 {
(kernels * 100) / kernels_total
} else {
0
};
Cow::Owned(format!("Validating state - kernels: {}%", k_percent))
}
SyncStatus::TxHashsetSave => {
Cow::Borrowed("Finalizing chain state")
}
SyncStatus::TxHashsetDone => {
Cow::Borrowed("Finalized chain state")
}
SyncStatus::BodySync {
current_height,
highest_height,
} => {
if highest_height == 0 {
Cow::Borrowed("Downloading blocks data")
} else {
Cow::Owned(format!(
"Downloading blocks: {}%",
current_height * 100 / highest_height
))
}
}
SyncStatus::Shutdown => Cow::Borrowed("Shutting down"),
}
}

View file

@ -0,0 +1,13 @@
// Copyright 2023 The Grim Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

View file

@ -0,0 +1,76 @@
// Copyright 2023 The Grim Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::borrow::Cow;
use std::ptr::null;
use std::sync::mpsc;
use chrono::Utc;
use egui::{Ui, Widget};
use grin_chain::SyncStatus;
use grin_core::global::ChainTypes;
use grin_servers::ServerStats;
use crate::gui::views::NetworkTab;
use crate::node::Node;
pub struct NetworkNode {
title: String
}
impl Default for NetworkNode {
fn default() -> Self {
Self {
title: t!("node"),
}
}
}
impl NetworkTab for NetworkNode {
fn ui(&mut self, ui: &mut Ui, node: &mut Node) {
// ui.vertical_centered_justified(|ui| {
// let node_state = node.acquire_state();
// let stats = &node_state.stats;
// if stats.is_some() {
// ui.horizontal_wrapped(|ui| {
// let sync_status = stats.as_ref().unwrap().sync_status;
// ui.label(get_sync_progress_status(sync_status));
// ui.spinner();
// });
// } else {
// if node.stop_state.is_stopped() {
// ui.label("Stopped");
// } else {
// ui.label(get_sync_progress_status(SyncStatus::Initial));
// }
// }
// });
if ui.button("stop").clicked() {
node.stop();
}
if ui.button("re-start").clicked() {
node.restart(ChainTypes::Mainnet);
}
if ui.button("start").clicked() {
node.start(ChainTypes::Mainnet);
}
}
fn title(&self) -> &String {
&self.title
}
}

View file

@ -0,0 +1,13 @@
// Copyright 2023 The Grim Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

View file

@ -12,61 +12,55 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use eframe::epaint::text::{LayoutJob, TextFormat, TextWrapping}; use eframe::epaint::text::{LayoutJob, TextFormat, TextWrapping};
use egui::{Color32, FontId, RichText, Sense, Stroke, Widget}; use egui::{Color32, FontId, RichText, Sense, Stroke, Widget};
use egui::style::Margin; use egui::style::Margin;
use egui_extras::{Size, StripBuilder}; use egui_extras::{Size, StripBuilder};
use crate::gui::{COLOR_DARK, COLOR_YELLOW}; use crate::gui::{COLOR_DARK, COLOR_YELLOW};
use crate::gui::screens::Navigator; use crate::gui::screens::Navigator;
use crate::gui::views::View;
pub struct PanelAction { pub struct TitlePanelAction {
pub(crate) icon: Box<str>, pub(crate) icon: Box<str>,
pub(crate) on_click: Box<dyn Fn(&mut Option<&mut Navigator>)>, pub(crate) on_click: Box<dyn Fn(&mut Option<&mut Navigator>)>,
} }
#[derive(Default)] #[derive(Default)]
pub struct PanelActions { pub struct TitlePanelActions {
left: Option<PanelAction>, left: Option<TitlePanelAction>,
right: Option<PanelAction> right: Option<TitlePanelAction>
} }
#[derive(Default)] #[derive(Default)]
pub struct TitlePanel<'screen> { pub struct TitlePanel<'nav> {
title: Option<&'screen String>, title: Option<&'nav str>,
actions: PanelActions, actions: TitlePanelActions,
navigator: Option<&'screen mut Navigator> navigator: Option<&'nav mut Navigator>
} }
impl<'screen> TitlePanel<'screen> { impl<'nav> TitlePanel<'nav> {
pub fn title(mut self, title: &'screen String) -> Self { pub fn title(mut self, title: &'nav str) -> Self {
self.title = Some(title); self.title = Some(title);
self self
} }
pub fn left_action(mut self, action: PanelAction) -> Self { pub fn left_action(mut self, action: TitlePanelAction) -> Self {
self.actions.left = Some(action); self.actions.left = Some(action);
self self
} }
pub fn right_action(mut self, action: PanelAction) -> Self { pub fn right_action(mut self, action: TitlePanelAction) -> Self {
self.actions.right = Some(action); self.actions.right = Some(action);
self self
} }
pub fn with_navigator(mut self, nav: &'screen mut Navigator) -> Self { pub fn with_navigator(mut self, nav: &'nav mut Navigator) -> Self {
self.navigator = Some(nav); self.navigator = Some(nav);
self self
} }
}
impl View for TitlePanel<'_> { pub fn ui(&mut self, ui: &mut egui::Ui) {
fn ui(&mut self, ui: &mut egui::Ui) { // Disable stroke around panel buttons on hover
// Disable stroke around panel
ui.style_mut().visuals.widgets.noninteractive.bg_stroke = Stroke::NONE;
// Disable stroke around buttons on hover
ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE; ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE;
let Self { actions, title, navigator } = self; let Self { actions, title, navigator } = self;
@ -114,7 +108,7 @@ impl View for TitlePanel<'_> {
strip.cell(|ui| { strip.cell(|ui| {
if title.is_some() { if title.is_some() {
ui.centered_and_justified(|ui| { ui.centered_and_justified(|ui| {
show_title(title.as_ref().unwrap(), ui); Self::show_title(title.unwrap(), ui);
}); });
} }
}); });
@ -141,19 +135,20 @@ impl View for TitlePanel<'_> {
}); });
}); });
} }
fn show_title(title: &str, ui: &mut egui::Ui) {
let mut job = LayoutJob::single_section(title.to_uppercase(), TextFormat {
font_id: FontId::proportional(20.0),
color: COLOR_DARK,
.. Default::default()
});
job.wrap = TextWrapping {
max_rows: 1,
break_anywhere: false,
overflow_character: Option::from('…'),
..Default::default()
};
ui.label(job);
}
} }
fn show_title(title: &String, ui: &mut egui::Ui) {
let mut job = LayoutJob::single_section(title.to_uppercase(), TextFormat {
font_id: FontId::proportional(20.0),
color: COLOR_DARK,
.. Default::default()
});
job.wrap = TextWrapping {
max_rows: 1,
break_anywhere: false,
overflow_character: Option::from('…'),
..Default::default()
};
ui.label(job);
}

View file

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub mod node; mod node;
pub use self::node::start; pub use self::node::Node;
pub use self::node::NodeState;

View file

@ -12,63 +12,231 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::sync::mpsc; use std::{fs, thread};
use grin_config::{config, GlobalConfig}; use std::fmt::format;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::{Arc, LockResult, mpsc, Mutex, MutexGuard};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::JoinHandle;
use std::time::Duration;
use futures::channel::oneshot;
use grin_chain::SyncStatus;
use grin_config::config;
use grin_core::global; use grin_core::global;
use grin_core::global::ChainTypes; use grin_core::global::ChainTypes;
use grin_servers::{Server, ServerStats};
use grin_servers::common::types::Error;
use grin_util::logger::LogEntry; use grin_util::logger::LogEntry;
use grin_util::StopState;
use log::info; use log::info;
use futures::channel::oneshot;
pub fn start(chain_type: &ChainTypes) { pub struct Node {
let node_config = Some( /// Node state updated from the separate thread
config::initial_setup_server(&ChainTypes::Mainnet).unwrap_or_else(|e| { node_state: Arc<Mutex<NodeState>>,
//TODO: Error handling }
panic!("Error loading server configuration: {}", e);
}),
);
impl Node {
/// Instantiate new node with provided chain type, start server if needed
pub fn new(chain_type: ChainTypes, start: bool) -> Self {
let stop_state = Arc::new(StopState::new());
let mut state = NodeState::new(chain_type, stop_state.clone());
let node_state = Arc::new(Mutex::new(state));
if start {
let server = start_server(&chain_type, stop_state);
start_server_thread(node_state.clone(), server);
} else {
stop_state.stop();
}
Self { node_state }
}
/// Acquire node state to be used by a current thread
pub fn acquire_state(&self) -> MutexGuard<'_, NodeState> {
self.node_state.lock().unwrap()
}
/// Stop server
pub fn stop(&self) {
self.acquire_state().stop_needed = true;
}
/// Start server with provided chain type
pub fn start(&self, chain_type: ChainTypes) {
let mut state = self.node_state.lock().unwrap();
if state.stop_state.is_stopped() {
self.start_with_acquired_state(state, chain_type);
}
}
/// Restart server with provided chain type
pub fn restart(&mut self, chain_type: ChainTypes) {
let mut state = self.acquire_state();
if !state.stop_state.is_stopped() {
state.chain_type = chain_type;
state.restart_needed = true;
} else {
self.start_with_acquired_state(state, chain_type);
}
}
/// Start server with provided acquired state
fn start_with_acquired_state(&self, mut state: MutexGuard<NodeState>, chain_type: ChainTypes) {
state.chain_type = chain_type;
state.stop_state = Arc::new(StopState::new());
let server = start_server(&chain_type, state.stop_state.clone());
start_server_thread(self.node_state.clone(), server);
}
}
pub struct NodeState {
/// To check server state
stop_state: Arc<StopState>,
/// Data for UI, None means server is not started
pub(crate) stats: Option<ServerStats>,
/// Chain type of launched server
chain_type: ChainTypes,
/// Thread flag to stop the server and start it again
restart_needed: bool,
/// Thread flag to stop the server
stop_needed: bool,
}
impl NodeState {
/// Instantiate new node state with provided chain type and server state
pub fn new(chain_type: ChainTypes, stop_state: Arc<StopState>) -> Self {
Self {
stop_state,
stats: None,
chain_type,
restart_needed: false,
stop_needed: false,
}
}
/// Check if server is stopping at separate thread
pub fn is_stopping(&self) -> bool {
return self.stop_needed
}
/// Check if server is restarting at separate thread
pub fn is_restarting(&self) -> bool {
return self.restart_needed
}
}
/// Start server with provided chain type and node state
fn start_server(chain_type: &ChainTypes, stop_state: Arc<StopState>) -> Server {
let mut node_config_result = config::initial_setup_server(chain_type);
if node_config_result.is_err() {
// Remove config file on init error
let mut grin_path = dirs::home_dir().unwrap();
grin_path.push(".grin");
grin_path.push(chain_type.shortname());
grin_path.push(config::SERVER_CONFIG_FILE_NAME);
fs::remove_file(grin_path).unwrap();
// Reinit config
node_config_result = config::initial_setup_server(chain_type);
}
let node_config = node_config_result.ok();
let config = node_config.clone().unwrap(); let config = node_config.clone().unwrap();
let server_config = config.members.as_ref().unwrap().server.clone(); let server_config = config.members.as_ref().unwrap().server.clone();
// Initialize our global chain_type, feature flags (NRD kernel support currently), accept_fee_base, and future_time_limit. let mut db_path = PathBuf::from(&server_config.db_root);
db_path.push("grin.lock");
fs::remove_file(db_path).unwrap();
// Initialize our global chain_type, feature flags (NRD kernel support currently),
// accept_fee_base, and future_time_limit.
// These are read via global and not read from config beyond this point. // These are read via global and not read from config beyond this point.
global::init_global_chain_type(config.members.as_ref().unwrap().server.chain_type); if !global::GLOBAL_CHAIN_TYPE.is_init() {
global::init_global_chain_type(config.members.as_ref().unwrap().server.chain_type);
}
info!("Chain: {:?}", global::get_chain_type()); info!("Chain: {:?}", global::get_chain_type());
match global::get_chain_type() {
ChainTypes::Mainnet => { if !global::GLOBAL_NRD_FEATURE_ENABLED.is_init() {
// Set various mainnet specific feature flags. match global::get_chain_type() {
global::init_global_nrd_enabled(false); ChainTypes::Mainnet => {
} // Set various mainnet specific feature flags.
_ => { global::init_global_nrd_enabled(false);
// Set various non-mainnet feature flags. }
global::init_global_nrd_enabled(true); _ => {
// Set various non-mainnet feature flags.
global::init_global_nrd_enabled(true);
}
} }
} }
let afb = config if !global::GLOBAL_ACCEPT_FEE_BASE.is_init() {
.members let afb = config
.as_ref() .members
.unwrap() .as_ref()
.server .unwrap()
.pool_config .server
.accept_fee_base; .pool_config
global::init_global_accept_fee_base(afb); .accept_fee_base;
info!("Accept Fee Base: {:?}", global::get_accept_fee_base()); global::init_global_accept_fee_base(afb);
global::init_global_future_time_limit(config.members.unwrap().server.future_time_limit); info!("Accept Fee Base: {:?}", global::get_accept_fee_base());
info!("Future Time Limit: {:?}", global::get_future_time_limit()); }
if !global::GLOBAL_FUTURE_TIME_LIMIT.is_init() {
global::init_global_future_time_limit(config.members.unwrap().server.future_time_limit);
info!("Future Time Limit: {:?}", global::get_future_time_limit());
}
let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) = let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) =
Box::leak(Box::new(oneshot::channel::<()>())); Box::leak(Box::new(oneshot::channel::<()>()));
grin_servers::Server::start( let mut server_result = Server::new(server_config.clone(), Some(stop_state.clone()), api_chan);
server_config, if server_result.is_err() {
None, let mut db_path = PathBuf::from(&server_config.db_root);
|serv: grin_servers::Server, info: Option<mpsc::Receiver<LogEntry>>| { db_path.push("grin.lock");
serv.get_server_stats(); fs::remove_file(db_path).unwrap();
info!("Info callback")
//serv.stop(); // Remove chain data on server start error
}, let dirs_to_remove: Vec<&str> = vec!["header", "lmdb", "txhashset", "peer"];
None, for dir in dirs_to_remove {
api_chan let mut path = PathBuf::from(&server_config.db_root);
) path.push(dir);
.unwrap(); fs::remove_dir_all(path).unwrap();
}
// Recreate server
let config = node_config.clone().unwrap();
let server_config = config.members.as_ref().unwrap().server.clone();
let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) =
Box::leak(Box::new(oneshot::channel::<()>()));
server_result = Server::new(server_config.clone(), Some(stop_state.clone()), api_chan);
}
server_result.unwrap()
}
/// Start a thread to launch server and update node state with server stats
fn start_server_thread(node_state: Arc<Mutex<NodeState>>, mut server: Server) -> JoinHandle<()> {
thread::spawn(move || loop {
thread::sleep(Duration::from_millis(500));
let mut state = node_state.lock().unwrap();
if state.restart_needed {
server.stop();
// Create new server with new stop state
state.stop_state = Arc::new(StopState::new());
server = start_server(&state.chain_type, state.stop_state.clone());
state.restart_needed = false;
} else if state.stop_needed {
server.stop();
state.stats = None;
state.stop_needed = false;
break;
}
if !state.stop_state.is_stopped() {
let stats = server.get_server_stats();
if stats.is_ok() {
state.stats = Some(stats.as_ref().ok().unwrap().clone());
}
}
})
} }