Handy/src-tauri/src/settings.rs

184 lines
5.6 KiB
Rust

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tauri::{App, AppHandle};
use tauri_plugin_store::StoreExt;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ShortcutBinding {
pub id: String,
pub name: String,
pub description: String,
pub default_binding: String,
pub current_binding: String,
}
/* still handy for composing the initial JSON in the store ------------- */
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AppSettings {
pub bindings: HashMap<String, ShortcutBinding>,
pub push_to_talk: bool,
pub audio_feedback: bool,
#[serde(default = "default_model")]
pub selected_model: String,
#[serde(default = "default_always_on_microphone")]
pub always_on_microphone: bool,
#[serde(default)]
pub selected_microphone: Option<String>,
#[serde(default)]
pub selected_output_device: Option<String>,
#[serde(default = "default_translate_to_english")]
pub translate_to_english: bool,
#[serde(default = "default_selected_language")]
pub selected_language: String,
#[serde(default = "default_show_overlay")]
pub show_overlay: bool,
}
fn default_model() -> String {
// Default to empty string if no models are available yet
// The UI will handle prompting for model download
"".to_string()
}
fn default_always_on_microphone() -> bool {
// Default to false for better user experience
// True would be the old behavior (always-on for low latency)
false
}
fn default_translate_to_english() -> bool {
// Default to false - users need to opt-in to translation
false
}
fn default_selected_language() -> String {
// Default to auto-detection for backward compatibility
"auto".to_string()
}
fn default_show_overlay() -> bool {
// Default to true - users expect visual feedback by default
true
}
pub const SETTINGS_STORE_PATH: &str = "settings_store.json";
pub fn get_default_settings() -> AppSettings {
// Set platform-specific default keyboard shortcuts
#[cfg(target_os = "windows")]
let default_shortcut = "ctrl+space";
#[cfg(target_os = "macos")]
let default_shortcut = "alt+space"; // Alt key on macOS (Option key)
#[cfg(target_os = "linux")]
let default_shortcut = "ctrl+space";
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
let default_shortcut = "alt+space"; // Fallback for other platforms
let mut bindings = HashMap::new();
bindings.insert(
"transcribe".to_string(),
ShortcutBinding {
id: "transcribe".to_string(),
name: "Transcribe".to_string(),
description: "Converts your speech into text.".to_string(),
default_binding: default_shortcut.to_string(),
current_binding: default_shortcut.to_string(),
},
);
// bindings.insert(
// "test".to_string(),
// ShortcutBinding {
// id: "test".to_string(),
// name: "Test".to_string(),
// description: "This is a test binding.".to_string(),
// default_binding: "ctrl+d".to_string(),
// current_binding: "ctrl+d".to_string(),
// },
// );
AppSettings {
bindings,
push_to_talk: true,
audio_feedback: false,
selected_model: "".to_string(),
always_on_microphone: false,
selected_microphone: None,
selected_output_device: None,
translate_to_english: false,
selected_language: "auto".to_string(),
show_overlay: true,
}
}
pub fn load_or_create_app_settings(app: &App) -> AppSettings {
// Initialize store
let store = app
.store(SETTINGS_STORE_PATH)
.expect("Failed to initialize store");
let settings = if let Some(settings_value) = store.get("settings") {
// Parse the entire settings object
match serde_json::from_value::<AppSettings>(settings_value) {
Ok(settings) => {
println!("Found existing settings: {:?}", settings);
settings
}
Err(e) => {
println!("Failed to parse settings: {}", e);
// Fall back to default settings if parsing fails
let default_settings = get_default_settings();
// Store the default settings
store.set("settings", serde_json::to_value(&default_settings).unwrap());
default_settings
}
}
} else {
// Create default settings
let default_settings = get_default_settings();
// Store the settings
store.set("settings", serde_json::to_value(&default_settings).unwrap());
default_settings
};
settings
}
pub fn get_settings(app: &AppHandle) -> AppSettings {
let store = app
.store(SETTINGS_STORE_PATH)
.expect("Failed to initialize store");
if let Some(settings_value) = store.get("settings") {
serde_json::from_value::<AppSettings>(settings_value)
.unwrap_or_else(|_| get_default_settings())
} else {
get_default_settings()
}
}
pub fn write_settings(app: &AppHandle, settings: AppSettings) {
let store = app
.store(SETTINGS_STORE_PATH)
.expect("Failed to initialize store");
store.set("settings", serde_json::to_value(&settings).unwrap());
}
pub fn get_bindings(app: &AppHandle) -> HashMap<String, ShortcutBinding> {
let settings = get_settings(app);
settings.bindings
}
pub fn get_stored_binding(app: &AppHandle, id: &str) -> ShortcutBinding {
let bindings = get_bindings(app);
let binding = bindings.get(id).unwrap().clone();
binding
}