From 45b7bc2c84fb4ecafeb010d2547e2b306c0bf8d0 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 20 Feb 2023 00:11:15 -0800 Subject: [PATCH] Add system tray --- src-tauri/Cargo.lock | 37 ++++++++++++++++ src-tauri/Cargo.toml | 6 +-- src-tauri/src/main.rs | 24 +++++++++- src-tauri/tauri.conf.json | 82 ----------------------------------- src-tauri/tauri.toml | 73 +++++++++++++++++++++++++++++++ src-web/App.tsx | 32 +++++++------- src-web/components/Input.tsx | 2 +- src-web/components/Stacks.tsx | 2 +- 8 files changed, 154 insertions(+), 104 deletions(-) delete mode 100644 src-tauri/tauri.conf.json create mode 100644 src-tauri/tauri.toml diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c1146743..da52f926 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1627,12 +1627,46 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "libappindicator" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + [[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[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 = "line-wrap" version = "0.1.1" @@ -3407,6 +3441,7 @@ dependencies = [ "core-foundation", "core-graphics", "crossbeam-channel", + "dirs-next", "dispatch", "gdk", "gdk-pixbuf", @@ -3420,6 +3455,7 @@ dependencies = [ "instant", "jni", "lazy_static", + "libappindicator", "libc", "log", "ndk", @@ -3635,6 +3671,7 @@ dependencies = [ "serde_json", "serde_with", "thiserror", + "toml", "url", "walkdir", "windows", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 48c5041e..891fcd09 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -15,15 +15,15 @@ tauri-build = { version = "1.2", features = [] } [dependencies] serde_json = { version = "1.0" } serde = { version = "1.0", features = ["derive"] } -tauri = { version = "1.2", features = ["devtools", "shell-open", "window-start-dragging"] } +tauri = { version = "1.2", features = ["config-toml", "devtools", "shell-open", "system-tray", "window-start-dragging"] } http = { version = "0.2.8" } reqwest = { version = "0.11.14", features = ["json"] } tokio = { version = "1.25.0", features = ["full"] } futures = { version = "0.3.26" } deno_core = { version = "0.171.0" } deno_ast = { version = "0.24.0", features = ["transpiling"] } -objc = "0.2.7" -cocoa = "0.24.1" +objc = { version = "0.2.7" } +cocoa = { version = "0.24.1" } [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 85fcbb46..a1e76ccd 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -11,16 +11,38 @@ mod commands; mod runtime; mod window_ext; -use tauri::{Manager, WindowEvent}; +use tauri::{ + CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, + WindowEvent, +}; use window_ext::WindowExt; fn main() { + // here `"quit".to_string()` defines the menu item id, and the second parameter is the menu item label. + let quit = CustomMenuItem::new("quit".to_string(), "Quit"); + let tray_menu = SystemTrayMenu::new().add_item(quit); + let system_tray = SystemTray::new().with_menu(tray_menu); + tauri::Builder::default() + .system_tray(system_tray) .setup(|app| { let win = app.get_window("main").unwrap(); win.position_traffic_lights(); Ok(()) }) + .on_system_tray_event(|app, event| match event { + SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { + "quit" => { + std::process::exit(0); + } + "hide" => { + let window = app.get_window("main").unwrap(); + window.hide().unwrap(); + } + _ => {} + }, + _ => {} + }) .on_window_event(|e| { let apply_offset = || { let win = e.window(); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json deleted file mode 100644 index 275e1cdb..00000000 --- a/src-tauri/tauri.conf.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "build": { - "beforeDevCommand": "npm run dev", - "beforeBuildCommand": "npm run build", - "devPath": "http://localhost:1420", - "distDir": "../dist", - "withGlobalTauri": false - }, - "package": { - "productName": "Twosomnia", - "version": "0.0.1" - }, - "tauri": { - "allowlist": { - "all": false, - "shell": { - "all": false, - "open": true - }, - "window": { - "startDragging": true - }, - "fs": { - "scope": [ - "$RESOURCE/*" - ] - } - }, - "bundle": { - "active": true, - "category": "DeveloperTool", - "copyright": "", - "deb": { - "depends": [] - }, - "externalBin": [], - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "identifier": "co.schier.twosomnia", - "longDescription": "", - "macOS": { - "entitlements": null, - "exceptionDomain": "", - "frameworks": [], - "providerShortName": null, - "signingIdentity": null - }, - "resources": [ - "plugins/*" - ], - "shortDescription": "", - "targets": "all", - "windows": { - "certificateThumbprint": null, - "digestAlgorithm": "sha256", - "timestampUrl": "" - } - }, - "security": { - "csp": null - }, - "updater": { - "active": false - }, - "windows": [ - { - "fullscreen": false, - "height": 800, - "resizable": true, - "title": "Twosomnia", - "width": 1400, - "titleBarStyle": "Overlay", - "hiddenTitle": true - } - ] - } -} diff --git a/src-tauri/tauri.toml b/src-tauri/tauri.toml new file mode 100644 index 00000000..b8a5eb6f --- /dev/null +++ b/src-tauri/tauri.toml @@ -0,0 +1,73 @@ +[build] +beforeDevCommand = "npm run dev" +beforeBuildCommand = "npm run build" +devPath = "http://localhost:1420" +distDir = "../dist" +withGlobalTauri = false + +[package] +productName = "Twosomnia" +version = "0.0.1" + +[tauri.allowlist] +all = false + +[tauri.allowlist.shell] +all = false +open = true + +[tauri.allowlist.window] +startDragging = true + +[tauri.allowlist.fs] +scope = [ "$RESOURCE/*" ] + +[tauri.bundle] +active = true +category = "DeveloperTool" +copyright = "" +externalBin = [ ] +icon = [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" +] +identifier = "co.schier.twosomnia" +longDescription = "" +resources = [ "plugins/*" ] +shortDescription = "" +targets = "all" + +[tauri.bundle.deb] +depends = [ ] + +[tauri.bundle.macOS] +exceptionDomain = "" +frameworks = [ ] + +[tauri.bundle.windows] +digestAlgorithm = "sha256" +timestampUrl = "" + +[tauri.security] + +[tauri.updater] +active = false +endpoints = [ ] +pubkey = "" +dialog = true + +[[tauri.windows]] +fullscreen = false +height = 800 +resizable = true +title = "Twosomnia" +width = 1_400 +titleBarStyle = "Overlay" +hiddenTitle = true + +[tauri.systemTray] +iconPath = "icons/icon.png" +iconAsTemplate = true diff --git a/src-web/App.tsx b/src-web/App.tsx index 315cdf14..ebc2b1eb 100644 --- a/src-web/App.tsx +++ b/src-web/App.tsx @@ -20,7 +20,7 @@ interface Response { function App() { const [error, setError] = useState(null); - const [responseBody, setResponseBody] = useState(null); + const [response, setResponse] = useState(null); const [url, setUrl] = useState('https://go-server.schier.dev/debug'); const [loading, setLoading] = useState(false); const [method, setMethod] = useState('get'); @@ -36,14 +36,14 @@ function App() { resp.body = resp.body.replace(//gi, ``); } setLoading(false); - setResponseBody(resp); + setResponse(resp); } catch (err) { setLoading(false); setError(`${err}`); } } - const contentType = responseBody?.headers['content-type']?.split(';')[0] ?? 'text/plain'; + const contentType = response?.headers['content-type']?.split(';')[0] ?? 'text/plain'; return ( <> @@ -64,12 +64,12 @@ function App() { -
+
Hello, Friend!
- + {error &&
{error}
} - {responseBody !== null && ( + {response !== null && ( <> -
- {responseBody?.method.toUpperCase()} +
+ {response?.method.toUpperCase()}  •  - {responseBody?.status} + {response?.status}  •  - {responseBody?.elapsed}ms  •  - {responseBody?.elapsed2}ms + {response?.elapsed}ms  •  + {response?.elapsed2}ms
{contentType.includes('html') ? (