feat(settings): add autostart toggle in advanced settings (#177)
* feat(settings): add autostart toggle in advanced settings Enable users to configure autostart behavior through a new toggle in the advanced settings UI. The backend now checks user preferences on startup to enable or disable autostart accordingly, with the setting persisted and manageable via a new Tauri command. This provides better control over app initialization without affecting existing functionality. * immediate toggle effect? --------- Co-authored-by: CJ Pais <cj@cjpais.com>
This commit is contained in:
parent
d602a3a8e2
commit
aed3a75d54
8 changed files with 81 additions and 3 deletions
|
|
@ -137,10 +137,17 @@ pub fn run() {
|
|||
// Initialize tray menu with idle state
|
||||
utils::update_tray_menu(&app.handle(), &utils::TrayIconState::Idle);
|
||||
|
||||
// Get the autostart manager
|
||||
// Get the autostart manager and configure based on user setting
|
||||
let autostart_manager = app.autolaunch();
|
||||
// Enable autostart
|
||||
let _ = autostart_manager.enable();
|
||||
let settings = settings::get_settings(&app.handle());
|
||||
|
||||
if settings.autostart_enabled {
|
||||
// Enable autostart if user has opted in
|
||||
let _ = autostart_manager.enable();
|
||||
} else {
|
||||
// Disable autostart if user has opted out
|
||||
let _ = autostart_manager.disable();
|
||||
}
|
||||
|
||||
// Window is configured to start hidden to avoid flicker.
|
||||
// If user didn't choose Start Hidden, show it now.
|
||||
|
|
@ -205,6 +212,7 @@ pub fn run() {
|
|||
shortcut::change_ptt_setting,
|
||||
shortcut::change_audio_feedback_setting,
|
||||
shortcut::change_start_hidden_setting,
|
||||
shortcut::change_autostart_setting,
|
||||
shortcut::change_translate_to_english_setting,
|
||||
shortcut::change_selected_language_setting,
|
||||
shortcut::change_overlay_position_setting,
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ pub struct AppSettings {
|
|||
pub audio_feedback: bool,
|
||||
#[serde(default = "default_start_hidden")]
|
||||
pub start_hidden: bool,
|
||||
#[serde(default = "default_autostart_enabled")]
|
||||
pub autostart_enabled: bool,
|
||||
#[serde(default = "default_model")]
|
||||
pub selected_model: String,
|
||||
#[serde(default = "default_always_on_microphone")]
|
||||
|
|
@ -132,6 +134,10 @@ fn default_start_hidden() -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
fn default_autostart_enabled() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn default_selected_language() -> String {
|
||||
"auto".to_string()
|
||||
}
|
||||
|
|
@ -181,6 +187,7 @@ pub fn get_default_settings() -> AppSettings {
|
|||
push_to_talk: true,
|
||||
audio_feedback: false,
|
||||
start_hidden: default_start_hidden(),
|
||||
autostart_enabled: default_autostart_enabled(),
|
||||
selected_model: "".to_string(),
|
||||
always_on_microphone: false,
|
||||
selected_microphone: None,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use serde::Serialize;
|
||||
use tauri::{App, AppHandle, Emitter, Manager};
|
||||
use tauri_plugin_autostart::ManagerExt;
|
||||
use tauri_plugin_global_shortcut::GlobalShortcutExt;
|
||||
use tauri_plugin_global_shortcut::{Shortcut, ShortcutState};
|
||||
|
||||
|
|
@ -191,6 +192,32 @@ pub fn change_start_hidden_setting(app: AppHandle, enabled: bool) -> Result<(),
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn change_autostart_setting(app: AppHandle, enabled: bool) -> Result<(), String> {
|
||||
let mut settings = settings::get_settings(&app);
|
||||
settings.autostart_enabled = enabled;
|
||||
settings::write_settings(&app, settings);
|
||||
|
||||
// Apply the autostart setting immediately
|
||||
let autostart_manager = app.autolaunch();
|
||||
if enabled {
|
||||
let _ = autostart_manager.enable();
|
||||
} else {
|
||||
let _ = autostart_manager.disable();
|
||||
}
|
||||
|
||||
// Notify frontend
|
||||
let _ = app.emit(
|
||||
"settings-changed",
|
||||
serde_json::json!({
|
||||
"setting": "autostart_enabled",
|
||||
"value": enabled
|
||||
}),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn update_custom_words(app: AppHandle, words: Vec<String>) -> Result<(), String> {
|
||||
let mut settings = settings::get_settings(&app);
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import { CustomWords } from "./CustomWords";
|
|||
import { AlwaysOnMicrophone } from "./AlwaysOnMicrophone";
|
||||
import { SettingsGroup } from "../ui/SettingsGroup";
|
||||
import { StartHidden } from "./StartHidden";
|
||||
import { AutostartToggle } from "./AutostartToggle";
|
||||
|
||||
export const AdvancedSettings: React.FC = () => {
|
||||
return (
|
||||
<div className="max-w-3xl w-full mx-auto space-y-6">
|
||||
<SettingsGroup title="Advanced">
|
||||
<StartHidden descriptionMode="tooltip" grouped={true} />
|
||||
<AutostartToggle descriptionMode="tooltip" grouped={true} />
|
||||
<ShowOverlay descriptionMode="tooltip" grouped={true} />
|
||||
<TranslateToEnglish descriptionMode="tooltip" grouped={true} />
|
||||
<ModelUnloadTimeoutSetting descriptionMode="tooltip" grouped={true} />
|
||||
|
|
|
|||
28
src/components/settings/AutostartToggle.tsx
Normal file
28
src/components/settings/AutostartToggle.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import React from "react";
|
||||
import { ToggleSwitch } from "../ui/ToggleSwitch";
|
||||
import { useSettings } from "../../hooks/useSettings";
|
||||
|
||||
interface AutostartToggleProps {
|
||||
descriptionMode?: "inline" | "tooltip";
|
||||
grouped?: boolean;
|
||||
}
|
||||
|
||||
export const AutostartToggle: React.FC<AutostartToggleProps> = React.memo(
|
||||
({ descriptionMode = "tooltip", grouped = false }) => {
|
||||
const { getSetting, updateSetting, isUpdating } = useSettings();
|
||||
|
||||
const autostartEnabled = getSetting("autostart_enabled") ?? false;
|
||||
|
||||
return (
|
||||
<ToggleSwitch
|
||||
checked={autostartEnabled}
|
||||
onChange={(enabled) => updateSetting("autostart_enabled", enabled)}
|
||||
isUpdating={isUpdating("autostart_enabled")}
|
||||
label="Launch on Startup"
|
||||
description="Automatically start Handy when you log in to your computer."
|
||||
descriptionMode={descriptionMode}
|
||||
grouped={grouped}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -19,3 +19,4 @@ export { AppDataDirectory } from "./AppDataDirectory";
|
|||
export { ModelUnloadTimeoutSetting } from "./ModelUnloadTimeout";
|
||||
export { StartHidden } from "./StartHidden";
|
||||
export { HistoryLimit } from "./HistoryLimit";
|
||||
export { AutostartToggle } from "./AutostartToggle";
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ export const SettingsSchema = z.object({
|
|||
push_to_talk: z.boolean(),
|
||||
audio_feedback: z.boolean(),
|
||||
start_hidden: z.boolean().optional().default(false),
|
||||
autostart_enabled: z.boolean().optional().default(false),
|
||||
selected_model: z.string(),
|
||||
always_on_microphone: z.boolean(),
|
||||
selected_microphone: z.string().nullable().optional(),
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ const DEFAULT_SETTINGS: Partial<Settings> = {
|
|||
always_on_microphone: false,
|
||||
audio_feedback: true,
|
||||
start_hidden: false,
|
||||
autostart_enabled: false,
|
||||
push_to_talk: false,
|
||||
selected_microphone: "Default",
|
||||
selected_output_device: "Default",
|
||||
|
|
@ -181,6 +182,9 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||
case "start_hidden":
|
||||
await invoke("change_start_hidden_setting", { enabled: value });
|
||||
break;
|
||||
case "autostart_enabled":
|
||||
await invoke("change_autostart_setting", { enabled: value });
|
||||
break;
|
||||
case "push_to_talk":
|
||||
await invoke("change_ptt_setting", { enabled: value });
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in a new issue