Files
clash-verge-rev/src/components/layout/layout-traffic.tsx
T
Tunglies b1eb011050 refactor(ui): extract useProxyDelayState hook and tighten types
- Extract shared delay state logic from ProxyItem and ProxyItemMini
  into `useProxyDelayState` hook (src/hooks/use-proxy-delay-state.ts);
  JSX display thresholds preserved per-component.
- Deduplicate rAF/setTimeout/Promise scheduling in DelayManager via
  a private `scheduleOnNextFrame` helper.
- Drop no-op `useMemo(() => MODES, [])` in proxies page.
- Replace `any` on `setClashLog` prev params and layout-traffic sx
  objects with proper types (`pre!`, `Pick<BoxProps|...>`).
2026-04-19 17:25:57 +08:00

154 lines
4.6 KiB
TypeScript

import {
ArrowDownwardRounded,
ArrowUpwardRounded,
MemoryRounded,
} from '@mui/icons-material'
import { Box, Typography } from '@mui/material'
import type { BoxProps, SvgIconProps, TypographyProps } from '@mui/material'
import { useEffect, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { LightweightTrafficErrorBoundary } from '@/components/shared/traffic-error-boundary'
import { useMemoryData } from '@/hooks/use-memory-data'
import { useTrafficData } from '@/hooks/use-traffic-data'
import { useVerge } from '@/hooks/use-verge'
import { useVisibility } from '@/hooks/use-visibility'
import parseTraffic from '@/utils/parse-traffic'
import { TrafficGraph, type TrafficRef } from './traffic-graph'
// setup the traffic
export const LayoutTraffic = () => {
const { t } = useTranslation()
const { verge } = useVerge()
// whether hide traffic graph
const trafficGraph = verge?.traffic_graph ?? true
const trafficRef = useRef<TrafficRef>(null)
const pageVisible = useVisibility()
const {
response: { data: traffic },
} = useTrafficData({ enabled: trafficGraph && pageVisible })
const {
response: { data: memory },
} = useMemoryData()
// 监听数据变化,为图表添加数据点
useEffect(() => {
if (trafficRef.current) {
trafficRef.current.appendData({
up: traffic?.up || 0,
down: traffic?.down || 0,
})
}
}, [traffic])
// 显示内存使用情况的设置
const displayMemory = verge?.enable_memory_usage ?? true
// 使用parseTraffic统一处理转换,保持与首页一致的显示格式
const [up, upUnit] = parseTraffic(traffic?.up || 0)
const [down, downUnit] = parseTraffic(traffic?.down || 0)
const [inuse, inuseUnit] = parseTraffic(memory?.inuse || 0)
const boxStyle: Pick<BoxProps, 'sx'> = {
sx: {
display: 'flex',
alignItems: 'center',
whiteSpace: 'nowrap',
},
}
const iconStyle: Pick<SvgIconProps, 'sx'> = {
sx: { mr: '8px', fontSize: 16 },
}
const valStyle: Pick<TypographyProps, 'component' | 'sx'> = {
component: 'span',
sx: { flex: '1 1 56px', userSelect: 'none', textAlign: 'center' },
}
const unitStyle: Pick<TypographyProps, 'component' | 'color' | 'sx'> = {
component: 'span',
color: 'grey.500',
sx: {
flex: '0 1 27px',
userSelect: 'none',
fontSize: '12px',
textAlign: 'right',
},
}
return (
<LightweightTrafficErrorBoundary>
<Box sx={{ position: 'relative' }}>
{trafficGraph && pageVisible && (
<div
style={{ width: '100%', height: 60, marginBottom: 6 }}
onClick={trafficRef.current?.toggleStyle}
>
<TrafficGraph ref={trafficRef} />
</div>
)}
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.75 }}>
<Box
title={`${t('home.components.traffic.metrics.uploadSpeed')}`}
{...boxStyle}
sx={{
...boxStyle.sx,
// opacity: traffic?.is_fresh ? 1 : 0.6,
}}
>
<ArrowUpwardRounded
{...iconStyle}
color={(traffic?.up || 0) > 0 ? 'secondary' : 'disabled'}
/>
<Typography {...valStyle} color="secondary">
{up}
</Typography>
<Typography {...unitStyle}>{upUnit}/s</Typography>
</Box>
<Box
title={`${t('home.components.traffic.metrics.downloadSpeed')}`}
{...boxStyle}
sx={{
...boxStyle.sx,
// opacity: traffic?.is_fresh ? 1 : 0.6,
}}
>
<ArrowDownwardRounded
{...iconStyle}
color={(traffic?.down || 0) > 0 ? 'primary' : 'disabled'}
/>
<Typography {...valStyle} color="primary">
{down}
</Typography>
<Typography {...unitStyle}>{downUnit}/s</Typography>
</Box>
{displayMemory && (
<Box
title={`${t('home.components.traffic.metrics.memoryUsage')} `}
{...boxStyle}
sx={{
...boxStyle.sx,
cursor: 'auto',
// opacity: memory?.is_fresh ? 1 : 0.6,
}}
color={'disabled'}
onClick={async () => {
// isDebug && (await gc());
}}
>
<MemoryRounded {...iconStyle} />
<Typography {...valStyle}>{inuse}</Typography>
<Typography {...unitStyle}>{inuseUnit}</Typography>
</Box>
)}
</Box>
</Box>
</LightweightTrafficErrorBoundary>
)
}