2025-03-03 17:54:00 +08:00
|
|
|
mod assistant;
|
2024-12-14 15:38:32 +08:00
|
|
|
mod autostart;
|
2025-02-06 11:45:37 +08:00
|
|
|
mod common;
|
2025-02-12 16:15:55 +08:00
|
|
|
mod local;
|
|
|
|
|
mod search;
|
2025-02-06 11:45:37 +08:00
|
|
|
mod server;
|
2025-03-03 17:54:00 +08:00
|
|
|
mod setup;
|
2025-01-20 19:38:59 +08:00
|
|
|
mod shortcut;
|
2025-02-06 11:45:37 +08:00
|
|
|
mod util;
|
2025-01-10 14:59:03 +08:00
|
|
|
|
2025-02-07 16:31:05 +08:00
|
|
|
use crate::common::register::SearchSourceRegistry;
|
2025-02-18 11:51:50 +08:00
|
|
|
// use crate::common::traits::SearchSource;
|
2025-02-08 07:38:02 +08:00
|
|
|
use crate::common::{MAIN_WINDOW_LABEL, SETTINGS_WINDOW_LABEL};
|
2025-02-07 16:31:05 +08:00
|
|
|
use crate::server::search::CocoSearchSource;
|
2025-02-06 11:45:37 +08:00
|
|
|
use crate::server::servers::{load_or_insert_default_server, load_servers_token};
|
2025-01-20 19:38:59 +08:00
|
|
|
use autostart::{change_autostart, enable_autostart};
|
2025-02-25 16:22:22 +08:00
|
|
|
use lazy_static::lazy_static;
|
2025-02-07 16:31:05 +08:00
|
|
|
use reqwest::Client;
|
|
|
|
|
use std::path::PathBuf;
|
2025-02-25 16:22:22 +08:00
|
|
|
use std::sync::Mutex;
|
2024-12-22 15:35:05 +08:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
use tauri::ActivationPolicy;
|
2025-02-18 11:51:50 +08:00
|
|
|
use tauri::{
|
2025-02-25 16:22:22 +08:00
|
|
|
AppHandle, Emitter, Manager, PhysicalPosition, Runtime, State, WebviewWindow, Window,
|
2025-02-18 11:51:50 +08:00
|
|
|
WindowEvent,
|
|
|
|
|
};
|
2025-01-20 19:38:59 +08:00
|
|
|
use tauri_plugin_autostart::MacosLauncher;
|
2025-02-07 16:31:05 +08:00
|
|
|
use tokio::runtime::Runtime as RT;
|
2025-02-06 11:45:37 +08:00
|
|
|
|
|
|
|
|
/// Tauri store name
|
|
|
|
|
pub(crate) const COCO_TAURI_STORE: &str = "coco_tauri_store";
|
2024-10-13 17:41:16 +08:00
|
|
|
|
2025-02-25 16:22:22 +08:00
|
|
|
lazy_static! {
|
|
|
|
|
static ref PREVIOUS_MONITOR_NAME: Mutex<Option<String>> = Mutex::new(None);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-30 15:29:00 +08:00
|
|
|
#[tauri::command]
|
|
|
|
|
fn change_window_height(handle: AppHandle, height: u32) {
|
2025-02-08 07:38:02 +08:00
|
|
|
let window: WebviewWindow = handle.get_webview_window(MAIN_WINDOW_LABEL).unwrap();
|
2024-11-30 15:29:00 +08:00
|
|
|
|
|
|
|
|
let mut size = window.outer_size().unwrap();
|
|
|
|
|
size.height = height;
|
|
|
|
|
window.set_size(size).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-26 10:08:55 +08:00
|
|
|
#[derive(serde::Deserialize)]
|
|
|
|
|
struct ThemeChangedPayload {
|
|
|
|
|
is_dark_mode: bool,
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-10 14:59:03 +08:00
|
|
|
#[derive(Clone, serde::Serialize)]
|
|
|
|
|
struct Payload {
|
|
|
|
|
args: Vec<String>,
|
|
|
|
|
cwd: String,
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-13 17:41:16 +08:00
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
|
|
|
pub fn run() {
|
2024-12-19 12:06:40 +08:00
|
|
|
let mut ctx = tauri::generate_context!();
|
2025-02-21 18:57:32 +08:00
|
|
|
// Initialize logger
|
|
|
|
|
env_logger::init();
|
2025-02-23 13:09:38 +08:00
|
|
|
|
2025-02-19 13:02:22 +08:00
|
|
|
let mut app_builder = tauri::Builder::default();
|
|
|
|
|
|
|
|
|
|
#[cfg(desktop)]
|
|
|
|
|
{
|
|
|
|
|
app_builder = app_builder.plugin(tauri_plugin_single_instance::init(|_app, argv, _cwd| {
|
|
|
|
|
println!("a new app instance was opened with {argv:?} and the deep link event was already triggered");
|
|
|
|
|
// when defining deep link schemes at runtime, you must also check `argv` here
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 18:57:32 +08:00
|
|
|
app_builder = app_builder
|
|
|
|
|
.plugin(tauri_plugin_http::init())
|
2024-10-13 17:41:16 +08:00
|
|
|
.plugin(tauri_plugin_shell::init())
|
2024-12-11 10:45:54 +08:00
|
|
|
.plugin(tauri_plugin_autostart::init(
|
|
|
|
|
MacosLauncher::AppleScript,
|
|
|
|
|
None,
|
|
|
|
|
))
|
2024-12-19 12:06:40 +08:00
|
|
|
.plugin(tauri_plugin_theme::init(ctx.config_mut()))
|
2025-01-10 14:59:03 +08:00
|
|
|
.plugin(tauri_plugin_deep_link::init())
|
2025-03-03 17:54:00 +08:00
|
|
|
.plugin(tauri_plugin_store::Builder::default().build())
|
|
|
|
|
.plugin(tauri_plugin_dialog::init())
|
2025-03-05 12:22:33 +08:00
|
|
|
.plugin(tauri_plugin_fs_pro::init())
|
|
|
|
|
.plugin(tauri_plugin_macos_permissions::init())
|
|
|
|
|
.plugin(tauri_plugin_screenshots::init());
|
2025-02-18 08:26:52 +08:00
|
|
|
|
|
|
|
|
// Conditional compilation for macOS
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
{
|
|
|
|
|
app_builder = app_builder.plugin(tauri_nspanel::init());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let app = app_builder
|
2024-11-30 15:29:00 +08:00
|
|
|
.invoke_handler(tauri::generate_handler![
|
|
|
|
|
change_window_height,
|
2025-01-20 19:38:59 +08:00
|
|
|
shortcut::change_shortcut,
|
|
|
|
|
shortcut::unregister_shortcut,
|
|
|
|
|
shortcut::get_current_shortcut,
|
2024-12-14 15:38:32 +08:00
|
|
|
change_autostart,
|
2024-12-24 18:24:53 +08:00
|
|
|
hide_coco,
|
2025-02-12 16:15:55 +08:00
|
|
|
server::servers::get_server_token,
|
2025-02-06 11:45:37 +08:00
|
|
|
server::servers::add_coco_server,
|
|
|
|
|
server::servers::remove_coco_server,
|
|
|
|
|
server::servers::list_coco_servers,
|
|
|
|
|
server::servers::logout_coco_server,
|
|
|
|
|
server::servers::refresh_coco_server_info,
|
2025-02-24 18:14:43 +08:00
|
|
|
server::servers::enable_server,
|
|
|
|
|
server::servers::disable_server,
|
2025-02-06 11:45:37 +08:00
|
|
|
server::auth::handle_sso_callback,
|
|
|
|
|
server::profile::get_user_profiles,
|
|
|
|
|
server::datasource::get_datasources_by_server,
|
|
|
|
|
server::connector::get_connectors_by_server,
|
2025-02-07 16:31:05 +08:00
|
|
|
search::query_coco_fusion,
|
2025-02-25 15:01:32 +08:00
|
|
|
assistant::chat_history,
|
|
|
|
|
assistant::new_chat,
|
|
|
|
|
assistant::send_message,
|
|
|
|
|
assistant::session_chat_history,
|
|
|
|
|
assistant::open_session_chat,
|
|
|
|
|
assistant::close_session_chat,
|
|
|
|
|
assistant::cancel_session_chat,
|
2025-02-06 11:45:37 +08:00
|
|
|
// server::get_coco_server_datasources,
|
2025-02-21 18:57:32 +08:00
|
|
|
// server::get_coco_server_connectors,
|
|
|
|
|
server::websocket::connect_to_server,
|
|
|
|
|
server::websocket::disconnect,
|
2024-11-30 15:29:00 +08:00
|
|
|
])
|
|
|
|
|
.setup(|app| {
|
2025-02-07 16:31:05 +08:00
|
|
|
let registry = SearchSourceRegistry::default();
|
2025-02-06 11:45:37 +08:00
|
|
|
|
2025-02-07 16:31:05 +08:00
|
|
|
app.manage(registry); // Store registry in Tauri's app state
|
2025-02-21 18:57:32 +08:00
|
|
|
app.manage(server::websocket::WebSocketManager::default());
|
2025-02-06 11:45:37 +08:00
|
|
|
|
|
|
|
|
// Get app handle
|
|
|
|
|
let app_handle = app.handle().clone();
|
|
|
|
|
|
|
|
|
|
// Create a single Tokio runtime instance
|
|
|
|
|
let rt = RT::new().expect("Failed to create Tokio runtime");
|
|
|
|
|
|
|
|
|
|
// Use the runtime to spawn the async initialization tasks
|
2025-02-23 13:09:38 +08:00
|
|
|
let init_app_handle = app.handle().clone();
|
2025-02-06 11:45:37 +08:00
|
|
|
rt.spawn(async move {
|
2025-02-23 13:09:38 +08:00
|
|
|
init(&init_app_handle).await; // Pass a reference to `app_handle`
|
2025-02-06 11:45:37 +08:00
|
|
|
});
|
|
|
|
|
|
2025-02-11 14:53:46 +08:00
|
|
|
shortcut::enable_shortcut(&app);
|
2024-11-30 20:41:47 +08:00
|
|
|
enable_tray(app);
|
2024-12-14 15:38:32 +08:00
|
|
|
enable_autostart(app);
|
2024-11-30 15:29:00 +08:00
|
|
|
|
2024-12-17 11:20:50 +08:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
app.set_activation_policy(ActivationPolicy::Accessory);
|
|
|
|
|
|
2025-02-24 08:22:01 +08:00
|
|
|
// app.listen("theme-changed", move |event| {
|
|
|
|
|
// if let Ok(payload) = serde_json::from_str::<ThemeChangedPayload>(event.payload()) {
|
|
|
|
|
// // switch_tray_icon(app.app_handle(), payload.is_dark_mode);
|
|
|
|
|
// println!("Theme changed: is_dark_mode = {}", payload.is_dark_mode);
|
|
|
|
|
// }
|
|
|
|
|
// });
|
2024-12-26 10:08:55 +08:00
|
|
|
|
2025-02-19 13:02:22 +08:00
|
|
|
#[cfg(desktop)]
|
|
|
|
|
{
|
|
|
|
|
#[cfg(any(windows, target_os = "linux"))]
|
|
|
|
|
{
|
|
|
|
|
app.deep_link().register("coco")?;
|
|
|
|
|
use tauri_plugin_deep_link::DeepLinkExt;
|
|
|
|
|
app.deep_link().register_all()?;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-10 14:59:03 +08:00
|
|
|
|
2025-02-24 08:22:01 +08:00
|
|
|
// app.deep_link().on_open_url(|event| {
|
|
|
|
|
// dbg!(event.urls());
|
|
|
|
|
// });
|
2025-01-10 14:59:03 +08:00
|
|
|
|
2025-02-08 07:38:02 +08:00
|
|
|
let main_window = app.get_webview_window(MAIN_WINDOW_LABEL).unwrap();
|
|
|
|
|
let settings_window = app.get_webview_window(SETTINGS_WINDOW_LABEL).unwrap();
|
|
|
|
|
setup::default(app, main_window.clone(), settings_window.clone());
|
2025-02-06 11:45:37 +08:00
|
|
|
|
2024-11-30 15:29:00 +08:00
|
|
|
Ok(())
|
2025-02-12 16:15:55 +08:00
|
|
|
})
|
|
|
|
|
.on_window_event(|window, event| match event {
|
|
|
|
|
WindowEvent::CloseRequested { api, .. } => {
|
|
|
|
|
dbg!("Close requested event received");
|
|
|
|
|
window.hide().unwrap();
|
|
|
|
|
api.prevent_close();
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
})
|
|
|
|
|
.build(ctx)
|
2024-10-13 17:41:16 +08:00
|
|
|
.expect("error while running tauri application");
|
2025-02-09 21:51:03 +08:00
|
|
|
|
2025-02-23 13:09:38 +08:00
|
|
|
// Create a single Tokio runtime instance
|
|
|
|
|
let rt = RT::new().expect("Failed to create Tokio runtime");
|
|
|
|
|
let app_handle = app.handle().clone();
|
|
|
|
|
rt.spawn(async move {
|
|
|
|
|
init_app_search_source(&app_handle).await;
|
2025-02-24 08:22:01 +08:00
|
|
|
let _ = server::connector::refresh_all_connectors(&app_handle).await;
|
|
|
|
|
let _ = server::datasource::refresh_all_datasources(&app_handle).await;
|
2025-02-23 13:09:38 +08:00
|
|
|
});
|
|
|
|
|
|
2025-02-09 21:51:03 +08:00
|
|
|
app.run(|app_handle, event| match event {
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
tauri::RunEvent::Reopen {
|
|
|
|
|
has_visible_windows,
|
|
|
|
|
..
|
|
|
|
|
} => {
|
2025-02-12 16:15:55 +08:00
|
|
|
dbg!(
|
|
|
|
|
"Reopen event received: has_visible_windows = {}",
|
|
|
|
|
has_visible_windows
|
|
|
|
|
);
|
2025-02-09 21:51:03 +08:00
|
|
|
if has_visible_windows {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
let _ = app_handle;
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-10-13 17:41:16 +08:00
|
|
|
}
|
2024-11-30 15:29:00 +08:00
|
|
|
|
2025-02-06 11:45:37 +08:00
|
|
|
pub async fn init<R: Runtime>(app_handle: &AppHandle<R>) {
|
|
|
|
|
// Await the async functions to load the servers and tokens
|
|
|
|
|
if let Err(err) = load_or_insert_default_server(app_handle).await {
|
|
|
|
|
eprintln!("Failed to load servers: {}", err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Err(err) = load_servers_token(app_handle).await {
|
|
|
|
|
eprintln!("Failed to load server tokens: {}", err);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-07 16:31:05 +08:00
|
|
|
let coco_servers = server::servers::get_all_servers();
|
|
|
|
|
|
|
|
|
|
// Get the registry from Tauri's state
|
2025-02-18 11:51:50 +08:00
|
|
|
let registry: State<SearchSourceRegistry> = app_handle.state::<SearchSourceRegistry>();
|
2025-02-07 16:31:05 +08:00
|
|
|
|
|
|
|
|
for server in coco_servers {
|
|
|
|
|
let source = CocoSearchSource::new(server.clone(), Client::new());
|
|
|
|
|
registry.register_source(source).await;
|
|
|
|
|
}
|
2025-02-23 13:09:38 +08:00
|
|
|
}
|
2025-02-07 16:31:05 +08:00
|
|
|
|
2025-02-23 13:09:38 +08:00
|
|
|
async fn init_app_search_source<R: Runtime>(app_handle: &AppHandle<R>) {
|
2025-02-11 14:53:46 +08:00
|
|
|
// Run the slow application directory search in the background
|
2025-02-23 13:09:38 +08:00
|
|
|
let dir = vec![
|
|
|
|
|
dirs::home_dir().map(|home| home.join("Applications")), // Resolve `~/Applications`
|
|
|
|
|
Some(PathBuf::from("/Applications")),
|
|
|
|
|
Some(PathBuf::from("/System/Applications")),
|
|
|
|
|
Some(PathBuf::from("/System/Applications/Utilities")),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Remove any `None` values if `home_dir()` fails
|
|
|
|
|
let app_dirs: Vec<PathBuf> = dir.into_iter().flatten().collect();
|
|
|
|
|
|
2025-02-24 18:41:06 +08:00
|
|
|
let application_search = local::application::ApplicationSearchSource::new(1000f64, app_dirs);
|
2025-02-23 13:09:38 +08:00
|
|
|
|
|
|
|
|
// Register the application search source
|
|
|
|
|
let registry = app_handle.state::<SearchSourceRegistry>();
|
|
|
|
|
registry.register_source(application_search).await;
|
2025-01-02 14:41:54 +08:00
|
|
|
}
|
2024-11-30 15:29:00 +08:00
|
|
|
|
2024-12-24 18:24:53 +08:00
|
|
|
#[tauri::command]
|
|
|
|
|
fn hide_coco(app: tauri::AppHandle) {
|
2025-02-08 07:38:02 +08:00
|
|
|
if let Some(window) = app.get_window(MAIN_WINDOW_LABEL) {
|
2024-12-24 18:24:53 +08:00
|
|
|
match window.is_visible() {
|
|
|
|
|
Ok(true) => {
|
|
|
|
|
if let Err(err) = window.hide() {
|
|
|
|
|
eprintln!("Failed to hide the window: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(false) => {
|
|
|
|
|
println!("Window is already hidden.");
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
eprintln!("Failed to check window visibility: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-17 11:20:50 +08:00
|
|
|
fn handle_open_coco(app: &AppHandle) {
|
2025-02-08 07:38:02 +08:00
|
|
|
if let Some(window) = app.get_window(MAIN_WINDOW_LABEL) {
|
2025-02-11 14:53:46 +08:00
|
|
|
move_window_to_active_monitor(&window);
|
|
|
|
|
|
2024-12-17 11:20:50 +08:00
|
|
|
window.show().unwrap();
|
2025-02-08 07:38:02 +08:00
|
|
|
window.set_visible_on_all_workspaces(true).unwrap();
|
|
|
|
|
window.set_always_on_top(true).unwrap();
|
2024-12-17 11:20:50 +08:00
|
|
|
window.set_focus().unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-11 14:53:46 +08:00
|
|
|
fn move_window_to_active_monitor<R: Runtime>(window: &Window<R>) {
|
|
|
|
|
dbg!("Moving window to active monitor");
|
|
|
|
|
// Try to get the available monitors, handle failure gracefully
|
|
|
|
|
let available_monitors = match window.available_monitors() {
|
|
|
|
|
Ok(monitors) => monitors,
|
|
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("Failed to get monitors: {}", e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Attempt to get the cursor position, handle failure gracefully
|
|
|
|
|
let cursor_position = match window.cursor_position() {
|
|
|
|
|
Ok(pos) => Some(pos),
|
|
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("Failed to get cursor position: {}", e);
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Find the monitor that contains the cursor or default to the primary monitor
|
|
|
|
|
let target_monitor = if let Some(cursor_position) = cursor_position {
|
|
|
|
|
// Convert cursor position to integers
|
|
|
|
|
let cursor_x = cursor_position.x.round() as i32;
|
|
|
|
|
let cursor_y = cursor_position.y.round() as i32;
|
|
|
|
|
|
|
|
|
|
// Find the monitor that contains the cursor
|
|
|
|
|
available_monitors.into_iter().find(|monitor| {
|
|
|
|
|
let monitor_position = monitor.position();
|
|
|
|
|
let monitor_size = monitor.size();
|
|
|
|
|
|
|
|
|
|
cursor_x >= monitor_position.x
|
|
|
|
|
&& cursor_x <= monitor_position.x + monitor_size.width as i32
|
|
|
|
|
&& cursor_y >= monitor_position.y
|
|
|
|
|
&& cursor_y <= monitor_position.y + monitor_size.height as i32
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Use the target monitor or default to the primary monitor
|
|
|
|
|
let monitor = match target_monitor.or_else(|| window.primary_monitor().ok().flatten()) {
|
|
|
|
|
Some(monitor) => monitor,
|
|
|
|
|
None => {
|
|
|
|
|
eprintln!("No monitor found!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-25 16:22:22 +08:00
|
|
|
if let Some(name) = monitor.name() {
|
|
|
|
|
let previous_monitor_name = PREVIOUS_MONITOR_NAME.lock().unwrap();
|
|
|
|
|
|
|
|
|
|
if let Some(ref prev_name) = *previous_monitor_name {
|
|
|
|
|
if name.to_string() == *prev_name {
|
|
|
|
|
println!("Currently on the same monitor");
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-11 14:53:46 +08:00
|
|
|
let monitor_position = monitor.position();
|
|
|
|
|
let monitor_size = monitor.size();
|
|
|
|
|
|
|
|
|
|
// Get the current size of the window
|
|
|
|
|
let window_size = match window.inner_size() {
|
|
|
|
|
Ok(size) => size,
|
|
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("Failed to get window size: {}", e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let window_width = window_size.width as i32;
|
|
|
|
|
let window_height = window_size.height as i32;
|
|
|
|
|
|
|
|
|
|
// Calculate the new position to center the window on the monitor
|
|
|
|
|
let window_x = monitor_position.x + (monitor_size.width as i32 - window_width) / 2;
|
|
|
|
|
let window_y = monitor_position.y + (monitor_size.height as i32 - window_height) / 2;
|
|
|
|
|
|
|
|
|
|
// Move the window to the new position
|
|
|
|
|
if let Err(e) = window.set_position(PhysicalPosition::new(window_x, window_y)) {
|
|
|
|
|
eprintln!("Failed to move window: {}", e);
|
|
|
|
|
}
|
2025-02-25 16:22:22 +08:00
|
|
|
|
|
|
|
|
if let Some(name) = monitor.name() {
|
|
|
|
|
println!("Window moved to monitor: {}", name);
|
|
|
|
|
|
|
|
|
|
let mut previous_monitor = PREVIOUS_MONITOR_NAME.lock().unwrap();
|
|
|
|
|
*previous_monitor = Some(name.to_string());
|
|
|
|
|
}
|
2025-02-11 14:53:46 +08:00
|
|
|
}
|
|
|
|
|
|
2024-12-24 18:24:53 +08:00
|
|
|
fn handle_hide_coco(app: &AppHandle) {
|
2025-02-08 07:38:02 +08:00
|
|
|
if let Some(window) = app.get_window(MAIN_WINDOW_LABEL) {
|
2024-12-24 18:24:53 +08:00
|
|
|
if let Err(err) = window.hide() {
|
|
|
|
|
eprintln!("Failed to hide the window: {}", err);
|
|
|
|
|
} else {
|
|
|
|
|
println!("Window successfully hidden.");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
eprintln!("Main window not found.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-30 20:41:47 +08:00
|
|
|
fn enable_tray(app: &mut tauri::App) {
|
|
|
|
|
use tauri::{
|
2024-12-25 17:43:56 +08:00
|
|
|
image::Image,
|
2024-12-11 16:52:13 +08:00
|
|
|
menu::{MenuBuilder, MenuItem},
|
2024-11-30 20:41:47 +08:00
|
|
|
tray::TrayIconBuilder,
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-11 16:52:13 +08:00
|
|
|
let quit_i = MenuItem::with_id(app, "quit", "Quit Coco", true, None::<&str>).unwrap();
|
2024-12-17 16:25:45 +08:00
|
|
|
let settings_i = MenuItem::with_id(app, "settings", "Settings...", true, None::<&str>).unwrap();
|
2025-02-06 11:45:37 +08:00
|
|
|
let open_i = MenuItem::with_id(app, "open", "Show Coco", true, None::<&str>).unwrap();
|
|
|
|
|
// let about_i = MenuItem::with_id(app, "about", "About Coco", true, None::<&str>).unwrap();
|
2025-01-15 10:33:51 +08:00
|
|
|
// let hide_i = MenuItem::with_id(app, "hide", "Hide Coco", true, None::<&str>).unwrap();
|
2024-12-11 10:45:54 +08:00
|
|
|
|
2024-12-11 16:52:13 +08:00
|
|
|
let menu = MenuBuilder::new(app)
|
|
|
|
|
.item(&open_i)
|
2024-12-17 16:25:45 +08:00
|
|
|
.separator()
|
2025-01-15 10:33:51 +08:00
|
|
|
// .item(&hide_i)
|
2025-02-06 11:45:37 +08:00
|
|
|
// .item(&about_i)
|
2024-12-11 16:52:13 +08:00
|
|
|
.item(&settings_i)
|
|
|
|
|
.separator()
|
|
|
|
|
.item(&quit_i)
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
2024-12-26 10:08:55 +08:00
|
|
|
let _tray = TrayIconBuilder::with_id("tray")
|
2025-02-09 21:51:03 +08:00
|
|
|
.icon_as_template(true)
|
2024-12-25 17:43:56 +08:00
|
|
|
// .icon(app.default_window_icon().unwrap().clone())
|
2025-02-12 16:15:55 +08:00
|
|
|
.icon(
|
|
|
|
|
Image::from_bytes(include_bytes!("../assets/tray-mac.ico"))
|
|
|
|
|
.expect("Failed to load icon"),
|
|
|
|
|
)
|
2024-11-30 20:41:47 +08:00
|
|
|
.menu(&menu)
|
|
|
|
|
.on_menu_event(|app, event| match event.id.as_ref() {
|
2024-12-17 16:25:45 +08:00
|
|
|
"open" => {
|
2024-12-17 11:20:50 +08:00
|
|
|
handle_open_coco(app);
|
2024-12-11 10:45:54 +08:00
|
|
|
}
|
2024-12-24 18:24:53 +08:00
|
|
|
"hide" => {
|
|
|
|
|
handle_hide_coco(app);
|
|
|
|
|
}
|
2024-12-17 16:25:45 +08:00
|
|
|
"about" => {
|
|
|
|
|
let _ = app.emit("open_settings", "about");
|
|
|
|
|
}
|
2024-12-10 13:38:31 +08:00
|
|
|
"settings" => {
|
2024-12-22 15:35:05 +08:00
|
|
|
// windows failed to open second window, issue: https://github.com/tauri-apps/tauri/issues/11144 https://github.com/tauri-apps/tauri/issues/8196
|
2024-12-14 15:38:32 +08:00
|
|
|
//#[cfg(windows)]
|
2025-02-09 21:51:03 +08:00
|
|
|
let _ = app.emit("open_settings", "settings");
|
2024-12-14 15:38:32 +08:00
|
|
|
|
|
|
|
|
// #[cfg(not(windows))]
|
2024-12-22 15:35:05 +08:00
|
|
|
// open_settings(&app);
|
2024-12-10 13:38:31 +08:00
|
|
|
}
|
2024-11-30 20:41:47 +08:00
|
|
|
"quit" => {
|
|
|
|
|
println!("quit menu item was clicked");
|
|
|
|
|
app.exit(0);
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
println!("menu item {:?} not handled", event.id);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.build(app)
|
|
|
|
|
.unwrap();
|
|
|
|
|
}
|
2024-12-14 15:38:32 +08:00
|
|
|
|
2024-12-15 21:06:23 +08:00
|
|
|
#[allow(dead_code)]
|
2024-12-22 15:35:05 +08:00
|
|
|
fn open_settings(app: &tauri::AppHandle) {
|
2024-12-15 21:06:23 +08:00
|
|
|
use tauri::webview::WebviewBuilder;
|
2024-12-14 15:38:32 +08:00
|
|
|
println!("settings menu item was clicked");
|
|
|
|
|
let window = app.get_webview_window("settings");
|
|
|
|
|
if let Some(window) = window {
|
|
|
|
|
window.show().unwrap();
|
|
|
|
|
window.set_focus().unwrap();
|
|
|
|
|
} else {
|
|
|
|
|
let window = tauri::window::WindowBuilder::new(app, "settings")
|
|
|
|
|
.title("Settings Window")
|
|
|
|
|
.fullscreen(false)
|
2024-12-17 16:25:45 +08:00
|
|
|
.resizable(false)
|
|
|
|
|
.minimizable(false)
|
|
|
|
|
.maximizable(false)
|
|
|
|
|
.inner_size(800.0, 600.0)
|
2024-12-14 15:38:32 +08:00
|
|
|
.build()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let webview_builder =
|
|
|
|
|
WebviewBuilder::new("settings", tauri::WebviewUrl::App("/ui/settings".into()));
|
|
|
|
|
let _webview = window
|
|
|
|
|
.add_child(
|
|
|
|
|
webview_builder,
|
|
|
|
|
tauri::LogicalPosition::new(0, 0),
|
|
|
|
|
window.inner_size().unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|