mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
optimize proxy list performance
This commit is contained in:
parent
2eb3370df7
commit
f9ba7996c5
@ -1,3 +1,4 @@
|
||||
import { Divider } from '@nextui-org/react'
|
||||
import React from 'react'
|
||||
interface Props {
|
||||
title?: React.ReactNode
|
||||
@ -14,6 +15,7 @@ const BasePage: React.FC<Props> = (props) => {
|
||||
<div className="select-none title h-full text-lg leading-[32px]">{props.title}</div>
|
||||
<div className="header h-full">{props.header}</div>
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
<div className="content">{props.children}</div>
|
||||
</div>
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { Button, Card, CardBody, Divider } from '@nextui-org/react'
|
||||
import { Button, Card, CardBody } from '@nextui-org/react'
|
||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||
import PubSub from 'pubsub-js'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
onProxyDelay: (proxy: string) => Promise<IMihomoDelay>
|
||||
onProxyDelay: (proxy: string, url?: string) => Promise<IMihomoDelay>
|
||||
proxyDisplayMode: 'simple' | 'full'
|
||||
proxy: IMihomoProxy | IMihomoGroup
|
||||
group: string
|
||||
onSelect: (proxy: string) => void
|
||||
onSelect: (group: string, proxy: string) => void
|
||||
selected: boolean
|
||||
}
|
||||
|
||||
@ -61,36 +61,33 @@ const ProxyItem: React.FC<Props> = (props) => {
|
||||
}
|
||||
}, [])
|
||||
return (
|
||||
<>
|
||||
<Divider />
|
||||
<Card
|
||||
onPress={() => onSelect(proxy.name)}
|
||||
isPressable
|
||||
fullWidth
|
||||
className={`my-1 ${selected ? 'bg-primary/30' : ''}`}
|
||||
radius="sm"
|
||||
>
|
||||
<CardBody className="p-1">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<div className="inline">{proxy.name}</div>
|
||||
{proxyDisplayMode === 'full' && (
|
||||
<div className="inline ml-2 text-default-500">{proxy.type}</div>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
isLoading={loading}
|
||||
color={delayColor(delay)}
|
||||
onPress={onDelay}
|
||||
variant="light"
|
||||
className="h-full min-w-[50px] p-0 mx-2 text-sm hover:bg-content"
|
||||
>
|
||||
{delayText(delay)}
|
||||
</Button>
|
||||
<Card
|
||||
onPress={() => onSelect(group, proxy.name)}
|
||||
isPressable
|
||||
fullWidth
|
||||
className={`${selected ? 'bg-primary/30' : ''}`}
|
||||
radius="sm"
|
||||
>
|
||||
<CardBody className="p-1">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<div className="inline">{proxy.name}</div>
|
||||
{proxyDisplayMode === 'full' && (
|
||||
<div className="inline ml-2 text-default-500">{proxy.type}</div>
|
||||
)}
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</>
|
||||
<Button
|
||||
isLoading={loading}
|
||||
color={delayColor(delay)}
|
||||
onPress={onDelay}
|
||||
variant="light"
|
||||
className="h-full min-w-[50px] p-0 mx-2 text-sm hover:bg-content"
|
||||
>
|
||||
{delayText(delay)}
|
||||
</Button>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import React from 'react'
|
||||
import { Virtuoso } from 'react-virtuoso'
|
||||
import ProxyItem from './proxy-item'
|
||||
|
||||
interface Props {
|
||||
onProxyDelay: (proxy: string) => Promise<IMihomoDelay>
|
||||
onChangeProxy: (proxy: string) => void
|
||||
proxyDisplayMode: 'simple' | 'full'
|
||||
proxies: (IMihomoProxy | IMihomoGroup)[]
|
||||
group: string
|
||||
now: string
|
||||
}
|
||||
|
||||
const ProxyList: React.FC<Props> = (props) => {
|
||||
const { proxyDisplayMode, onProxyDelay, onChangeProxy, proxies, group, now } = props
|
||||
|
||||
return (
|
||||
<Virtuoso
|
||||
style={{ height: `min(calc(100vh - 200px), ${proxies.length * 44}px)` }}
|
||||
totalCount={proxies.length}
|
||||
increaseViewportBy={100}
|
||||
itemContent={(index) => (
|
||||
<ProxyItem
|
||||
onProxyDelay={onProxyDelay}
|
||||
onSelect={onChangeProxy}
|
||||
proxy={proxies[index]}
|
||||
group={group}
|
||||
proxyDisplayMode={proxyDisplayMode}
|
||||
selected={proxies[index].name === now}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProxyList
|
||||
@ -1,13 +1,14 @@
|
||||
import { Accordion, AccordionItem, Avatar, Button } from '@nextui-org/react'
|
||||
import { Avatar, Button, Card, CardBody } from '@nextui-org/react'
|
||||
import BasePage from '@renderer/components/base/base-page'
|
||||
import ProxyList from '@renderer/components/proxies/proxy-list'
|
||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||
import { MdOutlineSpeed } from 'react-icons/md'
|
||||
import { mihomoChangeProxy, mihomoProxies, mihomoProxyDelay } from '@renderer/utils/ipc'
|
||||
import { CgDetailsLess, CgDetailsMore } from 'react-icons/cg'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import PubSub from 'pubsub-js'
|
||||
import { useMemo, useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { GroupedVirtuoso } from 'react-virtuoso'
|
||||
import ProxyItem from '@renderer/components/proxies/proxy-item'
|
||||
import { IoIosArrowBack } from 'react-icons/io'
|
||||
import { MdOutlineSpeed } from 'react-icons/md'
|
||||
|
||||
const Proxies: React.FC = () => {
|
||||
const { data: proxies, mutate } = useSWR('mihomoProxies', mihomoProxies)
|
||||
@ -34,15 +35,21 @@ const Proxies: React.FC = () => {
|
||||
return groups
|
||||
}, [proxies])
|
||||
|
||||
const groupProxies = useMemo(() => {
|
||||
const groupProxies: Record<string, (IMihomoProxy | IMihomoGroup)[]> = {}
|
||||
if (proxies) {
|
||||
for (const group of groups) {
|
||||
groupProxies[group.name] = group.all.map((name) => proxies.proxies[name])
|
||||
const [isOpen, setIsOpen] = useState(Array(groups.length).fill(false))
|
||||
|
||||
const { groupCounts, allProxies } = useMemo(() => {
|
||||
const groupCounts = groups.map((group, index) => {
|
||||
return isOpen[index] ? group.all.length : 0
|
||||
})
|
||||
const allProxies: (IMihomoProxy | IMihomoGroup)[] = []
|
||||
groups.forEach((group, index) => {
|
||||
if (isOpen[index] && proxies) {
|
||||
allProxies.push(...group.all.map((name) => proxies.proxies[name]))
|
||||
}
|
||||
}
|
||||
return groupProxies
|
||||
}, [proxies])
|
||||
})
|
||||
|
||||
return { groupCounts, allProxies }
|
||||
}, [groups, isOpen])
|
||||
|
||||
const onChangeProxy = (group: string, proxy: string): void => {
|
||||
mihomoChangeProxy(group, proxy).then(() => {
|
||||
@ -54,7 +61,6 @@ const Proxies: React.FC = () => {
|
||||
return await mihomoProxyDelay(proxy, url)
|
||||
}
|
||||
|
||||
useEffect(() => {}, [])
|
||||
return (
|
||||
<BasePage
|
||||
title="代理组"
|
||||
@ -74,54 +80,86 @@ const Proxies: React.FC = () => {
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Accordion variant="splitted" className="p-2">
|
||||
{groups.map((group) => {
|
||||
<GroupedVirtuoso
|
||||
style={{ height: 'calc(100vh - 50px)' }}
|
||||
groupCounts={groupCounts}
|
||||
groupContent={(index) => {
|
||||
return (
|
||||
<AccordionItem
|
||||
textValue={group.name}
|
||||
key={group.name}
|
||||
title={
|
||||
<div className="flex justify-between">
|
||||
<div className="">
|
||||
<div className="inline">{group.name}</div>
|
||||
{proxyDisplayMode === 'full' && (
|
||||
<>
|
||||
<div className="inline ml-2 text-sm text-default-500">{group.type}</div>
|
||||
<div className="inline ml-2 text-sm text-default-500">{group.now}</div>
|
||||
</>
|
||||
)}
|
||||
<div className={`w-full pt-2 ${index === groupCounts.length - 1 ? 'pb-2' : ''} px-2`}>
|
||||
<Card
|
||||
isPressable
|
||||
fullWidth
|
||||
onPress={() => {
|
||||
setIsOpen((prev) => {
|
||||
const newOpen = [...prev]
|
||||
newOpen[index] = !prev[index]
|
||||
return newOpen
|
||||
})
|
||||
}}
|
||||
>
|
||||
<CardBody>
|
||||
<div className="flex justify-between">
|
||||
<div className="flex">
|
||||
{groups[index].icon.length > 0 ? (
|
||||
<Avatar
|
||||
className="bg-transparent mr-2"
|
||||
size="sm"
|
||||
radius="sm"
|
||||
src={groups[index].icon}
|
||||
/>
|
||||
) : null}
|
||||
<div className="h-[32px] text-md leading-[32px]">
|
||||
{groups[index].name}
|
||||
{proxyDisplayMode === 'full' && (
|
||||
<>
|
||||
<div className="inline ml-2 text-sm text-default-500">
|
||||
{groups[index].type}
|
||||
</div>
|
||||
<div className="inline ml-2 text-sm text-default-500">
|
||||
{groups[index].now}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<Button
|
||||
variant="light"
|
||||
size="sm"
|
||||
isIconOnly
|
||||
onPress={() => {
|
||||
PubSub.publish(`${groups[index].name}-delay`)
|
||||
}}
|
||||
>
|
||||
<MdOutlineSpeed className="text-lg text-default-500" />
|
||||
</Button>
|
||||
<IoIosArrowBack
|
||||
className={`transition duration-200 ml-2 h-[32px] text-lg text-default-500 ${isOpen[index] ? '-rotate-90' : ''}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="light"
|
||||
size="sm"
|
||||
isIconOnly
|
||||
onPress={() => {
|
||||
PubSub.publish(`${group.name}-delay`)
|
||||
}}
|
||||
>
|
||||
<MdOutlineSpeed className="text-lg text-default-500" />
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
classNames={{ title: 'select-none', base: 'px-2', content: 'pt-2', trigger: 'py-2' }}
|
||||
startContent={
|
||||
group.icon.length > 0 ? (
|
||||
<Avatar className="bg-transparent" size="sm" radius="sm" src={group.icon} />
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<ProxyList
|
||||
onProxyDelay={(proxy) => onProxyDelay(proxy, group.testUrl)}
|
||||
onChangeProxy={(proxy) => onChangeProxy(group.name, proxy)}
|
||||
proxyDisplayMode={proxyDisplayMode}
|
||||
proxies={groupProxies[group.name]}
|
||||
group={group.name}
|
||||
now={group.now}
|
||||
/>
|
||||
</AccordionItem>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Accordion>
|
||||
}}
|
||||
itemContent={(index, groupIndex) => {
|
||||
return allProxies[index] ? (
|
||||
<div className="pt-2 mx-2">
|
||||
<ProxyItem
|
||||
onProxyDelay={onProxyDelay}
|
||||
onSelect={onChangeProxy}
|
||||
proxy={allProxies[index]}
|
||||
group={groups[groupIndex].name}
|
||||
proxyDisplayMode={proxyDisplayMode}
|
||||
selected={allProxies[index]?.name === groups[groupIndex].now}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>Never See This</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</BasePage>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user