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"; interface SettingsDialogProps { open: boolean; onOpenChange: (open: boolean) => void; onImportSuccess?: () => void | Promise; } export function SettingsDialog({ open, onOpenChange, onImportSuccess, }: SettingsDialogProps) { const { t } = useTranslation(); const { settings, isLoading, isSaving, isPortable, appConfigDir, resolvedDirs, updateSettings, updateDirectory, updateAppConfigDir, browseDirectory, browseAppConfigDir, resetDirectory, resetAppConfigDir, saveSettings, resetSettings, 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 closeDialog = useCallback(() => { // 取消/直接关闭:恢复到初始设置(包括语言回滚) resetSettings(); acknowledgeRestart(); clearSelection(); resetStatus(); onOpenChange(false); }, [ acknowledgeRestart, clearSelection, onOpenChange, resetSettings, resetStatus, ]); const closeAfterSave = useCallback(() => { // 保存成功后关闭:不再重置语言,避免需要“保存两次”才生效 acknowledgeRestart(); clearSelection(); resetStatus(); onOpenChange(false); }, [acknowledgeRestart, clearSelection, onOpenChange, resetStatus]); const handleDialogChange = useCallback( (nextOpen: boolean) => { if (!nextOpen) { closeDialog(); } else { onOpenChange(true); } }, [closeDialog, onOpenChange], ); const handleCancel = useCallback(() => { closeDialog(); }, [closeDialog]); const handleSave = useCallback(async () => { try { const result = await saveSettings(); if (!result) return; if (result.requiresRestart) { setShowRestartPrompt(true); return; } closeAfterSave(); } catch (error) { console.error("[SettingsDialog] Failed to save settings", error); } }, [closeDialog, 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("[SettingsDialog] Failed to restart app", error); toast.error(t("settings.restartFailed")); } finally { closeAfterSave(); } }, [closeAfterSave, t]); const isBusy = useMemo(() => isLoading && !settings, [isLoading, settings]); return ( {t("settings.title")} {isBusy ? (
) : (
{t("settings.tabGeneral")} {t("settings.tabAdvanced")} {t("common.about")} {settings ? ( <> updateSettings({ language: lang })} /> ) : null} {settings ? ( <> ) : null}
)}
!open && handleRestartLater()} > {t("settings.restartRequired")}

{t("settings.restartRequiredMessage")}

); }