mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-26 20:50:30 +08:00
feat: add animation during latency testing for better user feedback
This commit is contained in:
parent
d6e456302e
commit
0b8c77d200
@ -1,6 +1,7 @@
|
||||
import { Button, Card, CardBody } from '@heroui/react'
|
||||
import { mihomoUnfixedProxy } from '@renderer/utils/ipc'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import React from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { FaMapPin } from 'react-icons/fa6'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
@ -12,11 +13,12 @@ interface Props {
|
||||
group: IMihomoMixedGroup
|
||||
onSelect: (group: string, proxy: string) => void
|
||||
selected: boolean
|
||||
isGroupTesting?: boolean
|
||||
}
|
||||
|
||||
const ProxyItem: React.FC<Props> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const { mutateProxies, proxyDisplayMode, group, proxy, selected, onSelect, onProxyDelay } = props
|
||||
const { mutateProxies, proxyDisplayMode, group, proxy, selected, onSelect, onProxyDelay, isGroupTesting = false } = props
|
||||
|
||||
const delay = useMemo(() => {
|
||||
if (proxy.history.length > 0) {
|
||||
@ -26,6 +28,9 @@ const ProxyItem: React.FC<Props> = (props) => {
|
||||
}, [proxy])
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const isLoading = loading || isGroupTesting
|
||||
|
||||
function delayColor(delay: number): 'primary' | 'success' | 'warning' | 'danger' {
|
||||
if (delay === -1) return 'primary'
|
||||
if (delay === 0) return 'danger'
|
||||
@ -106,7 +111,7 @@ const ProxyItem: React.FC<Props> = (props) => {
|
||||
<Button
|
||||
isIconOnly
|
||||
title={proxy.type}
|
||||
isLoading={loading}
|
||||
isLoading={isLoading}
|
||||
color={delayColor(delay)}
|
||||
onPress={onDelay}
|
||||
variant="light"
|
||||
@ -144,11 +149,11 @@ const ProxyItem: React.FC<Props> = (props) => {
|
||||
<Button
|
||||
isIconOnly
|
||||
title={proxy.type}
|
||||
isLoading={loading}
|
||||
isLoading={isLoading}
|
||||
color={delayColor(delay)}
|
||||
onPress={onDelay}
|
||||
variant="light"
|
||||
className="h-[24px] text-sm px-2 relative w-min whitespace-nowrap"
|
||||
className="h-full text-sm px-2 relative w-min whitespace-nowrap"
|
||||
>
|
||||
<div className="w-full h-full flex items-center justify-end">
|
||||
{delayText(delay)}
|
||||
|
||||
@ -29,7 +29,6 @@ const useProxyState = (groups: IMihomoMixedGroup[]): {
|
||||
virtuosoRef: React.RefObject<GroupedVirtuosoHandle>;
|
||||
isOpen: boolean[];
|
||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean[]>>;
|
||||
onScroll: (e: React.UIEvent<HTMLElement>) => void;
|
||||
} => {
|
||||
const virtuosoRef = useRef<GroupedVirtuosoHandle>(null)
|
||||
|
||||
@ -56,10 +55,7 @@ const useProxyState = (groups: IMihomoMixedGroup[]): {
|
||||
return {
|
||||
virtuosoRef,
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
onScroll: useCallback((_e: React.UIEvent<HTMLElement>) => {
|
||||
// 空实现,不再保存滚动位置
|
||||
}, [])
|
||||
setIsOpen
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,8 +74,9 @@ const Proxies: React.FC = () => {
|
||||
} = appConfig || {}
|
||||
|
||||
const [cols, setCols] = useState(1)
|
||||
const { virtuosoRef, isOpen, setIsOpen, onScroll } = useProxyState(groups)
|
||||
const { virtuosoRef, isOpen, setIsOpen } = useProxyState(groups)
|
||||
const [delaying, setDelaying] = useState(Array(groups.length).fill(false))
|
||||
const [proxyDelaying, setProxyDelaying] = useState<Record<string, boolean>>({})
|
||||
const [searchValue, setSearchValue] = useState(Array(groups.length).fill(''))
|
||||
const { groupCounts, allProxies } = useMemo(() => {
|
||||
const groupCounts: number[] = []
|
||||
@ -139,6 +136,16 @@ const Proxies: React.FC = () => {
|
||||
return newDelaying
|
||||
})
|
||||
|
||||
// 本组测试状态
|
||||
const groupProxies = allProxies[index]
|
||||
setProxyDelaying((prev) => {
|
||||
const newProxyDelaying = { ...prev }
|
||||
groupProxies.forEach(proxy => {
|
||||
newProxyDelaying[proxy.name] = true
|
||||
})
|
||||
return newProxyDelaying
|
||||
})
|
||||
|
||||
try {
|
||||
// 限制并发数量
|
||||
const result: Promise<void>[] = []
|
||||
@ -150,6 +157,12 @@ const Proxies: React.FC = () => {
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
// 立即更新状态
|
||||
setProxyDelaying((prev) => {
|
||||
const newProxyDelaying = { ...prev }
|
||||
delete newProxyDelaying[proxy.name]
|
||||
return newProxyDelaying
|
||||
})
|
||||
mutate()
|
||||
}
|
||||
})
|
||||
@ -169,6 +182,14 @@ const Proxies: React.FC = () => {
|
||||
newDelaying[index] = false
|
||||
return newDelaying
|
||||
})
|
||||
// 状态清理
|
||||
setProxyDelaying((prev) => {
|
||||
const newProxyDelaying = { ...prev }
|
||||
groupProxies.forEach(proxy => {
|
||||
delete newProxyDelaying[proxy.name]
|
||||
})
|
||||
return newProxyDelaying
|
||||
})
|
||||
}
|
||||
}, [allProxies, groups, delayTestConcurrency, mutate])
|
||||
|
||||
@ -256,7 +277,6 @@ const Proxies: React.FC = () => {
|
||||
<GroupedVirtuoso
|
||||
ref={virtuosoRef}
|
||||
groupCounts={groupCounts}
|
||||
onScroll={onScroll}
|
||||
defaultItemHeight={80}
|
||||
increaseViewportBy={{ top: 300, bottom: 300 }}
|
||||
overscan={500}
|
||||
@ -434,6 +454,7 @@ const Proxies: React.FC = () => {
|
||||
allProxies[groupIndex][innerIndex * cols + i]?.name ===
|
||||
groups[groupIndex].now
|
||||
}
|
||||
isGroupTesting={!!proxyDelaying[allProxies[groupIndex][innerIndex * cols + i].name]}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user