mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-22 05:34:04 +02:00
image handeling
This commit is contained in:
parent
296a844aaa
commit
2695d8cd4c
9 changed files with 427 additions and 112 deletions
96
src-tauri/src/clipboard.rs
Normal file
96
src-tauri/src/clipboard.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
use rdev::{listen, simulate, EventType, Key};
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tauri::Manager;
|
||||
use arboard::{Clipboard, ImageData};
|
||||
use sqlx::SqlitePool;
|
||||
use tokio::runtime::Runtime;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use base64::Engine;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn simulate_paste() {
|
||||
let mut events = vec![
|
||||
EventType::KeyPress(Key::MetaLeft),
|
||||
EventType::KeyPress(Key::KeyV),
|
||||
EventType::KeyRelease(Key::KeyV),
|
||||
EventType::KeyRelease(Key::MetaLeft),
|
||||
];
|
||||
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
|
||||
for event in events.drain(..) {
|
||||
simulate(&event).unwrap();
|
||||
thread::sleep(Duration::from_millis(20));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup(app_handle: tauri::AppHandle) {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
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() {
|
||||
let mut clipboard = Clipboard::new().unwrap();
|
||||
let pool = app_handle.state::<SqlitePool>();
|
||||
let rt = app_handle.state::<Runtime>();
|
||||
|
||||
if let Ok(content) = clipboard.get_text() {
|
||||
rt.block_on(async {
|
||||
insert_content_if_not_exists(&pool, "text", content).await;
|
||||
});
|
||||
}
|
||||
|
||||
match clipboard.get_image() {
|
||||
Ok(image) => {
|
||||
println!("Image found in clipboard");
|
||||
rt.block_on(async {
|
||||
let base64_image = STANDARD.encode(&image.bytes);
|
||||
println!("Image encoded to base64");
|
||||
insert_content_if_not_exists(&pool, "image", base64_image).await;
|
||||
println!("Image inserted into database");
|
||||
});
|
||||
},
|
||||
Err(e) => {
|
||||
println!("Error reading image from clipboard: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
async fn insert_content_if_not_exists(pool: &SqlitePool, content_type: &str, content: String) {
|
||||
// Check if content already exists
|
||||
let exists: bool = sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM history WHERE content_type = ? AND content = ?)")
|
||||
.bind(content_type)
|
||||
.bind(&content)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.unwrap_or(false);
|
||||
|
||||
if !exists {
|
||||
let id: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
let _ = sqlx::query("INSERT INTO history (id, content_type, content) VALUES (?, ?, ?)")
|
||||
.bind(id)
|
||||
.bind(content_type)
|
||||
.bind(content)
|
||||
.execute(pool)
|
||||
.await;
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
use rdev::{listen, simulate, EventType, Key};
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tauri::Manager;
|
||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||
use sqlx::SqlitePool;
|
||||
use tokio::runtime::Runtime;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::distributions::Alphanumeric;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn simulate_paste() {
|
||||
let mut events = vec![
|
||||
EventType::KeyPress(Key::MetaLeft),
|
||||
EventType::KeyPress(Key::KeyV),
|
||||
EventType::KeyRelease(Key::KeyV),
|
||||
EventType::KeyRelease(Key::MetaLeft),
|
||||
];
|
||||
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
|
||||
for event in events.drain(..) {
|
||||
simulate(&event).unwrap();
|
||||
thread::sleep(Duration::from_millis(20));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup(app_handle: tauri::AppHandle) {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
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() {
|
||||
match app_handle.clipboard().read_text() {
|
||||
Ok(content) => {
|
||||
let pool = app_handle.state::<SqlitePool>();
|
||||
let rt = app_handle.state::<Runtime>();
|
||||
rt.block_on(async {
|
||||
let exists = sqlx::query_scalar::<_, bool>("SELECT EXISTS(SELECT 1 FROM history WHERE content = ?)")
|
||||
.bind(&content)
|
||||
.fetch_one(&*pool)
|
||||
.await
|
||||
.unwrap_or(false);
|
||||
|
||||
if !exists {
|
||||
let id: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
let _ = sqlx::query("INSERT INTO history (id, content) VALUES (?, ?)")
|
||||
.bind(id)
|
||||
.bind(content)
|
||||
.execute(&*pool)
|
||||
.await;
|
||||
}
|
||||
});
|
||||
},
|
||||
Err(e) => eprintln!("Error reading clipboard: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
}
|
|
@ -30,6 +30,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
|||
sqlx::query(
|
||||
"CREATE TABLE IF NOT EXISTS history (
|
||||
id TEXT PRIMARY KEY,
|
||||
content_type TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
|
@ -44,7 +45,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
|||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
sqlx::query("INSERT INTO history (id, content) VALUES (?, ?)")
|
||||
sqlx::query("INSERT INTO history (id, content_type, content) VALUES (?, text, ?)")
|
||||
.bind(id)
|
||||
.bind("Welcome to your clipboard history!")
|
||||
.execute(&pool)
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
mod clipboard_listener;
|
||||
mod clipboard;
|
||||
mod database;
|
||||
mod global_shortcut;
|
||||
mod hotkeys;
|
||||
mod tray;
|
||||
|
||||
use tauri::Manager;
|
||||
|
@ -20,16 +20,15 @@ fn main() {
|
|||
Some(vec![]),
|
||||
))
|
||||
.plugin(tauri_plugin_global_shortcut::Builder::new().build())
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||
.plugin(tauri_plugin_sql::Builder::default().build())
|
||||
.setup(|app| {
|
||||
let app_handle = app.handle().clone();
|
||||
|
||||
global_shortcut::setup(app_handle.clone());
|
||||
hotkeys::setup(app_handle.clone());
|
||||
tray::setup(app)?;
|
||||
database::setup(app)?;
|
||||
clipboard_listener::setup(app_handle);
|
||||
clipboard::setup(app_handle);
|
||||
|
||||
if let Some(window) = app.get_window("main") {
|
||||
let _ = window.restore_state(StateFlags::POSITION);
|
||||
|
@ -46,7 +45,7 @@ fn main() {
|
|||
}
|
||||
_ => {}
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![clipboard_listener::simulate_paste])
|
||||
.invoke_handler(tauri::generate_handler![clipboard::simulate_paste])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue