From 82500b35f484f2d8dff29202c41efc0ae86f7a2a Mon Sep 17 00:00:00 2001 From: reya Date: Thu, 19 Sep 2024 08:59:17 +0700 Subject: [PATCH] feat: add tray icon --- src-tauri/src/commands/account.rs | 23 ++++++++--- src-tauri/src/commands/mod.rs | 1 + src-tauri/src/commands/tray.rs | 64 +++++++++++++++++++++++++++++++ src-tauri/src/main.rs | 18 ++++++--- src-tauri/tauri.conf.json | 14 +++++-- src/commands.ts | 8 ++++ src/routes/index.tsx | 13 +++++++ 7 files changed, 125 insertions(+), 16 deletions(-) create mode 100644 src-tauri/src/commands/tray.rs diff --git a/src-tauri/src/commands/account.rs b/src-tauri/src/commands/account.rs index 86c3a72..aba11f4 100644 --- a/src-tauri/src/commands/account.rs +++ b/src-tauri/src/commands/account.rs @@ -15,6 +15,12 @@ pub struct EventPayload { sender: String, } +#[derive(Debug, Clone, Serialize, Deserialize, Type)] +struct Account { + password: String, + nostr_connect: Option, +} + #[tauri::command] #[specta::specta] pub async fn get_metadata(user_id: String, state: State<'_, Nostr>) -> Result { @@ -37,12 +43,6 @@ pub async fn get_metadata(user_id: String, state: State<'_, Nostr>) -> Result, -} - #[tauri::command] #[specta::specta] pub fn get_accounts() -> Vec { @@ -55,6 +55,17 @@ pub fn get_accounts() -> Vec { accounts.into_iter().collect() } +#[tauri::command] +#[specta::specta] +pub async fn get_current_account(state: State<'_, Nostr>) -> Result { + let client = &state.client; + let signer = client.signer().await.map_err(|e| e.to_string())?; + let public_key = signer.public_key().await.map_err(|e| e.to_string())?; + let bech32 = public_key.to_bech32().map_err(|e| e.to_string())?; + + Ok(bech32) +} + #[tauri::command] #[specta::specta] pub async fn create_account( diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index e0068a5..46130c5 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -1,3 +1,4 @@ pub mod account; pub mod chat; pub mod relay; +pub mod tray; diff --git a/src-tauri/src/commands/tray.rs b/src-tauri/src/commands/tray.rs new file mode 100644 index 0000000..3b82f49 --- /dev/null +++ b/src-tauri/src/commands/tray.rs @@ -0,0 +1,64 @@ +#[cfg(target_os = "macos")] +use border::WebviewWindowExt as WebviewWindowExtAlt; +use tauri::{Manager, WebviewWindowBuilder}; +#[cfg(not(target_os = "linux"))] +use tauri_plugin_decorum::WebviewWindowExt; + +pub fn setup_tray_icon(app: &tauri::AppHandle) -> tauri::Result<()> { + let tray = app.tray_by_id("main").expect("Error: tray icon not found."); + + let menu = tauri::menu::MenuBuilder::new(app) + .item( + &tauri::menu::MenuItem::with_id(app, "open", "Open Coop", true, None::<&str>).unwrap(), + ) + .item(&tauri::menu::MenuItem::with_id(app, "quit", "Quit", true, None::<&str>).unwrap()) + .build() + .expect("Error: cannot create menu."); + + if tray.set_menu(Some(menu)).is_err() { + panic!("Error: cannot set menu for tray icon.") + } + + tray.on_menu_event(move |app, event| match event.id.0.as_str() { + "open" => { + if let Some(window) = app.get_webview_window("main") { + if window.is_visible().unwrap_or_default() { + let _ = window.set_focus(); + } else { + let _ = window.show(); + let _ = window.set_focus(); + }; + } else { + let config = app.config().app.windows.first().unwrap(); + let window = + WebviewWindowBuilder::from_config(app, config).unwrap().build().unwrap(); + + // Set custom decoration + #[cfg(target_os = "windows")] + window.create_overlay_titlebar().unwrap(); + + // Set traffic light inset + #[cfg(target_os = "macos")] + window.set_traffic_lights_inset(12.0, 18.0).unwrap(); + + // Workaround for reset traffic light when theme changed + #[cfg(target_os = "macos")] + let win_ = window.clone(); + #[cfg(target_os = "macos")] + window.on_window_event(move |event| { + if let tauri::WindowEvent::ThemeChanged(_) = event { + win_.set_traffic_lights_inset(12.0, 18.0).unwrap(); + } + }); + + // Restore native border + #[cfg(target_os = "macos")] + window.add_border(None); + } + } + "quit" => std::process::exit(0), + _ => {} + }); + + Ok(()) +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 3564774..d790e1d 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,12 +3,12 @@ #[cfg(target_os = "macos")] use border::WebviewWindowExt as WebviewWindowExtAlt; +use commands::tray::setup_tray_icon; use nostr_sdk::prelude::*; use specta_typescript::Typescript; -use std::env; use std::{ collections::HashMap, - fs, + env, fs, io::{self, BufRead}, str::FromStr, time::Duration, @@ -47,6 +47,7 @@ fn main() { delete_account, reset_password, get_accounts, + get_current_account, get_metadata, get_contact_list, get_chats, @@ -72,6 +73,8 @@ fn main() { builder.mount_events(app); let handle = app.handle(); + let _ = setup_tray_icon(handle); + #[cfg(not(target_os = "linux"))] let main_window = app.get_webview_window("main").unwrap(); @@ -129,7 +132,6 @@ fn main() { if let Some((relay, option)) = line.split_once(',') { match RelayMetadata::from_str(option) { Ok(meta) => { - println!("Connecting to relay...: {} - {}", relay, meta); let opts = if meta == RelayMetadata::Read { RelayOptions::new().read(true).write(false) } else { @@ -138,7 +140,6 @@ fn main() { let _ = client.pool().add_relay(relay, opts).await; } Err(_) => { - println!("Connecting to relay...: {}", relay); let _ = client.add_relay(relay).await; } } @@ -175,8 +176,13 @@ fn main() { .plugin(tauri_plugin_decorum::init()) .plugin(tauri_plugin_notification::init()) .plugin(tauri_plugin_shell::init()) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + .build(tauri::generate_context!()) + .expect("error while running tauri application") + .run(|_app_handle, event| { + if let tauri::RunEvent::ExitRequested { api, .. } = event { + api.prevent_exit(); + } + }); } #[cfg(debug_assertions)] diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index bee1a49..2919fb7 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "productName": "Coop", "version": "0.1.7", - "identifier": "nu.lume.coop", + "identifier": "su.reya.coop", "build": { "beforeDevCommand": "pnpm dev", "devUrl": "http://localhost:1420", @@ -29,12 +29,18 @@ "$RESOURCE/*" ] } + }, + "trayIcon": { + "id": "main", + "iconPath": "./icons/32x32.png", + "iconAsTemplate": true, + "menuOnLeftClick": true } }, "bundle": { - "homepage": "https://lume.nu/coop", - "longDescription": "direct message client for desktop", - "shortDescription": "nostr client", + "homepage": "https://coop.reya.su", + "longDescription": "A direct message nostr client for desktop.", + "shortDescription": "Nostr NIP-17 client", "targets": "all", "active": true, "category": "SocialNetworking", diff --git a/src/commands.ts b/src/commands.ts index 7388938..2615522 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -112,6 +112,14 @@ async resetPassword(key: string, password: string) : Promise { return await TAURI_INVOKE("get_accounts"); }, +async getCurrentAccount() : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_current_account") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, async getMetadata(userId: string) : Promise> { try { return { status: "ok", data: await TAURI_INVOKE("get_metadata", { userId }) }; diff --git a/src/routes/index.tsx b/src/routes/index.tsx index efd3396..ac10b4c 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -7,6 +7,19 @@ export const Route = createFileRoute("/")({ // Check for app updates await checkForAppUpdates(true); + // Get current account + const checkAccount = await commands.getCurrentAccount(); + + if (checkAccount.status === "ok") { + const currentAccount = checkAccount.data; + + throw redirect({ + to: "/$account/chats/new", + params: { account: currentAccount }, + replace: true, + }); + } + // Get all accounts from system const accounts = await commands.getAccounts();