setting-clash.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import { useRef } from "react";
  2. import { useTranslation } from "react-i18next";
  3. import { useLockFn } from "ahooks";
  4. import {
  5. TextField,
  6. Switch,
  7. Select,
  8. MenuItem,
  9. Typography,
  10. IconButton,
  11. Tooltip,
  12. } from "@mui/material";
  13. import { ArrowForward, Settings, Shuffle } from "@mui/icons-material";
  14. import { DialogRef, Notice } from "@/components/base";
  15. import { useClash } from "@/hooks/use-clash";
  16. import { GuardState } from "./mods/guard-state";
  17. import { WebUIViewer } from "./mods/web-ui-viewer";
  18. import { ClashPortViewer } from "./mods/clash-port-viewer";
  19. import { ControllerViewer } from "./mods/controller-viewer";
  20. import { SettingList, SettingItem } from "./mods/setting-comp";
  21. import { ClashCoreViewer } from "./mods/clash-core-viewer";
  22. import { invoke_uwp_tool } from "@/services/cmds";
  23. import getSystem from "@/utils/get-system";
  24. import { useVerge } from "@/hooks/use-verge";
  25. import { updateGeoData } from "@/services/api";
  26. const isWIN = getSystem() === "windows";
  27. interface Props {
  28. onError: (err: Error) => void;
  29. }
  30. const SettingClash = ({ onError }: Props) => {
  31. const { t } = useTranslation();
  32. const { clash, version, mutateClash, patchClash } = useClash();
  33. const { verge, mutateVerge, patchVerge } = useVerge();
  34. const { ipv6, "allow-lan": allowLan, "log-level": logLevel } = clash ?? {};
  35. const { enable_random_port = false, verge_mixed_port } = verge ?? {};
  36. const webRef = useRef<DialogRef>(null);
  37. const portRef = useRef<DialogRef>(null);
  38. const ctrlRef = useRef<DialogRef>(null);
  39. const coreRef = useRef<DialogRef>(null);
  40. const onSwitchFormat = (_e: any, value: boolean) => value;
  41. const onChangeData = (patch: Partial<IConfigData>) => {
  42. mutateClash((old) => ({ ...(old! || {}), ...patch }), false);
  43. };
  44. const onChangeVerge = (patch: Partial<IVergeConfig>) => {
  45. mutateVerge({ ...verge, ...patch }, false);
  46. };
  47. const onUpdateGeo = useLockFn(async () => {
  48. try {
  49. await updateGeoData();
  50. Notice.success("Start update geodata");
  51. } catch (err: any) {
  52. Notice.error(err?.response.data.message || err.toString());
  53. }
  54. });
  55. return (
  56. <SettingList title={t("Clash Setting")}>
  57. <WebUIViewer ref={webRef} />
  58. <ClashPortViewer ref={portRef} />
  59. <ControllerViewer ref={ctrlRef} />
  60. <ClashCoreViewer ref={coreRef} />
  61. <SettingItem label={t("Allow Lan")}>
  62. <GuardState
  63. value={allowLan ?? false}
  64. valueProps="checked"
  65. onCatch={onError}
  66. onFormat={onSwitchFormat}
  67. onChange={(e) => onChangeData({ "allow-lan": e })}
  68. onGuard={(e) => patchClash({ "allow-lan": e })}
  69. >
  70. <Switch edge="end" />
  71. </GuardState>
  72. </SettingItem>
  73. <SettingItem label={t("IPv6")}>
  74. <GuardState
  75. value={ipv6 ?? false}
  76. valueProps="checked"
  77. onCatch={onError}
  78. onFormat={onSwitchFormat}
  79. onChange={(e) => onChangeData({ ipv6: e })}
  80. onGuard={(e) => patchClash({ ipv6: e })}
  81. >
  82. <Switch edge="end" />
  83. </GuardState>
  84. </SettingItem>
  85. <SettingItem label={t("Log Level")}>
  86. <GuardState
  87. // clash premium 2022.08.26 值为warn
  88. value={logLevel === "warn" ? "warning" : logLevel ?? "info"}
  89. onCatch={onError}
  90. onFormat={(e: any) => e.target.value}
  91. onChange={(e) => onChangeData({ "log-level": e })}
  92. onGuard={(e) => patchClash({ "log-level": e })}
  93. >
  94. <Select size="small" sx={{ width: 100, "> div": { py: "7.5px" } }}>
  95. <MenuItem value="debug">Debug</MenuItem>
  96. <MenuItem value="info">Info</MenuItem>
  97. <MenuItem value="warning">Warn</MenuItem>
  98. <MenuItem value="error">Error</MenuItem>
  99. <MenuItem value="silent">Silent</MenuItem>
  100. </Select>
  101. </GuardState>
  102. </SettingItem>
  103. <SettingItem
  104. label={t("Port Config")}
  105. extra={
  106. <Tooltip title={t("Random Port")}>
  107. <IconButton
  108. color={enable_random_port ? "success" : "inherit"}
  109. size="small"
  110. onClick={() => {
  111. Notice.success(t("After restart to take effect"), 1000);
  112. onChangeVerge({ enable_random_port: !enable_random_port });
  113. patchVerge({ enable_random_port: !enable_random_port });
  114. }}
  115. >
  116. <Shuffle
  117. fontSize="inherit"
  118. style={{ cursor: "pointer", opacity: 0.75 }}
  119. />
  120. </IconButton>
  121. </Tooltip>
  122. }
  123. >
  124. <TextField
  125. disabled={enable_random_port}
  126. autoComplete="off"
  127. size="small"
  128. value={verge_mixed_port ?? 7897}
  129. sx={{ width: 100, input: { py: "7.5px", cursor: "pointer" } }}
  130. onClick={(e) => {
  131. portRef.current?.open();
  132. (e.target as any).blur();
  133. }}
  134. />
  135. </SettingItem>
  136. <SettingItem label={t("External")}>
  137. <IconButton
  138. color="inherit"
  139. size="small"
  140. sx={{ my: "2px" }}
  141. onClick={() => ctrlRef.current?.open()}
  142. >
  143. <ArrowForward />
  144. </IconButton>
  145. </SettingItem>
  146. <SettingItem label={t("Web UI")}>
  147. <IconButton
  148. color="inherit"
  149. size="small"
  150. sx={{ my: "2px" }}
  151. onClick={() => webRef.current?.open()}
  152. >
  153. <ArrowForward />
  154. </IconButton>
  155. </SettingItem>
  156. <SettingItem
  157. label={t("Clash Core")}
  158. extra={
  159. <IconButton
  160. color="inherit"
  161. size="small"
  162. onClick={() => coreRef.current?.open()}
  163. >
  164. <Settings
  165. fontSize="inherit"
  166. style={{ cursor: "pointer", opacity: 0.75 }}
  167. />
  168. </IconButton>
  169. }
  170. >
  171. <Typography sx={{ py: "7px", pr: 1 }}>{version}</Typography>
  172. </SettingItem>
  173. {isWIN && (
  174. <SettingItem label={t("Open UWP tool")}>
  175. <IconButton
  176. color="inherit"
  177. size="small"
  178. sx={{ my: "2px" }}
  179. onClick={invoke_uwp_tool}
  180. >
  181. <ArrowForward />
  182. </IconButton>
  183. </SettingItem>
  184. )}
  185. <SettingItem label={t("Update GeoData")}>
  186. <IconButton
  187. color="inherit"
  188. size="small"
  189. sx={{ my: "2px" }}
  190. onClick={onUpdateGeo}
  191. >
  192. <ArrowForward />
  193. </IconButton>
  194. </SettingItem>
  195. </SettingList>
  196. );
  197. };
  198. export default SettingClash;