import { useRef } from "react"; import { useLockFn } from "ahooks"; import { Box, ListItem, ListItemText, Typography } from "@mui/material"; import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"; import { ExpandLessRounded, ExpandMoreRounded, InboxRounded, SendRounded, } from "@mui/icons-material"; import { getConnections, providerHealthCheck, updateProxy, deleteConnection, } from "@/services/api"; import { useProfiles } from "@/hooks/use-profiles"; import { useVerge } from "@/hooks/use-verge"; import { useRenderList, type IRenderItem } from "./use-render-list"; import { HeadState } from "./use-head-state"; import { ProxyHead } from "./proxy-head"; import { ProxyItem } from "./proxy-item"; import delayManager from "@/services/delay"; interface Props { mode: string; } export const ProxyGroups = (props: Props) => { const { mode } = props; const { renderList, onProxies, onHeadState } = useRenderList(mode); const { verge } = useVerge(); const { current, patchCurrent } = useProfiles(); const virtuosoRef = useRef(null); // 切换分组的节点代理 const handleChangeProxy = useLockFn( async (group: IProxyGroupItem, proxy: IProxyItem) => { if (group.type !== "Selector") return; const { name, now } = group; await updateProxy(name, proxy.name); onProxies(); // 断开连接 if (verge?.auto_close_connection) { getConnections().then(({ connections }) => { connections.forEach((conn) => { if (conn.chains.includes(now!)) { deleteConnection(conn.id); } }); }); } // 保存到selected中 if (!current) return; if (!current.selected) current.selected = []; const index = current.selected.findIndex( (item) => item.name === group.name ); if (index < 0) { current.selected.push({ name, now: proxy.name }); } else { current.selected[index] = { name, now: proxy.name }; } await patchCurrent({ selected: current.selected }); } ); // 测全部延迟 const handleCheckAll = useLockFn(async (groupName: string) => { const proxies = renderList .filter((e) => e.type === 2 && e.group?.name === groupName) .map((e) => e.proxy!) .filter(Boolean); const providers = new Set(proxies.map((p) => p!.provider!).filter(Boolean)); if (providers.size) { Promise.allSettled( [...providers].map((p) => providerHealthCheck(p)) ).then(() => onProxies()); } const names = proxies.filter((p) => !p!.provider).map((p) => p!.name); await delayManager.checkListDelay(names, groupName, 24); onProxies(); }); // 滚到对应的节点 const handleLocation = (group: IProxyGroupItem) => { if (!group) return; const { name, now } = group; const index = renderList.findIndex( (e) => e.type === 2 && e.group?.name === name && e.proxy?.name === now ); if (index >= 0) { virtuosoRef.current?.scrollToIndex?.({ index, align: "center", behavior: "smooth", }); } }; return ( ( )} /> ); }; interface RenderProps { item: IRenderItem; indent: boolean; onLocation: (group: IProxyGroupItem) => void; onCheckAll: (groupName: string) => void; onHeadState: (groupName: string, patch: Partial) => void; onChangeProxy: (group: IProxyGroupItem, proxy: IProxyItem) => void; } function ProxyRenderItem(props: RenderProps) { const { indent, item, onLocation, onCheckAll, onHeadState, onChangeProxy } = props; const { type, group, headState, proxy } = item; if (type === 0) { return ( onHeadState(group.name, { open: !headState?.open })} > {/* {group.type} */} {group.now} } secondaryTypographyProps={{ sx: { display: "flex", alignItems: "center" }, }} /> {headState?.open ? : } ); } if (type === 1) { return ( onLocation(group)} onCheckDelay={() => onCheckAll(group.name)} onHeadState={(p) => onHeadState(group.name, p)} /> ); } if (type === 2) { return ( onChangeProxy(group, proxy!)} /> ); } if (type === 3) { return ( No Proxies ); } return null; }