diff --git a/app.vue b/app.vue index bf26ac9..8874f49 100644 --- a/app.vue +++ b/app.vue @@ -1,8 +1,8 @@ - Image - YouTube Thumbnail + Image + YouTube Thumbnail {{ selectedItem?.content || '' }} @@ -204,6 +209,15 @@ const refreshHistory = async () => { await loadMoreHistory(); }; +const onScroll = () => { + const resultsElement = resultsContainer.value.$el; + console.log('Scroll position:', resultsElement.scrollTop, 'Client height:', resultsElement.clientHeight, 'Scroll height:', resultsElement.scrollHeight); + if (resultsElement.scrollTop + resultsElement.clientHeight >= resultsElement.scrollHeight - 10) { + console.log('Scrolled to the end, loading more history...'); + loadMoreHistory(); + } +}; + const loadMoreHistory = async () => { const lastTimestamp = history.value.length > 0 ? history.value[history.value.length - 1].timestamp : '9999-12-31T23:59:59Z'; const batchSize = 100; @@ -215,17 +229,28 @@ const loadMoreHistory = async () => { const newItems = rawHistory.map(item => { if (item.type === 'image' && !item.content.startsWith('data:image')) { - return { ...item, content: `data:image/png;base64,${item.content}` }; + return { ...item, content: `data:image/bmp;base64,${item.content}` }; } return item; }); history.value = [...history.value, ...newItems]; + console.log('Loaded more history:', newItems.length, 'items'); + if (newItems.length < batchSize) { + resultsContainer.value.$el.removeEventListener('scroll', onScroll); + } }; onMounted(async () => { db.value = await Database.load('sqlite:data.db'); - await refreshHistory(); + + await listen('tauri://focus', focusSearchInput); + focusSearchInput(); + + const resultsElement = resultsContainer.value.$el; + resultsElement.addEventListener('scroll', onScroll); + console.log('Scroll event listener added'); + onScroll(); if (!await isEnabled()) { await enable() @@ -243,20 +268,11 @@ onMounted(async () => { } else { app.show() isVisible.value = true; - selectedIndex.value = 0; + selectedItemIndex.value = 0; } } }); - await listen('tauri://focus', focusSearchInput); - focusSearchInput(); - - const resultsElement = resultsContainer.value.$el; - resultsElement.addEventListener('scroll', () => { - if (resultsElement.scrollTop + resultsElement.clientHeight >= resultsElement.scrollHeight - 100) { - loadMoreHistory(); - } - }); }); const hideApp = async () => { diff --git a/server/tsconfig.json b/server/tsconfig.json deleted file mode 100644 index b9ed69c..0000000 --- a/server/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../.nuxt/tsconfig.server.json" -} diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 6a1c6e4..9e3ca5e 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2605,15 +2605,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - [[package]] name = "objc" version = "0.2.7" @@ -3224,14 +3215,12 @@ dependencies = [ "arboard", "base64 0.22.1", "image 0.25.1", - "log", "rand 0.8.5", "rdev", "regex", "reqwest", "serde", "serde_json", - "simplelog", "sqlx", "tauri", "tauri-build", @@ -4010,17 +3999,6 @@ dependencies = [ "quote", ] -[[package]] -name = "simplelog" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" -dependencies = [ - "log", - "termcolor", - "time", -] - [[package]] name = "siphasher" version = "0.3.11" @@ -4854,15 +4832,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thin-slice" version = "0.1.1" @@ -4918,9 +4887,7 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa 1.0.11", - "libc", "num-conv", - "num_threads", "powerfmt", "serde", "time-core", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1780d50..f74df4e 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-beta.18", features = [] } [dependencies] -tauri = { version = "2.0.0-beta.23", features = ["unstable", "tray-icon", "image-png"] } +tauri = { version = "2.0.0-beta.23", features = ["tray-icon", "image-png"] } tauri-plugin-sql = {version = "2.0.0-beta.8", features = ["sqlite"] } tauri-plugin-clipboard-manager = "2.1.0-beta.5" tauri-plugin-global-shortcut = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" } @@ -27,6 +27,4 @@ arboard = "3.4.0" image = "0.25.1" reqwest = { version = "0.12.5", features = ["blocking"] } url = "2.5.2" -log = "0.4" -simplelog = "0.12.2" regex = "1" \ No newline at end of file diff --git a/src-tauri/src/clipboard.rs b/src-tauri/src/clipboard.rs index a2df6ef..3c177eb 100644 --- a/src-tauri/src/clipboard.rs +++ b/src-tauri/src/clipboard.rs @@ -13,6 +13,9 @@ use url::Url; use reqwest::Client; use arboard::Clipboard; use regex::Regex; +use image::ImageFormat; +use image::DynamicImage; +use std::io::Cursor; #[tauri::command] pub fn simulate_paste() { @@ -33,45 +36,58 @@ pub fn simulate_paste() { pub fn setup(app_handle: tauri::AppHandle) { let (tx, rx) = mpsc::channel(); - let mut is_processing = false; + let is_processing = std::sync::Arc::new(std::sync::Mutex::new(false)); - std::thread::spawn(move || { - listen(move |event| match event.event_type { - EventType::KeyPress(Key::ControlLeft | Key::ControlRight) => { - let _ = tx.send(true); - } - EventType::KeyRelease(Key::KeyC) => { - if rx.try_recv().is_ok() && !is_processing { - is_processing = true; - let pool = app_handle.state::(); - let rt = app_handle.state::(); - - let mut clipboard = Clipboard::new().unwrap(); - - if let Ok(content) = clipboard.get_text() { - rt.block_on(async { - insert_content_if_not_exists(&pool, "text", content).await; - }); - } - - if let Ok(image) = clipboard.get_image() { - rt.block_on(async { - let base64_image = STANDARD.encode(&image.bytes); - insert_content_if_not_exists(&pool, "image", base64_image).await; - }); - } - is_processing = false; + std::thread::spawn({ + let is_processing = std::sync::Arc::clone(&is_processing); + move || { + listen(move |event| match event.event_type { + EventType::KeyPress(Key::ControlLeft | Key::ControlRight) => { + let _ = tx.send(true); } - } - EventType::KeyRelease(Key::ControlLeft | Key::ControlRight) => { - is_processing = false; - } - _ => {} - }) - .unwrap(); + EventType::KeyRelease(Key::KeyC) => { + let mut is_processing = is_processing.lock().unwrap(); + if rx.try_recv().is_ok() && !*is_processing { + *is_processing = true; + let pool = app_handle.state::(); + let rt = app_handle.state::(); + + let mut clipboard = Clipboard::new().unwrap(); + + if let Ok(content) = clipboard.get_text() { + rt.block_on(async { + insert_content_if_not_exists(&pool, "text", content).await; + }); + } + + if let Ok(image) = clipboard.get_image() { + rt.block_on(async { + let png_image = convert_to_png(image.bytes.to_vec()); + let base64_image = STANDARD.encode(&png_image); + insert_content_if_not_exists(&pool, "image", base64_image).await; + }); + } + *is_processing = false; + } + } + EventType::KeyRelease(Key::ControlLeft | Key::ControlRight) => { + let mut is_processing = is_processing.lock().unwrap(); + *is_processing = false; + } + _ => {} + }) + .unwrap(); + } }); } +fn convert_to_png(image_bytes: Vec) -> Vec { + let img = image::load_from_memory(&image_bytes).unwrap(); + let mut png_bytes: Vec = Vec::new(); + img.write_to(&mut Cursor::new(&mut png_bytes), ImageFormat::Png).unwrap(); + png_bytes +} + async fn insert_content_if_not_exists(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", diff --git a/src-tauri/src/database.rs b/src-tauri/src/database.rs index 6080687..cb6f88d 100644 --- a/src-tauri/src/database.rs +++ b/src-tauri/src/database.rs @@ -40,6 +40,13 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box> { .await .expect("Failed to create table"); + sqlx::query( + "CREATE INDEX IF NOT EXISTS idx_timestamp ON history (timestamp)" + ) + .execute(&pool) + .await + .expect("Failed to create index"); + if is_new_db { let id: String = thread_rng() .sample_iter(&Alphanumeric) diff --git a/src-tauri/src/hotkeys.rs b/src-tauri/src/hotkeys.rs index c5624ee..1e17f48 100644 --- a/src-tauri/src/hotkeys.rs +++ b/src-tauri/src/hotkeys.rs @@ -29,7 +29,7 @@ pub fn setup(app_handle: tauri::AppHandle) { println!("V key pressed"); if meta_pressed { println!("Meta+V detected"); - let window = app_handle.get_window("main").unwrap(); + let window = app_handle.get_webview_window("main").unwrap(); let is_visible = window.is_visible().unwrap(); if is_visible { println!("Hiding window"); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index d869adf..52fc194 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -12,7 +12,7 @@ use tauri::Manager; use tauri::PhysicalPosition; use tauri_plugin_autostart::MacosLauncher; -fn center_window_on_current_monitor(window: &tauri::Window) { +fn center_window_on_current_monitor(window: &tauri::WebviewWindow) { if let Some(monitor) = window.current_monitor().unwrap() { let monitor_size = monitor.size(); let window_size = window.outer_size().unwrap(); @@ -43,9 +43,9 @@ fn main() { hotkeys::setup(app_handle.clone()); tray::setup(app)?; database::setup(app)?; - clipboard::setup(app_handle); + clipboard::setup(app_handle.clone()); - if let Some(window) = app.get_window("main") { + if let Some(window) = app.get_webview_window("main") { center_window_on_current_monitor(&window); window.hide().unwrap(); } @@ -60,15 +60,12 @@ fn main() { Ok(()) }) .on_window_event(|app, event| match event { + #[cfg(not(dev))] tauri::WindowEvent::Focused(false) => { - println!("Window lost focus"); - if let Some(window) = app.get_window("main") { + if let Some(window) = app.get_webview_window("main") { window.hide().unwrap(); } } - tauri::WindowEvent::Focused(true) => { - println!("Window gained focus"); - } _ => {} }) .invoke_handler(tauri::generate_handler![clipboard::simulate_paste]) diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 4c54319..b8115ba 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -5,7 +5,7 @@ use tauri::{ }; pub fn setup(app: &mut tauri::App) -> Result<(), Box> { - let window = app.get_window("main").unwrap(); + let window = app.get_webview_window("main").unwrap(); let window_clone_for_tray = window.clone(); let window_clone_for_click = window.clone();