mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-04 22:52:23 +08:00
113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
import { invoke } from "@tauri-apps/api/core";
|
|
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 isInitialized = false;
|
|
let isCancelled = false;
|
|
const timers = new Set<number>();
|
|
|
|
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 notifyBackend = async (stage?: string) => {
|
|
if (isCancelled) return;
|
|
|
|
try {
|
|
if (stage) {
|
|
await invoke("update_ui_stage", { stage });
|
|
} else {
|
|
await invoke("notify_ui_ready");
|
|
}
|
|
} catch (err) {
|
|
console.error(`[Initialization] Failed to notify backend:`, err);
|
|
}
|
|
};
|
|
|
|
const removeLoadingOverlay = () => {
|
|
hideInitialOverlay({ schedule: scheduleTimeout });
|
|
};
|
|
|
|
const performInitialization = async () => {
|
|
if (isCancelled || isInitialized) return;
|
|
isInitialized = true;
|
|
|
|
try {
|
|
removeLoadingOverlay();
|
|
await notifyBackend("Loading");
|
|
|
|
await new Promise<void>((resolve) => {
|
|
const check = () => {
|
|
const root = document.getElementById("root");
|
|
if (root && root.children.length > 0) {
|
|
resolve();
|
|
} else {
|
|
scheduleTimeout(check, 50);
|
|
}
|
|
};
|
|
check();
|
|
scheduleTimeout(resolve, 2000);
|
|
});
|
|
|
|
await notifyBackend("DomReady");
|
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
await notifyBackend("ResourcesLoaded");
|
|
await notifyBackend();
|
|
} catch (error) {
|
|
if (!isCancelled) {
|
|
console.error("[Initialization] Failed:", error);
|
|
removeLoadingOverlay();
|
|
notifyBackend().catch(console.error);
|
|
}
|
|
}
|
|
};
|
|
|
|
const checkBackendReady = async () => {
|
|
try {
|
|
if (isCancelled) return;
|
|
|
|
await invoke("update_ui_stage", { stage: "Loading" });
|
|
performInitialization();
|
|
} catch {
|
|
scheduleTimeout(performInitialization, 1500);
|
|
}
|
|
};
|
|
|
|
scheduleTimeout(checkBackendReady, 100);
|
|
scheduleTimeout(() => {
|
|
if (!isInitialized) {
|
|
removeLoadingOverlay();
|
|
notifyBackend().catch(console.error);
|
|
}
|
|
}, 5000);
|
|
|
|
return () => {
|
|
isCancelled = true;
|
|
timers.forEach((id) => {
|
|
try {
|
|
window.clearTimeout(id);
|
|
} catch (error) {
|
|
console.warn("[Initialization] Failed to clear timer:", error);
|
|
}
|
|
});
|
|
timers.clear();
|
|
};
|
|
}, []);
|
|
};
|