mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-13 05:20:28 +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'
|
||||
import { Box, Typography, alpha, useTheme } from '@mui/material'
|
||||
import { useLockFn } from 'ahooks'
|
||||
import React, { useCallback, useRef } from 'react'
|
||||
import React, { useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { DialogRef, Switch, TooltipIcon } from '@/components/base'
|
||||
import { GuardState } from '@/components/setting/mods/guard-state'
|
||||
import { SysproxyViewer } from '@/components/setting/mods/sysproxy-viewer'
|
||||
import { TunViewer } from '@/components/setting/mods/tun-viewer'
|
||||
import { useServiceInstaller } from '@/hooks/use-service-installer'
|
||||
@ -42,6 +41,7 @@ interface SwitchRowProps {
|
||||
|
||||
/**
|
||||
* 抽取的子组件:统一的开关 UI
|
||||
* active = 真实状态OS/配置 乐观更新
|
||||
*/
|
||||
const SwitchRow = ({
|
||||
label,
|
||||
@ -55,6 +55,24 @@ const SwitchRow = ({
|
||||
highlight,
|
||||
}: SwitchRowProps) => {
|
||||
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 (
|
||||
<Box
|
||||
sx={{
|
||||
@ -92,15 +110,12 @@ const SwitchRow = ({
|
||||
{extraIcons}
|
||||
</Box>
|
||||
|
||||
<GuardState
|
||||
value={active}
|
||||
valueProps="checked"
|
||||
onCatch={onError}
|
||||
onFormat={(_, v) => v}
|
||||
onGuard={onToggle}
|
||||
>
|
||||
<Switch edge="end" disabled={disabled} />
|
||||
</GuardState>
|
||||
<Switch
|
||||
edge="end"
|
||||
disabled={disabled}
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useLockFn } from 'ahooks'
|
||||
import { useRef } from 'react'
|
||||
import useSWR, { mutate } from 'swr'
|
||||
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 () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, enabled ? 20 : 10))
|
||||
await mutate('getSystemProxy')
|
||||
await mutate('getAutotemProxy')
|
||||
}
|
||||
const toggleSystemProxy = async (enabled: boolean) => {
|
||||
mutateVerge({ ...verge, enable_system_proxy: enabled }, false)
|
||||
pendingRef.current = enabled
|
||||
|
||||
if (busyRef.current) return
|
||||
busyRef.current = true
|
||||
|
||||
try {
|
||||
if (!enabled && verge?.auto_close_connection) {
|
||||
await closeAllConnections()
|
||||
while (pendingRef.current !== null) {
|
||||
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 })
|
||||
await updateProxyStatus()
|
||||
} catch (error) {
|
||||
console.warn('[useSystemProxyState] toggleSystemProxy failed:', error)
|
||||
mutateVerge({ ...verge, enable_system_proxy: !enabled }, false)
|
||||
await updateProxyStatus()
|
||||
throw error
|
||||
} finally {
|
||||
busyRef.current = false
|
||||
await Promise.all([mutate('getSystemProxy'), mutate('getAutotemProxy')])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
indicator,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user