diff --git a/src-tauri/src/commands/clipboard.rs b/src-tauri/src/commands/clipboard.rs index 1d24a8fb..974503b8 100644 --- a/src-tauri/src/commands/clipboard.rs +++ b/src-tauri/src/commands/clipboard.rs @@ -31,7 +31,7 @@ pub async fn get_clipboards( star: Option, img: Option, ) -> Result { - let clipboards = get_clipboards_db(cursor, search.clone(), star, img) + let clipboards = get_clipboards_db(cursor, search, star, img) .await .expect("Error getting clipboards"); @@ -73,8 +73,8 @@ pub async fn delete_clipboard(id: i32) -> Result<(), CommandError> { } #[tauri::command] -pub async fn clear_clipboards() -> Result<(), CommandError> { - clear_clipboards_db().await?; +pub async fn clear_clipboards(r#type: Option) -> Result<(), CommandError> { + clear_clipboards_db(r#type).await?; get_main_window() .emit(ListenEvent::Init.to_string().as_str(), ()) .expect("Failed to emit"); diff --git a/src-tauri/src/commands/window.rs b/src-tauri/src/commands/window.rs index 7bde68c0..e792194d 100644 --- a/src-tauri/src/commands/window.rs +++ b/src-tauri/src/commands/window.rs @@ -51,6 +51,12 @@ pub async fn get_db_path() -> Result { Ok(config.db) } +#[tauri::command] +pub async fn get_config_path() -> Result { + let data_path = get_data_path(); + Ok(data_path.config_file_path) +} + #[tauri::command] pub async fn open_folder(location: FolderLocation) -> Result<(), CommandError> { let data_path = get_data_path(); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index d61ac470..274c0505 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -46,6 +46,7 @@ pub fn run() { window::get_app_version, window::get_db_info, window::get_db_path, + window::get_config_path, window::open_folder, ]) .run(tauri::generate_context!()) diff --git a/src-tauri/src/service/clipboard.rs b/src-tauri/src/service/clipboard.rs index 3af11d60..46ee3a20 100644 --- a/src-tauri/src/service/clipboard.rs +++ b/src-tauri/src/service/clipboard.rs @@ -238,13 +238,86 @@ pub async fn delete_clipboard_db(id: i32) -> Result { Ok(true) } -pub async fn clear_clipboards_db() -> Result<(), DbErr> { +pub async fn clear_clipboards_db(r#type: Option) -> Result<(), DbErr> { let db = connection::db().await?; - clipboard::Entity::delete_many() - .filter(clipboard::Column::Star.eq(false)) - .exec(&db) - .await?; + match r#type { + None => { + // Keep existing behavior - delete all non-starred clipboards + clipboard::Entity::delete_many() + .filter(clipboard::Column::Star.eq(false)) + .exec(&db) + .await?; + } + Some(clipboard_type) => { + // Find all non-starred clipboards that contain the specified type + let clipboards = clipboard::Entity::find() + .filter( + clipboard::Column::Star + .eq(false) + .and(clipboard::Column::Types.contains(clipboard_type.to_string())), + ) + .all(&db) + .await?; + + for clipboard in clipboards { + // Delete the type-specific data first + match clipboard_type { + ClipboardType::Text => { + clipboard_text::Entity::delete_many() + .filter(clipboard_text::Column::ClipboardId.eq(clipboard.id)) + .exec(&db) + .await?; + } + ClipboardType::Image => { + clipboard_image::Entity::delete_many() + .filter(clipboard_image::Column::ClipboardId.eq(clipboard.id)) + .exec(&db) + .await?; + } + ClipboardType::Html => { + clipboard_html::Entity::delete_many() + .filter(clipboard_html::Column::ClipboardId.eq(clipboard.id)) + .exec(&db) + .await?; + } + ClipboardType::Rtf => { + clipboard_rtf::Entity::delete_many() + .filter(clipboard_rtf::Column::ClipboardId.eq(clipboard.id)) + .exec(&db) + .await?; + } + ClipboardType::File => { + clipboard_file::Entity::delete_many() + .filter(clipboard_file::Column::ClipboardId.eq(clipboard.id)) + .exec(&db) + .await?; + } + } + + // Parse and update the types JSON array + if let Some(mut types) = ClipboardType::from_json_value(&clipboard.types) { + // Remove the specified type + types.retain(|t| t != &clipboard_type); + + if types.is_empty() { + // If no types remain, delete the clipboard + clipboard::Entity::delete_by_id(clipboard.id) + .exec(&db) + .await?; + } else { + // Update the clipboard with the remaining types + let model = clipboard::ActiveModel { + id: Set(clipboard.id), + types: Set(ClipboardType::to_json_value(&types)), + ..Default::default() + }; + clipboard::Entity::update(model).exec(&db).await?; + } + } + } + } + } Ok(()) } diff --git a/src-tauri/src/service/settings.rs b/src-tauri/src/service/settings.rs index 49a380e9..0758f5df 100644 --- a/src-tauri/src/service/settings.rs +++ b/src-tauri/src/service/settings.rs @@ -2,8 +2,8 @@ use super::clipboard::get_last_clipboard_db; use super::global::get_app; use crate::connection; use crate::prelude::*; +use crate::service::hotkey::with_hotkeys; use crate::service::window::get_monitor_scale_factor; -use crate::{commands::settings::get_settings, service::hotkey::with_hotkeys}; use common::constants::CONFIG_NAME; use common::constants::DB_NAME; use common::language::get_system_language; @@ -183,7 +183,7 @@ pub async fn sync_clipboard_history_disable() { } pub async fn sync_clipboard_history_toggle() { - let settings = get_settings().await.expect("Failed to get settings"); + let settings = get_settings_db().await.expect("Failed to get settings"); printlog!("synchronize: {}", settings.synchronize); with_hotkeys(false, async move { diff --git a/src-tauri/src/tauri_config/config.rs b/src-tauri/src/tauri_config/config.rs index 4f39e938..5611475a 100644 --- a/src-tauri/src/tauri_config/config.rs +++ b/src-tauri/src/tauri_config/config.rs @@ -1,7 +1,6 @@ -use crate::commands::settings::get_settings; use crate::prelude::*; use crate::service::global::get_app; -use crate::service::settings::get_data_path; +use crate::service::settings::{get_data_path, get_settings_db}; use common::types::enums::WebWindow; use common::types::hotkey::SafeHotKeyManager; use common::types::types::{Config, Key}; @@ -72,7 +71,7 @@ pub fn create_config() { pub fn autostart() { tauri::async_runtime::spawn(async { let app: &tauri::AppHandle = get_app(); - let settings = get_settings().await.expect("Failed to get settings"); + let settings = get_settings_db().await.expect("Failed to get settings"); let manager: tauri::State<'_, AutoLaunchManager> = app.state::(); // Use the manager as needed diff --git a/src/components/pages/app/clipboard/base-clipboard.tsx b/src/components/pages/app/clipboard/base-clipboard.tsx index 25e6cc23..df7d3e8e 100644 --- a/src/components/pages/app/clipboard/base-clipboard.tsx +++ b/src/components/pages/app/clipboard/base-clipboard.tsx @@ -23,13 +23,12 @@ export const BaseClipboard: Component = (props) => { const { clipboard } = props.data; const handleDelete = async (id: number) => { - if (await invokeCommand(InvokeCommand.DeleteClipboard, { id })) { - setClipboards((prev) => { - const updated = prev.filter((o) => o.clipboard.id !== id); - if (!updated.length) resetClipboards(); - return updated; - }); - } + await invokeCommand(InvokeCommand.DeleteClipboard, { id }); + setClipboards((prev) => { + const updated = prev.filter((o) => o.clipboard.id !== id); + if (!updated.length) resetClipboards(); + return updated; + }); }; const handleStar = async (clipboard: ClipboardModel) => { diff --git a/src/components/pages/settings/settings-backup.tsx b/src/components/pages/settings/settings-backup.tsx index f112320c..e40f7b86 100644 --- a/src/components/pages/settings/settings-backup.tsx +++ b/src/components/pages/settings/settings-backup.tsx @@ -1,8 +1,9 @@ -import { BsGlobeAmericas } from "solid-icons/bs"; -import { FiUpload } from "solid-icons/fi"; +import { AiTwotoneFolderOpen } from "solid-icons/ai"; +import { BsGearWideConnected } from "solid-icons/bs"; import { RiDeviceSave3Fill } from "solid-icons/ri"; +import { SiSqlite } from "solid-icons/si"; import { TbDatabaseStar } from "solid-icons/tb"; -import { Component, Show, createEffect, createSignal, on } from "solid-js"; +import { Component, createResource } from "solid-js"; import { SettingsStore } from "../../../store/settings-store"; import { FolderLocation } from "../../../types/enums"; import { InvokeCommand } from "../../../types/tauri-invoke"; @@ -13,14 +14,8 @@ import { Toggle } from "../../elements/toggle"; interface SettingsBackupProps {} export const SettingsBackup: Component = ({}) => { - const [url, setUrl] = createSignal(); - - createEffect( - on( - () => SettingsStore.settings()?.synchronize, - () => setTimeout(async () => setUrl(await invokeCommand(InvokeCommand.GetDbPath)), 100) - ) - ); + const [databaseUrl, setDatabaseUrl] = createResource(() => invokeCommand(InvokeCommand.GetDbPath)); + const [configUrl] = createResource(() => invokeCommand(InvokeCommand.GetConfigPath)); return ( <> @@ -33,34 +28,55 @@ export const SettingsBackup: Component = ({}) => { void SettingsStore.syncClipboard()} + onChange={async () => { + await SettingsStore.syncClipboard(); + setDatabaseUrl.refetch(); + }} /> - - -
-
-
invokeCommand(InvokeCommand.OpenFolder, { location: FolderLocation.Database })} - class="w-full truncate rounded-md border border-gray-300 px-3 py-0.5 text-left text-sm italic focus:outline-none dark:border-dark-light dark:bg-dark-light dark:text-white dark:focus:bg-dark-dark" - > - {url()} -
- + +
+
+
+ {databaseUrl()}
+
- - +
+
+ + +
+
+
+ {configUrl()} +
+ +
+
+
); }; diff --git a/src/components/pages/settings/settings-history.tsx b/src/components/pages/settings/settings-history.tsx index 365f38fd..6d82bfff 100644 --- a/src/components/pages/settings/settings-history.tsx +++ b/src/components/pages/settings/settings-history.tsx @@ -1,45 +1,54 @@ import { BsDeviceHdd } from "solid-icons/bs"; import { FiTrash2 } from "solid-icons/fi"; -import { Component, createSignal, onMount } from "solid-js"; -import { DatabaseInfo } from "../../../types"; +import { SiSqlite } from "solid-icons/si"; +import { Component, createResource } from "solid-js"; +import { ClipboardType } from "../../../types/enums"; import { InvokeCommand } from "../../../types/tauri-invoke"; import { formatBytes } from "../../../utils/helpers"; import { invokeCommand } from "../../../utils/tauri"; import { TextBlock } from "../../elements/text-block"; -interface SettingsHistoryProps {} +const CLIPBOARD_TYPES: { type: ClipboardType | null; label: string }[] = [ + { type: null, label: "Clear All" }, + { type: ClipboardType.Text, label: "Clear Text" }, + { type: ClipboardType.Html, label: "Clear Html" }, + { type: ClipboardType.Rtf, label: "Clear Rtf" }, + { type: ClipboardType.Image, label: "Clear Image" }, + { type: ClipboardType.File, label: "Clear File" }, +]; -export const SettingsHistory: Component = ({}) => { - const [databaseInfo, setDatabaseInfo] = createSignal({ - records: 0, - size: 0, - }); +export const SettingsHistory: Component = () => { + const [databaseInfo, { refetch }] = createResource(() => invokeCommand(InvokeCommand.GetDbInfo)); - onMount(async () => setDatabaseInfo(await invokeCommand(InvokeCommand.GetDbInfo))); + const handleClear = async (type: ClipboardType | null) => { + await invokeCommand(InvokeCommand.ClearClipboards, { type }); + refetch(); + }; return ( <> - +
    -
  • {`${databaseInfo().records} local items (${formatBytes( - databaseInfo().size - )}) are saved on this computer`}
  • +
  • + {`${databaseInfo()?.records} local items (${formatBytes(databaseInfo()?.size)}) are saved on this computer`} +
-
- -
+ +
+ {CLIPBOARD_TYPES.map(({ type, label }) => ( + + ))} +
+
); }; diff --git a/src/types/tauri-invoke.ts b/src/types/tauri-invoke.ts index ef3849f7..ecf3c8bd 100644 --- a/src/types/tauri-invoke.ts +++ b/src/types/tauri-invoke.ts @@ -31,6 +31,7 @@ export enum InvokeCommand { GetAppVersion = "get_app_version", GetDbInfo = "get_db_info", GetDbPath = "get_db_path", + GetConfigPath = "get_config_path", } export interface TauriInvokeCommands { @@ -41,18 +42,18 @@ export interface TauriInvokeCommands { }; [InvokeCommand.DeleteClipboard]: { args: { id: number }; - return: boolean; + return: void; }; [InvokeCommand.StarClipboard]: { args: { id: number; star: boolean }; return: boolean; }; [InvokeCommand.CopyClipboard]: { - args: { id: number; type: ClipboardType }; + args: { id: number; type?: ClipboardType | null }; return: boolean; }; [InvokeCommand.ClearClipboards]: { - args: undefined; + args: { type?: ClipboardType | null }; return: void; }; [InvokeCommand.SaveClipboardImage]: { @@ -123,4 +124,8 @@ export interface TauriInvokeCommands { args: undefined; return: string; }; + [InvokeCommand.GetConfigPath]: { + args: undefined; + return: string; + }; } diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 386cd1d7..02011208 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -1,4 +1,4 @@ -export function formatBytes(bytes: number, decimals = 2) { +export function formatBytes(bytes: number = 0, decimals = 2) { if (bytes === 0) return "0 Bytes"; const k = 1024;