setting-clash.tsx 5.5 KB

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