mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-18 08:21:34 +08:00
feat: use optimistic updates for system proxy toggle
This commit is contained in:
parent
b69a97a7c1
commit
56141e6dfa
@ -8,11 +8,10 @@ import {
|
|||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import { Box, Typography, alpha, useTheme } from '@mui/material'
|
import { Box, Typography, alpha, useTheme } from '@mui/material'
|
||||||
import { useLockFn } from 'ahooks'
|
import { useLockFn } from 'ahooks'
|
||||||
import React, { useCallback, useRef } from 'react'
|
import React, { useCallback, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { DialogRef, Switch, TooltipIcon } from '@/components/base'
|
import { DialogRef, Switch, TooltipIcon } from '@/components/base'
|
||||||
import { GuardState } from '@/components/setting/mods/guard-state'
|
|
||||||
import { SysproxyViewer } from '@/components/setting/mods/sysproxy-viewer'
|
import { SysproxyViewer } from '@/components/setting/mods/sysproxy-viewer'
|
||||||
import { TunViewer } from '@/components/setting/mods/tun-viewer'
|
import { TunViewer } from '@/components/setting/mods/tun-viewer'
|
||||||
import { useServiceInstaller } from '@/hooks/use-service-installer'
|
import { useServiceInstaller } from '@/hooks/use-service-installer'
|
||||||
@ -42,6 +41,7 @@ interface SwitchRowProps {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 抽取的子组件:统一的开关 UI
|
* 抽取的子组件:统一的开关 UI
|
||||||
|
* active = 真实状态OS/配置 乐观更新
|
||||||
*/
|
*/
|
||||||
const SwitchRow = ({
|
const SwitchRow = ({
|
||||||
label,
|
label,
|
||||||
@ -55,6 +55,24 @@ const SwitchRow = ({
|
|||||||
highlight,
|
highlight,
|
||||||
}: SwitchRowProps) => {
|
}: SwitchRowProps) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const [checked, setChecked] = useState(active)
|
||||||
|
const pendingRef = useRef(false)
|
||||||
|
|
||||||
|
if (pendingRef.current) {
|
||||||
|
if (active === checked) pendingRef.current = false
|
||||||
|
} else if (checked !== active) {
|
||||||
|
setChecked(active)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = (_: React.ChangeEvent, value: boolean) => {
|
||||||
|
pendingRef.current = true
|
||||||
|
setChecked(value)
|
||||||
|
onToggle(value).catch((err: any) => {
|
||||||
|
pendingRef.current = false
|
||||||
|
onError?.(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -92,15 +110,12 @@ const SwitchRow = ({
|
|||||||
{extraIcons}
|
{extraIcons}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<GuardState
|
<Switch
|
||||||
value={active}
|
edge="end"
|
||||||
valueProps="checked"
|
disabled={disabled}
|
||||||
onCatch={onError}
|
checked={checked}
|
||||||
onFormat={(_, v) => v}
|
onChange={handleChange}
|
||||||
onGuard={onToggle}
|
/>
|
||||||
>
|
|
||||||
<Switch edge="end" disabled={disabled} />
|
|
||||||
</GuardState>
|
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useLockFn } from 'ahooks'
|
import { useRef } from 'react'
|
||||||
import useSWR, { mutate } from 'swr'
|
import useSWR, { mutate } from 'swr'
|
||||||
import { closeAllConnections } from 'tauri-plugin-mihomo-api'
|
import { closeAllConnections } from 'tauri-plugin-mihomo-api'
|
||||||
|
|
||||||
@ -36,28 +36,31 @@ export const useSystemProxyState = () => {
|
|||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
|
||||||
const toggleSystemProxy = useLockFn(async (enabled: boolean) => {
|
// "最后一次生效"模式:快速连续点击时,只执行最终状态
|
||||||
mutateVerge({ ...verge, enable_system_proxy: enabled }, false)
|
const pendingRef = useRef<boolean | null>(null)
|
||||||
|
const busyRef = useRef(false)
|
||||||
|
|
||||||
const updateProxyStatus = async () => {
|
const toggleSystemProxy = async (enabled: boolean) => {
|
||||||
await new Promise((resolve) => setTimeout(resolve, enabled ? 20 : 10))
|
mutateVerge({ ...verge, enable_system_proxy: enabled }, false)
|
||||||
await mutate('getSystemProxy')
|
pendingRef.current = enabled
|
||||||
await mutate('getAutotemProxy')
|
|
||||||
}
|
if (busyRef.current) return
|
||||||
|
busyRef.current = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!enabled && verge?.auto_close_connection) {
|
while (pendingRef.current !== null) {
|
||||||
await closeAllConnections()
|
const target = pendingRef.current
|
||||||
|
pendingRef.current = null
|
||||||
|
if (!target && verge?.auto_close_connection) {
|
||||||
|
await closeAllConnections().catch(() => {})
|
||||||
|
}
|
||||||
|
await patchVerge({ enable_system_proxy: target })
|
||||||
}
|
}
|
||||||
await patchVerge({ enable_system_proxy: enabled })
|
} finally {
|
||||||
await updateProxyStatus()
|
busyRef.current = false
|
||||||
} catch (error) {
|
await Promise.all([mutate('getSystemProxy'), mutate('getAutotemProxy')])
|
||||||
console.warn('[useSystemProxyState] toggleSystemProxy failed:', error)
|
|
||||||
mutateVerge({ ...verge, enable_system_proxy: !enabled }, false)
|
|
||||||
await updateProxyStatus()
|
|
||||||
throw error
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
indicator,
|
indicator,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user