import useSWR from "swr"; import { useState } from "react"; import { useLockFn } from "ahooks"; import { Box, Divider, Grid, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, Stack, } from "@mui/material"; import { AddchartRounded, CheckRounded, MenuRounded, RestartAltRounded, } from "@mui/icons-material"; import { getProfiles, deleteProfile, enhanceProfiles, changeProfileChain, changeProfileValid, } from "../../services/cmds"; import { CmdType } from "../../services/types"; import getSystem from "../../utils/get-system"; import ProfileMore from "./profile-more"; import Notice from "../base/base-notice"; interface Props { items: CmdType.ProfileItem[]; chain: string[]; } const OS = getSystem(); const EnhancedMode = (props: Props) => { const { items, chain } = props; const { data, mutate } = useSWR("getProfiles", getProfiles); const valid = data?.valid || []; const [anchorEl, setAnchorEl] = useState(null); // handler const onEnhance = useLockFn(async () => { try { await enhanceProfiles(); Notice.success("Refresh clash config", 2000); } catch (err: any) { Notice.error(err.message || err.toString()); } }); const onEnhanceEnable = useLockFn(async (uid: string) => { if (chain.includes(uid)) return; const newChain = [...chain, uid]; await changeProfileChain(newChain); mutate((conf = {}) => ({ ...conf, chain: newChain }), true); }); const onEnhanceDisable = useLockFn(async (uid: string) => { if (!chain.includes(uid)) return; const newChain = chain.filter((i) => i !== uid); await changeProfileChain(newChain); mutate((conf = {}) => ({ ...conf, chain: newChain }), true); }); const onEnhanceDelete = useLockFn(async (uid: string) => { try { await onEnhanceDisable(uid); await deleteProfile(uid); mutate(); } catch (err: any) { Notice.error(err?.message || err.toString()); } }); const onMoveTop = useLockFn(async (uid: string) => { if (!chain.includes(uid)) return; const newChain = [uid].concat(chain.filter((i) => i !== uid)); await changeProfileChain(newChain); mutate((conf = {}) => ({ ...conf, chain: newChain }), true); }); const onMoveEnd = useLockFn(async (uid: string) => { if (!chain.includes(uid)) return; const newChain = chain.filter((i) => i !== uid).concat([uid]); await changeProfileChain(newChain); mutate((conf = {}) => ({ ...conf, chain: newChain }), true); }); // update valid list const onToggleValid = useLockFn(async (key: string) => { try { const newValid = valid.includes(key) ? valid.filter((i) => i !== key) : valid.concat(key); await changeProfileValid(newValid); mutate(); } catch (err: any) { Notice.error(err.message || err.toString()); } }); return ( setAnchorEl(e.currentTarget)} > setAnchorEl(null)} transitionDuration={225} TransitionProps={ OS === "macos" ? { style: { transitionDuration: "225ms" } } : {} } MenuListProps={{ dense: true, "aria-labelledby": "profile-use-button", }} onContextMenu={(e) => { setAnchorEl(null); e.preventDefault(); }} > Use Clash Fields {[ "tun", "dns", "hosts", "script", "profile", "payload", "interface-name", "routing-mark", ].map((key) => { const has = valid.includes(key); return ( onToggleValid(key)} > {has && ( )} {key} ); })} {items.map((item) => ( onEnhanceEnable(item.uid)} onDisable={() => onEnhanceDisable(item.uid)} onDelete={() => onEnhanceDelete(item.uid)} onMoveTop={() => onMoveTop(item.uid)} onMoveEnd={() => onMoveEnd(item.uid)} /> ))} ); }; export default EnhancedMode;