feat: system tray icon build flag (#6500)
* feat: system tray icon build flag * fix: missing tray feature for testing * fix: failed tests * fix: left click should not show menu * ci: add system dependencies for appindicator lib on Linux --------- Co-authored-by: Minh141120 <minh.itptit@gmail.com>
This commit is contained in:
commit
973f77cdc6
@ -64,7 +64,7 @@ jobs:
|
||||
- name: Install Tauri dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2
|
||||
sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 libayatana-appindicator3-dev
|
||||
|
||||
- name: Update app version
|
||||
run: |
|
||||
|
||||
@ -101,7 +101,7 @@ jobs:
|
||||
- name: Install Tauri dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2
|
||||
sudo apt install -y libglib2.0-dev libatk1.0-dev libpango1.0-dev libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev librsvg2-dev libfuse2 libayatana-appindicator3-dev
|
||||
|
||||
- name: Update app version base public_provider
|
||||
run: |
|
||||
|
||||
@ -517,41 +517,41 @@ __metadata:
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=c5357d&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=fcb200&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/95e2ec1f1213d604730f5c9c381c80840402b00a9649039d1a9754ee3efa13e224e4ca39ea094aab5751f3f2ace1860c7640769e66b191b8c56998fd5f2ba5b9
|
||||
checksum: 10c0/603e79794614f861a9cf5693a4bbc480a62242309a6cb94a97c81e31518032c7462b2edad93a4380a18110f817ab15d85dc91a7924fd6e103a3462f6915ee368
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=c5357d&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=fcb200&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/95e2ec1f1213d604730f5c9c381c80840402b00a9649039d1a9754ee3efa13e224e4ca39ea094aab5751f3f2ace1860c7640769e66b191b8c56998fd5f2ba5b9
|
||||
checksum: 10c0/603e79794614f861a9cf5693a4bbc480a62242309a6cb94a97c81e31518032c7462b2edad93a4380a18110f817ab15d85dc91a7924fd6e103a3462f6915ee368
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fdownload-extension%40workspace%3Adownload-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=c5357d&locator=%40janhq%2Fdownload-extension%40workspace%3Adownload-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=fcb200&locator=%40janhq%2Fdownload-extension%40workspace%3Adownload-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/95e2ec1f1213d604730f5c9c381c80840402b00a9649039d1a9754ee3efa13e224e4ca39ea094aab5751f3f2ace1860c7640769e66b191b8c56998fd5f2ba5b9
|
||||
checksum: 10c0/603e79794614f861a9cf5693a4bbc480a62242309a6cb94a97c81e31518032c7462b2edad93a4380a18110f817ab15d85dc91a7924fd6e103a3462f6915ee368
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fllamacpp-extension%40workspace%3Allamacpp-extension":
|
||||
version: 0.1.10
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=c5357d&locator=%40janhq%2Fllamacpp-extension%40workspace%3Allamacpp-extension"
|
||||
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=fcb200&locator=%40janhq%2Fllamacpp-extension%40workspace%3Allamacpp-extension"
|
||||
dependencies:
|
||||
rxjs: "npm:^7.8.1"
|
||||
ulidx: "npm:^2.3.0"
|
||||
checksum: 10c0/95e2ec1f1213d604730f5c9c381c80840402b00a9649039d1a9754ee3efa13e224e4ca39ea094aab5751f3f2ace1860c7640769e66b191b8c56998fd5f2ba5b9
|
||||
checksum: 10c0/603e79794614f861a9cf5693a4bbc480a62242309a6cb94a97c81e31518032c7462b2edad93a4380a18110f817ab15d85dc91a7924fd6e103a3462f6915ee368
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@ -2,3 +2,4 @@
|
||||
# workaround needed to prevent `STATUS_ENTRYPOINT_NOT_FOUND` error in tests
|
||||
# see https://github.com/tauri-apps/tauri/pull/4383#issuecomment-1212221864
|
||||
__TAURI_WORKSPACE__ = "true"
|
||||
ENABLE_SYSTEM_TRAY_ICON = "false"
|
||||
|
||||
@ -20,6 +20,7 @@ default = [
|
||||
"tauri/x11",
|
||||
"tauri/protocol-asset",
|
||||
"tauri/macos-private-api",
|
||||
"tauri/tray-icon",
|
||||
"tauri/test",
|
||||
]
|
||||
test-tauri = [
|
||||
@ -27,6 +28,7 @@ test-tauri = [
|
||||
"tauri/x11",
|
||||
"tauri/protocol-asset",
|
||||
"tauri/macos-private-api",
|
||||
"tauri/tray-icon",
|
||||
"tauri/test",
|
||||
]
|
||||
|
||||
|
||||
@ -296,7 +296,6 @@ pub async fn cancel_tool_call(
|
||||
pub async fn get_mcp_configs(app: AppHandle) -> Result<String, String> {
|
||||
let mut path = get_jan_data_folder_path(app);
|
||||
path.push("mcp_config.json");
|
||||
log::info!("read mcp configs, path: {:?}", path);
|
||||
|
||||
// Create default empty config if file doesn't exist
|
||||
if !path.exists() {
|
||||
|
||||
@ -5,7 +5,11 @@ use std::{
|
||||
path::PathBuf,
|
||||
};
|
||||
use tar::Archive;
|
||||
use tauri::{App, Emitter, Manager};
|
||||
use tauri::{
|
||||
menu::{Menu, MenuItem, PredefinedMenuItem},
|
||||
tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder, TrayIconEvent},
|
||||
App, Emitter, Manager,
|
||||
};
|
||||
use tauri_plugin_store::StoreExt;
|
||||
// use tokio::sync::Mutex;
|
||||
// use tokio::time::{sleep, Duration}; // Using tokio::sync::Mutex
|
||||
@ -82,7 +86,6 @@ pub fn install_extensions(app: tauri::AppHandle, force: bool) -> Result<(), Stri
|
||||
let path = entry.path();
|
||||
|
||||
if path.extension().map_or(false, |ext| ext == "tgz") {
|
||||
log::info!("Installing extension from {:?}", path);
|
||||
let tar_gz = File::open(&path).map_err(|e| e.to_string())?;
|
||||
let gz_decoder = GzDecoder::new(tar_gz);
|
||||
let mut archive = Archive::new(gz_decoder);
|
||||
@ -207,3 +210,46 @@ pub fn setup_mcp(app: &App) {
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn setup_tray(app: &App) -> tauri::Result<TrayIcon> {
|
||||
let show_i = MenuItem::with_id(app.handle(), "open", "Open Jan", true, None::<&str>)?;
|
||||
let quit_i = MenuItem::with_id(app.handle(), "quit", "Quit", true, None::<&str>)?;
|
||||
let separator_i = PredefinedMenuItem::separator(app.handle())?;
|
||||
let menu = Menu::with_items(app.handle(), &[&show_i, &separator_i, &quit_i])?;
|
||||
TrayIconBuilder::with_id("tray")
|
||||
.icon(app.default_window_icon().unwrap().clone())
|
||||
.menu(&menu)
|
||||
.show_menu_on_left_click(false)
|
||||
.on_tray_icon_event(|tray, event| match event {
|
||||
TrayIconEvent::Click {
|
||||
button: MouseButton::Left,
|
||||
button_state: MouseButtonState::Up,
|
||||
..
|
||||
} => {
|
||||
// let's show and focus the main window when the tray is clicked
|
||||
let app = tray.app_handle();
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
let _ = window.unminimize();
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
log::debug!("unhandled event {event:?}");
|
||||
}
|
||||
})
|
||||
.on_menu_event(|app, event| match event.id.as_ref() {
|
||||
"open" => {
|
||||
let window = app.get_webview_window("main").unwrap();
|
||||
window.show().unwrap();
|
||||
window.set_focus().unwrap();
|
||||
}
|
||||
"quit" => {
|
||||
app.exit(0);
|
||||
}
|
||||
other => {
|
||||
println!("menu item {} not handled", other);
|
||||
}
|
||||
})
|
||||
.build(app)
|
||||
}
|
||||
|
||||
@ -8,10 +8,12 @@ use core::{
|
||||
};
|
||||
use jan_utils::generate_app_token;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tauri::{Emitter, Manager, RunEvent};
|
||||
use tauri::{Manager, RunEvent};
|
||||
use tauri_plugin_llamacpp::cleanup_llama_processes;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::core::setup::setup_tray;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let mut builder = tauri::Builder::default();
|
||||
@ -108,6 +110,21 @@ pub fn run() {
|
||||
server_handle: Arc::new(Mutex::new(None)),
|
||||
tool_call_cancellations: Arc::new(Mutex::new(HashMap::new())),
|
||||
})
|
||||
.on_window_event(|window, event| match event {
|
||||
tauri::WindowEvent::CloseRequested { api, .. } => {
|
||||
if option_env!("ENABLE_SYSTEM_TRAY_ICON").unwrap_or("false") == "true" {
|
||||
#[cfg(target_os = "macos")]
|
||||
window
|
||||
.app_handle()
|
||||
.set_activation_policy(tauri::ActivationPolicy::Accessory)
|
||||
.unwrap();
|
||||
|
||||
window.hide().unwrap();
|
||||
api.prevent_close();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
.setup(|app| {
|
||||
app.handle().plugin(
|
||||
tauri_plugin_log::Builder::default()
|
||||
@ -129,6 +146,11 @@ pub fn run() {
|
||||
log::error!("Failed to install extensions: {}", e);
|
||||
}
|
||||
|
||||
if option_env!("ENABLE_SYSTEM_TRAY_ICON").unwrap_or("false") == "true" {
|
||||
log::info!("Enabling system tray icon");
|
||||
let _ = setup_tray(app);
|
||||
}
|
||||
|
||||
#[cfg(any(windows, target_os = "linux"))]
|
||||
{
|
||||
use tauri_plugin_deep_link::DeepLinkExt;
|
||||
@ -146,14 +168,12 @@ pub fn run() {
|
||||
// This is called when the app is actually exiting (e.g., macOS dock quit)
|
||||
// We can't prevent this, so run cleanup quickly
|
||||
let app_handle = app.clone();
|
||||
// Hide window immediately
|
||||
if let Some(window) = app_handle.get_webview_window("main") {
|
||||
let _ = window.hide();
|
||||
}
|
||||
tokio::task::block_in_place(|| {
|
||||
tauri::async_runtime::block_on(async {
|
||||
// Hide window immediately
|
||||
if let Some(window) = app_handle.get_webview_window("main") {
|
||||
let _ = window.hide();
|
||||
let _ = window.emit("kill-mcp-servers", ());
|
||||
}
|
||||
|
||||
// Quick cleanup with shorter timeout
|
||||
let state = app_handle.state::<AppState>();
|
||||
let _ = clean_up_mcp_servers(state).await;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user