import { BaseDialog, DialogRef } from "@/components/base"; import { useClashInfo } from "@/hooks/use-clash"; import { patchClashConfig } from "@/services/cmds"; import { showNotice } from "@/services/noticeService"; import { ContentCopy } from "@mui/icons-material"; import { Alert, Box, CircularProgress, IconButton, List, ListItem, ListItemText, Snackbar, TextField, Tooltip, } from "@mui/material"; import { useLockFn } from "ahooks"; import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; import { useTranslation } from "react-i18next"; export const ControllerViewer = forwardRef((props, ref) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); const [copySuccess, setCopySuccess] = useState(null); const [isSaving, setIsSaving] = useState(false); const { clashInfo, patchInfo } = useClashInfo(); const [controller, setController] = useState(clashInfo?.server || ""); const [secret, setSecret] = useState(clashInfo?.secret || ""); // 对话框打开时初始化配置 useImperativeHandle(ref, () => ({ open: async () => { setOpen(true); setController(clashInfo?.server || ""); setSecret(clashInfo?.secret || ""); }, close: () => setOpen(false), })); // 保存配置 const onSave = useLockFn(async () => { if (!controller.trim()) { showNotice("error", t("Controller address cannot be empty"), 3000); return; } if (!secret.trim()) { showNotice("error", t("Secret cannot be empty"), 3000); return; } try { setIsSaving(true); await patchInfo({ "external-controller": controller, secret }); showNotice("success", t("Configuration saved successfully"), 2000); setOpen(false); } catch (err: any) { showNotice( "error", err.message || t("Failed to save configuration"), 4000, ); } finally { setIsSaving(false); } }); // 复制到剪贴板 const handleCopyToClipboard = useLockFn( async (text: string, type: string) => { try { await navigator.clipboard.writeText(text); setCopySuccess(type); setTimeout(() => setCopySuccess(null), 2000); } catch (err) { showNotice("error", t("Failed to copy"), 2000); } }, ); return ( {t("Saving...")} ) : ( t("Save") ) } cancelBtn={t("Cancel")} onClose={() => setOpen(false)} onCancel={() => setOpen(false)} onOk={onSave} > setController(e.target.value)} disabled={isSaving} /> handleCopyToClipboard(controller, "controller")} color="primary" disabled={isSaving} > setSecret(e.target.value)} disabled={isSaving} /> handleCopyToClipboard(secret, "secret")} color="primary" disabled={isSaving} > {copySuccess === "controller" ? t("Controller address copied to clipboard") : t("Secret copied to clipboard")} ); });