refactor: frontend (#5068)
* refactor: setting components * refactor: frontend * fix: settings router
This commit is contained in:
@@ -133,11 +133,22 @@ export const useLogData = () => {
|
||||
mutate(`$sub$${subscriptKey}`);
|
||||
}, [date, subscriptKey]);
|
||||
|
||||
const previousLogLevel = useRef<string | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (!logLevel) return;
|
||||
if (!logLevel) {
|
||||
previousLogLevel.current = logLevel ?? undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousLogLevel.current === logLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
previousLogLevel.current = logLevel;
|
||||
ws.current?.close();
|
||||
setDate(Date.now());
|
||||
}, [logLevel]);
|
||||
}, [logLevel, setDate]);
|
||||
|
||||
const refreshGetClashLog = (clear = false) => {
|
||||
if (clear) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useRef, useCallback } from "react";
|
||||
import { useEffect, useRef, useCallback, useReducer } from "react";
|
||||
|
||||
// import { useClashInfo } from "@/hooks/use-clash";
|
||||
// import { useVisibility } from "@/hooks/use-visibility";
|
||||
@@ -196,12 +196,11 @@ export const useTrafficMonitorEnhanced = () => {
|
||||
});
|
||||
}
|
||||
|
||||
const [, forceUpdate] = useState({});
|
||||
const [, forceRender] = useReducer((version: number) => version + 1, 0);
|
||||
const cleanupRef = useRef<(() => void) | null>(null);
|
||||
|
||||
// 强制组件更新
|
||||
const triggerUpdate = useCallback(() => {
|
||||
forceUpdate({});
|
||||
const bumpRenderVersion = useCallback(() => {
|
||||
forceRender();
|
||||
}, []);
|
||||
|
||||
// 注册引用计数
|
||||
@@ -250,9 +249,8 @@ export const useTrafficMonitorEnhanced = () => {
|
||||
}),
|
||||
};
|
||||
globalSampler.addDataPoint(dataPoint);
|
||||
triggerUpdate();
|
||||
}
|
||||
}, [traffic, triggerUpdate]);
|
||||
}, [traffic]);
|
||||
|
||||
// const { data: monitorData, error } = useSWR<ISystemMonitorOverview>(
|
||||
// shouldFetch ? "getSystemMonitorOverviewSafe" : null,
|
||||
@@ -328,9 +326,9 @@ export const useTrafficMonitorEnhanced = () => {
|
||||
const clearData = useCallback(() => {
|
||||
if (globalSampler) {
|
||||
globalSampler.clear();
|
||||
triggerUpdate();
|
||||
bumpRenderVersion();
|
||||
}
|
||||
}, [triggerUpdate]);
|
||||
}, [bumpRenderVersion]);
|
||||
|
||||
// 获取采样器统计信息
|
||||
const getSamplerStats = useCallback(() => {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export const useVisibility = () => {
|
||||
const [visible, setVisible] = useState(true);
|
||||
const [visible, setVisible] = useState(() =>
|
||||
typeof document === "undefined"
|
||||
? true
|
||||
: document.visibilityState === "visible",
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleVisibilityChange = () => {
|
||||
@@ -9,16 +13,15 @@ export const useVisibility = () => {
|
||||
};
|
||||
|
||||
const handleFocus = () => setVisible(true);
|
||||
const handleClick = () => setVisible(true);
|
||||
const handlePointerDown = () => setVisible(true);
|
||||
|
||||
handleVisibilityChange();
|
||||
document.addEventListener("focus", handleFocus);
|
||||
document.addEventListener("pointerdown", handleClick);
|
||||
document.addEventListener("pointerdown", handlePointerDown);
|
||||
document.addEventListener("visibilitychange", handleVisibilityChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("focus", handleFocus);
|
||||
document.removeEventListener("pointerdown", handleClick);
|
||||
document.removeEventListener("pointerdown", handlePointerDown);
|
||||
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
46
src/hooks/use-window.ts
Normal file
46
src/hooks/use-window.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { use } from "react";
|
||||
|
||||
import { WindowContext, type WindowContextType } from "@/providers/window";
|
||||
|
||||
export const useWindow = () => {
|
||||
const context = use(WindowContext);
|
||||
if (context === undefined) {
|
||||
throw new Error("useWindow must be used within WindowProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const useWindowControls = () => {
|
||||
const {
|
||||
maximized,
|
||||
minimize,
|
||||
toggleMaximize,
|
||||
close,
|
||||
toggleFullscreen,
|
||||
currentWindow,
|
||||
} = useWindow();
|
||||
return {
|
||||
maximized,
|
||||
minimize,
|
||||
toggleMaximize,
|
||||
close,
|
||||
toggleFullscreen,
|
||||
currentWindow,
|
||||
} satisfies Pick<
|
||||
WindowContextType,
|
||||
| "maximized"
|
||||
| "minimize"
|
||||
| "toggleMaximize"
|
||||
| "close"
|
||||
| "toggleFullscreen"
|
||||
| "currentWindow"
|
||||
>;
|
||||
};
|
||||
|
||||
export const useWindowDecorations = () => {
|
||||
const { decorated, toggleDecorations, refreshDecorated } = useWindow();
|
||||
return { decorated, toggleDecorations, refreshDecorated } satisfies Pick<
|
||||
WindowContextType,
|
||||
"decorated" | "toggleDecorations" | "refreshDecorated"
|
||||
>;
|
||||
};
|
||||
@@ -1,129 +0,0 @@
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import { debounce } from "lodash-es";
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
use,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
interface WindowContextType {
|
||||
decorated: boolean | null;
|
||||
maximized: boolean | null;
|
||||
toggleDecorations: () => Promise<void>;
|
||||
refreshDecorated: () => Promise<boolean>;
|
||||
minimize: () => void;
|
||||
close: () => void;
|
||||
toggleMaximize: () => Promise<void>;
|
||||
toggleFullscreen: () => Promise<void>;
|
||||
currentWindow: ReturnType<typeof getCurrentWindow>;
|
||||
}
|
||||
|
||||
const WindowContext = createContext<WindowContextType | undefined>(undefined);
|
||||
|
||||
export const WindowProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const currentWindow = getCurrentWindow();
|
||||
const [decorated, setDecorated] = useState<boolean | null>(null);
|
||||
const [maximized, setMaximized] = useState<boolean | null>(null);
|
||||
|
||||
const close = useCallback(() => currentWindow.close(), [currentWindow]);
|
||||
const minimize = useCallback(() => currentWindow.minimize(), [currentWindow]);
|
||||
|
||||
useEffect(() => {
|
||||
const checkMaximized = debounce(async () => {
|
||||
const value = await currentWindow.isMaximized();
|
||||
if (maximized !== value) {
|
||||
setMaximized(value);
|
||||
}
|
||||
}, 100);
|
||||
const unlistenResize = currentWindow.onResized(checkMaximized);
|
||||
|
||||
return () => {
|
||||
unlistenResize.then((fn) => fn());
|
||||
};
|
||||
}, [currentWindow, maximized]);
|
||||
|
||||
const toggleMaximize = useCallback(async () => {
|
||||
if (await currentWindow.isMaximized()) {
|
||||
await currentWindow.unmaximize();
|
||||
setMaximized(false);
|
||||
} else {
|
||||
await currentWindow.maximize();
|
||||
setMaximized(true);
|
||||
}
|
||||
}, [currentWindow]);
|
||||
|
||||
const toggleFullscreen = useCallback(async () => {
|
||||
await currentWindow.setFullscreen(!(await currentWindow.isFullscreen()));
|
||||
}, [currentWindow]);
|
||||
|
||||
const refreshDecorated = useCallback(async () => {
|
||||
const val = await currentWindow.isDecorated();
|
||||
setDecorated(val);
|
||||
return val;
|
||||
}, [currentWindow]);
|
||||
|
||||
const toggleDecorations = useCallback(async () => {
|
||||
const currentVal = await currentWindow.isDecorated();
|
||||
await currentWindow.setDecorations(!currentVal);
|
||||
setDecorated(!currentVal);
|
||||
}, [currentWindow]);
|
||||
|
||||
useEffect(() => {
|
||||
refreshDecorated();
|
||||
currentWindow.setMinimizable?.(true);
|
||||
}, [currentWindow, refreshDecorated]);
|
||||
|
||||
return (
|
||||
<WindowContext
|
||||
value={{
|
||||
decorated,
|
||||
maximized,
|
||||
toggleDecorations,
|
||||
refreshDecorated,
|
||||
minimize,
|
||||
close,
|
||||
toggleMaximize,
|
||||
toggleFullscreen,
|
||||
currentWindow,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</WindowContext>
|
||||
);
|
||||
};
|
||||
|
||||
export const useWindow = () => {
|
||||
const context = use(WindowContext);
|
||||
if (context === undefined) {
|
||||
throw new Error("useWindow must be used within WindowProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const useWindowControls = () => {
|
||||
const {
|
||||
maximized,
|
||||
minimize,
|
||||
toggleMaximize,
|
||||
close,
|
||||
toggleFullscreen,
|
||||
currentWindow,
|
||||
} = useWindow();
|
||||
return {
|
||||
maximized,
|
||||
minimize,
|
||||
toggleMaximize,
|
||||
close,
|
||||
toggleFullscreen,
|
||||
currentWindow,
|
||||
};
|
||||
};
|
||||
|
||||
export const useWindowDecorations = () => {
|
||||
const { decorated, toggleDecorations, refreshDecorated } = useWindow();
|
||||
return { decorated, toggleDecorations, refreshDecorated };
|
||||
};
|
||||
Reference in New Issue
Block a user