setting-verge.tsx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { useRef } from "react";
  2. import { useLockFn } from "ahooks";
  3. import { useTranslation } from "react-i18next";
  4. import { open } from "@tauri-apps/api/dialog";
  5. import { Button, MenuItem, Select, Input, Typography } from "@mui/material";
  6. import {
  7. exitApp,
  8. openAppDir,
  9. openCoreDir,
  10. openLogsDir,
  11. openDevTools,
  12. } from "@/services/cmds";
  13. import { checkUpdate } from "@tauri-apps/api/updater";
  14. import { useVerge } from "@/hooks/use-verge";
  15. import { version } from "@root/package.json";
  16. import { DialogRef, Notice } from "@/components/base";
  17. import { SettingList, SettingItem } from "./mods/setting-comp";
  18. import { ThemeModeSwitch } from "./mods/theme-mode-switch";
  19. import { ConfigViewer } from "./mods/config-viewer";
  20. import { HotkeyViewer } from "./mods/hotkey-viewer";
  21. import { MiscViewer } from "./mods/misc-viewer";
  22. import { ThemeViewer } from "./mods/theme-viewer";
  23. import { GuardState } from "./mods/guard-state";
  24. import { LayoutViewer } from "./mods/layout-viewer";
  25. import { UpdateViewer } from "./mods/update-viewer";
  26. import getSystem from "@/utils/get-system";
  27. import { routers } from "@/pages/_routers";
  28. interface Props {
  29. onError?: (err: Error) => void;
  30. }
  31. const OS = getSystem();
  32. const SettingVerge = ({ onError }: Props) => {
  33. const { t } = useTranslation();
  34. const { verge, patchVerge, mutateVerge } = useVerge();
  35. const {
  36. theme_mode,
  37. language,
  38. tray_event,
  39. env_type,
  40. startup_script,
  41. start_page,
  42. } = verge ?? {};
  43. const configRef = useRef<DialogRef>(null);
  44. const hotkeyRef = useRef<DialogRef>(null);
  45. const miscRef = useRef<DialogRef>(null);
  46. const themeRef = useRef<DialogRef>(null);
  47. const layoutRef = useRef<DialogRef>(null);
  48. const updateRef = useRef<DialogRef>(null);
  49. const onChangeData = (patch: Partial<IVergeConfig>) => {
  50. mutateVerge({ ...verge, ...patch }, false);
  51. };
  52. const onCheckUpdate = useLockFn(async () => {
  53. try {
  54. const info = await checkUpdate();
  55. if (!info?.shouldUpdate) {
  56. Notice.success(t("Currently on the Latest Version"));
  57. } else {
  58. updateRef.current?.open();
  59. }
  60. } catch (err: any) {
  61. Notice.error(err.message || err.toString());
  62. }
  63. });
  64. return (
  65. <SettingList title={t("Verge Setting")}>
  66. <ThemeViewer ref={themeRef} />
  67. <ConfigViewer ref={configRef} />
  68. <HotkeyViewer ref={hotkeyRef} />
  69. <MiscViewer ref={miscRef} />
  70. <LayoutViewer ref={layoutRef} />
  71. <UpdateViewer ref={updateRef} />
  72. <SettingItem label={t("Language")}>
  73. <GuardState
  74. value={language ?? "en"}
  75. onCatch={onError}
  76. onFormat={(e: any) => e.target.value}
  77. onChange={(e) => onChangeData({ language: e })}
  78. onGuard={(e) => patchVerge({ language: e })}
  79. >
  80. <Select size="small" sx={{ width: 110, "> div": { py: "7.5px" } }}>
  81. <MenuItem value="zh">中文</MenuItem>
  82. <MenuItem value="en">English</MenuItem>
  83. <MenuItem value="ru">Русский</MenuItem>
  84. <MenuItem value="fa">فارسی</MenuItem>
  85. </Select>
  86. </GuardState>
  87. </SettingItem>
  88. <SettingItem label={t("Theme Mode")}>
  89. <GuardState
  90. value={theme_mode}
  91. onCatch={onError}
  92. onChange={(e) => onChangeData({ theme_mode: e })}
  93. onGuard={(e) => patchVerge({ theme_mode: e })}
  94. >
  95. <ThemeModeSwitch />
  96. </GuardState>
  97. </SettingItem>
  98. {OS !== "linux" && (
  99. <SettingItem label={t("Tray Click Event")}>
  100. <GuardState
  101. value={tray_event ?? "main_window"}
  102. onCatch={onError}
  103. onFormat={(e: any) => e.target.value}
  104. onChange={(e) => onChangeData({ tray_event: e })}
  105. onGuard={(e) => patchVerge({ tray_event: e })}
  106. >
  107. <Select size="small" sx={{ width: 140, "> div": { py: "7.5px" } }}>
  108. <MenuItem value="main_window">{t("Show Main Window")}</MenuItem>
  109. <MenuItem value="system_proxy">{t("System Proxy")}</MenuItem>
  110. <MenuItem value="tun_mode">{t("Tun Mode")}</MenuItem>
  111. <MenuItem value="disable">{t("Disable")}</MenuItem>
  112. </Select>
  113. </GuardState>
  114. </SettingItem>
  115. )}
  116. <SettingItem label={t("Copy Env Type")}>
  117. <GuardState
  118. value={env_type ?? (OS === "windows" ? "powershell" : "bash")}
  119. onCatch={onError}
  120. onFormat={(e: any) => e.target.value}
  121. onChange={(e) => onChangeData({ env_type: e })}
  122. onGuard={(e) => patchVerge({ env_type: e })}
  123. >
  124. <Select size="small" sx={{ width: 140, "> div": { py: "7.5px" } }}>
  125. <MenuItem value="bash">Bash</MenuItem>
  126. <MenuItem value="cmd">CMD</MenuItem>
  127. <MenuItem value="powershell">PowerShell</MenuItem>
  128. </Select>
  129. </GuardState>
  130. </SettingItem>
  131. <SettingItem label={t("Start Page")}>
  132. <GuardState
  133. value={start_page ?? "/"}
  134. onCatch={onError}
  135. onFormat={(e: any) => e.target.value}
  136. onChange={(e) => onChangeData({ start_page: e })}
  137. onGuard={(e) => patchVerge({ start_page: e })}
  138. >
  139. <Select size="small" sx={{ width: 140, "> div": { py: "7.5px" } }}>
  140. {routers.map((page: { label: string; path: string }) => {
  141. return <MenuItem value={page.path}>{t(page.label)}</MenuItem>;
  142. })}
  143. </Select>
  144. </GuardState>
  145. </SettingItem>
  146. <SettingItem label={t("Startup Script")}>
  147. <GuardState
  148. value={startup_script ?? ""}
  149. onCatch={onError}
  150. onFormat={(e: any) => e.target.value}
  151. onChange={(e) => onChangeData({ startup_script: e })}
  152. onGuard={(e) => patchVerge({ startup_script: e })}
  153. >
  154. <Input
  155. value={startup_script}
  156. disabled
  157. sx={{ width: 230 }}
  158. endAdornment={
  159. <>
  160. <Button
  161. onClick={async () => {
  162. const path = await open({
  163. directory: false,
  164. multiple: false,
  165. filters: [
  166. {
  167. name: "Shell Script",
  168. extensions: ["sh", "bat", "ps1"],
  169. },
  170. ],
  171. });
  172. if (path?.length) {
  173. onChangeData({ startup_script: `${path}` });
  174. patchVerge({ startup_script: `${path}` });
  175. }
  176. }}
  177. >
  178. {t("Browse")}
  179. </Button>
  180. {startup_script && (
  181. <Button
  182. onClick={async () => {
  183. onChangeData({ startup_script: "" });
  184. patchVerge({ startup_script: "" });
  185. }}
  186. >
  187. {t("Clear")}
  188. </Button>
  189. )}
  190. </>
  191. }
  192. ></Input>
  193. </GuardState>
  194. </SettingItem>
  195. <SettingItem
  196. onClick={() => themeRef.current?.open()}
  197. label={t("Theme Setting")}
  198. />
  199. <SettingItem
  200. onClick={() => layoutRef.current?.open()}
  201. label={t("Layout Setting")}
  202. />
  203. <SettingItem
  204. onClick={() => miscRef.current?.open()}
  205. label={t("Miscellaneous")}
  206. />
  207. <SettingItem
  208. onClick={() => hotkeyRef.current?.open()}
  209. label={t("Hotkey Setting")}
  210. />
  211. <SettingItem
  212. onClick={() => configRef.current?.open()}
  213. label={t("Runtime Config")}
  214. />
  215. <SettingItem onClick={openAppDir} label={t("Open App Dir")} />
  216. <SettingItem onClick={openCoreDir} label={t("Open Core Dir")} />
  217. <SettingItem onClick={openLogsDir} label={t("Open Logs Dir")} />
  218. <SettingItem onClick={onCheckUpdate} label={t("Check for Updates")} />
  219. <SettingItem onClick={openDevTools} label={t("Open Dev Tools")} />
  220. <SettingItem
  221. onClick={() => {
  222. exitApp();
  223. }}
  224. label={t("Exit")}
  225. />
  226. <SettingItem label={t("Verge Version")}>
  227. <Typography sx={{ py: "7px", pr: 1 }}>v{version}</Typography>
  228. </SettingItem>
  229. </SettingList>
  230. );
  231. };
  232. export default SettingVerge;