feat: add animation during latency testing for better user feedback

This commit is contained in:
ezequielnick 2025-06-06 19:29:49 +08:00
parent d6e456302e
commit 0b8c77d200
2 changed files with 38 additions and 12 deletions

View File

@ -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)}

View File

@ -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]}
/>
)
})}