proxy order

This commit is contained in:
pompurin404 2024-08-04 22:24:20 +08:00
parent 0ed0931b75
commit 3cf9f0dccc
No known key found for this signature in database
5 changed files with 107 additions and 39 deletions

View File

@ -2,6 +2,7 @@ export const defaultConfig: IAppConfig = {
core: 'mihomo', core: 'mihomo',
silentStart: false, silentStart: false,
proxyDisplayMode: 'simple', proxyDisplayMode: 'simple',
proxyDisplayOrder: 'default',
sysProxy: { enable: false, mode: 'manual' } sysProxy: { enable: false, mode: 'manual' }
} }

View File

@ -1,5 +1,5 @@
import { Button, Card, CardBody } from '@nextui-org/react' import { Button, Card, CardBody } from '@nextui-org/react'
import React, { useEffect, useState } from 'react' import React, { useEffect, useMemo, useState } from 'react'
import PubSub from 'pubsub-js' import PubSub from 'pubsub-js'
interface Props { interface Props {
@ -14,12 +14,14 @@ interface Props {
const ProxyItem: React.FC<Props> = (props) => { const ProxyItem: React.FC<Props> = (props) => {
const { mutateProxies, proxyDisplayMode, group, proxy, selected, onSelect, onProxyDelay } = props const { mutateProxies, proxyDisplayMode, group, proxy, selected, onSelect, onProxyDelay } = props
const [delay, setDelay] = useState(() => {
const delay = useMemo(() => {
if (proxy.history.length > 0) { if (proxy.history.length > 0) {
return proxy.history[proxy.history.length - 1].delay return proxy.history[proxy.history.length - 1].delay
} }
return -1 return -1
}) }, [proxy])
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
function delayColor(delay: number): 'primary' | 'success' | 'warning' | 'danger' { function delayColor(delay: number): 'primary' | 'success' | 'warning' | 'danger' {
@ -37,19 +39,11 @@ const ProxyItem: React.FC<Props> = (props) => {
const onDelay = (): void => { const onDelay = (): void => {
setLoading(true) setLoading(true)
onProxyDelay(proxy.name, group.testUrl).then( onProxyDelay(proxy.name, group.testUrl).finally(() => {
(delay) => { mutateProxies()
setDelay(delay.delay || 0) setLoading(false)
mutateProxies() })
setLoading(false)
},
() => {
setDelay(0)
setLoading(false)
}
)
} }
console.log(delay)
useEffect(() => { useEffect(() => {
const token = PubSub.subscribe(`${group.name}-delay`, onDelay) const token = PubSub.subscribe(`${group.name}-delay`, onDelay)
@ -58,6 +52,7 @@ const ProxyItem: React.FC<Props> = (props) => {
PubSub.unsubscribe(token) PubSub.unsubscribe(token)
} }
}, []) }, [])
return ( return (
<Card <Card
onPress={() => onSelect(group.name, proxy.name)} onPress={() => onSelect(group.name, proxy.name)}
@ -66,12 +61,16 @@ const ProxyItem: React.FC<Props> = (props) => {
className={`${selected ? 'bg-primary/30' : ''}`} className={`${selected ? 'bg-primary/30' : ''}`}
radius="sm" radius="sm"
> >
<CardBody className="p-1"> <CardBody className="p-2">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<div> <div>
<div className="inline">{proxy.name}</div> <div className="inline text-ellipsis whitespace-nowrap overflow-hidden">
{proxy.name}
</div>
{proxyDisplayMode === 'full' && ( {proxyDisplayMode === 'full' && (
<div className="inline ml-2 text-default-500">{proxy.type}</div> <div className="inline ml-2 text-ellipsis whitespace-nowrap overflow-hidden text-default-500">
{proxy.type}
</div>
)} )}
</div> </div>
<Button <Button

View File

@ -3,9 +3,13 @@ import BasePage from '@renderer/components/base/base-page'
import { useAppConfig } from '@renderer/hooks/use-app-config' import { useAppConfig } from '@renderer/hooks/use-app-config'
import { mihomoChangeProxy, mihomoProxies, mihomoProxyDelay } from '@renderer/utils/ipc' import { mihomoChangeProxy, mihomoProxies, mihomoProxyDelay } from '@renderer/utils/ipc'
import { CgDetailsLess, CgDetailsMore } from 'react-icons/cg' import { CgDetailsLess, CgDetailsMore } from 'react-icons/cg'
import { useMemo, useState } from 'react' import { FaBoltLightning } from 'react-icons/fa6'
import { TbCircleLetterD } from 'react-icons/tb'
import { FaLocationCrosshairs } from 'react-icons/fa6'
import { RxLetterCaseCapitalize } from 'react-icons/rx'
import { useMemo, useRef, useState } from 'react'
import useSWR from 'swr' import useSWR from 'swr'
import { GroupedVirtuoso } from 'react-virtuoso' import { GroupedVirtuoso, GroupedVirtuosoHandle } from 'react-virtuoso'
import ProxyItem from '@renderer/components/proxies/proxy-item' import ProxyItem from '@renderer/components/proxies/proxy-item'
import { IoIosArrowBack } from 'react-icons/io' import { IoIosArrowBack } from 'react-icons/io'
import { MdOutlineSpeed } from 'react-icons/md' import { MdOutlineSpeed } from 'react-icons/md'
@ -13,7 +17,7 @@ import { MdOutlineSpeed } from 'react-icons/md'
const Proxies: React.FC = () => { const Proxies: React.FC = () => {
const { data: proxies, mutate } = useSWR('mihomoProxies', mihomoProxies) const { data: proxies, mutate } = useSWR('mihomoProxies', mihomoProxies)
const { appConfig, patchAppConfig } = useAppConfig() const { appConfig, patchAppConfig } = useAppConfig()
const { proxyDisplayMode = 'simple' } = appConfig || {} const { proxyDisplayMode = 'simple', proxyDisplayOrder = 'default' } = appConfig || {}
const groups = useMemo(() => { const groups = useMemo(() => {
const groups: IMihomoGroup[] = [] const groups: IMihomoGroup[] = []
@ -36,7 +40,7 @@ const Proxies: React.FC = () => {
}, [proxies]) }, [proxies])
const [isOpen, setIsOpen] = useState(Array(groups.length).fill(false)) const [isOpen, setIsOpen] = useState(Array(groups.length).fill(false))
const virtuosoRef = useRef<GroupedVirtuosoHandle>(null)
const { groupCounts, allProxies } = useMemo(() => { const { groupCounts, allProxies } = useMemo(() => {
const groupCounts = groups.map((group, index) => { const groupCounts = groups.map((group, index) => {
return isOpen[index] ? group.all.length : 0 return isOpen[index] ? group.all.length : 0
@ -44,12 +48,25 @@ const Proxies: React.FC = () => {
const allProxies: (IMihomoProxy | IMihomoGroup)[] = [] const allProxies: (IMihomoProxy | IMihomoGroup)[] = []
groups.forEach((group, index) => { groups.forEach((group, index) => {
if (isOpen[index] && proxies) { if (isOpen[index] && proxies) {
allProxies.push(...group.all.map((name) => proxies.proxies[name])) let groupProxies = group.all.map((name) => proxies.proxies[name])
if (proxyDisplayOrder === 'delay') {
groupProxies = groupProxies.sort((a, b) => {
if (a.history.length === 0) return -1
if (b.history.length === 0) return 1
if (a.history[a.history.length - 1].delay === 0) return 1
if (b.history[b.history.length - 1].delay === 0) return -1
return a.history[a.history.length - 1].delay - b.history[b.history.length - 1].delay
})
}
if (proxyDisplayOrder === 'name') {
groupProxies = groupProxies.sort((a, b) => a.name.localeCompare(b.name))
}
allProxies.push(...groupProxies)
} }
}) })
return { groupCounts, allProxies } return { groupCounts, allProxies }
}, [groups, isOpen]) }, [groups, isOpen, proxyDisplayOrder])
const onChangeProxy = (group: string, proxy: string): void => { const onChangeProxy = (group: string, proxy: string): void => {
mihomoChangeProxy(group, proxy).then(() => { mihomoChangeProxy(group, proxy).then(() => {
@ -69,22 +86,50 @@ const Proxies: React.FC = () => {
<BasePage <BasePage
title="代理组" title="代理组"
header={ header={
<Button <div>
size="sm" <Button
isIconOnly size="sm"
onPress={() => { isIconOnly
patchAppConfig({ proxyDisplayMode: proxyDisplayMode === 'simple' ? 'full' : 'simple' }) onPress={() => {
}} patchAppConfig({
> proxyDisplayOrder:
{proxyDisplayMode === 'simple' ? ( proxyDisplayOrder === 'default'
<CgDetailsMore size={20} /> ? 'delay'
) : ( : proxyDisplayOrder === 'delay'
<CgDetailsLess size={20} /> ? 'name'
)} : 'default'
</Button> })
}}
>
{proxyDisplayOrder === 'default' ? (
<TbCircleLetterD size={20} title="默认" />
) : proxyDisplayOrder === 'delay' ? (
<FaBoltLightning size={20} title="延迟" />
) : (
<RxLetterCaseCapitalize size={20} title="名称" />
)}
</Button>
<Button
size="sm"
isIconOnly
className="ml-2"
onPress={() => {
patchAppConfig({
proxyDisplayMode: proxyDisplayMode === 'simple' ? 'full' : 'simple'
})
}}
>
{proxyDisplayMode === 'simple' ? (
<CgDetailsMore size={20} title="详细信息" />
) : (
<CgDetailsLess size={20} title="简洁信息" />
)}
</Button>
</div>
} }
> >
<GroupedVirtuoso <GroupedVirtuoso
ref={virtuosoRef}
style={{ height: 'calc(100vh - 50px)' }} style={{ height: 'calc(100vh - 50px)' }}
groupCounts={groupCounts} groupCounts={groupCounts}
groupContent={(index) => { groupContent={(index) => {
@ -112,7 +157,7 @@ const Proxies: React.FC = () => {
src={groups[index].icon} src={groups[index].icon}
/> />
) : null} ) : null}
<div className="h-[32px] text-md leading-[32px]"> <div className="h-[32px] text-ellipsis whitespace-nowrap overflow-hidden text-md leading-[32px]">
{groups[index].name} {groups[index].name}
{proxyDisplayMode === 'full' && ( {proxyDisplayMode === 'full' && (
<> <>
@ -128,6 +173,29 @@ const Proxies: React.FC = () => {
</div> </div>
<div className="flex"> <div className="flex">
<Button <Button
title="定位到当前节点"
variant="light"
size="sm"
isIconOnly
onPress={() => {
if (!isOpen[index]) return
let i = 0
for (let j = 0; j < index; j++) {
i += groupCounts[j]
}
for (let j = 0; j < groupCounts[index]; j++) {
if (allProxies[i + j].name === groups[index].now) {
i += j
break
}
}
virtuosoRef.current?.scrollToIndex({ index: i, align: 'start' })
}}
>
<FaLocationCrosshairs className="text-lg text-default-500" />
</Button>
<Button
title="延迟测试"
variant="light" variant="light"
size="sm" size="sm"
isIconOnly isIconOnly

View File

@ -32,7 +32,6 @@ export async function mihomoChangeProxy(group: string, proxy: string): Promise<I
export async function mihomoProxyDelay(proxy: string, url?: string): Promise<IMihomoDelay> { export async function mihomoProxyDelay(proxy: string, url?: string): Promise<IMihomoDelay> {
const res = await window.electron.ipcRenderer.invoke('mihomoProxyDelay', proxy, url) const res = await window.electron.ipcRenderer.invoke('mihomoProxyDelay', proxy, url)
console.log(res)
return res return res
} }

View File

@ -131,6 +131,7 @@ interface ISysProxyConfig {
interface IAppConfig { interface IAppConfig {
core: 'mihomo' | 'mihomo-alpha' core: 'mihomo' | 'mihomo-alpha'
proxyDisplayMode: 'simple' | 'full' proxyDisplayMode: 'simple' | 'full'
proxyDisplayOrder: 'default' | 'delay' | 'name'
silentStart: boolean silentStart: boolean
sysProxy: ISysProxyConfig sysProxy: ISysProxyConfig
userAgent?: string userAgent?: string