refactor: Clean up code formatting in utils module

This commit is contained in:
PandaDEV 2025-01-04 11:58:52 +10:00
parent 60b670c7a7
commit 22fcd84b8d
No known key found for this signature in database
GPG key ID: 13EFF9BAF70EE75C
14 changed files with 485 additions and 394 deletions

View file

@ -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");

View file

@ -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" }
})),
})
)
);
}

View file

@ -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)?;

View file

@ -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(|_| {});
}