setting-clash.tsx 5.3 KB

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