fix: optimize asynchronous handling to prevent UI blocking in various components
fix: add missing showNotice error handling and improve async UI feedback - Add showNotice error notifications to unlock page async error branches - Restore showNotice for YAML serialization errors in rules/groups/proxies editor - Ensure all user-facing async errors are surfaced via showNotice - Add fade-in animation to layout for smoother theme transition and reduce white screen - Use requestIdleCallback/setTimeout for heavy UI state updates to avoid UI blocking - Minor: remove window.showNotice usage, use direct import instead
This commit is contained in:
@@ -132,8 +132,8 @@ const handleNoticeMessage = (
|
||||
showNotice('error', `${t("Failed to Change Core")}: ${msg}`);
|
||||
break;
|
||||
default: // Optional: Log unhandled statuses
|
||||
console.warn(`[通知监听 V2] 未处理的状态: ${status}`);
|
||||
break;
|
||||
console.warn(`[通知监听 V2] 未处理的状态: ${status}`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -151,6 +151,11 @@ const Layout = () => {
|
||||
const routersEles = useRoutes(routers);
|
||||
const { addListener, setupCloseListener } = useListen();
|
||||
const initRef = useRef(false);
|
||||
const [themeReady, setThemeReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setThemeReady(true);
|
||||
}, [theme]);
|
||||
|
||||
const handleNotice = useCallback(
|
||||
(payload: [string, string]) => {
|
||||
@@ -271,7 +276,7 @@ const Layout = () => {
|
||||
return unlisten;
|
||||
} catch (err) {
|
||||
console.error("[Layout] 监听启动完成事件失败:", err);
|
||||
return () => {};
|
||||
return () => { };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -288,7 +293,7 @@ const Layout = () => {
|
||||
}, 100);
|
||||
}, 100);
|
||||
}, 100);
|
||||
|
||||
|
||||
// 启动监听器
|
||||
const unlistenPromise = listenStartupCompleted();
|
||||
|
||||
@@ -311,13 +316,39 @@ const Layout = () => {
|
||||
}
|
||||
}, [start_page]);
|
||||
|
||||
if (!themeReady) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
background: mode === "light" ? "#fff" : "#181a1b",
|
||||
transition: "background 0.2s",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!routersEles) return null;
|
||||
|
||||
return (
|
||||
<SWRConfig value={{ errorRetryCount: 3 }}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<NoticeManager />
|
||||
|
||||
<div
|
||||
style={{
|
||||
animation: "fadeIn 0.5s",
|
||||
WebkitAnimation: "fadeIn 0.5s",
|
||||
}}
|
||||
/>
|
||||
<style>
|
||||
{`
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<Paper
|
||||
square
|
||||
elevation={0}
|
||||
@@ -337,11 +368,11 @@ const Layout = () => {
|
||||
({ palette }) => ({ bgcolor: palette.background.paper }),
|
||||
OS === "linux"
|
||||
? {
|
||||
borderRadius: "8px",
|
||||
border: "1px solid var(--divider-color)",
|
||||
width: "calc(100vw - 4px)",
|
||||
height: "calc(100vh - 4px)",
|
||||
}
|
||||
borderRadius: "8px",
|
||||
border: "1px solid var(--divider-color)",
|
||||
width: "calc(100vw - 4px)",
|
||||
height: "calc(100vh - 4px)",
|
||||
}
|
||||
: {},
|
||||
]}
|
||||
>
|
||||
|
||||
@@ -252,9 +252,13 @@ export const HomePage = () => {
|
||||
setSettingsOpen(true);
|
||||
};
|
||||
|
||||
// 新增:保存设置
|
||||
// 新增:保存设置时用requestIdleCallback/setTimeout
|
||||
const handleSaveSettings = (newCards: HomeCardsSettings) => {
|
||||
setHomeCards(newCards);
|
||||
if (window.requestIdleCallback) {
|
||||
window.requestIdleCallback(() => setHomeCards(newCards));
|
||||
} else {
|
||||
setTimeout(() => setHomeCards(newCards), 0);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
RefreshRounded,
|
||||
AccessTimeOutlined,
|
||||
} from "@mui/icons-material";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
// 定义流媒体检测项类型
|
||||
interface UnlockItem {
|
||||
@@ -121,61 +122,67 @@ const UnlockPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// invoke加超时,防止后端卡死
|
||||
const invokeWithTimeout = async <T,>(
|
||||
cmd: string,
|
||||
args?: any,
|
||||
timeout = 15000,
|
||||
): Promise<T> => {
|
||||
return Promise.race([
|
||||
invoke<T>(cmd, args),
|
||||
new Promise<T>((_, reject) => setTimeout(() => reject(new Error("Timeout")), timeout)),
|
||||
]);
|
||||
};
|
||||
|
||||
// 执行全部项目检测
|
||||
const checkAllMedia = useLockFn(async () => {
|
||||
try {
|
||||
setIsCheckingAll(true);
|
||||
const result = await invoke<UnlockItem[]>("check_media_unlock");
|
||||
const result = await invokeWithTimeout<UnlockItem[]>("check_media_unlock");
|
||||
const sortedItems = sortItemsByName(result);
|
||||
|
||||
// 更新UI
|
||||
setUnlockItems(sortedItems);
|
||||
const currentTime = new Date().toLocaleString();
|
||||
setLastCheckTime(currentTime);
|
||||
|
||||
// 保存结果到本地存储
|
||||
saveResultsToStorage(sortedItems, currentTime);
|
||||
|
||||
setIsCheckingAll(false);
|
||||
} catch (err: any) {
|
||||
setIsCheckingAll(false);
|
||||
showNotice('error', err?.message || err?.toString() || '检测超时或失败');
|
||||
alert("检测超时或失败: " + (err?.message || err));
|
||||
console.error("Failed to check media unlock:", err);
|
||||
}
|
||||
});
|
||||
|
||||
// 根据项目名称检测单个流媒体服务
|
||||
// 检测单个流媒体服务
|
||||
const checkSingleMedia = useLockFn(async (name: string) => {
|
||||
try {
|
||||
// 将该项目添加到加载状态
|
||||
setLoadingItems((prev) => [...prev, name]);
|
||||
const result = await invokeWithTimeout<UnlockItem[]>("check_media_unlock");
|
||||
|
||||
// 执行检测
|
||||
const result = await invoke<UnlockItem[]>("check_media_unlock");
|
||||
|
||||
// 找到对应的检测结果
|
||||
const targetItem = result.find((item: UnlockItem) => item.name === name);
|
||||
|
||||
if (targetItem) {
|
||||
// 更新单个检测项结果并按名称排序
|
||||
const updatedItems = sortItemsByName(
|
||||
unlockItems.map((item: UnlockItem) =>
|
||||
item.name === name ? targetItem : item,
|
||||
),
|
||||
);
|
||||
|
||||
// 更新UI
|
||||
setUnlockItems(updatedItems);
|
||||
const currentTime = new Date().toLocaleString();
|
||||
setLastCheckTime(currentTime);
|
||||
|
||||
// 保存结果到本地存储
|
||||
saveResultsToStorage(updatedItems, currentTime);
|
||||
}
|
||||
|
||||
// 移除加载状态
|
||||
setLoadingItems((prev) => prev.filter((item) => item !== name));
|
||||
} catch (err: any) {
|
||||
setLoadingItems((prev) => prev.filter((item) => item !== name));
|
||||
showNotice('error', err?.message || err?.toString() || `检测${name}失败`);
|
||||
alert("检测超时或失败: " + (err?.message || err));
|
||||
console.error(`Failed to check ${name}:`, err);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user