import { PauseCircleOutlineRounded, PlayCircleOutlineRounded, TableChartRounded, TableRowsRounded, } from "@mui/icons-material"; import { Box, Button, IconButton, MenuItem } from "@mui/material"; import { useLockFn } from "ahooks"; import { useCallback, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { Virtuoso } from "react-virtuoso"; import { closeAllConnections } from "tauri-plugin-mihomo-api"; import { BaseEmpty, BasePage } from "@/components/base"; import { BaseSearchBox } from "@/components/base/base-search-box"; import { BaseStyledSelect } from "@/components/base/base-styled-select"; import { ConnectionDetail, ConnectionDetailRef, } from "@/components/connection/connection-detail"; import { ConnectionItem } from "@/components/connection/connection-item"; import { ConnectionTable } from "@/components/connection/connection-table"; import { useConnectionData } from "@/hooks/use-connection-data"; import { useVisibility } from "@/hooks/use-visibility"; import { useConnectionSetting } from "@/services/states"; import parseTraffic from "@/utils/parse-traffic"; const initConn: IConnections = { uploadTotal: 0, downloadTotal: 0, connections: [], }; type OrderFunc = (list: IConnectionsItem[]) => IConnectionsItem[]; const ConnectionsPage = () => { const { t } = useTranslation(); const pageVisible = useVisibility(); const [match, setMatch] = useState<(input: string) => boolean>( () => () => true, ); const [curOrderOpt, setCurOrderOpt] = useState("Default"); const { response: { data: connections }, } = useConnectionData(); const [setting, setSetting] = useConnectionSetting(); const isTableLayout = setting.layout === "table"; const orderOpts = useMemo>( () => ({ Default: (list) => list.sort( (a, b) => new Date(b.start || "0").getTime()! - new Date(a.start || "0").getTime()!, ), "Upload Speed": (list) => list.sort((a, b) => b.curUpload! - a.curUpload!), "Download Speed": (list) => list.sort((a, b) => b.curDownload! - a.curDownload!), }), [], ); const [isPaused, setIsPaused] = useState(false); const [frozenData, setFrozenData] = useState(null); // 使用全局连接数据 const displayData = useMemo(() => { if (!pageVisible) return initConn; if (isPaused) { return ( frozenData ?? { uploadTotal: connections?.uploadTotal, downloadTotal: connections?.downloadTotal, connections: connections?.connections, } ); } return { uploadTotal: connections?.uploadTotal, downloadTotal: connections?.downloadTotal, connections: connections?.connections, }; }, [isPaused, frozenData, connections, pageVisible]); const [filterConn] = useMemo(() => { const orderFunc = orderOpts[curOrderOpt]; let conns = displayData.connections?.filter((conn) => { const { host, destinationIP, process } = conn.metadata; return ( match(host || "") || match(destinationIP || "") || match(process || "") ); }); if (orderFunc) conns = orderFunc(conns ?? []); return [conns]; }, [displayData, match, curOrderOpt, orderOpts]); const onCloseAll = useLockFn(closeAllConnections); const detailRef = useRef(null!); const handleSearch = useCallback((match: (content: string) => boolean) => { setMatch(() => match); }, []); const handlePauseToggle = useCallback(() => { setIsPaused((prev) => { if (!prev) { setFrozenData({ uploadTotal: connections?.uploadTotal ?? 0, downloadTotal: connections?.downloadTotal ?? 0, connections: connections?.connections ?? [], }); } else { setFrozenData(null); } return !prev; }); }, [connections]); return ( {t("Connections")}} contentStyle={{ height: "100%", display: "flex", flexDirection: "column", overflow: "auto", borderRadius: "8px", }} header={ {t("Downloaded")}: {parseTraffic(displayData.downloadTotal)} {t("Uploaded")}: {parseTraffic(displayData.uploadTotal)} setSetting((o) => o?.layout !== "table" ? { ...o, layout: "table" } : { ...o, layout: "list" }, ) } > {isTableLayout ? ( ) : ( )} {isPaused ? ( ) : ( )} } > {!isTableLayout && ( setCurOrderOpt(e.target.value)} > {Object.keys(orderOpts).map((opt) => ( {t(opt)} ))} )} {!filterConn || filterConn.length === 0 ? ( ) : isTableLayout ? ( detailRef.current?.open(detail)} /> ) : ( ( detailRef.current?.open(item)} /> )} /> )} ); }; export default ConnectionsPage;