mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 13:10:30 +08:00
proxy order
This commit is contained in:
parent
0ed0931b75
commit
3cf9f0dccc
@ -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' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
src/shared/types.d.ts
vendored
1
src/shared/types.d.ts
vendored
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user