diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 70b7d128f58e5a9124c4b14755cddcbdb8ca4661..bf1e852ca66d4eae293c3e5e130df1df4eb42d0d 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -125,6 +125,23 @@ pub fn change_profile_chain( wrap_err!(clash.activate_enhanced(&profiles, false, false)) } +/// change the profile valid fields +#[tauri::command] +pub fn change_profile_valid( + valid: Option<Vec<String>>, + app_handle: tauri::AppHandle, + clash_state: State<'_, ClashState>, + profiles_state: State<'_, ProfilesState>, +) -> Result<(), String> { + let mut clash = clash_state.0.lock().unwrap(); + let mut profiles = profiles_state.0.lock().unwrap(); + + profiles.put_valid(valid); + clash.set_window(app_handle.get_window("main")); + + wrap_err!(clash.activate_enhanced(&profiles, false, false)) +} + /// manually exec enhanced profile #[tauri::command] pub fn enhance_profiles( diff --git a/src-tauri/src/core/profiles.rs b/src-tauri/src/core/profiles.rs index 075a5846f781a12891bf08ea3ba45bda95dd7137..c84eb717ec1a4d2edd49f308b2065c89c04e49f7 100644 --- a/src-tauri/src/core/profiles.rs +++ b/src-tauri/src/core/profiles.rs @@ -316,6 +316,9 @@ pub struct Profiles { /// same as PrfConfig.chain chain: Option<Vec<String>>, + /// record valid fields for clash + valid: Option<Vec<String>>, + /// profile list items: Option<Vec<PrfItem>>, } @@ -399,6 +402,11 @@ impl Profiles { self.chain = chain; } + /// just change the `field` + pub fn put_valid(&mut self, valid: Option<Vec<String>>) { + self.valid = valid; + } + /// find the item by the uid pub fn get_item(&self, uid: &String) -> Result<&PrfItem> { if self.items.is_some() { @@ -599,9 +607,12 @@ impl Profiles { None => vec![], }; + let valid = self.valid.clone().unwrap_or(vec![]); + Ok(PrfEnhanced { current, chain, + valid, callback, }) } @@ -613,6 +624,8 @@ pub struct PrfEnhanced { pub chain: Vec<PrfData>, + pub valid: Vec<String>, + pub callback: String, } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index cada75fbfc03028b03712f7388b379edfff928de..6e401b3174258d2787013f8b6847607a19bb4f0e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -119,6 +119,7 @@ fn main() -> std::io::Result<()> { cmds::sync_profiles, cmds::enhance_profiles, cmds::change_profile_chain, + cmds::change_profile_valid, cmds::read_profile_file, cmds::save_profile_file ]); diff --git a/src/components/profile/enhanced.tsx b/src/components/profile/enhanced.tsx index dc603c30832722a08d9f2c7a13c2f3b9430366a4..2a5ab6a6722edaa9ab1d913656ec61ffef31accb 100644 --- a/src/components/profile/enhanced.tsx +++ b/src/components/profile/enhanced.tsx @@ -1,26 +1,49 @@ import useSWR from "swr"; +import { useState } from "react"; import { useLockFn } from "ahooks"; -import { Box, Grid, IconButton, Stack } from "@mui/material"; -import { RestartAltRounded } from "@mui/icons-material"; +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 Notice from "../base/base-notice"; +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 { mutate } = useSWR("getProfiles", getProfiles); + const { data, mutate } = useSWR("getProfiles", getProfiles); + const valid = data?.valid || []; + + const [anchorEl, setAnchorEl] = useState<any>(null); // handler const onEnhance = useLockFn(async () => { @@ -74,6 +97,19 @@ const EnhancedMode = (props: Props) => { 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 ( <Box sx={{ mt: 4 }}> <Stack @@ -92,9 +128,74 @@ const EnhancedMode = (props: Props) => { <RestartAltRounded /> </IconButton> - {/* <IconButton size="small" color="inherit"> + <IconButton + size="small" + color="inherit" + id="profile-use-button" + title="enable clash fields" + aria-controls={!!anchorEl ? "profile-use-menu" : undefined} + aria-haspopup="true" + aria-expanded={!!anchorEl ? "true" : undefined} + onClick={(e) => setAnchorEl(e.currentTarget)} + > <MenuRounded /> - </IconButton> */} + </IconButton> + + <Menu + id="profile-use-menu" + open={!!anchorEl} + anchorEl={anchorEl} + onClose={() => setAnchorEl(null)} + transitionDuration={225} + TransitionProps={ + OS === "macos" ? { style: { transitionDuration: "225ms" } } : {} + } + MenuListProps={{ + dense: true, + "aria-labelledby": "profile-use-button", + }} + onContextMenu={(e) => { + setAnchorEl(null); + e.preventDefault(); + }} + > + <MenuItem> + <ListItemIcon color="inherit"> + <AddchartRounded /> + </ListItemIcon> + Use Clash Fields + </MenuItem> + + <Divider /> + + {[ + "tun", + "dns", + "hosts", + "script", + "profile", + "payload", + "interface-name", + "routing-mark", + ].map((key) => { + const has = valid.includes(key); + + return ( + <MenuItem + key={key} + sx={{ width: 180 }} + onClick={() => onToggleValid(key)} + > + {has && ( + <ListItemIcon color="inherit"> + <CheckRounded /> + </ListItemIcon> + )} + <ListItemText inset={!has}>{key}</ListItemText> + </MenuItem> + ); + })} + </Menu> </Stack> <Grid container spacing={2}> diff --git a/src/services/cmds.ts b/src/services/cmds.ts index cf4729566bd6461c0f14d83fc197f96eb96dff1e..bc4555e8ca9f67c6e5ecb2ae9f61a3e829376464 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -66,6 +66,10 @@ export async function changeProfileChain(chain?: string[]) { return invoke<void>("change_profile_chain", { chain }); } +export async function changeProfileValid(valid?: string[]) { + return invoke<void>("change_profile_valid", { valid }); +} + export async function getClashInfo() { return invoke<CmdType.ClashInfo | null>("get_clash_info"); } diff --git a/src/services/enhance.ts b/src/services/enhance.ts index ee746d35f7ceb80be6c7dff7727be234a259b8ba..a1ebf5a765ae62040a28bc41fe2604febd7d9891 100644 --- a/src/services/enhance.ts +++ b/src/services/enhance.ts @@ -145,11 +145,12 @@ class Enhance { // enhanced mode runner private async runner(payload: CmdType.EnhancedPayload) { const chain = payload.chain || []; + const valid = payload.valid || []; if (!Array.isArray(chain)) throw new Error("unhandle error"); let pdata = payload.current || {}; - let useList = [] as string[]; + let useList = valid; for (const each of chain) { const { uid, type = "" } = each.item; diff --git a/src/services/types.ts b/src/services/types.ts index 0d5bf3c608ceeaea2dd467e53de788515be4afe5..50b81fc3d21443e547fa765345937bdbca2acc43 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -116,6 +116,7 @@ export namespace CmdType { export interface ProfilesConfig { current?: string; chain?: string[]; + valid?: string[]; items?: ProfileItem[]; } @@ -191,6 +192,7 @@ export namespace CmdType { export interface EnhancedPayload { chain: ChainItem[]; + valid: string[]; current: ProfileData; callback: string; }