diff --git a/src/components/proxy/proxy-global.tsx b/src/components/proxy/proxy-global.tsx index ee22542..75d110b 100644 --- a/src/components/proxy/proxy-global.tsx +++ b/src/components/proxy/proxy-global.tsx @@ -1,22 +1,14 @@ import useSWR, { useSWRConfig } from "swr"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useLockFn } from "ahooks"; import { Virtuoso } from "react-virtuoso"; -import { Box, IconButton, TextField } from "@mui/material"; -import { - MyLocationRounded, - NetworkCheckRounded, - FilterAltRounded, - FilterAltOffRounded, - VisibilityRounded, - VisibilityOffRounded, -} from "@mui/icons-material"; import { ApiType } from "../../services/types"; import { updateProxy } from "../../services/api"; import { getProfiles, patchProfile } from "../../services/cmds"; +import useFilterProxy, { ProxySortType } from "./use-filter-proxy"; import delayManager from "../../services/delay"; -import useFilterProxy from "./use-filter-proxy"; import ProxyItem from "./proxy-item"; +import ProxyHead from "./proxy-head"; interface Props { groupName: string; @@ -30,13 +22,38 @@ const ProxyGlobal = (props: Props) => { const { mutate } = useSWRConfig(); const [now, setNow] = useState(curProxy || "DIRECT"); + const [showType, setShowType] = useState(true); - const [showFilter, setShowFilter] = useState(false); + const [sortType, setSortType] = useState(0); + + const [urlText, setUrlText] = useState(""); const [filterText, setFilterText] = useState(""); const virtuosoRef = useRef(); const filterProxies = useFilterProxy(proxies, groupName, filterText); + const sortedProxies = useMemo(() => { + if (sortType === 0) return filterProxies; + + const list = filterProxies.slice(); + + if (sortType === 1) { + list.sort((a, b) => a.name.localeCompare(b.name)); + } else { + list.sort((a, b) => { + const ad = delayManager.getDelay(a.name, groupName); + const bd = delayManager.getDelay(b.name, groupName); + + if (ad === -1) return 1; + if (bd === -1) return -1; + + return ad - bd; + }); + } + + return list; + }, [filterProxies, sortType, groupName]); + const { data: profiles } = useSWR("getProfiles", getProfiles); const onChangeProxy = useLockFn(async (name: string) => { @@ -61,7 +78,7 @@ const ProxyGlobal = (props: Props) => { }); const onLocation = (smooth = true) => { - const index = filterProxies.findIndex((p) => p.name === now); + const index = sortedProxies.findIndex((p) => p.name === now); if (index >= 0) { virtuosoRef.current?.scrollToIndex?.({ @@ -73,7 +90,7 @@ const ProxyGlobal = (props: Props) => { }; const onCheckAll = useLockFn(async () => { - const names = filterProxies.map((p) => p.name); + const names = sortedProxies.map((p) => p.name); await delayManager.checkListDelay( { names, groupName, skipNum: 8, maxTimeout: 600 }, @@ -85,10 +102,6 @@ const ProxyGlobal = (props: Props) => { useEffect(() => onLocation(false), [groupName]); - useEffect(() => { - if (!showFilter) setFilterText(""); - }, [showFilter]); - useEffect(() => { if (groupName === "DIRECT") setNow("DIRECT"); else if (groupName === "GLOBAL") { @@ -112,74 +125,29 @@ const ProxyGlobal = (props: Props) => { return ( <> - - onLocation(true)} - > - - - - - - - - setShowType(!showType)} - > - {showType ? : } - - - setShowFilter(!showFilter)} - > - {showFilter ? : } - - - {showFilter && ( - setFilterText(e.target.value)} - sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }} - /> - )} - + ( { const [showFilter, setShowFilter] = useState(false); const [filterText, setFilterText] = useState(""); - const proxies = group.all ?? []; const virtuosoRef = useRef(); - const filterProxies = useFilterProxy(proxies, group.name, filterText); + const filterProxies = useFilterProxy(group.all, group.name, filterText); const { data: profiles } = useSWR("getProfiles", getProfiles); diff --git a/src/components/proxy/proxy-head.tsx b/src/components/proxy/proxy-head.tsx new file mode 100644 index 0000000..ac3a680 --- /dev/null +++ b/src/components/proxy/proxy-head.tsx @@ -0,0 +1,134 @@ +import { useState } from "react"; +import { Box, IconButton, TextField, SxProps } from "@mui/material"; +import { + AccessTimeRounded, + MyLocationRounded, + NetworkCheckRounded, + FilterAltRounded, + FilterAltOffRounded, + VisibilityRounded, + VisibilityOffRounded, + WifiTetheringRounded, + WifiTetheringOffRounded, + SortByAlphaRounded, + SortRounded, +} from "@mui/icons-material"; +import type { ProxySortType } from "./use-filter-proxy"; + +interface Props { + sx?: SxProps; + showType: boolean; + sortType: ProxySortType; + urlText: string; + filterText: string; + onLocation: () => void; + onCheckDelay: () => void; + onShowType: (val: boolean) => void; + onSortType: (val: ProxySortType) => void; + onUrlText: (val: string) => void; + onFilterText: (val: string) => void; +} + +const ProxyHead = (props: Props) => { + const { sx = {}, showType, sortType, urlText, filterText } = props; + + const [textState, setTextState] = useState<"url" | "filter" | null>(null); + + return ( + + + + + + + + + + props.onSortType(((sortType + 1) % 3) as ProxySortType)} + > + {sortType === 0 && } + {sortType === 1 && } + {sortType === 2 && } + + + setTextState((ts) => (ts === "url" ? null : "url"))} + > + {textState === "url" ? ( + + ) : ( + + )} + + + props.onShowType(!showType)} + > + {showType ? : } + + + + setTextState((ts) => (ts === "filter" ? null : "filter")) + } + > + {textState === "filter" ? ( + + ) : ( + + )} + + + {textState === "filter" && ( + props.onFilterText(e.target.value)} + sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }} + /> + )} + + {textState === "url" && ( + props.onUrlText(e.target.value)} + sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }} + /> + )} + + ); +}; + +export default ProxyHead; diff --git a/src/components/proxy/use-filter-proxy.ts b/src/components/proxy/use-filter-proxy.ts index eb32057..231a09c 100644 --- a/src/components/proxy/use-filter-proxy.ts +++ b/src/components/proxy/use-filter-proxy.ts @@ -5,6 +5,9 @@ import delayManager from "../../services/delay"; const regex1 = /delay([=<>])(\d+|timeout|error)/i; const regex2 = /type=(.*)/i; +// default | alpha | delay +export type ProxySortType = 0 | 1 | 2; + /** * filter the proxy * according to the regular conditions @@ -15,6 +18,7 @@ export default function useFilterProxy( filterText: string ) { return useMemo(() => { + if (!proxies) return []; if (!filterText) return proxies; const res1 = regex1.exec(filterText);