Tray UI: start hidden, fixed window, grid layout, traffic + peers
Reworks the tray window per feedback and fills it in. - Starts hidden in the tray (no window on launch); the window opens from the menu. On macOS the app now uses the Accessory activation policy, so it lives in the menu bar with no Dock icon (via a winit event-loop hook, pinned to eframe's winit). Fixed, non-resizable 360x600 window; the layout targets it. - Tidied layout: top bar (title + refresh), a bottom panel with the join form and the action banner, and a scrolling list of network tiles between them. Labels and values sit on two-column grids so they align; the join name and secret inputs are the same fixed width. - A ⟳ button beside the secret generates a fresh random secret (NetworkSecret::generate), for creating a network. - Each network tile shows id, range, this device's address, peers (connected/known), the active and broadcast switches, a Leave button, and a collapsing "peers (N)" section with a formatted per-peer table (short key, address, handshake age, tx/rx packets, rate). - Traffic: a new sampler turns the agent's cumulative packet counters into a packets-per-second rate per network and per peer, from the deltas between snapshots (the snapshot now carries a generation and timestamp so each refresh is sampled once). The network tile shows the current rate and a small hand-drawn sparkline of recent rates (no extra dependency). Note: rates are packets/s — the report has no byte counters yet; bytes would need an agent change. Builds and is clippy-clean (-D warnings) on macOS; the UI has not been run in this headless session. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
19509dc833
commit
d1de61ba29
7 files changed
+416
-75
No files matched your search
@@ -11,6 +11,7 @@
|
||||
|
||||
mod agent;
|
||||
mod app;
|
||||
mod stats;
|
||||
mod tray;
|
||||
mod ui;
|
||||
|
||||
@@ -28,14 +29,28 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.build()?;
|
||||
let handle = runtime.handle().clone();
|
||||
|
||||
let options = eframe::NativeOptions {
|
||||
#[cfg_attr(not(target_os = "macos"), expect(unused_mut))]
|
||||
let mut options = eframe::NativeOptions {
|
||||
// A fixed, small window; the whole layout targets this size.
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_title("tsunagi")
|
||||
.with_inner_size([380.0, 540.0])
|
||||
.with_min_inner_size([320.0, 360.0]),
|
||||
.with_inner_size([360.0, 600.0])
|
||||
.with_resizable(false)
|
||||
// Start hidden: the app lives in the tray and the window opens from
|
||||
// the menu.
|
||||
.with_visible(false),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// macOS: live in the menu bar with no Dock icon (tray-only).
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
options.event_loop_builder = Some(Box::new(|builder| {
|
||||
use winit::platform::macos::{ActivationPolicy, EventLoopBuilderExtMacOS};
|
||||
builder.with_activation_policy(ActivationPolicy::Accessory);
|
||||
}));
|
||||
}
|
||||
|
||||
eframe::run_native(
|
||||
"tsunagi",
|
||||
options,
|
||||
|
||||
Reference in new issue
Block a user