import { useEffect, useState } from "react"; import { useLockFn } from "ahooks"; import { CheckCircleOutlineRounded } from "@mui/icons-material"; import { alpha, Box, ListItemButton, styled, Typography } from "@mui/material"; import { BaseLoading } from "@/components/base"; import delayManager from "@/services/delay"; import { useVerge } from "@/hooks/use-verge"; import { useTranslation } from "react-i18next"; interface Props { group: IProxyGroupItem; proxy: IProxyItem; selected: boolean; showType?: boolean; onClick?: (name: string) => void; } // 多列布局 export const ProxyItemMini = (props: Props) => { const { group, proxy, selected, showType = true, onClick } = props; const { t } = useTranslation(); const presetList = ["DIRECT", "REJECT", "REJECT-DROP", "PASS", "COMPATIBLE"]; const isPreset = presetList.includes(proxy.name); // -1/<=0 为 不显示 // -2 为 loading const [delay, setDelay] = useState(-1); const { verge } = useVerge(); const timeout = verge?.default_latency_timeout || 10000; useEffect(() => { if (isPreset) return; delayManager.setListener(proxy.name, group.name, setDelay); return () => { delayManager.removeListener(proxy.name, group.name); }; }, [proxy.name, group.name]); useEffect(() => { if (!proxy) return; setDelay(delayManager.getDelayFix(proxy, group.name)); }, [proxy]); const onDelay = useLockFn(async () => { setDelay(-2); setDelay(await delayManager.checkDelay(proxy.name, group.name, timeout)); }); return ( onClick?.(proxy.name)} sx={[ { height: 56, borderRadius: 1.5, pl: 1.5, pr: 1, justifyContent: "space-between", alignItems: "center", }, ({ palette: { mode, primary } }) => { const bgcolor = mode === "light" ? "#ffffff" : "#24252f"; const showDelay = delay > 0; const selectColor = mode === "light" ? primary.main : primary.light; return { "&:hover .the-check": { display: !showDelay ? "block" : "none" }, "&:hover .the-delay": { display: showDelay ? "block" : "none" }, "&:hover .the-icon": { display: "none" }, "& .the-pin, & .the-unpin": { position: "absolute", fontSize: "12px", top: "-5px", right: "-5px", }, "& .the-unpin": { filter: "grayscale(1)" }, "&.Mui-selected": { width: `calc(100% + 3px)`, marginLeft: `-3px`, borderLeft: `3px solid ${selectColor}`, bgcolor: mode === "light" ? alpha(primary.main, 0.15) : alpha(primary.main, 0.35), }, backgroundColor: bgcolor, }; }, ]} > {proxy.name} {showType && ( {proxy.now && ( {proxy.now} )} {!!proxy.provider && ( {proxy.provider} )} {proxy.type} {proxy.udp && ( UDP )} {proxy.xudp && ( XUDP )} {proxy.tfo && ( TFO )} )} {delay === -2 && ( )} {!proxy.provider && delay !== -2 && ( // provider的节点不支持检测 { e.preventDefault(); e.stopPropagation(); onDelay(); }} sx={({ palette }) => ({ display: "none", // hover才显示 ":hover": { bgcolor: alpha(palette.primary.main, 0.15) }, })} > Check )} {delay > 0 && ( // 显示延迟 { if (proxy.provider) return; e.preventDefault(); e.stopPropagation(); onDelay(); }} color={delayManager.formatDelayColor(delay, timeout)} sx={({ palette }) => !proxy.provider ? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } } : {} } > {delayManager.formatDelay(delay, timeout)} )} {delay !== -2 && delay <= 0 && selected && ( // 展示已选择的icon )} {group.fixed && group.fixed === proxy.name && ( // 展示fixed状态 📌 )} ); }; const Widget = styled(Box)(({ theme: { typography } }) => ({ padding: "2px 4px", fontSize: 14, fontFamily: typography.fontFamily, borderRadius: "4px", })); const TypeBox = styled(Box)(({ theme: { palette, typography } }) => ({ display: "inline-block", border: "1px solid #ccc", borderColor: "text.secondary", color: "text.secondary", borderRadius: 4, fontSize: 10, fontFamily: typography.fontFamily, marginRight: "4px", marginTop: "auto", padding: "0 4px", lineHeight: 1.5, }));