c65ada0ba9
- Add GET /health/version public endpoint to API - Extend Tauri with 4 plugins: notification, autostart, window-state, store - Implement close-to-tray with prevent_close + prevent_exit (Pitfall 2) - Tray menu with Oeffnen/Beenden (German labels) - Async startup version check against server /health/version - Generate Tessera-branded icons (yellow T on dark bg, OKLCH palette) - Update capabilities for notification, autostart, window-state permissions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
120 lines
4.5 KiB
Rust
120 lines
4.5 KiB
Rust
use tauri::{
|
|
Manager,
|
|
menu::{MenuBuilder, MenuItemBuilder},
|
|
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
|
|
RunEvent, WindowEvent,
|
|
};
|
|
use tauri_plugin_autostart::MacosLauncher;
|
|
use tauri_plugin_notification::NotificationExt;
|
|
use tauri_plugin_store::StoreExt;
|
|
|
|
#[derive(serde::Deserialize)]
|
|
struct VersionResponse {
|
|
version: String,
|
|
}
|
|
|
|
pub fn run() {
|
|
let app = tauri::Builder::default()
|
|
.plugin(tauri_plugin_store::Builder::new().build())
|
|
.plugin(tauri_plugin_notification::init())
|
|
.plugin(tauri_plugin_window_state::Builder::default().build())
|
|
.plugin(tauri_plugin_autostart::init(MacosLauncher::LaunchAgent, None))
|
|
.setup(|app| {
|
|
let store = app.store("config.json")?;
|
|
let server_url = store.get("server_url");
|
|
|
|
let mut url_for_check: Option<String> = None;
|
|
|
|
if let Some(url_value) = server_url {
|
|
if let Some(url_str) = url_value.as_str() {
|
|
if !url_str.is_empty() {
|
|
url_for_check = Some(url_str.to_string());
|
|
if let Some(window) = app.get_webview_window("main") {
|
|
if let Ok(parsed) = url_str.parse::<tauri::Url>() {
|
|
let _ = window.navigate(parsed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tray menu
|
|
let open = MenuItemBuilder::with_id("open", "Oeffnen").build(app)?;
|
|
let quit = MenuItemBuilder::with_id("quit", "Beenden").build(app)?;
|
|
let menu = MenuBuilder::new(app)
|
|
.item(&open)
|
|
.separator()
|
|
.item(&quit)
|
|
.build()?;
|
|
|
|
let _tray = TrayIconBuilder::new()
|
|
.icon(app.default_window_icon().unwrap().clone())
|
|
.menu(&menu)
|
|
.tooltip("Tessera")
|
|
.show_menu_on_left_click(false)
|
|
.on_menu_event(|app, event| match event.id().as_ref() {
|
|
"open" => {
|
|
if let Some(w) = app.get_webview_window("main") {
|
|
let _ = w.show();
|
|
let _ = w.set_focus();
|
|
}
|
|
}
|
|
"quit" => {
|
|
app.exit(0);
|
|
}
|
|
_ => {}
|
|
})
|
|
.on_tray_icon_event(|tray, event| {
|
|
if let TrayIconEvent::Click {
|
|
button: MouseButton::Left,
|
|
button_state: MouseButtonState::Up,
|
|
..
|
|
} = event
|
|
{
|
|
if let Some(w) = tray.app_handle().get_webview_window("main") {
|
|
let _ = w.show();
|
|
let _ = w.set_focus();
|
|
}
|
|
}
|
|
})
|
|
.build(app)?;
|
|
|
|
// Version check (async, non-blocking)
|
|
if let Some(server_url) = url_for_check {
|
|
let app_handle = app.handle().clone();
|
|
let app_version = env!("CARGO_PKG_VERSION").to_string();
|
|
tauri::async_runtime::spawn(async move {
|
|
let url = format!("{}/health/version", server_url.trim_end_matches('/'));
|
|
if let Ok(resp) = reqwest::get(&url).await {
|
|
if let Ok(info) = resp.json::<VersionResponse>().await {
|
|
if info.version != app_version {
|
|
let _ = app_handle
|
|
.notification()
|
|
.builder()
|
|
.title("Tessera Update")
|
|
.body("Eine neue Version ist verfuegbar.")
|
|
.show();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
Ok(())
|
|
})
|
|
.on_window_event(|window, event| {
|
|
if let WindowEvent::CloseRequested { api, .. } = event {
|
|
let _ = window.hide();
|
|
api.prevent_close();
|
|
}
|
|
})
|
|
.build(tauri::generate_context!())
|
|
.expect("error while building Tessera desktop application");
|
|
|
|
app.run(|_app, event| {
|
|
if let RunEvent::ExitRequested { api, .. } = event {
|
|
api.prevent_exit();
|
|
}
|
|
});
|
|
}
|