fix:prevent stale countdown IPC updates from repainting overlay

This commit is contained in:
Galactic99
2026-04-16 19:22:57 +05:30
parent 6b08a0a72a
commit ea68e4cfc3
5 changed files with 47 additions and 24 deletions
+3 -3
View File
@@ -135,9 +135,9 @@ interface Window {
saveShortcuts: (shortcuts: unknown) => Promise<{ success: boolean; error?: string }>;
hudOverlayHide: () => void;
hudOverlayClose: () => void;
showCountdownOverlay: (value: number) => Promise<void>;
setCountdownOverlayValue: (value: number) => Promise<void>;
hideCountdownOverlay: () => Promise<void>;
showCountdownOverlay: (value: number, runId: number) => Promise<void>;
setCountdownOverlayValue: (value: number, runId: number) => Promise<void>;
hideCountdownOverlay: (runId: number) => Promise<void>;
onCountdownOverlayValue: (callback: (value: number | null) => void) => () => void;
setMicrophoneExpanded: (expanded: boolean) => void;
setHasUnsavedChanges: (hasChanges: boolean) => void;
+13 -3
View File
@@ -362,6 +362,7 @@ export function registerIpcHandlers(
const countdownOverlayState = {
visible: false,
value: null as number | null,
activeRunId: null as number | null,
};
const flushCountdownOverlayState = (win: BrowserWindow) => {
@@ -379,7 +380,8 @@ export function registerIpcHandlers(
}
};
ipcMain.handle("countdown-overlay-show", (_, value: number) => {
ipcMain.handle("countdown-overlay-show", (_, value: number, runId: number) => {
countdownOverlayState.activeRunId = runId;
countdownOverlayState.visible = true;
countdownOverlayState.value = value;
@@ -399,7 +401,11 @@ export function registerIpcHandlers(
}
});
ipcMain.handle("countdown-overlay-set-value", (_, value: number) => {
ipcMain.handle("countdown-overlay-set-value", (_, value: number, runId: number) => {
if (countdownOverlayState.activeRunId !== runId || !countdownOverlayState.visible) {
return;
}
countdownOverlayState.value = value;
const win = getCountdownOverlayWindow();
@@ -414,7 +420,11 @@ export function registerIpcHandlers(
win.webContents.send("countdown-overlay-value", value);
});
ipcMain.handle("countdown-overlay-hide", () => {
ipcMain.handle("countdown-overlay-hide", (_, runId: number) => {
if (countdownOverlayState.activeRunId !== runId) {
return;
}
countdownOverlayState.visible = false;
countdownOverlayState.value = null;
+6 -6
View File
@@ -130,14 +130,14 @@ contextBridge.exposeInMainWorld("electronAPI", {
setHasUnsavedChanges: (hasChanges: boolean) => {
ipcRenderer.send("set-has-unsaved-changes", hasChanges);
},
showCountdownOverlay: (value: number) => {
return ipcRenderer.invoke("countdown-overlay-show", value);
showCountdownOverlay: (value: number, runId: number) => {
return ipcRenderer.invoke("countdown-overlay-show", value, runId);
},
setCountdownOverlayValue: (value: number) => {
return ipcRenderer.invoke("countdown-overlay-set-value", value);
setCountdownOverlayValue: (value: number, runId: number) => {
return ipcRenderer.invoke("countdown-overlay-set-value", value, runId);
},
hideCountdownOverlay: () => {
return ipcRenderer.invoke("countdown-overlay-hide");
hideCountdownOverlay: (runId: number) => {
return ipcRenderer.invoke("countdown-overlay-hide", runId);
},
onCountdownOverlayValue: (callback: (value: number | null) => void) => {
const listener = (_event: unknown, value: number | null) => callback(value);
+4 -1
View File
@@ -14,7 +14,10 @@ export function CountdownOverlay() {
return (
<div className="w-screen h-screen bg-transparent flex items-center justify-center pointer-events-none select-none">
{value === null ? null : (
<div className="text-white/90 text-[120px] font-bold leading-none tabular-nums">
<div
className="text-white/90 text-[120px] font-bold leading-none tabular-nums"
style={{ textShadow: "0 4px 24px rgba(0, 0, 0, 0.65)" }}
>
{value}
</div>
)}
+21 -11
View File
@@ -336,9 +336,10 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
}
return () => {
const activeRunId = countdownRunId.current;
if (cleanup) cleanup();
countdownRunId.current += 1;
void window.electronAPI.hideCountdownOverlay();
void window.electronAPI.hideCountdownOverlay(activeRunId);
allowAutoFinalize.current = false;
restarting.current = false;
discardRecordingId.current = null;
@@ -370,14 +371,15 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
}, [teardownMedia]);
const cancelCountdown = () => {
const activeRunId = countdownRunId.current;
countdownRunId.current += 1;
setCountdownActive(false);
void window.electronAPI.hideCountdownOverlay();
void window.electronAPI.hideCountdownOverlay(activeRunId);
};
const safeShowCountdownOverlay = async (value: number) => {
const safeShowCountdownOverlay = async (value: number, runId: number) => {
try {
await window.electronAPI.showCountdownOverlay(value);
await window.electronAPI.showCountdownOverlay(value, runId);
return true;
} catch (error) {
console.warn("Failed to show countdown overlay:", error);
@@ -385,17 +387,17 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
}
};
const safeSetCountdownOverlayValue = async (value: number) => {
const safeSetCountdownOverlayValue = async (value: number, runId: number) => {
try {
await window.electronAPI.setCountdownOverlayValue(value);
await window.electronAPI.setCountdownOverlayValue(value, runId);
} catch (error) {
console.warn("Failed to update countdown overlay value:", error);
}
};
const safeHideCountdownOverlay = async () => {
const safeHideCountdownOverlay = async (runId: number) => {
try {
await window.electronAPI.hideCountdownOverlay();
await window.electronAPI.hideCountdownOverlay(runId);
} catch (error) {
console.warn("Failed to hide countdown overlay:", error);
}
@@ -427,7 +429,11 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
try {
const values = [3, 2, 1];
const overlayShown = await safeShowCountdownOverlay(values[0]);
const overlayShown = await safeShowCountdownOverlay(values[0], runId);
if (countdownRunId.current !== runId) {
return;
}
for (const value of values) {
if (countdownRunId.current !== runId) {
@@ -435,7 +441,11 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
}
if (overlayShown && value !== values[0]) {
await safeSetCountdownOverlayValue(value);
await safeSetCountdownOverlayValue(value, runId);
if (countdownRunId.current !== runId) {
return;
}
}
await new Promise((resolve) => window.setTimeout(resolve, 1000));
@@ -449,7 +459,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
} finally {
if (countdownRunId.current === runId) {
setCountdownActive(false);
await safeHideCountdownOverlay();
await safeHideCountdownOverlay(runId);
}
}
};