import { BuildRounded, DeleteForeverRounded, PauseCircleOutlineRounded, PlayCircleOutlineRounded, SettingsRounded, WarningRounded, } from "@mui/icons-material"; import { Box, Typography, alpha, useTheme } from "@mui/material"; import { useLockFn } from "ahooks"; import React, { useCallback, useRef } from "react"; import { useTranslation } from "react-i18next"; import { DialogRef, Switch } from "@/components/base"; import { TooltipIcon } from "@/components/base/base-tooltip-icon"; 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 { useSystemProxyState } from "@/hooks/use-system-proxy-state"; import { useSystemState } from "@/hooks/use-system-state"; import { useVerge } from "@/hooks/use-verge"; import { useServiceInstaller } from "@/hooks/useServiceInstaller"; import { useServiceUninstaller } from "@/hooks/useServiceUninstaller"; import { showNotice } from "@/services/noticeService"; interface ProxySwitchProps { label?: string; onError?: (err: Error) => void; noRightPadding?: boolean; } interface SwitchRowProps { label: string; active: boolean; disabled?: boolean; infoTitle: string; onInfoClick?: () => void; extraIcons?: React.ReactNode; onToggle: (value: boolean) => Promise; onError?: (err: Error) => void; highlight?: boolean; } /** * 抽取的子组件:统一的开关 UI */ const SwitchRow = ({ label, active, disabled, infoTitle, onInfoClick, extraIcons, onToggle, onError, highlight, }: SwitchRowProps) => { const theme = useTheme(); return ( {active ? ( ) : ( )} {label} {extraIcons} v} onGuard={onToggle} > ); }; const ProxyControlSwitches = ({ label, onError, noRightPadding = false, }: ProxySwitchProps) => { const { t } = useTranslation(); const { verge, mutateVerge, patchVerge } = useVerge(); const { installServiceAndRestartCore } = useServiceInstaller(); const { uninstallServiceAndRestartCore } = useServiceUninstaller(); const { actualState: systemProxyActualState, toggleSystemProxy } = useSystemProxyState(); const { isServiceMode, isTunModeAvailable, mutateRunningMode, mutateServiceOk, mutateTunModeAvailable, } = useSystemState(); const sysproxyRef = useRef(null); const tunRef = useRef(null); const { enable_tun_mode, enable_system_proxy } = verge ?? {}; const showErrorNotice = useCallback( (msg: string) => showNotice("error", t(msg)), [t], ); const handleTunToggle = async (value: boolean) => { if (!isTunModeAvailable) { const msg = "TUN requires Service Mode or Admin Mode"; showErrorNotice(msg); throw new Error(t(msg)); } mutateVerge({ ...verge, enable_tun_mode: value }, false); await patchVerge({ enable_tun_mode: value }); }; const onInstallService = useLockFn(async () => { try { await installServiceAndRestartCore(); await mutateRunningMode(); await mutateServiceOk(); await mutateTunModeAvailable(); } catch (err) { showNotice("error", (err as Error).message || String(err)); } }); const onUninstallService = useLockFn(async () => { try { await handleTunToggle(false); await uninstallServiceAndRestartCore(); await mutateRunningMode(); await mutateServiceOk(); await mutateTunModeAvailable(); } catch (err) { showNotice("error", (err as Error).message || String(err)); } }); const isSystemProxyMode = label === t("System Proxy") || !label; const isTunMode = label === t("Tun Mode"); return ( {isSystemProxyMode && ( sysproxyRef.current?.open()} onToggle={(value) => toggleSystemProxy(value)} onError={onError} highlight={enable_system_proxy} /> )} {isTunMode && ( tunRef.current?.open()} onToggle={handleTunToggle} onError={onError} disabled={!isTunModeAvailable} highlight={enable_tun_mode || false} extraIcons={ <> {!isTunModeAvailable && ( )} {!isTunModeAvailable && ( )} {isServiceMode && ( )} } /> )} ); }; export default ProxyControlSwitches;