Merge pull request #61 from cjpais/debug-mode-toggle
add a very simple debug mode toggle
This commit is contained in:
commit
cbd55b728a
13 changed files with 336 additions and 4 deletions
|
|
@ -2,9 +2,19 @@ pub mod audio;
|
||||||
pub mod models;
|
pub mod models;
|
||||||
|
|
||||||
use crate::utils::cancel_current_operation;
|
use crate::utils::cancel_current_operation;
|
||||||
use tauri::AppHandle;
|
use tauri::{AppHandle, Manager};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn cancel_operation(app: AppHandle) {
|
pub fn cancel_operation(app: AppHandle) {
|
||||||
cancel_current_operation(&app);
|
cancel_current_operation(&app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn get_app_dir_path(app: AppHandle) -> Result<String, String> {
|
||||||
|
let app_data_dir = app
|
||||||
|
.path()
|
||||||
|
.app_data_dir()
|
||||||
|
.map_err(|e| format!("Failed to get app data directory: {}", e))?;
|
||||||
|
|
||||||
|
Ok(app_data_dir.to_string_lossy().to_string())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,8 +158,10 @@ pub fn run() {
|
||||||
shortcut::change_translate_to_english_setting,
|
shortcut::change_translate_to_english_setting,
|
||||||
shortcut::change_selected_language_setting,
|
shortcut::change_selected_language_setting,
|
||||||
shortcut::change_show_overlay_setting,
|
shortcut::change_show_overlay_setting,
|
||||||
|
shortcut::change_debug_mode_setting,
|
||||||
trigger_update_check,
|
trigger_update_check,
|
||||||
commands::cancel_operation,
|
commands::cancel_operation,
|
||||||
|
commands::get_app_dir_path,
|
||||||
commands::models::get_available_models,
|
commands::models::get_available_models,
|
||||||
commands::models::get_model_info,
|
commands::models::get_model_info,
|
||||||
commands::models::download_model,
|
commands::models::download_model,
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ pub struct AppSettings {
|
||||||
pub selected_language: String,
|
pub selected_language: String,
|
||||||
#[serde(default = "default_show_overlay")]
|
#[serde(default = "default_show_overlay")]
|
||||||
pub show_overlay: bool,
|
pub show_overlay: bool,
|
||||||
|
#[serde(default = "default_debug_mode")]
|
||||||
|
pub debug_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_model() -> String {
|
fn default_model() -> String {
|
||||||
|
|
@ -61,6 +63,11 @@ fn default_show_overlay() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_debug_mode() -> bool {
|
||||||
|
// Default to false - debug mode should be opt-in
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub const SETTINGS_STORE_PATH: &str = "settings_store.json";
|
pub const SETTINGS_STORE_PATH: &str = "settings_store.json";
|
||||||
|
|
||||||
pub fn get_default_settings() -> AppSettings {
|
pub fn get_default_settings() -> AppSettings {
|
||||||
|
|
@ -85,6 +92,7 @@ pub fn get_default_settings() -> AppSettings {
|
||||||
current_binding: default_shortcut.to_string(),
|
current_binding: default_shortcut.to_string(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// bindings.insert(
|
// bindings.insert(
|
||||||
// "test".to_string(),
|
// "test".to_string(),
|
||||||
// ShortcutBinding {
|
// ShortcutBinding {
|
||||||
|
|
@ -107,6 +115,7 @@ pub fn get_default_settings() -> AppSettings {
|
||||||
translate_to_english: false,
|
translate_to_english: false,
|
||||||
selected_language: "auto".to_string(),
|
selected_language: "auto".to_string(),
|
||||||
show_overlay: true,
|
show_overlay: true,
|
||||||
|
debug_mode: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,14 @@ pub fn change_show_overlay_setting(app: AppHandle, enabled: bool) -> Result<(),
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn change_debug_mode_setting(app: AppHandle, enabled: bool) -> Result<(), String> {
|
||||||
|
let mut settings = settings::get_settings(&app);
|
||||||
|
settings.debug_mode = enabled;
|
||||||
|
settings::write_settings(&app, settings);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn _register_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result<(), String> {
|
fn _register_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result<(), String> {
|
||||||
// Parse shortcut and return error if it fails
|
// Parse shortcut and return error if it fails
|
||||||
let shortcut = match binding.current_binding.parse::<Shortcut>() {
|
let shortcut = match binding.current_binding.parse::<Shortcut>() {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { MicrophoneSelector } from "./MicrophoneSelector";
|
import { MicrophoneSelector } from "./MicrophoneSelector";
|
||||||
import { AlwaysOnMicrophone } from "./AlwaysOnMicrophone";
|
import { AlwaysOnMicrophone } from "./AlwaysOnMicrophone";
|
||||||
import { PushToTalk } from "./PushToTalk";
|
import { PushToTalk } from "./PushToTalk";
|
||||||
|
|
@ -9,8 +9,37 @@ import { HandyShortcut } from "./HandyShortcut";
|
||||||
import { TranslateToEnglish } from "./TranslateToEnglish";
|
import { TranslateToEnglish } from "./TranslateToEnglish";
|
||||||
import { LanguageSelector } from "./LanguageSelector";
|
import { LanguageSelector } from "./LanguageSelector";
|
||||||
import { SettingsGroup } from "../ui/SettingsGroup";
|
import { SettingsGroup } from "../ui/SettingsGroup";
|
||||||
|
import { DebugSettings } from "./debug";
|
||||||
|
import { useSettings } from "../../hooks/useSettings";
|
||||||
|
|
||||||
export const Settings: React.FC = () => {
|
export const Settings: React.FC = () => {
|
||||||
|
const { settings, updateSetting } = useSettings();
|
||||||
|
|
||||||
|
// Handle keyboard shortcuts for debug mode toggle
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
// Check for Ctrl+Shift+D (Windows/Linux) or Cmd+Shift+D (macOS)
|
||||||
|
const isDebugShortcut =
|
||||||
|
event.shiftKey &&
|
||||||
|
event.key.toLowerCase() === "d" &&
|
||||||
|
(event.ctrlKey || event.metaKey);
|
||||||
|
|
||||||
|
if (isDebugShortcut) {
|
||||||
|
event.preventDefault();
|
||||||
|
const currentDebugMode = settings?.debug_mode ?? false;
|
||||||
|
updateSetting("debug_mode", !currentDebugMode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add event listener when component mounts
|
||||||
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
|
|
||||||
|
// Cleanup event listener when component unmounts
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("keydown", handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [settings?.debug_mode, updateSetting]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-3xl w-full mx-auto space-y-6">
|
<div className="max-w-3xl w-full mx-auto space-y-6">
|
||||||
<SettingsGroup>
|
<SettingsGroup>
|
||||||
|
|
@ -27,6 +56,12 @@ export const Settings: React.FC = () => {
|
||||||
<TranslateToEnglish descriptionMode="tooltip" grouped={true} />
|
<TranslateToEnglish descriptionMode="tooltip" grouped={true} />
|
||||||
<AlwaysOnMicrophone descriptionMode="tooltip" grouped={true} />
|
<AlwaysOnMicrophone descriptionMode="tooltip" grouped={true} />
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
|
|
||||||
|
{settings?.debug_mode && (
|
||||||
|
<SettingsGroup title="Debug">
|
||||||
|
<DebugSettings descriptionMode="tooltip" grouped={true} />
|
||||||
|
</SettingsGroup>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
69
src/components/settings/debug/DebugPaths.tsx
Normal file
69
src/components/settings/debug/DebugPaths.tsx
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import { TextDisplay, SettingsGroup } from "../../ui";
|
||||||
|
|
||||||
|
interface DebugPathsProps {
|
||||||
|
descriptionMode?: "tooltip" | "inline";
|
||||||
|
grouped?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DebugPaths: React.FC<DebugPathsProps> = ({
|
||||||
|
descriptionMode = "inline",
|
||||||
|
grouped = false,
|
||||||
|
}) => {
|
||||||
|
const [appDirPath, setAppDirPath] = useState<string>("");
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadPaths = async () => {
|
||||||
|
try {
|
||||||
|
const result = await invoke<string>("get_app_dir_path");
|
||||||
|
setAppDirPath(result);
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err.message : "Failed to load paths");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadPaths();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleCopy = (value: string) => {
|
||||||
|
// Could add a toast notification here if desired
|
||||||
|
console.log("Copied to clipboard:", value);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="animate-pulse">
|
||||||
|
<div className="h-4 bg-gray-200 rounded w-1/3 mb-2"></div>
|
||||||
|
<div className="h-8 bg-gray-100 rounded"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||||
|
<p className="text-red-600 text-sm">Error loading paths: {error}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextDisplay
|
||||||
|
label="App Data Directory"
|
||||||
|
description="Main directory where application data, settings, and models are stored"
|
||||||
|
value={appDirPath}
|
||||||
|
descriptionMode={descriptionMode}
|
||||||
|
grouped={true}
|
||||||
|
copyable={true}
|
||||||
|
monospace={true}
|
||||||
|
onCopy={handleCopy}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
30
src/components/settings/debug/DebugSettings.tsx
Normal file
30
src/components/settings/debug/DebugSettings.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import React from "react";
|
||||||
|
import { DebugPaths } from "./DebugPaths";
|
||||||
|
|
||||||
|
interface DebugSettingsProps {
|
||||||
|
descriptionMode?: "tooltip" | "inline";
|
||||||
|
grouped?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DebugSettings: React.FC<DebugSettingsProps> = ({
|
||||||
|
descriptionMode = "inline",
|
||||||
|
grouped = false,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
{descriptionMode === "inline" && !grouped && (
|
||||||
|
<div className="mb-6">
|
||||||
|
<div className="flex items-center space-x-2 mb-2">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900">Debug</h2>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-600">
|
||||||
|
Debug information and developer tools. These settings are only
|
||||||
|
visible when debug mode is enabled.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<DebugPaths descriptionMode={descriptionMode} grouped={true} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
2
src/components/settings/debug/index.ts
Normal file
2
src/components/settings/debug/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { DebugSettings } from "./DebugSettings";
|
||||||
|
export { DebugPaths } from "./DebugPaths";
|
||||||
|
|
@ -6,6 +6,7 @@ interface SettingContainerProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
descriptionMode?: "inline" | "tooltip";
|
descriptionMode?: "inline" | "tooltip";
|
||||||
grouped?: boolean;
|
grouped?: boolean;
|
||||||
|
layout?: "horizontal" | "stacked";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SettingContainer: React.FC<SettingContainerProps> = ({
|
export const SettingContainer: React.FC<SettingContainerProps> = ({
|
||||||
|
|
@ -14,6 +15,7 @@ export const SettingContainer: React.FC<SettingContainerProps> = ({
|
||||||
children,
|
children,
|
||||||
descriptionMode = "tooltip",
|
descriptionMode = "tooltip",
|
||||||
grouped = false,
|
grouped = false,
|
||||||
|
layout = "horizontal",
|
||||||
}) => {
|
}) => {
|
||||||
const [showTooltip, setShowTooltip] = useState(false);
|
const [showTooltip, setShowTooltip] = useState(false);
|
||||||
const tooltipRef = useRef<HTMLDivElement>(null);
|
const tooltipRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
@ -41,12 +43,78 @@ export const SettingContainer: React.FC<SettingContainerProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const containerClasses = grouped
|
const containerClasses = grouped
|
||||||
|
? "px-4 p-2"
|
||||||
|
: "px-4 p-2 rounded-lg border border-mid-gray/20";
|
||||||
|
|
||||||
|
if (layout === "stacked") {
|
||||||
|
if (descriptionMode === "tooltip") {
|
||||||
|
return (
|
||||||
|
<div className={containerClasses}>
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<h3 className="text-sm font-medium">{title}</h3>
|
||||||
|
<div
|
||||||
|
ref={tooltipRef}
|
||||||
|
className="relative"
|
||||||
|
onMouseEnter={() => setShowTooltip(true)}
|
||||||
|
onMouseLeave={() => setShowTooltip(false)}
|
||||||
|
onClick={toggleTooltip}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-4 h-4 text-mid-gray cursor-help hover:text-logo-primary transition-colors duration-200 select-none"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
aria-label="More information"
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter" || e.key === " ") {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTooltip();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{showTooltip && (
|
||||||
|
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-2 bg-background border border-mid-gray/80 rounded-lg shadow-lg z-50 max-w-xs min-w-[200px] whitespace-normal animate-in fade-in-0 zoom-in-95 duration-200">
|
||||||
|
<p className="text-sm text-center leading-relaxed">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
<div className="absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-[6px] border-r-[6px] border-t-[6px] border-l-transparent border-r-transparent border-t-mid-gray/80"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">{children}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={containerClasses}>
|
||||||
|
<div className="mb-2">
|
||||||
|
<h3 className="text-sm font-medium">{title}</h3>
|
||||||
|
<p className="text-sm">{description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">{children}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal layout (default)
|
||||||
|
const horizontalContainerClasses = grouped
|
||||||
? "flex items-center justify-between px-4 p-2"
|
? "flex items-center justify-between px-4 p-2"
|
||||||
: "flex items-center justify-between px-4 p-2 rounded-lg border border-mid-gray/20";
|
: "flex items-center justify-between px-4 p-2 rounded-lg border border-mid-gray/20";
|
||||||
|
|
||||||
if (descriptionMode === "tooltip") {
|
if (descriptionMode === "tooltip") {
|
||||||
return (
|
return (
|
||||||
<div className={containerClasses}>
|
<div className={horizontalContainerClasses}>
|
||||||
<div className="max-w-2/3">
|
<div className="max-w-2/3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h3 className="text-sm font-medium ">{title}</h3>
|
<h3 className="text-sm font-medium ">{title}</h3>
|
||||||
|
|
@ -96,7 +164,7 @@ export const SettingContainer: React.FC<SettingContainerProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={containerClasses}>
|
<div className={horizontalContainerClasses}>
|
||||||
<div className="max-w-2/3">
|
<div className="max-w-2/3">
|
||||||
<h3 className="text-sm font-medium ">{title}</h3>
|
<h3 className="text-sm font-medium ">{title}</h3>
|
||||||
<p className="text-sm">{description}</p>
|
<p className="text-sm">{description}</p>
|
||||||
|
|
|
||||||
93
src/components/ui/TextDisplay.tsx
Normal file
93
src/components/ui/TextDisplay.tsx
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { SettingContainer } from "./SettingContainer";
|
||||||
|
|
||||||
|
interface TextDisplayProps {
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
value: string;
|
||||||
|
descriptionMode?: "inline" | "tooltip";
|
||||||
|
grouped?: boolean;
|
||||||
|
placeholder?: string;
|
||||||
|
copyable?: boolean;
|
||||||
|
monospace?: boolean;
|
||||||
|
onCopy?: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TextDisplay: React.FC<TextDisplayProps> = ({
|
||||||
|
label,
|
||||||
|
description,
|
||||||
|
value,
|
||||||
|
descriptionMode = "tooltip",
|
||||||
|
grouped = false,
|
||||||
|
placeholder = "Not available",
|
||||||
|
copyable = false,
|
||||||
|
monospace = false,
|
||||||
|
onCopy,
|
||||||
|
}) => {
|
||||||
|
const [showCopied, setShowCopied] = useState(false);
|
||||||
|
|
||||||
|
const handleCopy = async () => {
|
||||||
|
if (!value || !copyable) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(value);
|
||||||
|
setShowCopied(true);
|
||||||
|
setTimeout(() => setShowCopied(false), 1500);
|
||||||
|
if (onCopy) {
|
||||||
|
onCopy(value);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to copy to clipboard:", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const displayValue = value || placeholder;
|
||||||
|
const textClasses = monospace ? "font-mono break-all" : "break-words";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingContainer
|
||||||
|
title={label}
|
||||||
|
description={description}
|
||||||
|
descriptionMode={descriptionMode}
|
||||||
|
grouped={grouped}
|
||||||
|
layout="stacked"
|
||||||
|
>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div
|
||||||
|
className={`px-2 min-h-8 flex items-center bg-mid-gray/10 border border-mid-gray/80 rounded text-xs ${textClasses} ${!value ? "opacity-60" : ""}`}
|
||||||
|
>
|
||||||
|
{displayValue}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{copyable && value && (
|
||||||
|
<button
|
||||||
|
onClick={handleCopy}
|
||||||
|
className="flex items-center justify-center px-2 py-1 w-12 min-h-8 text-xs font-semibold bg-mid-gray/10 hover:bg-logo-primary/10 border border-mid-gray/80 hover:border-logo-primary hover:text-logo-primary rounded transition-all duration-150 flex-shrink-0 cursor-pointer"
|
||||||
|
title="Copy to clipboard"
|
||||||
|
>
|
||||||
|
{showCopied ? (
|
||||||
|
<div className="flex items-center space-x-1">
|
||||||
|
<svg
|
||||||
|
className="w-4 h-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M5 13l4 4L19 7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
"Copy"
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SettingContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -2,3 +2,4 @@ export { Dropdown } from "./Dropdown";
|
||||||
export { ToggleSwitch } from "./ToggleSwitch";
|
export { ToggleSwitch } from "./ToggleSwitch";
|
||||||
export { SettingContainer } from "./SettingContainer";
|
export { SettingContainer } from "./SettingContainer";
|
||||||
export { SettingsGroup } from "./SettingsGroup";
|
export { SettingsGroup } from "./SettingsGroup";
|
||||||
|
export { TextDisplay } from "./TextDisplay";
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,9 @@ export const useSettings = (): UseSettingsReturn => {
|
||||||
case "show_overlay":
|
case "show_overlay":
|
||||||
await invoke("change_show_overlay_setting", { enabled: value });
|
await invoke("change_show_overlay_setting", { enabled: value });
|
||||||
break;
|
break;
|
||||||
|
case "debug_mode":
|
||||||
|
await invoke("change_debug_mode_setting", { enabled: value });
|
||||||
|
break;
|
||||||
case "bindings":
|
case "bindings":
|
||||||
// Handle bindings separately - they use their own invoke methods
|
// Handle bindings separately - they use their own invoke methods
|
||||||
break;
|
break;
|
||||||
|
|
@ -247,6 +250,7 @@ export const useSettings = (): UseSettingsReturn => {
|
||||||
translate_to_english: false,
|
translate_to_english: false,
|
||||||
selected_language: "auto",
|
selected_language: "auto",
|
||||||
show_overlay: true,
|
show_overlay: true,
|
||||||
|
debug_mode: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValue = defaults[key];
|
const defaultValue = defaults[key];
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export const SettingsSchema = z.object({
|
||||||
translate_to_english: z.boolean(),
|
translate_to_english: z.boolean(),
|
||||||
selected_language: z.string(),
|
selected_language: z.string(),
|
||||||
show_overlay: z.boolean(),
|
show_overlay: z.boolean(),
|
||||||
|
debug_mode: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const BindingResponseSchema = z.object({
|
export const BindingResponseSchema = z.object({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue