mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 06:25:41 +00:00
- Type `window.__psyHidden` once via global declaration; drop 6 `(window as any)` casts. - `WindowVisibilityProvider` now ORs `window.__psyHidden` into the hidden state (and into the initial state). On WebView2 `document.hidden` does not always flip when `win.hide()` is called, so effects gated by `useWindowVisibility()` can now actually skip creating intervals/rAF instead of relying solely on the per-tick fallback check. - Slow visible-poll from 200 ms to 500 ms (5 → 2 wakeups/s for visibility alone). - Fix stray leading-space indent in `App.tsx` `window:close-requested` comment. Co-authored-by: Psychotoxical <dev@psysonic.app>
This commit is contained in:
committed by
GitHub
parent
0ead4fbeb1
commit
b97b6c545b
+1
-1
@@ -931,7 +931,7 @@ function TauriEventBridge() {
|
|||||||
unlisten.push(u);
|
unlisten.push(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
// window:close-requested is emitted by Rust (prevent_close + emit).
|
// window:close-requested is emitted by Rust (prevent_close + emit).
|
||||||
// JS decides: minimize to tray or exit, based on user setting.
|
// JS decides: minimize to tray or exit, based on user setting.
|
||||||
const u = await listen('window:close-requested', async () => {
|
const u = await listen('window:close-requested', async () => {
|
||||||
if (useAuthStore.getState().minimizeToTray) {
|
if (useAuthStore.getState().minimizeToTray) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default function Hero({ albums: albumsProp }: HeroProps = {}) {
|
|||||||
timerRef.current = null;
|
timerRef.current = null;
|
||||||
if (len <= 1 || windowHidden) return;
|
if (len <= 1 || windowHidden) return;
|
||||||
timerRef.current = setInterval(() => {
|
timerRef.current = setInterval(() => {
|
||||||
if (document.hidden || (window as any).__psyHidden) return;
|
if (document.hidden || window.__psyHidden) return;
|
||||||
setActiveIdx(prev => (prev + 1) % len);
|
setActiveIdx(prev => (prev + 1) % len);
|
||||||
}, INTERVAL_MS);
|
}, INTERVAL_MS);
|
||||||
}, [windowHidden]);
|
}, [windowHidden]);
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ export default function MiniPlayer() {
|
|||||||
if (typeof e.payload.volume === 'number') setVolumeState(e.payload.volume);
|
if (typeof e.payload.volume === 'number') setVolumeState(e.payload.volume);
|
||||||
});
|
});
|
||||||
const unProgress = listen<ProgressPayload>('audio:progress', (e) => {
|
const unProgress = listen<ProgressPayload>('audio:progress', (e) => {
|
||||||
if (hiddenRef.current || (window as any).__psyHidden) return;
|
if (hiddenRef.current || window.__psyHidden) return;
|
||||||
setCurrentTime(e.payload.current_time);
|
setCurrentTime(e.payload.current_time);
|
||||||
if (e.payload.duration > 0) setDuration(e.payload.duration);
|
if (e.payload.duration > 0) setDuration(e.payload.duration);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export default function PlaybackScheduleBadge({ layoutAnchorRef, className }: Pl
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (deadlineMs == null || windowHidden) return;
|
if (deadlineMs == null || windowHidden) return;
|
||||||
const id = window.setInterval(() => {
|
const id = window.setInterval(() => {
|
||||||
if (document.hidden || (window as any).__psyHidden) return;
|
if (document.hidden || window.__psyHidden) return;
|
||||||
setNowMs(Date.now());
|
setNowMs(Date.now());
|
||||||
}, 500);
|
}, 500);
|
||||||
return () => window.clearInterval(id);
|
return () => window.clearInterval(id);
|
||||||
|
|||||||
@@ -750,7 +750,7 @@ export function SeekbarPreview({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const tick = () => {
|
const tick = () => {
|
||||||
if (document.hidden || (window as any).__psyHidden) {
|
if (document.hidden || window.__psyHidden) {
|
||||||
pollId = window.setTimeout(() => {
|
pollId = window.setTimeout(() => {
|
||||||
pollId = null;
|
pollId = null;
|
||||||
tick();
|
tick();
|
||||||
@@ -900,7 +900,7 @@ export default function WaveformSeek({ trackId }: Props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const tick = () => {
|
const tick = () => {
|
||||||
if (document.hidden || (window as any).__psyHidden) {
|
if (document.hidden || window.__psyHidden) {
|
||||||
pollId = window.setTimeout(() => {
|
pollId = window.setTimeout(() => {
|
||||||
pollId = null;
|
pollId = null;
|
||||||
tick();
|
tick();
|
||||||
|
|||||||
@@ -14,25 +14,31 @@ const WindowVisibilityContext = createContext(false);
|
|||||||
*
|
*
|
||||||
* On Windows WebView2, `visibilitychange` and `blur`/`focus` events do not
|
* On Windows WebView2, `visibilitychange` and `blur`/`focus` events do not
|
||||||
* fire when `win.hide()` is called. We fall back to polling `document.hidden`
|
* fire when `win.hide()` is called. We fall back to polling `document.hidden`
|
||||||
* with an adaptive interval: fast checks while visible (to catch show quickly),
|
* OR-ed with `window.__psyHidden` (set from Rust before/after `win.hide()` /
|
||||||
* slow checks while hidden (to minimize CPU wakeups).
|
* `show()`) — the latter is the reliable signal on WebView2 where
|
||||||
|
* `document.hidden` may stay false. Adaptive interval: slow while hidden
|
||||||
|
* (minimize wakeups), 500 ms while visible (catch show without burning CPU).
|
||||||
*/
|
*/
|
||||||
|
function isWindowHidden() {
|
||||||
|
return document.hidden || !!window.__psyHidden;
|
||||||
|
}
|
||||||
|
|
||||||
export function WindowVisibilityProvider({ children }: { children: ReactNode }) {
|
export function WindowVisibilityProvider({ children }: { children: ReactNode }) {
|
||||||
const [hidden, setHidden] = useState(document.hidden);
|
const [hidden, setHidden] = useState(isWindowHidden);
|
||||||
const hiddenRef = useRef(hidden);
|
const hiddenRef = useRef(hidden);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
hiddenRef.current = document.hidden;
|
hiddenRef.current = isWindowHidden();
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
const schedule = () => {
|
const schedule = () => {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
const interval = hiddenRef.current ? 1000 : 200;
|
const interval = hiddenRef.current ? 1000 : 500;
|
||||||
timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
timeoutId = null;
|
timeoutId = null;
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
const current = document.hidden;
|
const current = isWindowHidden();
|
||||||
if (current !== hiddenRef.current) {
|
if (current !== hiddenRef.current) {
|
||||||
hiddenRef.current = current;
|
hiddenRef.current = current;
|
||||||
setHidden(current);
|
setHidden(current);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function usePlaybackScheduleRemaining(): PlaybackScheduleInfo | null {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (deadlineMs == null || windowHidden) return;
|
if (deadlineMs == null || windowHidden) return;
|
||||||
const id = window.setInterval(() => {
|
const id = window.setInterval(() => {
|
||||||
if (document.hidden || (window as any).__psyHidden) return;
|
if (document.hidden || window.__psyHidden) return;
|
||||||
setNowMs(Date.now());
|
setNowMs(Date.now());
|
||||||
}, 500);
|
}, 500);
|
||||||
return () => window.clearInterval(id);
|
return () => window.clearInterval(id);
|
||||||
|
|||||||
Vendored
+8
@@ -1 +1,9 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__psyHidden?: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
|
|||||||
Reference in New Issue
Block a user