mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-22 05:34:04 +02:00
refactor: Clean up code formatting in utils module
This commit is contained in:
parent
60b670c7a7
commit
22fcd84b8d
14 changed files with 485 additions and 394 deletions
|
@ -1,14 +1,14 @@
|
|||
use tauri_plugin_aptabase::EventTracker;
|
||||
use base64::{engine::general_purpose::STANDARD, Engine};
|
||||
use base64::{ engine::general_purpose::STANDARD, Engine };
|
||||
// use hyperpolyglot;
|
||||
use lazy_static::lazy_static;
|
||||
use rdev::{simulate, EventType, Key};
|
||||
use rdev::{ simulate, EventType, Key };
|
||||
use regex::Regex;
|
||||
use sqlx::SqlitePool;
|
||||
use std::fs;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::{thread, time::Duration};
|
||||
use tauri::{AppHandle, Emitter, Listener, Manager};
|
||||
use std::sync::atomic::{ AtomicBool, Ordering };
|
||||
use std::{ thread, time::Duration };
|
||||
use tauri::{ AppHandle, Emitter, Listener, Manager };
|
||||
use tauri_plugin_clipboard::Clipboard;
|
||||
use tokio::runtime::Runtime as TokioRuntime;
|
||||
use url::Url;
|
||||
|
@ -17,7 +17,7 @@ use uuid::Uuid;
|
|||
use crate::db;
|
||||
use crate::utils::commands::get_app_info;
|
||||
use crate::utils::favicon::fetch_favicon_as_base64;
|
||||
use crate::utils::types::{ContentType, HistoryItem};
|
||||
use crate::utils::types::{ ContentType, HistoryItem };
|
||||
|
||||
lazy_static! {
|
||||
static ref IS_PROGRAMMATIC_PASTE: AtomicBool = AtomicBool::new(false);
|
||||
|
@ -27,16 +27,14 @@ lazy_static! {
|
|||
pub async fn write_and_paste(
|
||||
app_handle: AppHandle,
|
||||
content: String,
|
||||
content_type: String,
|
||||
content_type: String
|
||||
) -> Result<(), String> {
|
||||
let clipboard = app_handle.state::<Clipboard>();
|
||||
|
||||
match content_type.as_str() {
|
||||
"text" => clipboard.write_text(content).map_err(|e| e.to_string())?,
|
||||
"image" => {
|
||||
clipboard
|
||||
.write_image_base64(content)
|
||||
.map_err(|e| e.to_string())?;
|
||||
clipboard.write_image_base64(content).map_err(|e| e.to_string())?;
|
||||
}
|
||||
"files" => {
|
||||
clipboard
|
||||
|
@ -44,11 +42,13 @@ pub async fn write_and_paste(
|
|||
content
|
||||
.split(", ")
|
||||
.map(|file| file.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
.collect::<Vec<String>>()
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
_ => return Err("Unsupported content type".to_string()),
|
||||
_ => {
|
||||
return Err("Unsupported content type".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
IS_PROGRAMMATIC_PASTE.store(true, Ordering::SeqCst);
|
||||
|
@ -65,7 +65,7 @@ pub async fn write_and_paste(
|
|||
EventType::KeyPress(modifier_key),
|
||||
EventType::KeyPress(Key::KeyV),
|
||||
EventType::KeyRelease(Key::KeyV),
|
||||
EventType::KeyRelease(modifier_key),
|
||||
EventType::KeyRelease(modifier_key)
|
||||
];
|
||||
|
||||
for event in events {
|
||||
|
@ -81,9 +81,12 @@ pub async fn write_and_paste(
|
|||
IS_PROGRAMMATIC_PASTE.store(false, Ordering::SeqCst);
|
||||
});
|
||||
|
||||
let _ = app_handle.track_event("clipboard_paste", Some(serde_json::json!({
|
||||
let _ = app_handle.track_event(
|
||||
"clipboard_paste",
|
||||
Some(serde_json::json!({
|
||||
"content_type": content_type
|
||||
})));
|
||||
}))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -92,79 +95,92 @@ pub fn setup(app: &AppHandle) {
|
|||
let app_handle = app.clone();
|
||||
let runtime = TokioRuntime::new().expect("Failed to create Tokio runtime");
|
||||
|
||||
app_handle.clone().listen(
|
||||
"plugin:clipboard://clipboard-monitor/update",
|
||||
move |_event| {
|
||||
let app_handle = app_handle.clone();
|
||||
runtime.block_on(async move {
|
||||
if IS_PROGRAMMATIC_PASTE.load(Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
app_handle.clone().listen("plugin:clipboard://clipboard-monitor/update", move |_event| {
|
||||
let app_handle = app_handle.clone();
|
||||
runtime.block_on(async move {
|
||||
if IS_PROGRAMMATIC_PASTE.load(Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
|
||||
let clipboard = app_handle.state::<Clipboard>();
|
||||
let available_types = clipboard.available_types().unwrap();
|
||||
let clipboard = app_handle.state::<Clipboard>();
|
||||
let available_types = clipboard.available_types().unwrap();
|
||||
|
||||
let (app_name, app_icon) = get_app_info();
|
||||
let (app_name, app_icon) = get_app_info();
|
||||
|
||||
match get_pool(&app_handle).await {
|
||||
Ok(pool) => {
|
||||
if available_types.image {
|
||||
println!("Handling image change");
|
||||
if let Ok(image_data) = clipboard.read_image_base64() {
|
||||
let file_path = save_image_to_file(&app_handle, &image_data)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
.unwrap_or_else(|e| e);
|
||||
match get_pool(&app_handle).await {
|
||||
Ok(pool) => {
|
||||
if available_types.image {
|
||||
println!("Handling image change");
|
||||
if let Ok(image_data) = clipboard.read_image_base64() {
|
||||
let file_path = save_image_to_file(&app_handle, &image_data).await
|
||||
.map_err(|e| e.to_string())
|
||||
.unwrap_or_else(|e| e);
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool,
|
||||
HistoryItem::new(
|
||||
app_name,
|
||||
ContentType::Image,
|
||||
file_path,
|
||||
None,
|
||||
app_icon,
|
||||
None
|
||||
)
|
||||
).await;
|
||||
}
|
||||
} else if available_types.files {
|
||||
println!("Handling files change");
|
||||
if let Ok(files) = clipboard.read_files() {
|
||||
for file in files {
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool,
|
||||
HistoryItem::new(app_name, ContentType::Image, file_path, None, app_icon, None)
|
||||
pool.clone(),
|
||||
HistoryItem::new(
|
||||
app_name.clone(),
|
||||
ContentType::File,
|
||||
file,
|
||||
None,
|
||||
app_icon.clone(),
|
||||
None
|
||||
)
|
||||
).await;
|
||||
}
|
||||
} else if available_types.files {
|
||||
println!("Handling files change");
|
||||
if let Ok(files) = clipboard.read_files() {
|
||||
for file in files {
|
||||
}
|
||||
} else if available_types.text {
|
||||
println!("Handling text change");
|
||||
if let Ok(text) = clipboard.read_text() {
|
||||
let text = text.to_string();
|
||||
let url_regex = Regex::new(
|
||||
r"^https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)$"
|
||||
).unwrap();
|
||||
|
||||
if url_regex.is_match(&text) {
|
||||
if let Ok(url) = Url::parse(&text) {
|
||||
let favicon = match fetch_favicon_as_base64(url).await {
|
||||
Ok(Some(f)) => Some(f),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool.clone(),
|
||||
pool,
|
||||
HistoryItem::new(
|
||||
app_name.clone(),
|
||||
ContentType::File,
|
||||
file,
|
||||
None,
|
||||
app_icon.clone(),
|
||||
app_name,
|
||||
ContentType::Link,
|
||||
text,
|
||||
favicon,
|
||||
app_icon,
|
||||
None
|
||||
),
|
||||
)
|
||||
).await;
|
||||
}
|
||||
}
|
||||
} else if available_types.text {
|
||||
println!("Handling text change");
|
||||
if let Ok(text) = clipboard.read_text() {
|
||||
let text = text.to_string();
|
||||
let url_regex = Regex::new(r"^https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)$").unwrap();
|
||||
} else {
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if url_regex.is_match(&text) {
|
||||
if let Ok(url) = Url::parse(&text) {
|
||||
let favicon = match fetch_favicon_as_base64(url).await {
|
||||
Ok(Some(f)) => Some(f),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool,
|
||||
HistoryItem::new(app_name, ContentType::Link, text, favicon, app_icon, None)
|
||||
).await;
|
||||
}
|
||||
} else {
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Temporarily disabled code detection
|
||||
/*if let Some(detection) = hyperpolyglot::detect_from_text(&text) {
|
||||
// Temporarily disabled code detection
|
||||
/*if let Some(detection) = hyperpolyglot::detect_from_text(&text) {
|
||||
let language = match detection {
|
||||
hyperpolyglot::Detection::Heuristics(lang) => lang.to_string(),
|
||||
_ => detection.language().to_string(),
|
||||
|
@ -175,43 +191,61 @@ pub fn setup(app: &AppHandle) {
|
|||
HistoryItem::new(app_name, ContentType::Code, text, None, app_icon, Some(language))
|
||||
).await;
|
||||
} else*/ if crate::utils::commands::detect_color(&text) {
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool,
|
||||
HistoryItem::new(app_name, ContentType::Color, text, None, app_icon, None)
|
||||
).await;
|
||||
} else {
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool,
|
||||
HistoryItem::new(app_name, ContentType::Text, text.clone(), None, app_icon, None)
|
||||
).await;
|
||||
}
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool,
|
||||
HistoryItem::new(
|
||||
app_name,
|
||||
ContentType::Color,
|
||||
text,
|
||||
None,
|
||||
app_icon,
|
||||
None
|
||||
)
|
||||
).await;
|
||||
} else {
|
||||
let _ = db::history::add_history_item(
|
||||
app_handle.clone(),
|
||||
pool,
|
||||
HistoryItem::new(
|
||||
app_name,
|
||||
ContentType::Text,
|
||||
text.clone(),
|
||||
None,
|
||||
app_icon,
|
||||
None
|
||||
)
|
||||
).await;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Unknown clipboard content type");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to get database pool: {}", e);
|
||||
} else {
|
||||
println!("Unknown clipboard content type");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to get database pool: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
let _ = app_handle.emit("clipboard-content-updated", ());
|
||||
let _ = app_handle.track_event("clipboard_copied", Some(serde_json::json!({
|
||||
let _ = app_handle.emit("clipboard-content-updated", ());
|
||||
let _ = app_handle.track_event(
|
||||
"clipboard_copied",
|
||||
Some(
|
||||
serde_json::json!({
|
||||
"content_type": if available_types.image { "image" }
|
||||
else if available_types.files { "files" }
|
||||
else if available_types.text { "text" }
|
||||
else { "unknown" }
|
||||
})));
|
||||
});
|
||||
},
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async fn get_pool(
|
||||
app_handle: &AppHandle,
|
||||
app_handle: &AppHandle
|
||||
) -> Result<tauri::State<'_, SqlitePool>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
Ok(app_handle.state::<SqlitePool>())
|
||||
}
|
||||
|
@ -219,9 +253,7 @@ async fn get_pool(
|
|||
#[tauri::command]
|
||||
pub fn start_monitor(app_handle: AppHandle) -> Result<(), String> {
|
||||
let clipboard = app_handle.state::<Clipboard>();
|
||||
clipboard
|
||||
.start_monitor(app_handle.clone())
|
||||
.map_err(|e| e.to_string())?;
|
||||
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())?;
|
||||
|
@ -230,7 +262,7 @@ pub fn start_monitor(app_handle: AppHandle) -> Result<(), String> {
|
|||
|
||||
async fn save_image_to_file(
|
||||
app_handle: &AppHandle,
|
||||
base64_data: &str,
|
||||
base64_data: &str
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let app_data_dir = app_handle.path().app_data_dir().unwrap();
|
||||
let images_dir = app_data_dir.join("images");
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
use crate::utils::commands::center_window_on_current_monitor;
|
||||
use crate::utils::keys::KeyCode;
|
||||
use global_hotkey::{
|
||||
hotkey::{Code, HotKey, Modifiers},
|
||||
GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState,
|
||||
hotkey::{ Code, HotKey, Modifiers },
|
||||
GlobalHotKeyEvent,
|
||||
GlobalHotKeyManager,
|
||||
HotKeyState,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Mutex;
|
||||
use tauri::{AppHandle, Listener, Manager};
|
||||
use tauri::{ AppHandle, Listener, Manager };
|
||||
use tauri_plugin_aptabase::EventTracker;
|
||||
|
||||
lazy_static! {
|
||||
|
@ -110,10 +112,18 @@ fn parse_hotkey(shortcut: &[String]) -> Result<HotKey, Box<dyn std::error::Error
|
|||
|
||||
for part in shortcut {
|
||||
match part.as_str() {
|
||||
"ControlLeft" => modifiers |= Modifiers::CONTROL,
|
||||
"AltLeft" => modifiers |= Modifiers::ALT,
|
||||
"ShiftLeft" => modifiers |= Modifiers::SHIFT,
|
||||
"MetaLeft" => modifiers |= Modifiers::META,
|
||||
"ControlLeft" => {
|
||||
modifiers |= Modifiers::CONTROL;
|
||||
}
|
||||
"AltLeft" => {
|
||||
modifiers |= Modifiers::ALT;
|
||||
}
|
||||
"ShiftLeft" => {
|
||||
modifiers |= Modifiers::SHIFT;
|
||||
}
|
||||
"MetaLeft" => {
|
||||
modifiers |= Modifiers::META;
|
||||
}
|
||||
key => {
|
||||
code = Some(Code::from(KeyCode::from_str(key)?));
|
||||
}
|
||||
|
@ -144,8 +154,10 @@ fn handle_hotkey_event(app_handle: &AppHandle) {
|
|||
|
||||
let _ = app_handle.track_event(
|
||||
"hotkey_triggered",
|
||||
Some(serde_json::json!({
|
||||
Some(
|
||||
serde_json::json!({
|
||||
"action": if window.is_visible().unwrap() { "hide" } else { "show" }
|
||||
})),
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
use tauri::{
|
||||
menu::{MenuBuilder, MenuItemBuilder},
|
||||
tray::TrayIconBuilder,
|
||||
Emitter, Manager,
|
||||
};
|
||||
use tauri::{ menu::{ MenuBuilder, MenuItemBuilder }, tray::TrayIconBuilder, Emitter, Manager };
|
||||
use tauri_plugin_aptabase::EventTracker;
|
||||
|
||||
pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let window = app.get_webview_window("main").unwrap();
|
||||
let is_visible = window.is_visible().unwrap();
|
||||
let _ = app.track_event("tray_toggle", Some(serde_json::json!({
|
||||
let _ = app.track_event(
|
||||
"tray_toggle",
|
||||
Some(serde_json::json!({
|
||||
"action": if is_visible { "hide" } else { "show" }
|
||||
})));
|
||||
}))
|
||||
);
|
||||
|
||||
let icon_bytes = include_bytes!("../../icons/Square71x71Logo.png");
|
||||
let icon = tauri::image::Image::from_bytes(icon_bytes).unwrap();
|
||||
|
@ -18,37 +17,42 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
|||
let _tray = TrayIconBuilder::new()
|
||||
.menu(
|
||||
&MenuBuilder::new(app)
|
||||
.items(&[&MenuItemBuilder::with_id("app_name", "Qopy")
|
||||
.enabled(false)
|
||||
.build(app)?])
|
||||
.items(&[&MenuItemBuilder::with_id("app_name", "Qopy").enabled(false).build(app)?])
|
||||
.items(&[&MenuItemBuilder::with_id("show", "Show/Hide").build(app)?])
|
||||
.items(&[&MenuItemBuilder::with_id("settings", "Settings").build(app)?])
|
||||
.items(&[&MenuItemBuilder::with_id("quit", "Quit").build(app)?])
|
||||
.build()?,
|
||||
.build()?
|
||||
)
|
||||
.on_menu_event(move |_app, event| match event.id().as_ref() {
|
||||
"quit" => {
|
||||
let _ = _app.track_event("app_quit", None);
|
||||
std::process::exit(0);
|
||||
}
|
||||
"show" => {
|
||||
let _ = _app.track_event("tray_toggle", Some(serde_json::json!({
|
||||
"action": if is_visible { "hide" } else { "show" }
|
||||
})));
|
||||
let is_visible = window.is_visible().unwrap();
|
||||
if is_visible {
|
||||
window.hide().unwrap();
|
||||
} else {
|
||||
window.show().unwrap();
|
||||
window.set_focus().unwrap();
|
||||
.on_menu_event(move |_app, event| {
|
||||
match event.id().as_ref() {
|
||||
"quit" => {
|
||||
let _ = _app.track_event("app_quit", None);
|
||||
std::process::exit(0);
|
||||
}
|
||||
window.emit("main_route", ()).unwrap();
|
||||
"show" => {
|
||||
let _ = _app.track_event(
|
||||
"tray_toggle",
|
||||
Some(
|
||||
serde_json::json!({
|
||||
"action": if is_visible { "hide" } else { "show" }
|
||||
})
|
||||
)
|
||||
);
|
||||
let is_visible = window.is_visible().unwrap();
|
||||
if is_visible {
|
||||
window.hide().unwrap();
|
||||
} else {
|
||||
window.show().unwrap();
|
||||
window.set_focus().unwrap();
|
||||
}
|
||||
window.emit("main_route", ()).unwrap();
|
||||
}
|
||||
"settings" => {
|
||||
let _ = _app.track_event("tray_settings", None);
|
||||
window.emit("settings", ()).unwrap();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
"settings" => {
|
||||
let _ = _app.track_event("tray_settings", None);
|
||||
window.emit("settings", ()).unwrap();
|
||||
}
|
||||
_ => (),
|
||||
})
|
||||
.icon(icon)
|
||||
.build(app)?;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use tauri::{async_runtime, AppHandle};
|
||||
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogKind};
|
||||
use tauri::{ async_runtime, AppHandle };
|
||||
use tauri_plugin_dialog::{ DialogExt, MessageDialogButtons, MessageDialogKind };
|
||||
use tauri_plugin_updater::UpdaterExt;
|
||||
|
||||
pub async fn check_for_updates(app: AppHandle) {
|
||||
|
@ -21,18 +21,35 @@ pub async fn check_for_updates(app: AppHandle) {
|
|||
app.dialog()
|
||||
.message(msg)
|
||||
.title("Qopy Update Available")
|
||||
.buttons(MessageDialogButtons::OkCancelCustom(String::from("Install"), String::from("Cancel")))
|
||||
.buttons(
|
||||
MessageDialogButtons::OkCancelCustom(
|
||||
String::from("Install"),
|
||||
String::from("Cancel")
|
||||
)
|
||||
)
|
||||
.show(move |response| {
|
||||
if !response {
|
||||
return;
|
||||
}
|
||||
async_runtime::spawn(async move {
|
||||
match update.download_and_install(|_, _| {}, || {}).await {
|
||||
match
|
||||
update.download_and_install(
|
||||
|_, _| {},
|
||||
|| {}
|
||||
).await
|
||||
{
|
||||
Ok(_) => {
|
||||
app.dialog()
|
||||
.message("Update installed successfully. The application needs to restart to apply the changes.")
|
||||
.message(
|
||||
"Update installed successfully. The application needs to restart to apply the changes."
|
||||
)
|
||||
.title("Qopy Update Installed")
|
||||
.buttons(MessageDialogButtons::OkCancelCustom(String::from("Restart"), String::from("Cancel")))
|
||||
.buttons(
|
||||
MessageDialogButtons::OkCancelCustom(
|
||||
String::from("Restart"),
|
||||
String::from("Cancel")
|
||||
)
|
||||
)
|
||||
.show(move |response| {
|
||||
if response {
|
||||
app.restart();
|
||||
|
@ -42,7 +59,9 @@ pub async fn check_for_updates(app: AppHandle) {
|
|||
Err(e) => {
|
||||
println!("Error installing new update: {:?}", e);
|
||||
app.dialog()
|
||||
.message("Failed to install new update. The new update can be downloaded from Github")
|
||||
.message(
|
||||
"Failed to install new update. The new update can be downloaded from Github"
|
||||
)
|
||||
.kind(MessageDialogKind::Error)
|
||||
.show(|_| {});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue