mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
fix(desktop): close preview on renderer reload (#680)
Close the native preview WebContentsView when the Electron renderer starts a top-level navigation so refreshed session pages cannot leave the in-app browser surface behind. Fixes #680 Tested: - bun run verify Confidence: high Scope-risk: narrow
This commit is contained in:
parent
c6a674003f
commit
fc5924f1f1
@ -28,6 +28,7 @@ import {
|
||||
import { installMacOsChromiumKeychainPromptGuard } from './services/keychain'
|
||||
import { applyWindowsAppUserModelId } from './services/appIdentity'
|
||||
import { installMainWindowNavigationGuards, installPreviewNavigationGuards } from './services/navigationGuards'
|
||||
import { installPreviewCleanupOnRendererNavigation } from './services/previewLifecycle'
|
||||
import { logNotificationSmokeRendererAck, scheduleNotificationSmoke } from './services/notificationSmoke'
|
||||
import { normalizeZoomFactor } from './services/zoom'
|
||||
import { resolveRendererEntry } from './services/rendererEntry'
|
||||
@ -316,6 +317,9 @@ async function createMainWindow() {
|
||||
})
|
||||
|
||||
installMainWindowNavigationGuards(mainWindow.webContents, { openExternal: openExternalUrl })
|
||||
installPreviewCleanupOnRendererNavigation(mainWindow.webContents, () => {
|
||||
previewService?.close()
|
||||
})
|
||||
|
||||
installWindowLifecycle({
|
||||
app,
|
||||
|
||||
68
desktop/electron/services/previewLifecycle.test.ts
Normal file
68
desktop/electron/services/previewLifecycle.test.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
installPreviewCleanupOnRendererNavigation,
|
||||
type PreviewCleanupWebContents,
|
||||
} from './previewLifecycle'
|
||||
|
||||
type DidStartNavigationHandler = Parameters<PreviewCleanupWebContents['on']>[1]
|
||||
|
||||
class FakeMainWebContents {
|
||||
didStartNavigationHandler: DidStartNavigationHandler | null = null
|
||||
|
||||
on(event: 'did-start-navigation', handler: DidStartNavigationHandler) {
|
||||
if (event === 'did-start-navigation') {
|
||||
this.didStartNavigationHandler = handler
|
||||
}
|
||||
}
|
||||
|
||||
emitDidStartNavigation(input: { isSameDocument?: boolean, isMainFrame?: boolean } = {}) {
|
||||
this.didStartNavigationHandler?.(
|
||||
{
|
||||
isSameDocument: input.isSameDocument ?? false,
|
||||
isMainFrame: input.isMainFrame ?? true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
emitDeprecatedDidStartNavigation(input: { url?: string, isInPlace?: boolean, isMainFrame?: boolean } = {}) {
|
||||
this.didStartNavigationHandler?.(
|
||||
{},
|
||||
input.url ?? 'app://renderer',
|
||||
input.isInPlace,
|
||||
input.isMainFrame ?? true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
describe('preview lifecycle cleanup', () => {
|
||||
it('closes the native preview view before the renderer performs a top-level reload', () => {
|
||||
const webContents = new FakeMainWebContents()
|
||||
const closePreview = vi.fn()
|
||||
|
||||
installPreviewCleanupOnRendererNavigation(webContents, closePreview)
|
||||
webContents.emitDidStartNavigation({ isMainFrame: true, isSameDocument: false })
|
||||
|
||||
expect(closePreview).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('keeps the native preview view for same-document or subframe navigation', () => {
|
||||
const webContents = new FakeMainWebContents()
|
||||
const closePreview = vi.fn()
|
||||
|
||||
installPreviewCleanupOnRendererNavigation(webContents, closePreview)
|
||||
webContents.emitDidStartNavigation({ isMainFrame: true, isSameDocument: true })
|
||||
webContents.emitDidStartNavigation({ isMainFrame: false, isSameDocument: false })
|
||||
|
||||
expect(closePreview).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('falls back to deprecated navigation booleans when Electron details are absent', () => {
|
||||
const webContents = new FakeMainWebContents()
|
||||
const closePreview = vi.fn()
|
||||
|
||||
installPreviewCleanupOnRendererNavigation(webContents, closePreview)
|
||||
webContents.emitDeprecatedDidStartNavigation({ isMainFrame: true, isInPlace: false })
|
||||
|
||||
expect(closePreview).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
42
desktop/electron/services/previewLifecycle.ts
Normal file
42
desktop/electron/services/previewLifecycle.ts
Normal file
@ -0,0 +1,42 @@
|
||||
type NavigationDetails = {
|
||||
isSameDocument?: boolean
|
||||
isMainFrame?: boolean
|
||||
}
|
||||
|
||||
export type PreviewCleanupWebContents = {
|
||||
on(
|
||||
event: 'did-start-navigation',
|
||||
handler: (
|
||||
details: NavigationDetails,
|
||||
url?: string,
|
||||
isInPlace?: boolean,
|
||||
isMainFrame?: boolean,
|
||||
) => void,
|
||||
): unknown
|
||||
}
|
||||
|
||||
function isMainFrameNavigation(
|
||||
details: NavigationDetails,
|
||||
deprecatedIsMainFrame?: boolean,
|
||||
) {
|
||||
return details.isMainFrame ?? deprecatedIsMainFrame === true
|
||||
}
|
||||
|
||||
function isSameDocumentNavigation(
|
||||
details: NavigationDetails,
|
||||
deprecatedIsInPlace?: boolean,
|
||||
) {
|
||||
return details.isSameDocument ?? deprecatedIsInPlace === true
|
||||
}
|
||||
|
||||
export function installPreviewCleanupOnRendererNavigation(
|
||||
webContents: PreviewCleanupWebContents,
|
||||
closePreview: () => void,
|
||||
): void {
|
||||
webContents.on('did-start-navigation', (details, _url, isInPlace, isMainFrame) => {
|
||||
if (!isMainFrameNavigation(details, isMainFrame)) return
|
||||
if (isSameDocumentNavigation(details, isInPlace)) return
|
||||
|
||||
closePreview()
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user