Added tray icon and ability to run UI hidden, but shown by tray icon actions.

This commit is contained in:
Revertron
2025-10-29 16:01:41 +01:00
parent bb3a33c103
commit 8f4cbf7dc0
4 changed files with 292 additions and 10 deletions
Generated
+218 -1
View File
@@ -76,6 +76,7 @@ dependencies = [
"time",
"tinyfiledialogs",
"toml 0.9.8",
"tray-icon",
"ureq",
"uuid",
"winapi",
@@ -172,6 +173,9 @@ name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
dependencies = [
"serde_core",
]
[[package]]
name = "blake2"
@@ -742,6 +746,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fdeflate"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
[[package]]
name = "fiat-crypto"
version = "0.2.9"
@@ -1526,6 +1539,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "keyboard-types"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
dependencies = [
"bitflags 2.10.0",
"serde",
"unicode-segmentation",
]
[[package]]
name = "kuchikiki"
version = "0.8.8-speedreader"
@@ -1544,12 +1568,46 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libappindicator"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a"
dependencies = [
"glib",
"gtk",
"gtk-sys",
"libappindicator-sys",
"log",
]
[[package]]
name = "libappindicator-sys"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf"
dependencies = [
"gtk-sys",
"libloading",
"once_cell",
]
[[package]]
name = "libc"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "libredox"
version = "0.1.10"
@@ -1560,6 +1618,25 @@ dependencies = [
"libc",
]
[[package]]
name = "libxdo"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00333b8756a3d28e78def82067a377de7fa61b24909000aeaa2b446a948d14db"
dependencies = [
"libxdo-sys",
]
[[package]]
name = "libxdo-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212"
dependencies = [
"libc",
"x11",
]
[[package]]
name = "litemap"
version = "0.8.0"
@@ -1664,6 +1741,27 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "muda"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a"
dependencies = [
"crossbeam-channel",
"dpi",
"gtk",
"keyboard-types",
"libxdo",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
"once_cell",
"png",
"thiserror 2.0.17",
"windows-sys 0.60.2",
]
[[package]]
name = "ndk"
version = "0.9.0"
@@ -1814,6 +1912,16 @@ dependencies = [
"objc2",
]
[[package]]
name = "objc2-core-graphics"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
dependencies = [
"bitflags 2.10.0",
"objc2-core-foundation",
]
[[package]]
name = "objc2-encode"
version = "4.1.0"
@@ -1836,6 +1944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [
"bitflags 2.10.0",
"block2",
"objc2",
"objc2-core-foundation",
]
@@ -2103,6 +2212,19 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "png"
version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "poly1305"
version = "0.8.0"
@@ -3054,6 +3176,27 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
[[package]]
name = "tray-icon"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d5572781bee8e3f994d7467084e1b1fd7a93ce66bd480f8156ba89dee55a2b"
dependencies = [
"crossbeam-channel",
"dirs",
"libappindicator",
"muda",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation",
"once_cell",
"png",
"thiserror 2.0.17",
"windows-sys 0.60.2",
]
[[package]]
name = "typenum"
version = "1.19.0"
@@ -3569,6 +3712,15 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.5",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
@@ -3602,13 +3754,30 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link 0.2.1",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows-threading"
version = "0.1.0"
@@ -3639,6 +3808,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -3651,6 +3826,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -3663,12 +3844,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -3681,6 +3874,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -3693,6 +3892,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -3705,6 +3910,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -3717,6 +3928,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
version = "0.5.40"
+2 -1
View File
@@ -44,6 +44,7 @@ thread-priority = "3.0.0"
# Optional dependencies regulated by features
wry = { version = "0.53", optional = true }
tao = { version = "0.34", optional = true }
tray-icon = { version = "0.21.2", optional = true }
tinyfiledialogs = { version = "3.9.1", optional = true }
open = { version = "5.3.0", optional = true }
@@ -70,6 +71,6 @@ ProductName="ALFIS"
FileDescription="Alternative Free Identity System"
[features]
webgui = ["wry", "tao", "tinyfiledialogs", "open"]
webgui = ["wry", "tao", "tray-icon", "tinyfiledialogs", "open"]
doh = ["ureq"]
default = ["webgui", "doh"]
+2 -1
View File
@@ -59,6 +59,7 @@ fn main() {
opts.optflag("v", "version", "Print version and exit");
opts.optflag("d", "debug", "Show debug messages, more than usual");
opts.optflag("t", "trace", "Show trace messages, more than debug");
opts.optflag("", "hide", "Hide UI, show only tray icon.");
opts.optflag("b", "blocks", "List blocks from DB and exit");
opts.optflag("g", "generate", "Generate new config file. Generated config will be printed to console.");
#[cfg(windows)]
@@ -251,7 +252,7 @@ fn main() {
});
}
#[cfg(feature = "webgui")]
web_ui::run_interface(Arc::clone(&context), miner);
web_ui::run_interface(Arc::clone(&context), miner, opt_matches.opt_present("hide"));
}
// Without explicitly detaching the console cmd won't redraw it's prompt.
+70 -7
View File
@@ -4,6 +4,7 @@ extern crate serde_json;
extern crate tinyfiledialogs as tfd;
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;
@@ -28,9 +29,11 @@ use tao::{
window::WindowBuilder,
};
use tao::dpi::PhysicalPosition;
use tray_icon::menu::{Menu, MenuEvent, MenuItem};
use tray_icon::{TrayIconBuilder, TrayIconEvent};
use wry::WebViewBuilder;
pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, hide: bool) {
let file_content = include_str!("webview/index.html");
let mut styles = inline_style(include_str!("webview/bulma.css"));
styles.push_str(&inline_style(include_str!("webview/styles.css")));
@@ -42,7 +45,25 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
// Create event loop and window
let event_loop = EventLoopBuilder::<UserEvent>::with_user_event().build();
let proxy = event_loop.create_proxy();
// Create tray menu
let tray_menu = Menu::new();
let show_item = MenuItem::new("Show Window", true, None);
let quit_item = MenuItem::new("Quit", true, None);
tray_menu.append(&show_item).unwrap();
tray_menu.append(&quit_item).unwrap();
#[cfg(windows)]
let icon = tray_icon::Icon::from_resource(1, None).unwrap();
// Create tray icon
#[cfg(windows)]
let _tray_icon = TrayIconBuilder::new()
.with_menu(Box::new(tray_menu))
.with_tooltip(&title)
.with_icon(icon)
.with_menu_on_left_click(false)
.build()
.unwrap();
let window_size = tao::dpi::LogicalSize::new(1024, 720);
// Get primary monitor and calculate center position
@@ -65,7 +86,7 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
.with_inner_size(window_size)
.with_min_inner_size(tao::dpi::LogicalSize::new(773, 350))
.with_resizable(true)
.with_visible(true);
.with_visible(!hide);
if let Some(position) = position {
builder = builder.with_position(position);
@@ -89,6 +110,7 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
// Clone for the IPC handler
let context_ipc = Arc::clone(&context);
let miner_ipc = Arc::clone(&miner);
let proxy = event_loop.create_proxy();
let proxy_ipc = proxy.clone();
// Create webview
@@ -173,10 +195,13 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
_ => threads
};
let status = Arc::new(Mutex::new(UiStatus::new(threads)));
let connected_nodes = Arc::new(AtomicUsize::new(0));
let nodes_copy = Arc::clone(&connected_nodes);
register(move |_uuid, e| {
let status = Arc::clone(&status);
let proxy = proxy_events.clone();
let nodes_copy = Arc::clone(&nodes_copy);
thread::Builder::new().name(String::from("webui")).spawn(move || {
let mut status = status.lock().unwrap();
@@ -267,6 +292,7 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
}
}
Event::NetworkStatus { blocks, domains, keys, nodes } => {
nodes_copy.store(nodes, Ordering::SeqCst);
if status.mining || status.syncing || nodes < 3 {
format!("setStats({}, {}, {}, {});", blocks, domains, keys, nodes)
} else {
@@ -289,6 +315,18 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
true
});
let proxy = event_loop.create_proxy();
TrayIconEvent::set_event_handler(Some(move |event| {
let _ = proxy.send_event(UserEvent::TrayIconEvent(event));
}));
let proxy = event_loop.create_proxy();
MenuEvent::set_event_handler(Some(move |event| {
let _ = proxy.send_event(UserEvent::MenuEvent(event));
}));
let proxy = event_loop.create_proxy();
// Run event loop
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
@@ -298,10 +336,7 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
event: WindowEvent::CloseRequested,
..
} => {
info!("Interface closed, exiting");
post(Event::ActionQuit);
thread::sleep(Duration::from_millis(100));
*control_flow = ControlFlow::Exit;
window.set_visible(false);
}
TaoEvent::UserEvent(user_event) => {
let wv = webview_clone.lock().unwrap();
@@ -324,6 +359,32 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
UserEvent::ShowWarning(text) => {
show_warning(&wv, &text);
}
UserEvent::TrayIconEvent(event) => {
match event {
TrayIconEvent::DoubleClick { button, .. } => {
if button == tray_icon::MouseButton::Left {
window.set_visible(true);
window.set_focus();
}
}
TrayIconEvent::Enter { .. } => {
let nodes = connected_nodes.load(Ordering::SeqCst);
let title = format!("ALFIS {}\nConnected: {nodes}", env!("CARGO_PKG_VERSION"));
let _ = _tray_icon.set_tooltip(Some(title));
}
_ => {}
}
}
UserEvent::MenuEvent(event) => {
if event.id == show_item.id() {
window.set_visible(true);
} else if event.id == quit_item.id() {
info!("Interface closed, exiting");
post(Event::ActionQuit);
thread::sleep(Duration::from_millis(100));
*control_flow = ControlFlow::Exit;
}
}
}
}
_ => {}
@@ -338,6 +399,8 @@ enum UserEvent {
LoadDomains,
SendKeysToUi,
ShowWarning(String),
TrayIconEvent(TrayIconEvent),
MenuEvent(MenuEvent)
}
fn check_record(data: &str) -> bool {