import { useCallback, useEffect, useMemo, useState } from "react"; import { Loader2, Save } from "lucide-react"; import { toast } from "sonner"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; import { settingsApi } from "@/lib/api"; import { LanguageSettings } from "@/components/settings/LanguageSettings"; import { ThemeSettings } from "@/components/settings/ThemeSettings"; import { WindowSettings } from "@/components/settings/WindowSettings"; import { DirectorySettings } from "@/components/settings/DirectorySettings"; import { ImportExportSection } from "@/components/settings/ImportExportSection"; import { AboutSection } from "@/components/settings/AboutSection"; import { useSettings } from "@/hooks/useSettings"; import { useImportExport } from "@/hooks/useImportExport"; import { useTranslation } from "react-i18next"; import type { SettingsFormState } from "@/hooks/useSettings"; interface SettingsDialogProps { open: boolean; onOpenChange: (open: boolean) => void; onImportSuccess?: () => void | Promise; } export function SettingsPage({ open, onOpenChange, onImportSuccess, }: SettingsDialogProps) { const { t } = useTranslation(); const { settings, isLoading, isSaving, isPortable, appConfigDir, resolvedDirs, updateSettings, updateDirectory, updateAppConfigDir, browseDirectory, browseAppConfigDir, resetDirectory, resetAppConfigDir, saveSettings, autoSaveSettings, requiresRestart, acknowledgeRestart, } = useSettings(); const { selectedFile, status: importStatus, errorMessage, backupId, isImporting, selectImportFile, importConfig, exportConfig, clearSelection, resetStatus, } = useImportExport({ onImportSuccess }); const [activeTab, setActiveTab] = useState("general"); const [showRestartPrompt, setShowRestartPrompt] = useState(false); useEffect(() => { if (open) { setActiveTab("general"); resetStatus(); } }, [open, resetStatus]); useEffect(() => { if (requiresRestart) { setShowRestartPrompt(true); } }, [requiresRestart]); const closeAfterSave = useCallback(() => { // 保存成功后关闭:不再重置语言,避免需要“保存两次”才生效 acknowledgeRestart(); clearSelection(); resetStatus(); onOpenChange(false); }, [acknowledgeRestart, clearSelection, onOpenChange, resetStatus]); const handleSave = useCallback(async () => { try { const result = await saveSettings(undefined, { silent: false }); if (!result) return; if (result.requiresRestart) { setShowRestartPrompt(true); return; } closeAfterSave(); } catch (error) { console.error("[SettingsPage] Failed to save settings", error); } }, [closeAfterSave, saveSettings]); const handleRestartLater = useCallback(() => { setShowRestartPrompt(false); closeAfterSave(); }, [closeAfterSave]); const handleRestartNow = useCallback(async () => { setShowRestartPrompt(false); if (import.meta.env.DEV) { toast.success(t("settings.devModeRestartHint")); closeAfterSave(); return; } try { await settingsApi.restart(); } catch (error) { console.error("[SettingsPage] Failed to restart app", error); toast.error(t("settings.restartFailed")); } finally { closeAfterSave(); } }, [closeAfterSave, t]); // 通用设置即时保存(无需手动点击) // 使用 autoSaveSettings 避免误触发系统 API(开机自启、Claude 插件等) const handleAutoSave = useCallback( async (updates: Partial) => { if (!settings) return; updateSettings(updates); try { await autoSaveSettings(updates); } catch (error) { console.error("[SettingsPage] Failed to autosave settings", error); toast.error( t("settings.saveFailedGeneric", { defaultValue: "保存失败,请重试", }), ); } }, [autoSaveSettings, settings, t, updateSettings], ); const isBusy = useMemo(() => isLoading && !settings, [isLoading, settings]); return (
{isBusy ? (
) : ( {t("settings.tabGeneral")} {t("settings.tabAdvanced")} {t("common.about")}
{settings ? ( <> handleAutoSave({ language: lang })} /> ) : null} {settings ? ( <>
) : null}
)} !open && handleRestartLater()} > {t("settings.restartRequired")}

{t("settings.restartRequiredMessage")}

); }