mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 23:05:49 +00:00
84 lines
2.7 KiB
TypeScript
84 lines
2.7 KiB
TypeScript
import type { BrowserWindow } from "electron";
|
|
|
|
type Result = { success: boolean; cancelled?: boolean; error?: string };
|
|
/** Every countdown exit settles the IPC request, including cancellation during window load. */
|
|
export function createCountdownController(
|
|
createWindow: () => BrowserWindow,
|
|
onRemaining: (seconds: number | null) => void,
|
|
) {
|
|
let finishActive: ((result: Result) => void) | null = null;
|
|
return {
|
|
start(seconds: number): Promise<Result> {
|
|
if (finishActive)
|
|
return Promise.resolve({ success: false, error: "Countdown already in progress" });
|
|
if (!Number.isFinite(seconds) || seconds < 0)
|
|
return Promise.resolve({ success: false, error: "Invalid countdown delay" });
|
|
return new Promise((resolve) => {
|
|
let win: BrowserWindow | undefined;
|
|
let timer: ReturnType<typeof setInterval> | undefined;
|
|
let settled = false;
|
|
let started = false;
|
|
let remaining = Math.ceil(seconds);
|
|
const finish = (result: Result) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
if (timer) clearInterval(timer);
|
|
finishActive = null;
|
|
onRemaining(null);
|
|
if (win) {
|
|
win.removeListener("closed", cancel);
|
|
win.webContents.removeListener("did-finish-load", begin);
|
|
win.webContents.removeListener("did-fail-load", fail);
|
|
win.webContents.removeListener("render-process-gone", cancel);
|
|
}
|
|
resolve(result);
|
|
if (win && !win.isDestroyed()) win.close();
|
|
};
|
|
const cancel = () => finish({ success: false, cancelled: true });
|
|
const fail = () =>
|
|
finish({ success: false, error: "Countdown window failed to load" });
|
|
const tick = () => {
|
|
if (!win || win.isDestroyed() || win.webContents.isDestroyed()) {
|
|
cancel();
|
|
return;
|
|
}
|
|
onRemaining(remaining);
|
|
win.webContents.send("countdown-tick", remaining);
|
|
};
|
|
const begin = () => {
|
|
if (settled || started) return;
|
|
started = true;
|
|
if (remaining === 0) {
|
|
finish({ success: true });
|
|
return;
|
|
}
|
|
tick();
|
|
if (settled) return;
|
|
timer = setInterval(() => {
|
|
remaining--;
|
|
if (remaining <= 0) finish({ success: true });
|
|
else tick();
|
|
}, 1000);
|
|
};
|
|
finishActive = finish;
|
|
onRemaining(remaining);
|
|
try {
|
|
win = createWindow();
|
|
win.once("closed", cancel);
|
|
win.webContents.once("did-fail-load", fail);
|
|
win.webContents.once("render-process-gone", cancel);
|
|
if (win.webContents.isLoadingMainFrame())
|
|
win.webContents.once("did-finish-load", begin);
|
|
else begin();
|
|
} catch (error) {
|
|
finish({ success: false, error: String(error) });
|
|
}
|
|
});
|
|
},
|
|
cancel() {
|
|
finishActive?.({ success: false, cancelled: true });
|
|
return { success: true };
|
|
},
|
|
};
|
|
}
|