From d3d35bcb422d2174c045e6a986042ee7941b4f9f Mon Sep 17 00:00:00 2001 From: AK <144495202+AKnassa@users.noreply.github.com> Date: Tue, 28 Apr 2026 01:26:42 -0400 Subject: [PATCH] perf(fullscreen): subscribe to SettingsUpdated, not every ctx NewState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous NewState listener fired on every change to the ctx model — notifications, search history, library sync, streaming-server URL — and each fire triggered a getState('ctx') round-trip to the worker just to re-read escExitFullscreen. Switch to the CoreEvent / SettingsUpdated channel (same pattern App.js uses for interfaceLanguage/quitOnClose), reading the new value straight from the event payload. Initial seed still uses getState('ctx') once on mount. Co-Authored-By: Claude Opus 4.7 --- src/common/Fullscreen/FullscreenProvider.tsx | 46 ++++++++++---------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/common/Fullscreen/FullscreenProvider.tsx b/src/common/Fullscreen/FullscreenProvider.tsx index 938df0b29..61a0f67c0 100644 --- a/src/common/Fullscreen/FullscreenProvider.tsx +++ b/src/common/Fullscreen/FullscreenProvider.tsx @@ -60,33 +60,35 @@ const FullscreenProvider = ({ children }: Props) => { if (!core?.active) return; let cancelled = false; - const refreshSettings = async () => { - try { - const ctx = await core.transport.getState('ctx') as Ctx | null; - if (!cancelled) { - escExitFullscreenRef.current = !!ctx?.profile?.settings?.escExitFullscreen; - } - } catch (err) { + + // CoreTransport.on types the listener as () => void, but 'CoreEvent' + // actually emits { event, args }. Read it via a rest-args wrapper to + // stay compatible with the ambient signature. + const onCoreEvent = (...listenerArgs: unknown[]) => { + const payload = listenerArgs[0] as + | { event?: string, args?: { settings?: { escExitFullscreen?: boolean } } } + | undefined; + if (payload?.event === 'SettingsUpdated' && + typeof payload.args?.settings?.escExitFullscreen === 'boolean') { + escExitFullscreenRef.current = payload.args.settings.escExitFullscreen; + } + }; + + core.transport.getState('ctx') + .then((ctx) => { + if (cancelled) return; + const settings = (ctx as Ctx | null)?.profile?.settings; + escExitFullscreenRef.current = !!settings?.escExitFullscreen; + }) + .catch((err) => { console.error('FullscreenProvider: failed to read ctx state', err); - } - }; + }); - // CoreTransport.on types the listener as () => void, but the 'NewState' - // event actually emits a string[] of changed model names. Read it via - // a rest-args wrapper to stay compatible with the ambient signature. - const onNewState = (...args: unknown[]) => { - const models = args[0]; - if (Array.isArray(models) && models.indexOf('ctx') !== -1) { - refreshSettings(); - } - }; - - refreshSettings(); - core.transport.on('NewState', onNewState); + core.transport.on('CoreEvent', onCoreEvent); return () => { cancelled = true; - core.transport.off('NewState', onNewState); + core.transport.off('CoreEvent', onCoreEvent); }; }, [core]);