From ec82b6978643d67ca81e3b359248e51adfdc2e11 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:53:11 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20eliminate=20startup=20flicker=20?= =?UTF-8?q?=E2=80=94=20defer=20window=20show=20until=20overlay=20renders?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove Rust-side `eval(INITIAL_LOADING_OVERLAY)` that prematurely dismissed the overlay before React/MUI theme was ready - Defer `window.show()` from Rust `activate_window` to an inline `
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index b20f0ad67..2021fcbbf 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -44,7 +44,6 @@ import { useThemeMode } from '@/services/states' import getSystem from '@/utils/get-system' import { - useAppInitialization, useCustomTheme, useLayoutEvents, useLoadingOverlay, @@ -217,7 +216,6 @@ const Layout = () => { ) useLoadingOverlay(themeReady) - useAppInitialization() const handleNotice = useCallback( (payload: [string, string]) => { diff --git a/src/pages/_layout/hooks/index.ts b/src/pages/_layout/hooks/index.ts index 08d85b86b..41182136a 100644 --- a/src/pages/_layout/hooks/index.ts +++ b/src/pages/_layout/hooks/index.ts @@ -1,4 +1,3 @@ -export { useAppInitialization } from './use-app-initialization' export { useLayoutEvents } from './use-layout-events' export { useLoadingOverlay } from './use-loading-overlay' export { useNavMenuOrder } from './use-nav-menu-order' diff --git a/src/pages/_layout/hooks/use-app-initialization.ts b/src/pages/_layout/hooks/use-app-initialization.ts deleted file mode 100644 index 14bdfb469..000000000 --- a/src/pages/_layout/hooks/use-app-initialization.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { useEffect, useRef } from 'react' - -import { hideInitialOverlay } from '../utils' - -export const useAppInitialization = () => { - const initRef = useRef(false) - - useEffect(() => { - if (initRef.current) return - initRef.current = true - - let isCancelled = false - const timers = new Set() - - const scheduleTimeout = (handler: () => void, delay: number) => { - if (isCancelled) return -1 - const id = window.setTimeout(() => { - if (!isCancelled) { - handler() - } - timers.delete(id) - }, delay) - timers.add(id) - return id - } - - const removeLoadingOverlay = () => { - hideInitialOverlay({ schedule: scheduleTimeout }) - } - - const performInitialization = () => { - if (isCancelled) return - removeLoadingOverlay() - } - - scheduleTimeout(performInitialization, 100) - scheduleTimeout(performInitialization, 5000) - - return () => { - isCancelled = true - timers.forEach((id) => { - try { - window.clearTimeout(id) - } catch (error) { - console.warn('[Initialization] Failed to clear timer:', error) - } - }) - timers.clear() - } - }, []) -} diff --git a/src/pages/_layout/hooks/use-loading-overlay.ts b/src/pages/_layout/hooks/use-loading-overlay.ts index 946c0f5a7..16af897bc 100644 --- a/src/pages/_layout/hooks/use-loading-overlay.ts +++ b/src/pages/_layout/hooks/use-loading-overlay.ts @@ -3,46 +3,15 @@ import { useEffect, useRef } from 'react' import { hideInitialOverlay } from '../utils' export const useLoadingOverlay = (themeReady: boolean) => { - const overlayRemovedRef = useRef(false) + const doneRef = useRef(false) useEffect(() => { - if (!themeReady || overlayRemovedRef.current) return - - let removalTimer: number | undefined - let retryTimer: number | undefined - let attempts = 0 - const maxAttempts = 50 - let stopped = false - - const tryRemoveOverlay = () => { - if (stopped || overlayRemovedRef.current) return - - const { removed, removalTimer: timerId } = hideInitialOverlay({ - assumeMissingAsRemoved: true, - }) - if (typeof timerId === 'number') { - removalTimer = timerId - } - - if (removed) { - overlayRemovedRef.current = true - return - } - - if (attempts < maxAttempts) { - attempts += 1 - retryTimer = window.setTimeout(tryRemoveOverlay, 100) - } else { - console.warn('[Loading Overlay] Element not found') - } - } - - tryRemoveOverlay() + if (!themeReady || doneRef.current) return + doneRef.current = true + const timer = hideInitialOverlay() return () => { - stopped = true - if (typeof removalTimer === 'number') window.clearTimeout(removalTimer) - if (typeof retryTimer === 'number') window.clearTimeout(retryTimer) + if (timer !== undefined) window.clearTimeout(timer) } }, [themeReady]) } diff --git a/src/pages/_layout/utils/initial-loading-overlay.ts b/src/pages/_layout/utils/initial-loading-overlay.ts index cda9ca2db..08d33f6aa 100644 --- a/src/pages/_layout/utils/initial-loading-overlay.ts +++ b/src/pages/_layout/utils/initial-loading-overlay.ts @@ -1,45 +1,17 @@ -const OVERLAY_ID = 'initial-loading-overlay' -const REMOVE_DELAY = 300 +let removed = false -let overlayRemoved = false +export const hideInitialOverlay = (): number | undefined => { + if (removed) return undefined -type HideOverlayOptions = { - schedule?: (handler: () => void, delay: number) => number - assumeMissingAsRemoved?: boolean -} - -type HideOverlayResult = { - removed: boolean - removalTimer?: number -} - -export const hideInitialOverlay = ( - options: HideOverlayOptions = {}, -): HideOverlayResult => { - if (overlayRemoved) { - return { removed: true } - } - - const overlay = document.getElementById(OVERLAY_ID) + const overlay = document.getElementById('initial-loading-overlay') if (!overlay) { - if (options.assumeMissingAsRemoved) { - overlayRemoved = true - return { removed: true } - } - return { removed: false } + removed = true + return undefined } - overlayRemoved = true + removed = true overlay.dataset.hidden = 'true' - const schedule = options.schedule ?? window.setTimeout - const removalTimer = schedule(() => { - try { - overlay.remove() - } catch (error) { - console.warn('[Loading Overlay] Removal failed:', error) - } - }, REMOVE_DELAY) - - return { removed: true, removalTimer } + const timer = window.setTimeout(() => overlay.remove(), 200) + return timer }