This commit is contained in:
cc
2026-04-25 18:38:15 +08:00
4 changed files with 92 additions and 20 deletions

View File

@@ -748,6 +748,10 @@ const getWindowCloseBehavior = (): WindowCloseBehavior => {
return behavior === 'tray' || behavior === 'quit' ? behavior : 'ask'
}
const isSilentStartupEnabled = (): boolean => {
return configService?.get('silentStartup') === true
}
const requestMainWindowCloseConfirmation = (win: BrowserWindow): void => {
if (isClosePromptVisible) return
isClosePromptVisible = true
@@ -3740,7 +3744,16 @@ function checkForUpdatesOnStartup() {
}
app.whenReady().then(async () => {
// 立即创建 Splash 窗口,确保用户尽快看到反馈
// 先初始化配置,以便在启动早期判定是否需要静默启动
configService = new ConfigService()
applyAutoUpdateChannel('startup')
syncLaunchAtStartupPreference()
const onboardingDone = configService.get('onboardingDone') === true
const startInBackground = onboardingDone && isSilentStartupEnabled()
shouldShowMain = onboardingDone
if (!startInBackground) {
// 非静默模式下显示 Splash提供启动反馈
createSplashWindow()
// 等待 Splash 页面加载完成后再推送进度
@@ -3756,6 +3769,7 @@ app.whenReady().then(async () => {
.executeJavaScript(`setVersion(${JSON.stringify(app.getVersion())})`)
.catch(() => {})
}
}
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
const withTimeout = <T>(task: () => Promise<T>, timeoutMs: number): Promise<{ timedOut: boolean; value?: T; error?: string }> => {
@@ -3783,13 +3797,7 @@ app.whenReady().then(async () => {
})
}
// 初始化配置服务
updateSplashProgress(5, '正在加载配置...')
configService = new ConfigService()
applyAutoUpdateChannel('startup')
syncLaunchAtStartupPreference()
const onboardingDone = configService.get('onboardingDone') === true
shouldShowMain = onboardingDone
// 将用户主题配置推送给 Splash 窗口
if (splashWindow && !splashWindow.isDestroyed()) {
@@ -3956,6 +3964,8 @@ app.whenReady().then(async () => {
if (!onboardingDone) {
createOnboardingWindow()
} else if (startInBackground && tray) {
mainWindow?.hide()
} else {
mainWindow?.show()
}

View File

@@ -36,6 +36,7 @@ interface ConfigSchema {
language: string
logEnabled: boolean
launchAtStartup?: boolean
silentStartup?: boolean
llmModelPath: string
whisperModelName: string
whisperModelDir: string
@@ -163,6 +164,7 @@ export class ConfigService {
themeId: 'cloud-dancer',
language: 'zh-CN',
logEnabled: false,
silentStartup: false,
llmModelPath: '',
whisperModelName: 'base',
whisperModelDir: '',

View File

@@ -195,6 +195,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
const [launchAtStartup, setLaunchAtStartup] = useState(false)
const [launchAtStartupSupported, setLaunchAtStartupSupported] = useState(isWindows || isMac)
const [launchAtStartupReason, setLaunchAtStartupReason] = useState('')
const [silentStartup, setSilentStartup] = useState(false)
const [windowCloseBehavior, setWindowCloseBehavior] = useState<configService.WindowCloseBehavior>('ask')
const [quoteLayout, setQuoteLayout] = useState<configService.QuoteLayout>('quote-top')
const [updateChannel, setUpdateChannel] = useState<configService.UpdateChannel>('stable')
@@ -222,6 +223,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
const [isFetchingImageKey, setIsFetchingImageKey] = useState(false)
const [isCheckingUpdate, setIsCheckingUpdate] = useState(false)
const [isUpdatingLaunchAtStartup, setIsUpdatingLaunchAtStartup] = useState(false)
const [isUpdatingSilentStartup, setIsUpdatingSilentStartup] = useState(false)
const [appVersion, setAppVersion] = useState('')
const [message, setMessage] = useState<{ text: string; success: boolean } | null>(null)
const [showDecryptKey, setShowDecryptKey] = useState(false)
@@ -445,6 +447,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
const savedMessagePushFilterList = await configService.getMessagePushFilterList()
const contactsResult = await window.electronAPI.chat.getContacts({ lite: true })
const savedLaunchAtStartupStatus = await window.electronAPI.app.getLaunchAtStartupStatus()
const savedSilentStartup = await configService.getSilentStartup()
const savedWindowCloseBehavior = await configService.getWindowCloseBehavior()
const savedQuoteLayout = await configService.getQuoteLayout()
const savedUpdateChannel = await configService.getUpdateChannel()
@@ -502,6 +505,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
setLaunchAtStartup(savedLaunchAtStartupStatus.enabled)
setLaunchAtStartupSupported(savedLaunchAtStartupStatus.supported)
setLaunchAtStartupReason(savedLaunchAtStartupStatus.reason || '')
setSilentStartup(savedSilentStartup)
setWindowCloseBehavior(savedWindowCloseBehavior)
setQuoteLayout(savedQuoteLayout)
if (savedUpdateChannel) {
@@ -615,6 +619,21 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
}
}
const handleSilentStartupChange = async (enabled: boolean) => {
if (isUpdatingSilentStartup) return
try {
setIsUpdatingSilentStartup(true)
await configService.setSilentStartup(enabled)
setSilentStartup(enabled)
showMessage(enabled ? '已开启静默启动' : '已关闭静默启动', true)
} catch (e: any) {
showMessage(`设置静默启动失败: ${e?.message || String(e)}`, false)
} finally {
setIsUpdatingSilentStartup(false)
}
}
const refreshWhisperStatus = async (modelDirValue = whisperModelDir) => {
try {
const result = await window.electronAPI.whisper?.getModelStatus()
@@ -1684,6 +1703,35 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
<div className="divider" />
<div className="form-group">
<label></label>
<span className="form-hint">
</span>
<div className="log-toggle-line">
<span className="log-status">
{isUpdatingSilentStartup
? '保存中...'
: (silentStartup ? '已开启' : '已关闭')}
</span>
<label className="switch" htmlFor="silent-startup-toggle">
<input
id="silent-startup-toggle"
className="switch-input"
type="checkbox"
checked={silentStartup}
disabled={isUpdatingSilentStartup}
onChange={(e) => {
void handleSilentStartupChange(e.target.checked)
}}
/>
<span className="switch-slider" />
</label>
</div>
</div>
<div className="divider" />
<div className="form-group">
<label></label>
<span className="form-hint"></span>

View File

@@ -15,6 +15,7 @@ export const CONFIG_KEYS = {
WINDOW_BOUNDS: 'windowBounds',
CACHE_PATH: 'cachePath',
LAUNCH_AT_STARTUP: 'launchAtStartup',
SILENT_STARTUP: 'silentStartup',
EXPORT_PATH: 'exportPath',
AGREEMENT_ACCEPTED: 'agreementAccepted',
@@ -321,6 +322,17 @@ export async function setLaunchAtStartup(enabled: boolean): Promise<void> {
await config.set(CONFIG_KEYS.LAUNCH_AT_STARTUP, enabled)
}
// 获取静默启动偏好
export async function getSilentStartup(): Promise<boolean> {
const value = await config.get(CONFIG_KEYS.SILENT_STARTUP)
return value === true
}
// 设置静默启动偏好
export async function setSilentStartup(enabled: boolean): Promise<void> {
await config.set(CONFIG_KEYS.SILENT_STARTUP, enabled)
}
// 获取 LLM 模型路径
export async function getLlmModelPath(): Promise<string | null> {
const value = await config.get(CONFIG_KEYS.LLM_MODEL_PATH)