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
|
// Initialize tray menu with idle state
|
||||||
utils::update_tray_menu(&app.handle(), &utils::TrayIconState::Idle);
|
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();
|
let autostart_manager = app.autolaunch();
|
||||||
// Enable autostart
|
let settings = settings::get_settings(&app.handle());
|
||||||
let _ = autostart_manager.enable();
|
|
||||||
|
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.
|
// Window is configured to start hidden to avoid flicker.
|
||||||
// If user didn't choose Start Hidden, show it now.
|
// If user didn't choose Start Hidden, show it now.
|
||||||
|
|
@ -205,6 +212,7 @@ pub fn run() {
|
||||||
shortcut::change_ptt_setting,
|
shortcut::change_ptt_setting,
|
||||||
shortcut::change_audio_feedback_setting,
|
shortcut::change_audio_feedback_setting,
|
||||||
shortcut::change_start_hidden_setting,
|
shortcut::change_start_hidden_setting,
|
||||||
|
shortcut::change_autostart_setting,
|
||||||
shortcut::change_translate_to_english_setting,
|
shortcut::change_translate_to_english_setting,
|
||||||
shortcut::change_selected_language_setting,
|
shortcut::change_selected_language_setting,
|
||||||
shortcut::change_overlay_position_setting,
|
shortcut::change_overlay_position_setting,
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,8 @@ pub struct AppSettings {
|
||||||
pub audio_feedback: bool,
|
pub audio_feedback: bool,
|
||||||
#[serde(default = "default_start_hidden")]
|
#[serde(default = "default_start_hidden")]
|
||||||
pub start_hidden: bool,
|
pub start_hidden: bool,
|
||||||
|
#[serde(default = "default_autostart_enabled")]
|
||||||
|
pub autostart_enabled: bool,
|
||||||
#[serde(default = "default_model")]
|
#[serde(default = "default_model")]
|
||||||
pub selected_model: String,
|
pub selected_model: String,
|
||||||
#[serde(default = "default_always_on_microphone")]
|
#[serde(default = "default_always_on_microphone")]
|
||||||
|
|
@ -132,6 +134,10 @@ fn default_start_hidden() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_autostart_enabled() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn default_selected_language() -> String {
|
fn default_selected_language() -> String {
|
||||||
"auto".to_string()
|
"auto".to_string()
|
||||||
}
|
}
|
||||||
|
|
@ -181,6 +187,7 @@ pub fn get_default_settings() -> AppSettings {
|
||||||
push_to_talk: true,
|
push_to_talk: true,
|
||||||
audio_feedback: false,
|
audio_feedback: false,
|
||||||
start_hidden: default_start_hidden(),
|
start_hidden: default_start_hidden(),
|
||||||
|
autostart_enabled: default_autostart_enabled(),
|
||||||
selected_model: "".to_string(),
|
selected_model: "".to_string(),
|
||||||
always_on_microphone: false,
|
always_on_microphone: false,
|
||||||
selected_microphone: None,
|
selected_microphone: None,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tauri::{App, AppHandle, Emitter, Manager};
|
use tauri::{App, AppHandle, Emitter, Manager};
|
||||||
|
use tauri_plugin_autostart::ManagerExt;
|
||||||
use tauri_plugin_global_shortcut::GlobalShortcutExt;
|
use tauri_plugin_global_shortcut::GlobalShortcutExt;
|
||||||
use tauri_plugin_global_shortcut::{Shortcut, ShortcutState};
|
use tauri_plugin_global_shortcut::{Shortcut, ShortcutState};
|
||||||
|
|
||||||
|
|
@ -191,6 +192,32 @@ pub fn change_start_hidden_setting(app: AppHandle, enabled: bool) -> Result<(),
|
||||||
Ok(())
|
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]
|
#[tauri::command]
|
||||||
pub fn update_custom_words(app: AppHandle, words: Vec<String>) -> Result<(), String> {
|
pub fn update_custom_words(app: AppHandle, words: Vec<String>) -> Result<(), String> {
|
||||||
let mut settings = settings::get_settings(&app);
|
let mut settings = settings::get_settings(&app);
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ import { CustomWords } from "./CustomWords";
|
||||||
import { AlwaysOnMicrophone } from "./AlwaysOnMicrophone";
|
import { AlwaysOnMicrophone } from "./AlwaysOnMicrophone";
|
||||||
import { SettingsGroup } from "../ui/SettingsGroup";
|
import { SettingsGroup } from "../ui/SettingsGroup";
|
||||||
import { StartHidden } from "./StartHidden";
|
import { StartHidden } from "./StartHidden";
|
||||||
|
import { AutostartToggle } from "./AutostartToggle";
|
||||||
|
|
||||||
export const AdvancedSettings: React.FC = () => {
|
export const AdvancedSettings: React.FC = () => {
|
||||||
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 title="Advanced">
|
<SettingsGroup title="Advanced">
|
||||||
<StartHidden descriptionMode="tooltip" grouped={true} />
|
<StartHidden descriptionMode="tooltip" grouped={true} />
|
||||||
|
<AutostartToggle descriptionMode="tooltip" grouped={true} />
|
||||||
<ShowOverlay descriptionMode="tooltip" grouped={true} />
|
<ShowOverlay descriptionMode="tooltip" grouped={true} />
|
||||||
<TranslateToEnglish descriptionMode="tooltip" grouped={true} />
|
<TranslateToEnglish descriptionMode="tooltip" grouped={true} />
|
||||||
<ModelUnloadTimeoutSetting 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 { ModelUnloadTimeoutSetting } from "./ModelUnloadTimeout";
|
||||||
export { StartHidden } from "./StartHidden";
|
export { StartHidden } from "./StartHidden";
|
||||||
export { HistoryLimit } from "./HistoryLimit";
|
export { HistoryLimit } from "./HistoryLimit";
|
||||||
|
export { AutostartToggle } from "./AutostartToggle";
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ export const SettingsSchema = z.object({
|
||||||
push_to_talk: z.boolean(),
|
push_to_talk: z.boolean(),
|
||||||
audio_feedback: z.boolean(),
|
audio_feedback: z.boolean(),
|
||||||
start_hidden: z.boolean().optional().default(false),
|
start_hidden: z.boolean().optional().default(false),
|
||||||
|
autostart_enabled: z.boolean().optional().default(false),
|
||||||
selected_model: z.string(),
|
selected_model: z.string(),
|
||||||
always_on_microphone: z.boolean(),
|
always_on_microphone: z.boolean(),
|
||||||
selected_microphone: z.string().nullable().optional(),
|
selected_microphone: z.string().nullable().optional(),
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ const DEFAULT_SETTINGS: Partial<Settings> = {
|
||||||
always_on_microphone: false,
|
always_on_microphone: false,
|
||||||
audio_feedback: true,
|
audio_feedback: true,
|
||||||
start_hidden: false,
|
start_hidden: false,
|
||||||
|
autostart_enabled: false,
|
||||||
push_to_talk: false,
|
push_to_talk: false,
|
||||||
selected_microphone: "Default",
|
selected_microphone: "Default",
|
||||||
selected_output_device: "Default",
|
selected_output_device: "Default",
|
||||||
|
|
@ -181,6 +182,9 @@ export const useSettingsStore = create<SettingsStore>()(
|
||||||
case "start_hidden":
|
case "start_hidden":
|
||||||
await invoke("change_start_hidden_setting", { enabled: value });
|
await invoke("change_start_hidden_setting", { enabled: value });
|
||||||
break;
|
break;
|
||||||
|
case "autostart_enabled":
|
||||||
|
await invoke("change_autostart_setting", { enabled: value });
|
||||||
|
break;
|
||||||
case "push_to_talk":
|
case "push_to_talk":
|
||||||
await invoke("change_ptt_setting", { enabled: value });
|
await invoke("change_ptt_setting", { enabled: value });
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue