diff --git a/src/components/proxies/Proxy.tsx b/src/components/proxies/Proxy.tsx index d7aec74..2bba9ea 100644 --- a/src/components/proxies/Proxy.tsx +++ b/src/components/proxies/Proxy.tsx @@ -4,7 +4,7 @@ import cx from 'clsx'; import { connect } from '../StateProvider'; import { ProxyLatency } from './ProxyLatency'; -import { getProxies, getDelay } from '../../store/proxies'; +import { NonProxyTypes, getProxies, getDelay } from '../../store/proxies'; import s0 from './Proxy.module.css'; @@ -36,6 +36,18 @@ function getLabelColor({ return colorMap.na; } +function getProxyDotBackgroundColor( + latency: { + number?: number; + }, + proxyType: string +) { + if (NonProxyTypes.indexOf(proxyType) > -1) { + return 'linear-gradient(135deg, white 15%, #999 15% 30%, white 30% 45%, #999 45% 60%, white 60% 75%, #999 75% 90%, white 90% 100%)'; + } + return getLabelColor(latency); +} + type ProxyProps = { name: string; now?: boolean; @@ -48,11 +60,15 @@ type ProxyProps = { function ProxySmallImpl({ now, name, + proxy, latency, isSelectable, onClick, }: ProxyProps) { - const color = useMemo(() => getLabelColor(latency), [latency]); + const color = useMemo(() => getProxyDotBackgroundColor(latency, proxy.type), [ + latency, + proxy, + ]); const title = useMemo(() => { let ret = name; if (latency && typeof latency.number === 'number') { @@ -67,7 +83,7 @@ function ProxySmallImpl({ [s0.now]: now, [s0.selectable]: isSelectable, })} - style={{ backgroundColor: color }} + style={{ background: color }} onClick={() => { isSelectable && onClick && onClick(name); }} diff --git a/src/components/proxies/ProxyGroup.tsx b/src/components/proxies/ProxyGroup.tsx index 3ee995e..6916619 100644 --- a/src/components/proxies/ProxyGroup.tsx +++ b/src/components/proxies/ProxyGroup.tsx @@ -3,13 +3,18 @@ import memoizeOne from 'memoize-one'; import { Zap } from 'react-feather'; import { connect, useStoreActions } from '../StateProvider'; -import { getProxies } from '../../store/proxies'; +import { + DelayMapping, + ProxiesMapping, + NonProxyTypes, + getProxies, + switchProxy, +} from '../../store/proxies'; import { getCollapsibleIsOpen, getProxySortBy, getHideUnavailableProxies, } from '../../store/app'; -import { switchProxy } from '../../store/proxies'; import CollapsibleSectionHeader from '../CollapsibleSectionHeader'; import Button from '../Button'; import { ProxyList, ProxyListSummaryView } from './ProxyList'; @@ -83,11 +88,15 @@ function ProxyGroupImpl({ name, all, type, now, isOpen, apiConfig, dispatch }) { ); } -const getSortDelay = (d, w) => { +const getSortDelay = (d, proxyInfo) => { if (d && typeof d.number === 'number' && d.number > 0) { return d.number; } - return w; + + const type = proxyInfo && proxyInfo.type; + if (type && NonProxyTypes.indexOf(type) > -1) return 999998; + + return 999999; }; function filterAvailableProxies(list, delay) { @@ -105,27 +114,33 @@ function filterAvailableProxies(list, delay) { } const ProxySortingFns = { - Natural: (proxies, _delay) => { - return proxies; - }, - LatencyAsc: (proxies, delay) => { + Natural: (proxies: string[]) => proxies, + LatencyAsc: ( + proxies: string[], + delay: DelayMapping, + proxyMapping?: ProxiesMapping + ) => { return proxies.sort((a, b) => { - const d1 = getSortDelay(delay[a], 999999); - const d2 = getSortDelay(delay[b], 999999); + const d1 = getSortDelay(delay[a], proxyMapping && proxyMapping[a]); + const d2 = getSortDelay(delay[b], proxyMapping && proxyMapping[b]); return d1 - d2; }); }, - LatencyDesc: (proxies, delay) => { + LatencyDesc: ( + proxies: string[], + delay: DelayMapping, + proxyMapping?: ProxiesMapping + ) => { return proxies.sort((a, b) => { - const d1 = getSortDelay(delay[a], 999999); - const d2 = getSortDelay(delay[b], 999999); + const d1 = getSortDelay(delay[a], proxyMapping && proxyMapping[a]); + const d2 = getSortDelay(delay[b], proxyMapping && proxyMapping[b]); return d2 - d1; }); }, - NameAsc: (proxies) => { + NameAsc: (proxies: string[]) => { return proxies.sort(); }, - NameDesc: (proxies) => { + NameDesc: (proxies: string[]) => { return proxies.sort((a, b) => { if (a > b) return -1; if (a < b) return 1; @@ -135,17 +150,18 @@ const ProxySortingFns = { }; function filterAvailableProxiesAndSortImpl( - all, - delay, - hideUnavailableProxies, - proxySortBy + all: string[], + delay: DelayMapping, + hideUnavailableProxies: boolean, + proxySortBy: string, + proxies?: ProxiesMapping ) { // all is freezed let filtered = [...all]; if (hideUnavailableProxies) { filtered = filterAvailableProxies(all, delay); } - return ProxySortingFns[proxySortBy](filtered, delay); + return ProxySortingFns[proxySortBy](filtered, delay, proxies); } export const filterAvailableProxiesAndSort = memoizeOne( @@ -165,7 +181,8 @@ export const ProxyGroup = connect((s, { name, delay }) => { all, delay, hideUnavailableProxies, - proxySortBy + proxySortBy, + proxies ), type, now, diff --git a/src/components/proxies/ProxyList.module.css b/src/components/proxies/ProxyList.module.css index ba00f90..00f8ad2 100644 --- a/src/components/proxies/ProxyList.module.css +++ b/src/components/proxies/ProxyList.module.css @@ -1,12 +1,12 @@ .list { - margin-top: 8px; + margin: 8px 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(auto, 280px)); grid-gap: 10px; } .listSummaryView { - margin-top: 8px; + margin: 8px 0; display: grid; grid-template-columns: repeat(auto-fill, 13px); grid-gap: 10px; diff --git a/src/store/proxies.tsx b/src/store/proxies.tsx index ac61ddf..915d9d7 100644 --- a/src/store/proxies.tsx +++ b/src/store/proxies.tsx @@ -6,7 +6,7 @@ type PrimitiveProxyType = 'Shadowsocks' | 'Snell' | 'Socks5' | 'Http' | 'Vmess'; type LatencyHistory = Array<{ time: string; delay: number }>; -type ProxyItem = { +export type ProxyItem = { name: string; type: PrimitiveProxyType; history: LatencyHistory; @@ -26,11 +26,12 @@ type FormattedProxyProvider = Omit & { proxies: string[]; }; -type ProxiesDict = { [name: string]: ProxyItem }; +export type ProxiesMapping = Record; +export type DelayMapping = Record; type ProxiesState = { - proxies: ProxiesDict; - delay: { [key: string]: { number: number } }; + proxies: ProxiesMapping; + delay: DelayMapping; groupNames: string[]; proxyProviders?: FormattedProxyProvider[]; dangleProxyNames?: string[]; @@ -61,7 +62,7 @@ const noop = () => null; // const ProxyGroupTypes = ['Fallback', 'URLTest', 'Selector', 'LoadBalance']; // const ProxyTypes = ['Shadowsocks', 'Snell', 'Socks5', 'Http', 'Vmess']; -const NonProxyTypes = [ +export const NonProxyTypes = [ 'Direct', 'Fallback', 'Reject', @@ -189,7 +190,7 @@ async function closeGroupConns( } function resolveChain( - proxies: ProxiesDict, + proxies: ProxiesMapping, groupName: string, itemName: string ) {