From 4ce376f8307d345d515b657502143082dd0820ae Mon Sep 17 00:00:00 2001 From: wonfen Date: Tue, 15 Apr 2025 21:16:13 +0800 Subject: [PATCH] feat: add External Controller toggle switch --- .../setting/mods/controller-viewer.tsx | 43 ++++++++++-- src/components/setting/mods/dns-viewer.tsx | 6 +- src/components/setting/setting-clash.tsx | 70 +++++++++++++++++-- src/locales/ar.json | 2 +- src/locales/en.json | 12 ++-- src/locales/fa.json | 2 +- src/locales/id.json | 4 +- src/locales/ru.json | 10 +-- src/locales/tt.json | 4 +- src/locales/zh.json | 14 ++-- src/services/types.d.ts | 1 + 11 files changed, 134 insertions(+), 34 deletions(-) diff --git a/src/components/setting/mods/controller-viewer.tsx b/src/components/setting/mods/controller-viewer.tsx index a52018cb..dfb50679 100644 --- a/src/components/setting/mods/controller-viewer.tsx +++ b/src/components/setting/mods/controller-viewer.tsx @@ -1,32 +1,53 @@ -import { forwardRef, useImperativeHandle, useState } from "react"; +import { forwardRef, useImperativeHandle, useState, useEffect } from "react"; import { useLockFn } from "ahooks"; import { useTranslation } from "react-i18next"; -import { List, ListItem, ListItemText, TextField } from "@mui/material"; +import { List, ListItem, ListItemText, TextField, Typography, Box } from "@mui/material"; import { useClashInfo } from "@/hooks/use-clash"; -import { BaseDialog, DialogRef, Notice } from "@/components/base"; +import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base"; +import { useVerge } from "@/hooks/use-verge"; export const ControllerViewer = forwardRef((props, ref) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); const { clashInfo, patchInfo } = useClashInfo(); + const { verge, patchVerge } = useVerge(); const [controller, setController] = useState(clashInfo?.server || ""); const [secret, setSecret] = useState(clashInfo?.secret || ""); + + // 获取外部控制器开关状态 + const [enableController, setEnableController] = useState(() => { + const savedState = localStorage.getItem("enable_external_controller"); + if (savedState !== null) { + return savedState === "true"; + } + return verge?.enable_external_controller ?? true; + }); useImperativeHandle(ref, () => ({ open: () => { setOpen(true); setController(clashInfo?.server || ""); setSecret(clashInfo?.secret || ""); + // 从localStorage更新开关状态 + const savedState = localStorage.getItem("enable_external_controller"); + if (savedState !== null) { + setEnableController(savedState === "true"); + } else { + setEnableController(verge?.enable_external_controller ?? true); + } }, close: () => setOpen(false), })); const onSave = useLockFn(async () => { try { - await patchInfo({ "external-controller": controller, secret }); - Notice.success(t("External Controller Address Modified"), 1000); + // 只有在启用外部控制器时才更新配置 + if (enableController) { + await patchInfo({ "external-controller": controller, secret }); + } + Notice.success(t("External Controller Settings Saved"), 1000); setOpen(false); } catch (err: any) { Notice.error(err.message || err.toString(), 4000); @@ -44,9 +65,17 @@ export const ControllerViewer = forwardRef((props, ref) => { onCancel={() => setOpen(false)} onOk={onSave} > + + + {enableController + ? t("External controller is enabled info") + : t("External controller is disabled info")} + + + - + ((props, ref) => { value={controller} placeholder="Required" onChange={(e) => setController(e.target.value)} + disabled={!enableController} /> @@ -68,6 +98,7 @@ export const ControllerViewer = forwardRef((props, ref) => { onChange={(e) => setSecret(e.target.value?.replace(/[^\x00-\x7F]/g, "")) } + disabled={!enableController} /> diff --git a/src/components/setting/mods/dns-viewer.tsx b/src/components/setting/mods/dns-viewer.tsx index be41e3be..ef342e18 100644 --- a/src/components/setting/mods/dns-viewer.tsx +++ b/src/components/setting/mods/dns-viewer.tsx @@ -701,7 +701,7 @@ export const DnsViewer = forwardRef((props, ref) => { ((props, ref) => { ((props, ref) => { { const { clash, version, mutateClash, patchClash } = useClash(); const { verge, mutateVerge, patchVerge } = useVerge(); + const { clashInfo, patchInfo } = useClashInfo(); const { ipv6, @@ -58,6 +59,15 @@ const SettingClash = ({ onError }: Props) => { return verge?.enable_dns_settings ?? false; }); + // 添加外部控制器开关状态 + const [enableController, setEnableController] = useState(() => { + const savedState = localStorage.getItem("enable_external_controller"); + if (savedState !== null) { + return savedState === "true"; + } + return verge?.enable_external_controller ?? true; + }); + const { addListener } = useListen(); const webRef = useRef(null); @@ -108,6 +118,26 @@ const SettingClash = ({ onError }: Props) => { } }); + // 处理外部控制器开关状态变化 + const handleControllerToggle = useLockFn(async (enable: boolean) => { + try { + setEnableController(enable); + localStorage.setItem("enable_external_controller", String(enable)); + await patchVerge({ enable_external_controller: enable }); + if (!enable) { + await patchInfo({ "external-controller": "", secret: "" }); + } else { + // 如果开启,恢复默认值或之前的值 + const server = clashInfo?.server || "127.0.0.1:9097"; + await patchInfo({ "external-controller": server, secret: clashInfo?.secret || "" }); + } + } catch (err: any) { + setEnableController(!enable); + localStorage.setItem("enable_external_controller", String(!enable)); + Notice.error(err.message || err.toString()); + } + }); + return ( @@ -248,11 +278,41 @@ const SettingClash = ({ onError }: Props) => { ctrlRef.current?.open()} - label={t("External")} - /> + label={t("External Controller")} + extra={ + ctrlRef.current?.open()} + /> + } + > + handleControllerToggle(checked)} + /> + - webRef.current?.open()} label={t("Web UI")} /> + webRef.current?.open() : undefined} + label={ + + {t("Web UI")} + + } + extra={ + !enableController && ( + + ) + } + />