From 3018b9b353a392497713f85f6fda9c49e2e3ac71 Mon Sep 17 00:00:00 2001 From: don Date: Sun, 22 Dec 2024 01:06:14 +0100 Subject: [PATCH] add more settings inf frontend --- src-tauri/common/src/language.rs | 24 +++++++- src-tauri/common/src/types/enums.rs | 53 ++++++++++++++++- src-tauri/entity/src/settings.rs | 3 + .../migration/src/m000007_create_settings.rs | 23 +++++++- src-tauri/src/service/window.rs | 10 ++++ src/components/elements/input.tsx | 43 +++++++++----- .../pages/settings/settings-general.tsx | 59 ++++++++++++++----- src/store/clipboard-store.ts | 2 +- src/store/settings-store.ts | 1 + src/types/enums.ts | 19 ++++++ 10 files changed, 200 insertions(+), 37 deletions(-) diff --git a/src-tauri/common/src/language.rs b/src-tauri/common/src/language.rs index 0716967a..bbd5ee76 100644 --- a/src-tauri/common/src/language.rs +++ b/src-tauri/common/src/language.rs @@ -6,9 +6,15 @@ pub fn get_system_language() -> Language { if let Ok(lang) = std::env::var("LANG") { let lang = lang.to_lowercase(); match &lang[..2] { - s if s == Language::German.to_string() => Language::German, + s if s == Language::Mandarin.to_string() => Language::Mandarin, + s if s == Language::Hindi.to_string() => Language::Hindi, s if s == Language::Spanish.to_string() => Language::Spanish, s if s == Language::French.to_string() => Language::French, + s if s == Language::Arabic.to_string() => Language::Arabic, + s if s == Language::Bengali.to_string() => Language::Bengali, + s if s == Language::Portuguese.to_string() => Language::Portuguese, + s if s == Language::Russian.to_string() => Language::Russian, + s if s == Language::Urdu.to_string() => Language::Urdu, _ => Language::English, } } else { @@ -24,9 +30,15 @@ pub fn get_system_language() -> Language { if let Ok(lang) = std::str::from_utf8(&result.stdout) { let lang = lang.trim().to_lowercase(); match lang.as_str() { - s if s == Language::German.to_string() => Language::German, + s if s == Language::Mandarin.to_string() => Language::Mandarin, + s if s == Language::Hindi.to_string() => Language::Hindi, s if s == Language::Spanish.to_string() => Language::Spanish, s if s == Language::French.to_string() => Language::French, + s if s == Language::Arabic.to_string() => Language::Arabic, + s if s == Language::Bengali.to_string() => Language::Bengali, + s if s == Language::Portuguese.to_string() => Language::Portuguese, + s if s == Language::Russian.to_string() => Language::Russian, + s if s == Language::Urdu.to_string() => Language::Urdu, _ => Language::English, } } else { @@ -46,9 +58,15 @@ pub fn get_system_language() -> Language { if let Ok(lang) = std::str::from_utf8(&result.stdout) { let lang = lang.to_lowercase(); match &lang[..2] { - s if s == Language::German.to_string() => Language::German, + s if s == Language::Mandarin.to_string() => Language::Mandarin, + s if s == Language::Hindi.to_string() => Language::Hindi, s if s == Language::Spanish.to_string() => Language::Spanish, s if s == Language::French.to_string() => Language::French, + s if s == Language::Arabic.to_string() => Language::Arabic, + s if s == Language::Bengali.to_string() => Language::Bengali, + s if s == Language::Portuguese.to_string() => Language::Portuguese, + s if s == Language::Russian.to_string() => Language::Russian, + s if s == Language::Urdu.to_string() => Language::Urdu, _ => Language::English, } } else { diff --git a/src-tauri/common/src/types/enums.rs b/src-tauri/common/src/types/enums.rs index ca659528..ad640620 100644 --- a/src-tauri/common/src/types/enums.rs +++ b/src-tauri/common/src/types/enums.rs @@ -3,6 +3,43 @@ use sea_orm::{sea_query, EnumIter}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value as JsonValue}; +#[derive(Iden, EnumIter, PartialEq, Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "lowercase")] +pub enum ClippyPosition { + #[iden = "mouse_pointer"] + MousePointer, + #[iden = "top_left"] + TopLeft, + #[iden = "top_right"] + TopRight, + #[iden = "bottom_left"] + BottomLeft, + #[iden = "bottom_right"] + BottomRight, + #[iden = "top_center"] + TopCenter, + #[iden = "bottom_center"] + BottomCenter, + #[iden = "left_center"] + LeftCenter, + #[iden = "right_center"] + RightCenter, + #[iden = "center"] + Center, + #[iden = "tray_left"] + TrayLeft, + #[iden = "tray_bottom_left"] + TrayBottomLeft, + #[iden = "tray_right"] + TrayRight, + #[iden = "tray_bottom_right"] + TrayBottomRight, + #[iden = "tray_center"] + TrayCenter, + #[iden = "tray_bottom_center"] + TrayBottomCenter, +} + #[derive(Iden, EnumIter, PartialEq, Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "lowercase")] pub enum FolderLocation { @@ -17,12 +54,24 @@ pub enum FolderLocation { pub enum Language { #[iden = "en"] English, + #[iden = "zh"] + Mandarin, + #[iden = "hi"] + Hindi, #[iden = "es"] Spanish, #[iden = "fr"] French, - #[iden = "de"] - German, + #[iden = "ar"] + Arabic, + #[iden = "bn"] + Bengali, + #[iden = "pt"] + Portuguese, + #[iden = "ru"] + Russian, + #[iden = "ur"] + Urdu, } #[derive(Iden, EnumIter, PartialEq, Serialize, Deserialize, Debug, Clone)] diff --git a/src-tauri/entity/src/settings.rs b/src-tauri/entity/src/settings.rs index 73e74023..c4e55d52 100644 --- a/src-tauri/entity/src/settings.rs +++ b/src-tauri/entity/src/settings.rs @@ -20,6 +20,7 @@ pub struct Model { pub synchronize: bool, pub dark_mode: bool, pub display_scale: f32, + pub position: String, pub max_file_size: i32, pub max_image_size: i32, pub max_text_size: i32, @@ -35,6 +36,7 @@ pub enum Column { Synchronize, DarkMode, DisplayScale, + Position, MaxFileSize, MaxImageSize, MaxTextSize, @@ -67,6 +69,7 @@ impl ColumnTrait for Column { Self::Synchronize => ColumnType::Boolean.def(), Self::DarkMode => ColumnType::Boolean.def(), Self::DisplayScale => ColumnType::Float.def(), + Self::Position => ColumnType::String(StringLen::None).def(), Self::MaxFileSize => ColumnType::Integer.def(), Self::MaxImageSize => ColumnType::Integer.def(), Self::MaxTextSize => ColumnType::Integer.def(), diff --git a/src-tauri/migration/src/m000007_create_settings.rs b/src-tauri/migration/src/m000007_create_settings.rs index ca81d7a9..152394d2 100644 --- a/src-tauri/migration/src/m000007_create_settings.rs +++ b/src-tauri/migration/src/m000007_create_settings.rs @@ -6,7 +6,9 @@ use common::{ MAX_TEXT_SIZE, MAX_TEXT_SIZE_MIN, }, language::get_system_language, + types::enums::{ClippyPosition, Language}, }; +use sea_orm::Iterable; use sea_orm_migration::{ prelude::*, schema::{boolean, float, integer, pk_auto, string}, @@ -22,6 +24,7 @@ enum Settings { Synchronize, DarkMode, DisplayScale, + Position, // MaxFileSize, MaxImageSize, @@ -45,7 +48,14 @@ impl MigrationTrait for Migration { .col( string(Settings::Language) .string_len(2) - .default(get_system_language().to_string()), + .default(get_system_language().to_string()) + .check( + Expr::col(Settings::Language).is_in( + Language::iter() + .map(|x| x.to_string()) + .collect::>(), + ), + ), ) .col(boolean(Settings::Startup).default(true)) .col(boolean(Settings::Synchronize).default(false)) @@ -62,6 +72,17 @@ impl MigrationTrait for Migration { ), ), ) + .col( + string(Settings::Position) + .default(ClippyPosition::MousePointer.to_string()) + .check( + Expr::col(Settings::Position).is_in( + ClippyPosition::iter() + .map(|x| x.to_string()) + .collect::>(), + ), + ), + ) // 10MB default, 0 min, 100MB max .col( integer(Settings::MaxFileSize).default(MAX_FILE_SIZE).check( diff --git a/src-tauri/src/service/window.rs b/src-tauri/src/service/window.rs index db03de97..74566806 100644 --- a/src-tauri/src/service/window.rs +++ b/src-tauri/src/service/window.rs @@ -14,6 +14,7 @@ use std::env; use std::process::Command; use tauri::{Emitter, LogicalSize, Manager, WebviewUrl}; use tauri::{PhysicalPosition, WebviewWindowBuilder}; +use tauri_plugin_positioner::{Position, WindowExt}; /// App pub fn init_window() { @@ -56,6 +57,14 @@ pub fn toggle_main_window() { .expect("Failed to emit set global hotkey event"); } else { position_window_near_cursor(); + tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + let size = calculate_logical_size(MAIN_WINDOW_X, MAIN_WINDOW_Y).await; + get_main_window() + .set_size(size) + .expect("Failed to set window size"); + }) + }); get_main_window() .emit( ListenEvent::ChangeTab.to_string().as_str(), @@ -145,6 +154,7 @@ pub fn position_window_near_cursor() { window .set_position(final_pos) .expect("Failed to set window position"); + let _ = window.as_ref().window().move_window(Position::TopRight); } } diff --git a/src/components/elements/input.tsx b/src/components/elements/input.tsx index f6dc1b6b..110492d1 100644 --- a/src/components/elements/input.tsx +++ b/src/components/elements/input.tsx @@ -1,27 +1,42 @@ -import { Component } from "solid-js"; +import { Component, JSX, createSignal } from "solid-js"; -interface InputProps { +type InputProps = JSX.InputHTMLAttributes & { + debounce?: number; className?: string; - value: string; - onChange: (value: string) => void; - placeholder?: string; - type?: string; -} +}; + +export const Input: Component = ({ className, debounce = 0, onInput, value: initialValue = "", ...props }) => { + let timeoutId: number; + const [value, setValue] = createSignal(initialValue as string); + + const handleInput: JSX.EventHandler = (e) => { + const target = e.currentTarget; + setValue(target.value); + + if (debounce > 0) { + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + // @ts-ignore + onInput?.(e); + }, debounce); + } else { + // @ts-ignore + onInput?.(e); + } + }; -export const Input: Component = (props) => { return (
props.onChange(e.currentTarget.value)} - placeholder={props.placeholder} + {...props} + onInput={handleInput} + value={value()} class="w-full appearance-none bg-transparent text-sm focus:outline-none focus:ring-0 dark:text-white" />
); -}; +}; \ No newline at end of file diff --git a/src/components/pages/settings/settings-general.tsx b/src/components/pages/settings/settings-general.tsx index 49ba0d62..2b44b681 100644 --- a/src/components/pages/settings/settings-general.tsx +++ b/src/components/pages/settings/settings-general.tsx @@ -4,10 +4,12 @@ import { HiSolidCog8Tooth } from "solid-icons/hi"; import { IoLanguageOutline } from "solid-icons/io"; import { RiDeviceKeyboardFill } from "solid-icons/ri"; import { VsRocket } from "solid-icons/vs"; -import { Component, Show } from "solid-js"; +import { Component, createEffect, Show } from "solid-js"; import { HotkeyStore } from "../../../store/hotkey-store"; import { SettingsStore } from "../../../store/settings-store"; -import { HotkeyEvent, Language } from "../../../types/enums"; +import { ClippyPosition, HotkeyEvent, Language, WebWindow } from "../../../types/enums"; +import { InvokeCommand } from "../../../types/tauri-invoke"; +import { invokeCommand } from "../../../utils/tauri"; import { Dropdown } from "../../elements/dropdown"; import { Input } from "../../elements/input"; import { TextBlock } from "../../elements/text-block"; @@ -18,6 +20,9 @@ import { Shortcut } from "../../utils/shortcut"; interface SettingsGeneralProps {} export const SettingsGeneral: Component = ({}) => { + createEffect(() => { + console.log("settings", SettingsStore.settings()); + }, []); return ( @@ -44,6 +49,16 @@ export const SettingsGeneral: Component = ({}) => { +
+
+ +
Switch Theme
+
+
+ +
+
+
@@ -51,8 +66,7 @@ export const SettingsGeneral: Component = ({}) => {
({ value: value, label: key }))} + items={Object.entries(ClippyPosition).map(([key, value]) => ({ value: value, label: key }))} value={SettingsStore.settings()!.language} onChange={(language) => { SettingsStore.updateSettings({ ...SettingsStore.settings()!, language: language as Language }); @@ -62,27 +76,40 @@ export const SettingsGeneral: Component = ({}) => {
- -
Display Scale
+ +
Change language
- { - SettingsStore.updateSettings({ ...SettingsStore.settings()!, display_scale: parseInt(display_scale) }); + ({ value: value, label: key }))} + value={SettingsStore.settings()!.language} + onChange={(language) => { + SettingsStore.updateSettings({ ...SettingsStore.settings()!, language: language as Language }); }} />
- -
Switch Theme.
-
-
- + +
Display Scale
+ + { + SettingsStore.updateSettings({ + ...SettingsStore.settings()!, + display_scale: Number(parseFloat(e.target.value).toFixed(2)), + }); + await invokeCommand(InvokeCommand.OpenNewWindow, { windowName: WebWindow.Settings }); + }} + />
diff --git a/src/store/clipboard-store.ts b/src/store/clipboard-store.ts index ca630c2c..02544ed1 100644 --- a/src/store/clipboard-store.ts +++ b/src/store/clipboard-store.ts @@ -32,7 +32,7 @@ function createClipboardStore() { setWhere(initialWhere); const clipboards = await getClipboards(); setClipboards(clipboards); - ClipboardStore.clipboardRef()!.scrollTo(0, 0); + ClipboardStore.clipboardRef()?.scrollTo(0, 0); }; const resetClipboards = async () => { diff --git a/src/store/settings-store.ts b/src/store/settings-store.ts index 85b69fe5..077aed81 100644 --- a/src/store/settings-store.ts +++ b/src/store/settings-store.ts @@ -40,6 +40,7 @@ function createSettingsStore() { const initSettings = async () => { const settings = await invokeCommand(InvokeCommand.GetSettings); setSettings(settings); + console.log(settings); }; const syncClipboard = async () => invokeCommand(InvokeCommand.SyncClipboardHistory); diff --git a/src/types/enums.ts b/src/types/enums.ts index bc6d971f..88165dac 100644 --- a/src/types/enums.ts +++ b/src/types/enums.ts @@ -9,6 +9,25 @@ export enum FolderLocation { Config = "config", } +export enum ClippyPosition { + MousePointer = "mouse_pointer", + TopLeft = "top_left", + TopRight = "top_right", + BottomLeft = "bottom_left", + BottomRight = "bottom_right", + TopCenter = "top_center", + BottomCenter = "bottom_center", + LeftCenter = "left_center", + RightCenter = "right_center", + Center = "center", + TrayLeft = "tray_left", + TrayBottomLeft = "tray_bottom_left", + TrayRight = "tray_right", + TrayBottomRight = "tray_bottom_right", + TrayCenter = "tray_center", + TrayBottomCenter = "tray_bottom_center", +} + export enum Language { // ~1.1 billion speakers English = "en",