From 266b6ff3e1326e1328686cba63116dc10d6cef4a Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sat, 24 Aug 2024 16:03:18 +1000 Subject: [PATCH] restructure --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 3 +- src-tauri/src/{ => api}/clipboard.rs | 51 +++++++++------ src-tauri/src/{ => api}/database.rs | 16 ++++- src-tauri/src/{ => api}/hotkeys.rs | 17 +++-- src-tauri/src/api/mod.rs | 5 ++ src-tauri/src/{ => api}/tray.rs | 23 ++++--- src-tauri/src/{ => api}/updater.rs | 14 ++++- src-tauri/src/main.rs | 94 +++++++++------------------- src-tauri/src/utils/commands.rs | 30 +++++++++ src-tauri/src/utils/mod.rs | 1 + src-tauri/tauri.conf.json | 6 +- 12 files changed, 158 insertions(+), 103 deletions(-) rename src-tauri/src/{ => api}/clipboard.rs (88%) rename src-tauri/src/{ => api}/database.rs (81%) rename src-tauri/src/{ => api}/hotkeys.rs (71%) create mode 100644 src-tauri/src/api/mod.rs rename src-tauri/src/{ => api}/tray.rs (75%) rename src-tauri/src/{ => api}/updater.rs (83%) create mode 100644 src-tauri/src/utils/commands.rs create mode 100644 src-tauri/src/utils/mod.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 9d3afb0..b80fada 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3625,6 +3625,7 @@ dependencies = [ "tauri-plugin-prevent-default", "tauri-plugin-sql", "tauri-plugin-updater", + "time", "tokio", "url", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index f6c585f..d7d454c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -10,7 +10,7 @@ rust-version = "1.70" tauri-build = { version = "2.0.0-rc.6", features = [] } [dependencies] -tauri = { version = "2.0.0-rc.6", features = ["tray-icon", "image-png"] } +tauri = { version = "2.0.0-rc.6", features = [ "macos-private-api", "tray-icon", "image-png"] } tauri-plugin-sql = {version = "2.0.0-rc.0", features = ["sqlite"] } tauri-plugin-autostart = "2.0.0-rc.0" tauri-plugin-os = "2.0.0-rc.0" @@ -31,6 +31,7 @@ url = "2.5.2" regex = "1" sha2 = "0.10.6" lazy_static = "1.4.0" +time = "0.3" [features] custom-protocol = ["tauri/custom-protocol"] diff --git a/src-tauri/src/clipboard.rs b/src-tauri/src/api/clipboard.rs similarity index 88% rename from src-tauri/src/clipboard.rs rename to src-tauri/src/api/clipboard.rs index 5bf29bc..385bd04 100644 --- a/src-tauri/src/clipboard.rs +++ b/src-tauri/src/api/clipboard.rs @@ -1,6 +1,6 @@ use base64::Engine; use base64::engine::general_purpose::STANDARD; -use tauri::{AppHandle, Manager, Runtime, Emitter, Listener}; +use tauri::{AppHandle, Manager, Emitter, Listener}; use tauri_plugin_clipboard::Clipboard; use tokio::runtime::Runtime as TokioRuntime; use regex::Regex; @@ -16,14 +16,20 @@ use sha2::{Sha256, Digest}; use rdev::{simulate, Key, EventType}; use lazy_static::lazy_static; use image::ImageFormat; +use tauri::plugin::TauriPlugin; -lazy_static! { - static ref APP_DATA_DIR: Mutex> = Mutex::new(None); -} - -pub fn set_app_data_dir(path: std::path::PathBuf) { - let mut dir = APP_DATA_DIR.lock().unwrap(); - *dir = Some(path); +pub fn init() -> TauriPlugin { + tauri::plugin::Builder::new("clipboard") + .invoke_handler(tauri::generate_handler![ + read_image, + simulate_paste, + get_image_path + ]) + .setup(|app_handle, _api| { + setup(app_handle.clone()); + Ok(()) + }) + .build() } #[tauri::command] @@ -58,7 +64,15 @@ pub fn get_image_path(app_handle: tauri::AppHandle, filename: String) -> String image_path.to_str().unwrap_or("").to_string() } -pub fn setup(app: &AppHandle) { +#[tauri::command] +pub fn start_monitor(app_handle: tauri::AppHandle) -> Result<(), String> { + let clipboard = app_handle.state::(); + clipboard.start_monitor(app_handle.clone()).map_err(|e| e.to_string())?; + app_handle.emit("plugin:clipboard://clipboard-monitor/status", true).map_err(|e| e.to_string())?; + Ok(()) +} + +fn setup(app: AppHandle) { let app = app.clone(); let runtime = TokioRuntime::new().expect("Failed to create Tokio runtime"); @@ -110,14 +124,14 @@ pub fn setup(app: &AppHandle) { }); } -async fn get_pool(app_handle: &AppHandle) -> Result> { +async fn get_pool(app_handle: &tauri::AppHandle) -> Result> { let app_data_dir = app_handle.path().app_data_dir().expect("Failed to get app data directory"); let db_path = app_data_dir.join("data.db"); let database_url = format!("sqlite:{}", db_path.to_str().unwrap()); SqlitePool::connect(&database_url).await.map_err(|e| Box::new(e) as Box) } -async fn insert_content_if_not_exists(app_handle: AppHandle, pool: SqlitePool, content_type: &str, content: String) { +async fn insert_content_if_not_exists(app_handle: tauri::AppHandle, pool: SqlitePool, content_type: &str, content: String) { let last_content: Option = sqlx::query_scalar( "SELECT content FROM history WHERE content_type = ? ORDER BY timestamp DESC LIMIT 1", ) @@ -177,7 +191,7 @@ async fn insert_content_if_not_exists(app_handle: AppHandle, pool } } -async fn save_image(app_handle: &AppHandle, base64_image: &str) -> Result> { +async fn save_image(app_handle: &tauri::AppHandle, base64_image: &str) -> Result> { let image_data = STANDARD.decode(base64_image)?; let mut hasher = Sha256::new(); hasher.update(&image_data); @@ -212,10 +226,11 @@ async fn fetch_favicon_as_base64(url: url::Url) -> Result, Box Result<(), String> { - let clipboard = app_handle.state::(); - clipboard.start_monitor(app_handle.clone()).map_err(|e| e.to_string())?; - app_handle.emit("plugin:clipboard://clipboard-monitor/status", true).map_err(|e| e.to_string())?; - Ok(()) +lazy_static! { + static ref APP_DATA_DIR: Mutex> = Mutex::new(None); +} + +pub fn set_app_data_dir(path: std::path::PathBuf) { + let mut dir = APP_DATA_DIR.lock().unwrap(); + *dir = Some(path); } \ No newline at end of file diff --git a/src-tauri/src/database.rs b/src-tauri/src/api/database.rs similarity index 81% rename from src-tauri/src/database.rs rename to src-tauri/src/api/database.rs index cb6f88d..d848d54 100644 --- a/src-tauri/src/database.rs +++ b/src-tauri/src/api/database.rs @@ -1,11 +1,21 @@ +use tauri::plugin::TauriPlugin; +use tauri::{AppHandle, Manager, Emitter}; use sqlx::sqlite::SqlitePoolOptions; use std::fs; use tokio::runtime::Runtime; -use tauri::Manager; use rand::{thread_rng, Rng}; use rand::distributions::Alphanumeric; -pub fn setup(app: &mut tauri::App) -> Result<(), Box> { +pub fn init() -> TauriPlugin { + tauri::plugin::Builder::new("database") + .setup(|app_handle: &AppHandle, _api| { + setup(app_handle)?; + Ok(()) + }) + .build() +} + +fn setup(app: &AppHandle) -> Result<(), Box> { let rt = Runtime::new().expect("Failed to create Tokio runtime"); let app_data_dir = app.path().app_data_dir().unwrap(); @@ -66,5 +76,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box> { app.manage(pool); app.manage(rt); + app.emit("database_initialized", ()).expect("Failed to emit database_initialized event"); + Ok(()) } \ No newline at end of file diff --git a/src-tauri/src/hotkeys.rs b/src-tauri/src/api/hotkeys.rs similarity index 71% rename from src-tauri/src/hotkeys.rs rename to src-tauri/src/api/hotkeys.rs index cef1687..4ec097d 100644 --- a/src-tauri/src/hotkeys.rs +++ b/src-tauri/src/api/hotkeys.rs @@ -1,9 +1,18 @@ -use rdev::{listen, EventType, Key}; +use tauri::plugin::TauriPlugin; use tauri::Manager; +use rdev::{listen, EventType, Key}; +use crate::utils::commands; -use crate::center_window_on_current_monitor; +pub fn init() -> TauriPlugin { + tauri::plugin::Builder::new("hotkeys") + .setup(|app, _| { + setup(app.app_handle().clone()); + Ok(()) + }) + .build() +} -pub fn setup(app_handle: tauri::AppHandle) { +fn setup(app_handle: tauri::AppHandle) { std::thread::spawn(move || { let mut meta_pressed = false; listen(move |event| { @@ -20,7 +29,7 @@ pub fn setup(app_handle: tauri::AppHandle) { let window = app_handle.get_webview_window("main").unwrap(); window.show().unwrap(); window.set_focus().unwrap(); - center_window_on_current_monitor(&window); + commands::center_window_on_current_monitor(&window); } } _ => {} diff --git a/src-tauri/src/api/mod.rs b/src-tauri/src/api/mod.rs new file mode 100644 index 0000000..b513b8d --- /dev/null +++ b/src-tauri/src/api/mod.rs @@ -0,0 +1,5 @@ +pub mod updater; +pub mod clipboard; +pub mod database; +pub mod tray; +pub mod hotkeys; diff --git a/src-tauri/src/tray.rs b/src-tauri/src/api/tray.rs similarity index 75% rename from src-tauri/src/tray.rs rename to src-tauri/src/api/tray.rs index b8115ba..f80f031 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/api/tray.rs @@ -1,15 +1,24 @@ -use tauri::{ - Manager, - menu::{MenuBuilder, MenuItemBuilder}, - tray::{MouseButton, TrayIconBuilder, TrayIconEvent}, -}; +use tauri::AppHandle; +use tauri::plugin::TauriPlugin; +use tauri::Manager; +use tauri::menu::{MenuBuilder, MenuItemBuilder}; +use tauri::tray::{MouseButton, TrayIconBuilder, TrayIconEvent}; -pub fn setup(app: &mut tauri::App) -> Result<(), Box> { +pub fn init() -> TauriPlugin { + tauri::plugin::Builder::new("tray") + .setup(|app, _api| { + setup(app)?; + Ok(()) + }) + .build() +} + +fn setup(app: &AppHandle) -> Result<(), Box> { let window = app.get_webview_window("main").unwrap(); let window_clone_for_tray = window.clone(); let window_clone_for_click = window.clone(); - let icon_bytes = include_bytes!("../icons/Square71x71Logo.png"); + let icon_bytes = include_bytes!("../../icons/Square71x71Logo.png"); let icon = tauri::image::Image::from_bytes(icon_bytes).unwrap(); let _tray = TrayIconBuilder::new() diff --git a/src-tauri/src/updater.rs b/src-tauri/src/api/updater.rs similarity index 83% rename from src-tauri/src/updater.rs rename to src-tauri/src/api/updater.rs index 6c474c2..567d028 100644 --- a/src-tauri/src/updater.rs +++ b/src-tauri/src/api/updater.rs @@ -1,8 +1,16 @@ -use tauri::{AppHandle, async_runtime}; +use tauri::plugin::TauriPlugin; +use tauri::AppHandle; use tauri_plugin_dialog::{DialogExt, MessageDialogKind}; use tauri_plugin_updater::UpdaterExt; +use tokio; +pub fn init() -> TauriPlugin { + tauri::plugin::Builder::new("updater") + .invoke_handler(tauri::generate_handler![check_for_updates]) + .build() +} +#[tauri::command] pub async fn check_for_updates(app: AppHandle) { println!("Checking for updates..."); @@ -28,7 +36,7 @@ pub async fn check_for_updates(app: AppHandle) { if !response { return; } - async_runtime::spawn(async move { + tokio::spawn(async move { if let Err(e) = update.download_and_install(|_, _| {}, || {}).await { println!("Error installing new update: {:?}", e); app.dialog().message( @@ -43,4 +51,4 @@ pub async fn check_for_updates(app: AppHandle) { println!("Failed to check for updates: {:?}", e); } } -} +} \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0ae640e..47fe10e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,46 +3,13 @@ windows_subsystem = "windows" )] -mod clipboard; -mod database; -mod hotkeys; -mod tray; -mod updater; +mod api; +mod utils; -use tauri::Manager; -use tauri::PhysicalPosition; +use tauri::{Manager, Listener}; use tauri_plugin_autostart::MacosLauncher; use tauri_plugin_prevent_default::Flags; -pub fn center_window_on_current_monitor(window: &tauri::WebviewWindow) { - if let Some(monitor) = window.available_monitors().unwrap().iter().find(|m| { - let primary_monitor = window - .primary_monitor() - .unwrap() - .expect("Failed to get primary monitor"); - let mouse_position = primary_monitor.position(); - let monitor_position = m.position(); - let monitor_size = m.size(); - mouse_position.x >= monitor_position.x - && mouse_position.x < monitor_position.x + monitor_size.width as i32 - && mouse_position.y >= monitor_position.y - && mouse_position.y < monitor_position.y + monitor_size.height as i32 - }) { - let monitor_size = monitor.size(); - let window_size = window.outer_size().unwrap(); - - let x = (monitor_size.width as i32 - window_size.width as i32) / 2; - let y = (monitor_size.height as i32 - window_size.height as i32) / 2; - - window - .set_position(PhysicalPosition::new( - monitor.position().x + x, - monitor.position().y + y, - )) - .unwrap(); - } -} - fn main() { tauri::Builder::default() .plugin(tauri_plugin_clipboard::init()) @@ -54,6 +21,11 @@ fn main() { MacosLauncher::LaunchAgent, Some(vec![]), )) + .plugin(api::updater::init()) + .plugin(api::database::init()) + .plugin(api::tray::init()) + .plugin(api::hotkeys::init()) + .plugin(api::clipboard::init()) .plugin( tauri_plugin_prevent_default::Builder::new() .with_flags(Flags::all().difference(Flags::CONTEXT_MENU)) @@ -61,51 +33,43 @@ fn main() { ) .setup(|app| { let app_handle = app.handle().clone(); - - hotkeys::setup(app_handle.clone()); - tray::setup(app)?; - database::setup(app)?; - clipboard::setup(app.handle()); - let _ = clipboard::start_monitor(app_handle.clone()); - - if let Some(window) = app.get_webview_window("main") { - center_window_on_current_monitor(&window); - window.hide().unwrap(); - } - - // #[cfg(dev)] - // { - // let window = app.get_webview_window("main").unwrap(); - // window.open_devtools(); - // window.close_devtools(); - // } - + let app_data_dir = app .path() .app_data_dir() .expect("Failed to get app data directory"); - clipboard::set_app_data_dir(app_data_dir); + api::clipboard::set_app_data_dir(app_data_dir); + if let Some(window) = app.get_webview_window("main") { + utils::commands::center_window_on_current_monitor(&window); + window.hide().unwrap(); + } + + let update_handle = app_handle.clone(); tauri::async_runtime::spawn(async move { - updater::check_for_updates(app_handle).await; + api::updater::check_for_updates(update_handle).await; + }); + + let monitor_handle = app_handle.clone(); + app_handle.listen("database_initialized", move |_| { + let _ = api::clipboard::start_monitor(monitor_handle.clone()); }); Ok(()) }) - .on_window_event(|app, event| match event { + .on_window_event(|app, event| { #[cfg(not(dev))] - tauri::WindowEvent::Focused(false) => { + if let WindowEvent::Focused(false) = event { if let Some(window) = app.get_webview_window("main") { - window.hide().unwrap(); + let _ = window.hide(); } } - _ => {} }) .invoke_handler(tauri::generate_handler![ - clipboard::simulate_paste, - clipboard::get_image_path, - clipboard::read_image + api::clipboard::simulate_paste, + api::clipboard::get_image_path, + api::clipboard::read_image ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); -} +} \ No newline at end of file diff --git a/src-tauri/src/utils/commands.rs b/src-tauri/src/utils/commands.rs new file mode 100644 index 0000000..5b1a736 --- /dev/null +++ b/src-tauri/src/utils/commands.rs @@ -0,0 +1,30 @@ +use tauri::PhysicalPosition; + +pub fn center_window_on_current_monitor(window: &tauri::WebviewWindow) { + if let Some(monitor) = window.available_monitors().unwrap().iter().find(|m| { + let primary_monitor = window + .primary_monitor() + .unwrap() + .expect("Failed to get primary monitor"); + let mouse_position = primary_monitor.position(); + let monitor_position = m.position(); + let monitor_size = m.size(); + mouse_position.x >= monitor_position.x + && mouse_position.x < monitor_position.x + monitor_size.width as i32 + && mouse_position.y >= monitor_position.y + && mouse_position.y < monitor_position.y + monitor_size.height as i32 + }) { + let monitor_size = monitor.size(); + let window_size = window.outer_size().unwrap(); + + let x = (monitor_size.width as i32 - window_size.width as i32) / 2; + let y = (monitor_size.height as i32 - window_size.height as i32) / 2; + + window + .set_position(PhysicalPosition::new( + monitor.position().x + x, + monitor.position().y + y, + )) + .unwrap(); + } +} \ No newline at end of file diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs new file mode 100644 index 0000000..6be336e --- /dev/null +++ b/src-tauri/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod commands; \ No newline at end of file diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index d5c90c8..378fe24 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -31,7 +31,8 @@ "security": { "csp": null }, - "withGlobalTauri": true + "withGlobalTauri": true, + "macOSPrivateApi": true }, "bundle": { "createUpdaterArtifacts": true, @@ -49,8 +50,7 @@ "updater": { "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDExNDIzNjA1QjE0NjU1OTkKUldTWlZVYXhCVFpDRWNvNmt0UE5lQmZkblEyZGZiZ2tHelJvT2YvNVpLU1RIM1RKZFQrb2tzWWwK", "endpoints": [ - "https://qopy-updater-server.pandadev.workers.dev/", - "https://qopy.pandadev.net/updater" + "https://qopy.pandadev.net/" ] } },