mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 11:42:21 +08:00
Compare commits
7 Commits
726ad84d7f
...
7a1f4f9abe
Author | SHA1 | Date | |
---|---|---|---|
|
7a1f4f9abe | ||
|
5768b01786 | ||
|
7e9079467f | ||
|
615e96922e | ||
|
8b94c452fb | ||
|
66dd510acc | ||
|
96e044566c |
13
.github/workflows/alpha.yml
vendored
13
.github/workflows/alpha.yml
vendored
|
@ -59,6 +59,12 @@ jobs:
|
|||
pnpm i
|
||||
pnpm check ${{ matrix.target }}
|
||||
|
||||
- name: Download and install Apple intermediate certificates
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
curl -O https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer
|
||||
sudo security add-trusted-cert -d -r trustRoot -k ${HOME}/Library/Keychains/login.keychain-db DeveloperIDG2CA.cer
|
||||
|
||||
- name: Tauri build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
|
@ -69,9 +75,10 @@ jobs:
|
|||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
#加入以下内容为提交app到apple认证,当前会报错,已发邮件与apple沟通
|
||||
#APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
#APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
#APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
with:
|
||||
tagName: alpha
|
||||
releaseName: "Clash Verge Rev Alpha"
|
||||
|
|
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
|
@ -56,6 +56,12 @@ jobs:
|
|||
pnpm i
|
||||
pnpm check ${{ matrix.target }}
|
||||
|
||||
- name: Download and install Apple intermediate certificates
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
curl -O https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer
|
||||
sudo security add-trusted-cert -d -r trustRoot -k ${HOME}/Library/Keychains/login.keychain-db DeveloperIDG2CA.cer
|
||||
|
||||
- name: Tauri build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
|
@ -103,9 +109,10 @@ jobs:
|
|||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
#加入以下内容为提交app到apple认证,当前会报错,已发邮件与apple沟通
|
||||
#APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
#APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
#APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
"ahooks": "^3.8.0",
|
||||
"axios": "^1.7.2",
|
||||
"dayjs": "1.11.5",
|
||||
"foxact": "^0.2.35",
|
||||
"i18next": "^23.11.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"meta-json-schema": "1.18.5-alpha4",
|
||||
|
@ -48,7 +49,6 @@
|
|||
"react-router-dom": "^6.23.1",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"react-virtuoso": "^4.7.11",
|
||||
"recoil": "^0.7.7",
|
||||
"swr": "^1.3.0",
|
||||
"tar": "^6.2.1",
|
||||
"types-pac": "^1.0.2"
|
||||
|
|
|
@ -52,6 +52,9 @@ importers:
|
|||
dayjs:
|
||||
specifier: 1.11.5
|
||||
version: 1.11.5
|
||||
foxact:
|
||||
specifier: ^0.2.35
|
||||
version: 0.2.35(react@18.3.1)
|
||||
i18next:
|
||||
specifier: ^23.11.5
|
||||
version: 23.11.5
|
||||
|
@ -97,9 +100,6 @@ importers:
|
|||
react-virtuoso:
|
||||
specifier: ^4.7.11
|
||||
version: 4.7.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
recoil:
|
||||
specifier: ^0.7.7
|
||||
version: 0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
swr:
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0(react@18.3.1)
|
||||
|
@ -2526,6 +2526,12 @@ packages:
|
|||
}
|
||||
engines: { node: ">=10" }
|
||||
|
||||
client-only@0.0.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==,
|
||||
}
|
||||
|
||||
clsx@2.1.1:
|
||||
resolution:
|
||||
{
|
||||
|
@ -2836,6 +2842,17 @@ packages:
|
|||
}
|
||||
engines: { node: ">=12.20.0" }
|
||||
|
||||
foxact@0.2.35:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-5e2p34TcBETZTTMhmf4WuljS07lgtv3laimqJer9OGOqYgOpYHgKfR0Cie8Q2IxH1FFhVkm1l0+2W/XL8nBL7Q==,
|
||||
}
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
|
||||
fs-extra@11.2.0:
|
||||
resolution:
|
||||
{
|
||||
|
@ -2898,12 +2915,6 @@ packages:
|
|||
integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==,
|
||||
}
|
||||
|
||||
hamt_plus@1.0.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==,
|
||||
}
|
||||
|
||||
has-flag@3.0.0:
|
||||
resolution:
|
||||
{
|
||||
|
@ -3876,21 +3887,6 @@ packages:
|
|||
}
|
||||
engines: { node: ">=8.10.0" }
|
||||
|
||||
recoil@0.7.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==,
|
||||
}
|
||||
peerDependencies:
|
||||
react: ">=16.13.1"
|
||||
react-dom: "*"
|
||||
react-native: "*"
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
|
||||
regenerate-unicode-properties@10.1.1:
|
||||
resolution:
|
||||
{
|
||||
|
@ -4004,6 +4000,12 @@ packages:
|
|||
}
|
||||
hasBin: true
|
||||
|
||||
server-only@0.0.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==,
|
||||
}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution:
|
||||
{
|
||||
|
@ -6054,6 +6056,8 @@ snapshots:
|
|||
|
||||
chownr@2.0.0: {}
|
||||
|
||||
client-only@0.0.1: {}
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
color-convert@1.9.3:
|
||||
|
@ -6233,6 +6237,13 @@ snapshots:
|
|||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
|
||||
foxact@0.2.35(react@18.3.1):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
server-only: 0.0.1
|
||||
optionalDependencies:
|
||||
react: 18.3.1
|
||||
|
||||
fs-extra@11.2.0:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
@ -6262,8 +6273,6 @@ snapshots:
|
|||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
hamt_plus@1.0.2: {}
|
||||
|
||||
has-flag@3.0.0: {}
|
||||
|
||||
hasown@2.0.2:
|
||||
|
@ -6914,13 +6923,6 @@ snapshots:
|
|||
dependencies:
|
||||
picomatch: 2.3.1
|
||||
|
||||
recoil@0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
hamt_plus: 1.0.2
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
regenerate-unicode-properties@10.1.1:
|
||||
dependencies:
|
||||
regenerate: 1.4.2
|
||||
|
@ -7011,6 +7013,8 @@ snapshots:
|
|||
|
||||
semver@6.3.1: {}
|
||||
|
||||
server-only@0.0.1: {}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { useEffect, useMemo } from "react";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { alpha, createTheme, Shadows, Theme } from "@mui/material";
|
||||
import { appWindow } from "@tauri-apps/api/window";
|
||||
import { atomThemeMode } from "@/services/states";
|
||||
import { useSetThemeMode, useThemeMode } from "@/services/states";
|
||||
import { defaultTheme, defaultDarkTheme } from "@/pages/_theme";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
|
||||
|
@ -12,7 +11,8 @@ import { useVerge } from "@/hooks/use-verge";
|
|||
export const useCustomTheme = () => {
|
||||
const { verge } = useVerge();
|
||||
const { theme_mode, theme_setting } = verge ?? {};
|
||||
const [mode, setMode] = useRecoilState(atomThemeMode);
|
||||
const mode = useThemeMode();
|
||||
const setMode = useSetThemeMode();
|
||||
|
||||
useEffect(() => {
|
||||
const themeMode = ["light", "dark", "system"].includes(theme_mode!)
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import dayjs from "dayjs";
|
||||
import { useEffect } from "react";
|
||||
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { getClashLogs } from "@/services/cmds";
|
||||
import { useClashInfo } from "@/hooks/use-clash";
|
||||
import { atomEnableLog, atomLogData } from "@/services/states";
|
||||
import { useEnableLog, useSetLogData } from "@/services/states";
|
||||
import { useWebsocket } from "@/hooks/use-websocket";
|
||||
|
||||
const MAX_LOG_NUM = 1000;
|
||||
|
@ -12,8 +11,8 @@ const MAX_LOG_NUM = 1000;
|
|||
export const useLogSetup = () => {
|
||||
const { clashInfo } = useClashInfo();
|
||||
|
||||
const enableLog = useRecoilValue(atomEnableLog);
|
||||
const setLogData = useSetRecoilState(atomLogData);
|
||||
const [enableLog] = useEnableLog();
|
||||
const setLogData = useSetLogData();
|
||||
|
||||
const { connect, disconnect } = useWebsocket((event) => {
|
||||
const data = JSON.parse(event.data) as ILogItem;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { ReactNode, useEffect, useRef } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Button,
|
||||
|
@ -9,7 +8,7 @@ import {
|
|||
DialogContent,
|
||||
DialogTitle,
|
||||
} from "@mui/material";
|
||||
import { atomThemeMode } from "@/services/states";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import { readProfileFile, saveProfileFile } from "@/services/cmds";
|
||||
import { Notice } from "@/components/base";
|
||||
import { nanoid } from "nanoid";
|
||||
|
@ -90,7 +89,7 @@ export const EditorViewer = (props: Props) => {
|
|||
const { t } = useTranslation();
|
||||
const editorRef = useRef<any>();
|
||||
const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
||||
const themeMode = useRecoilValue(atomThemeMode);
|
||||
const themeMode = useThemeMode();
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
|
|
|
@ -2,7 +2,6 @@ import dayjs from "dayjs";
|
|||
import { mutate } from "swr";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSortable } from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
|
@ -17,7 +16,7 @@ import {
|
|||
CircularProgress,
|
||||
} from "@mui/material";
|
||||
import { RefreshRounded, DragIndicator } from "@mui/icons-material";
|
||||
import { atomLoadingCache } from "@/services/states";
|
||||
import { useLoadingCache, useSetLoadingCache } from "@/services/states";
|
||||
import { updateProfile, deleteProfile, viewProfile } from "@/services/cmds";
|
||||
import { Notice } from "@/components/base";
|
||||
import { EditorViewer } from "@/components/profile/editor-viewer";
|
||||
|
@ -47,7 +46,8 @@ export const ProfileItem = (props: Props) => {
|
|||
const { t } = useTranslation();
|
||||
const [anchorEl, setAnchorEl] = useState<any>(null);
|
||||
const [position, setPosition] = useState({ left: 0, top: 0 });
|
||||
const [loadingCache, setLoadingCache] = useRecoilState(atomLoadingCache);
|
||||
const loadingCache = useLoadingCache();
|
||||
const setLoadingCache = useSetLoadingCache();
|
||||
|
||||
const { uid, name = "Profile", extra, updated = 0 } = itemData;
|
||||
|
||||
|
|
|
@ -17,8 +17,7 @@ import { ProxyItem } from "./proxy-item";
|
|||
import { ProxyItemMini } from "./proxy-item-mini";
|
||||
import type { IRenderItem } from "./use-render-list";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { atomThemeMode } from "@/services/states";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
||||
import { downloadIconCache } from "@/services/cmds";
|
||||
|
@ -38,7 +37,7 @@ export const ProxyRender = (props: RenderProps) => {
|
|||
const { type, group, headState, proxy, proxyCol } = item;
|
||||
const { verge } = useVerge();
|
||||
const enable_group_icon = verge?.enable_group_icon ?? true;
|
||||
const [mode] = useRecoilState(atomThemeMode);
|
||||
const mode = useThemeMode();
|
||||
const isDark = mode === "light" ? false : true;
|
||||
const itembackgroundcolor = isDark ? "#282A36" : "#ffffff";
|
||||
const [iconCachePath, setIconCachePath] = useState("");
|
||||
|
|
|
@ -3,32 +3,39 @@ import {
|
|||
Box,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
ListSubheader,
|
||||
} from "@mui/material";
|
||||
import { ChevronRightRounded } from "@mui/icons-material";
|
||||
|
||||
interface ItemProps {
|
||||
label: ReactNode;
|
||||
extra?: ReactNode;
|
||||
children?: ReactNode;
|
||||
secondary?: ReactNode;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const SettingItem: React.FC<ItemProps> = (props) => {
|
||||
const { label, extra, children, secondary } = props;
|
||||
const { label, extra, children, secondary, onClick } = props;
|
||||
const clickable = !!onClick;
|
||||
|
||||
const primary = !extra ? (
|
||||
const primary = (
|
||||
<Box sx={{ display: "flex", alignItems: "center", fontSize: "14px" }}>
|
||||
<span>{label}</span>
|
||||
</Box>
|
||||
) : (
|
||||
<Box sx={{ display: "flex", alignItems: "center", fontSize: "14px" }}>
|
||||
<span>{label}</span>
|
||||
{extra}
|
||||
{extra ? extra : null}
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
return clickable ? (
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton onClick={onClick}>
|
||||
<ListItemText primary={primary} secondary={secondary} />
|
||||
<ChevronRightRounded />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
) : (
|
||||
<ListItem sx={{ pt: "5px", pb: "5px" }}>
|
||||
<ListItemText primary={primary} secondary={secondary} />
|
||||
{children}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { forwardRef, useImperativeHandle, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { IconButton, Tooltip } from "@mui/material";
|
||||
import { InfoRounded } from "@mui/icons-material";
|
||||
import {
|
||||
Box,
|
||||
InputAdornment,
|
||||
|
@ -103,7 +105,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
<BaseDialog
|
||||
open={open}
|
||||
title={t("System Proxy Setting")}
|
||||
contentSx={{ width: 450, maxHeight: 300 }}
|
||||
contentSx={{ width: 450, maxHeight: 565 }}
|
||||
okBtn={t("Save")}
|
||||
cancelBtn={t("Cancel")}
|
||||
onClose={() => setOpen(false)}
|
||||
|
@ -111,6 +113,39 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
onOk={onSave}
|
||||
>
|
||||
<List>
|
||||
<Box
|
||||
sx={{
|
||||
border: "1px solid #bbb",
|
||||
borderRadius: "5px",
|
||||
padding: "8px",
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" sx={{ fontSize: "18px" }}>
|
||||
{t("Current System Proxy")}
|
||||
</Typography>
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Enable status")}</Typography>
|
||||
<Typography className="value">
|
||||
{value.pac
|
||||
? autoproxy?.enable
|
||||
? t("Enabled")
|
||||
: t("Disabled")
|
||||
: sysproxy?.enable
|
||||
? t("Enabled")
|
||||
: t("Disabled")}
|
||||
</Typography>
|
||||
</FlexBox>
|
||||
{!value.pac && (
|
||||
<>
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Server Addr")}</Typography>
|
||||
<Typography className="value">
|
||||
{sysproxy?.server ? sysproxy.server : t("Not available")}
|
||||
</Typography>
|
||||
</FlexBox>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Use PAC Mode")} />
|
||||
<Switch
|
||||
|
@ -120,8 +155,17 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
onChange={(_, e) => setValue((v) => ({ ...v, pac: e }))}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Proxy Guard")} />
|
||||
<Tooltip title={t("Proxy Guard Info")}>
|
||||
<IconButton color="inherit" size="small">
|
||||
<InfoRounded
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Switch
|
||||
edge="end"
|
||||
disabled={!enabled}
|
||||
|
@ -148,15 +192,13 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
{!value.pac && (
|
||||
<>
|
||||
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
|
||||
<ListItemText
|
||||
primary={t("Proxy Bypass")}
|
||||
sx={{ padding: "3px 0" }}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Proxy Bypass")}</Typography>
|
||||
</FlexBox>
|
||||
<FlexBox>
|
||||
<TextField
|
||||
disabled={!enabled}
|
||||
size="small"
|
||||
|
@ -170,9 +212,24 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
setValue((v) => ({ ...v, bypass: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</FlexBox>
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Bypass")}</Typography>
|
||||
</FlexBox>
|
||||
<FlexBox>
|
||||
<TextField
|
||||
disabled={true}
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{ width: "100%" }}
|
||||
value={sysproxy?.bypass || "-"}
|
||||
/>
|
||||
</FlexBox>
|
||||
</>
|
||||
)}
|
||||
|
||||
{value.pac && (
|
||||
<>
|
||||
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
|
||||
|
@ -209,53 +266,14 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
</ListItem>
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
|
||||
<Box sx={{ mt: 2.5 }}>
|
||||
<Typography variant="body1" sx={{ fontSize: "18px", mb: 1 }}>
|
||||
{t("Current System Proxy")}
|
||||
</Typography>
|
||||
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Enable status")}</Typography>
|
||||
<Typography className="value">
|
||||
{value.pac
|
||||
? (!!autoproxy?.enable).toString()
|
||||
: (!!sysproxy?.enable).toString()}
|
||||
</Typography>
|
||||
</FlexBox>
|
||||
{!value.pac && (
|
||||
<>
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Server Addr")}</Typography>
|
||||
<Typography className="value">
|
||||
{sysproxy?.server || "-"}
|
||||
</Typography>
|
||||
</FlexBox>
|
||||
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Bypass")}</Typography>
|
||||
</FlexBox>
|
||||
<FlexBox>
|
||||
<TextField
|
||||
disabled={true}
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{ width: "100%" }}
|
||||
value={sysproxy?.bypass || "-"}
|
||||
/>
|
||||
</FlexBox>
|
||||
</>
|
||||
)}
|
||||
{value.pac && (
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("PAC URL")}</Typography>
|
||||
<Typography className="value">{autoproxy?.url || "-"}</Typography>
|
||||
</FlexBox>
|
||||
)}
|
||||
</Box>
|
||||
</List>
|
||||
</BaseDialog>
|
||||
);
|
||||
});
|
||||
|
@ -266,6 +284,6 @@ const FlexBox = styled("div")`
|
|||
|
||||
.label {
|
||||
flex: none;
|
||||
width: 85px;
|
||||
//width: 85px;
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -81,7 +81,7 @@ export const ThemeViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
title={t("Theme Setting")}
|
||||
okBtn={t("Save")}
|
||||
cancelBtn={t("Cancel")}
|
||||
contentSx={{ width: 400, maxHeight: 300, overflow: "auto", pb: 0 }}
|
||||
contentSx={{ width: 400, maxHeight: 505, overflow: "auto", pb: 0 }}
|
||||
onClose={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
onOk={onSave}
|
||||
|
|
|
@ -2,12 +2,11 @@ import useSWR from "swr";
|
|||
import { forwardRef, useImperativeHandle, useState, useMemo } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { Box, LinearProgress } from "@mui/material";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { relaunch } from "@tauri-apps/api/process";
|
||||
import { checkUpdate, installUpdate } from "@tauri-apps/api/updater";
|
||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||
import { atomUpdateState } from "@/services/states";
|
||||
import { useUpdateState, useSetUpdateState } from "@/services/states";
|
||||
import { listen, Event, UnlistenFn } from "@tauri-apps/api/event";
|
||||
import { portableFlag } from "@/pages/_layout";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
|
@ -18,7 +17,9 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
|||
const { t } = useTranslation();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [updateState, setUpdateState] = useRecoilState(atomUpdateState);
|
||||
|
||||
const updateState = useUpdateState();
|
||||
const setUpdateState = useSetUpdateState();
|
||||
|
||||
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
||||
errorRetryCount: 2,
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
IconButton,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { ArrowForward, Settings, Shuffle } from "@mui/icons-material";
|
||||
import { Settings, Shuffle } from "@mui/icons-material";
|
||||
import { DialogRef, Notice, Switch } from "@/components/base";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { GuardState } from "./mods/guard-state";
|
||||
|
@ -120,7 +120,10 @@ const SettingClash = ({ onError }: Props) => {
|
|||
color={enable_random_port ? "primary" : "inherit"}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
Notice.success(t("Restart Application to Apply Modifications"), 1000);
|
||||
Notice.success(
|
||||
t("Restart Application to Apply Modifications"),
|
||||
1000
|
||||
);
|
||||
onChangeVerge({ enable_random_port: !enable_random_port });
|
||||
patchVerge({ enable_random_port: !enable_random_port });
|
||||
}}
|
||||
|
@ -146,27 +149,12 @@ const SettingClash = ({ onError }: Props) => {
|
|||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("External")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => ctrlRef.current?.open()}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
onClick={() => ctrlRef.current?.open()}
|
||||
label={t("External")}
|
||||
/>
|
||||
|
||||
<SettingItem label={t("Web UI")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => webRef.current?.open()}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={() => webRef.current?.open()} label={t("Web UI")} />
|
||||
|
||||
<SettingItem
|
||||
label={t("Clash Core")}
|
||||
|
@ -187,28 +175,10 @@ const SettingClash = ({ onError }: Props) => {
|
|||
</SettingItem>
|
||||
|
||||
{isWIN && (
|
||||
<SettingItem label={t("Open UWP tool")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={invoke_uwp_tool}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={invoke_uwp_tool} label={t("Open UWP tool")} />
|
||||
)}
|
||||
|
||||
<SettingItem label={t("Update GeoData")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={onUpdateGeo}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={onUpdateGeo} label={t("Update GeoData")} />
|
||||
</SettingList>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -123,16 +123,26 @@ const SettingSystem = ({ onError }: Props) => {
|
|||
<SettingItem
|
||||
label={t("System Proxy")}
|
||||
extra={
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
onClick={() => sysproxyRef.current?.open()}
|
||||
>
|
||||
<Settings
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
<>
|
||||
<Tooltip title={t("System Proxy Info")} placement="top">
|
||||
<IconButton color="inherit" size="small">
|
||||
<InfoRounded
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
onClick={() => sysproxyRef.current?.open()}
|
||||
>
|
||||
<Settings
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<GuardState
|
||||
|
|
|
@ -2,14 +2,7 @@ import { useRef } from "react";
|
|||
import { useLockFn } from "ahooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { open } from "@tauri-apps/api/dialog";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Select,
|
||||
Input,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { Button, MenuItem, Select, Input, Typography } from "@mui/material";
|
||||
import {
|
||||
exitApp,
|
||||
openAppDir,
|
||||
|
@ -17,7 +10,6 @@ import {
|
|||
openLogsDir,
|
||||
openDevTools,
|
||||
} from "@/services/cmds";
|
||||
import { ArrowForward } from "@mui/icons-material";
|
||||
import { checkUpdate } from "@tauri-apps/api/updater";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { version } from "@root/package.json";
|
||||
|
@ -213,128 +205,48 @@ const SettingVerge = ({ onError }: Props) => {
|
|||
></Input>
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
<SettingItem label={t("Theme Setting")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => themeRef.current?.open()}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("Layout Setting")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => layoutRef.current?.open()}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
onClick={() => themeRef.current?.open()}
|
||||
label={t("Theme Setting")}
|
||||
/>
|
||||
|
||||
<SettingItem label={t("Miscellaneous")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => miscRef.current?.open()}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
onClick={() => layoutRef.current?.open()}
|
||||
label={t("Layout Setting")}
|
||||
/>
|
||||
|
||||
<SettingItem label={t("Hotkey Setting")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => hotkeyRef.current?.open()}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
onClick={() => miscRef.current?.open()}
|
||||
label={t("Miscellaneous")}
|
||||
/>
|
||||
|
||||
<SettingItem label={t("Runtime Config")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => configRef.current?.open()}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
onClick={() => hotkeyRef.current?.open()}
|
||||
label={t("Hotkey Setting")}
|
||||
/>
|
||||
|
||||
<SettingItem label={t("Open App Dir")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={openAppDir}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
onClick={() => configRef.current?.open()}
|
||||
label={t("Runtime Config")}
|
||||
/>
|
||||
|
||||
<SettingItem label={t("Open Core Dir")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={openCoreDir}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={openAppDir} label={t("Open App Dir")} />
|
||||
|
||||
<SettingItem label={t("Open Logs Dir")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={openLogsDir}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={openCoreDir} label={t("Open Core Dir")} />
|
||||
|
||||
<SettingItem label={t("Check for Updates")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={onCheckUpdate}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={openLogsDir} label={t("Open Logs Dir")} />
|
||||
|
||||
<SettingItem label={t("Open Dev Tools")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={openDevTools}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={onCheckUpdate} label={t("Check for Updates")} />
|
||||
|
||||
<SettingItem label={t("Exit")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={() => {
|
||||
exitApp();
|
||||
}}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={openDevTools} label={t("Open Dev Tools")} />
|
||||
|
||||
<SettingItem
|
||||
onClick={() => {
|
||||
exitApp();
|
||||
}}
|
||||
label={t("Exit")}
|
||||
/>
|
||||
|
||||
<SettingItem label={t("Verge Version")}>
|
||||
<Typography sx={{ py: "7px", pr: 1 }}>v{version}</Typography>
|
||||
|
|
|
@ -115,19 +115,24 @@
|
|||
"Auto Launch": "Auto Launch",
|
||||
"Silent Start": "Silent Start",
|
||||
"System Proxy": "System Proxy",
|
||||
"System Proxy Info": "Enable to modify the operating system's proxy settings. If enabling fails, modify the operating system's proxy settings manually",
|
||||
"System Proxy Setting": "System Proxy Setting",
|
||||
"Open UWP tool": "Open UWP tool",
|
||||
"Update GeoData": "Update GeoData",
|
||||
"Use PAC Mode": "Use PAC Mode",
|
||||
"PAC URL": "PAC URL",
|
||||
"PAC URL": "PAC URL: ",
|
||||
"PAC Script Content": "PAC Script Content",
|
||||
"Proxy Guard": "Proxy Guard",
|
||||
"Proxy Guard Info": "Enable to prevent other software from modifying the operating system's proxy settings",
|
||||
"Guard Duration": "Guard Duration",
|
||||
"Proxy Bypass": "Proxy Bypass",
|
||||
"Proxy Bypass": "Proxy Bypass Settings:",
|
||||
"Current System Proxy": "Current System Proxy",
|
||||
"Enable status": "Enable status",
|
||||
"Server Addr": "Server Addr",
|
||||
"Bypass": "Bypass",
|
||||
"Enable status": "Enable Status:",
|
||||
"Enabled": "Enabled",
|
||||
"Disabled": "Disabled",
|
||||
"Server Addr": "Server Addr:",
|
||||
"Not available": "Not available",
|
||||
"Bypass": "Bypass:",
|
||||
"Theme Mode": "Theme Mode",
|
||||
"Tray Click Event": "Tray Click Event",
|
||||
"Copy Env Type": "Copy Env Type",
|
||||
|
|
|
@ -115,18 +115,23 @@
|
|||
"Auto Launch": "开机自启",
|
||||
"Silent Start": "静默启动",
|
||||
"System Proxy": "系统代理",
|
||||
"System Proxy Info": "打开此开关修改操作系统的代理设置,如果开启失败,可手动修改操作系统的代理设置",
|
||||
"System Proxy Setting": "系统代理设置",
|
||||
"Open UWP tool": "UWP 工具",
|
||||
"Update GeoData": "更新 GeoData",
|
||||
"Use PAC Mode": "使用PAC模式",
|
||||
"PAC URL": "PAC 地址",
|
||||
"PAC Script Content": "PAC 脚本内容",
|
||||
"PAC URL": "PAC地址:",
|
||||
"PAC Script Content": "PAC脚本内容",
|
||||
"Proxy Guard": "系统代理守卫",
|
||||
"Proxy Guard Info": "开启以防止其他软件修改操作系统的代理设置",
|
||||
"Guard Duration": "代理守卫间隔",
|
||||
"Proxy Bypass": "代理绕过",
|
||||
"Proxy Bypass": "代理绕过设置:",
|
||||
"Current System Proxy": "当前系统代理",
|
||||
"Enable status": "开启状态:",
|
||||
"Enabled": "成功",
|
||||
"Disabled": "失败",
|
||||
"Server Addr": "服务地址:",
|
||||
"Not available": "不可用",
|
||||
"Bypass": "当前绕过:",
|
||||
"Theme Mode": "主题模式",
|
||||
"Tray Click Event": "托盘点击事件",
|
||||
|
|
19
src/main.tsx
19
src/main.tsx
|
@ -9,11 +9,17 @@ if (!window.ResizeObserver) {
|
|||
|
||||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { RecoilRoot } from "recoil";
|
||||
import { ComposeContextProvider } from "foxact/compose-context-provider";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { BaseErrorBoundary } from "./components/base";
|
||||
import Layout from "./pages/_layout";
|
||||
import "./services/i18n";
|
||||
import {
|
||||
LoadingCacheProvider,
|
||||
LogDataProvider,
|
||||
ThemeModeProvider,
|
||||
UpdateStateProvider,
|
||||
} from "./services/states";
|
||||
|
||||
const mainElementId = "root";
|
||||
const container = document.getElementById(mainElementId);
|
||||
|
@ -37,14 +43,21 @@ document.addEventListener("keydown", (event) => {
|
|||
}
|
||||
});
|
||||
|
||||
const contexts = [
|
||||
<ThemeModeProvider />,
|
||||
<LogDataProvider />,
|
||||
<LoadingCacheProvider />,
|
||||
<UpdateStateProvider />,
|
||||
];
|
||||
|
||||
createRoot(container).render(
|
||||
<React.StrictMode>
|
||||
<RecoilRoot>
|
||||
<ComposeContextProvider contexts={contexts}>
|
||||
<BaseErrorBoundary>
|
||||
<BrowserRouter>
|
||||
<Layout />
|
||||
</BrowserRouter>
|
||||
</BaseErrorBoundary>
|
||||
</RecoilRoot>
|
||||
</ComposeContextProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
|
|
@ -14,8 +14,7 @@ import { useVerge } from "@/hooks/use-verge";
|
|||
import LogoSvg from "@/assets/image/logo.svg?react";
|
||||
import iconLight from "@/assets/image/icon_light.svg?react";
|
||||
import iconDark from "@/assets/image/icon_dark.svg?react";
|
||||
import { atomThemeMode } from "@/services/states";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
import { Notice } from "@/components/base";
|
||||
import { LayoutItem } from "@/components/layout/layout-item";
|
||||
import { LayoutControl } from "@/components/layout/layout-control";
|
||||
|
@ -36,7 +35,7 @@ dayjs.extend(relativeTime);
|
|||
const OS = getSystem();
|
||||
|
||||
const Layout = () => {
|
||||
const [mode] = useRecoilState(atomThemeMode);
|
||||
const mode = useThemeMode();
|
||||
const isDark = mode === "light" ? false : true;
|
||||
const { t } = useTranslation();
|
||||
const { theme } = useCustomTheme();
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { Box, Button, IconButton, MenuItem } from "@mui/material";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TableChartRounded, TableRowsRounded } from "@mui/icons-material";
|
||||
import { closeAllConnections } from "@/services/api";
|
||||
import { atomConnectionSetting } from "@/services/states";
|
||||
import { useConnectionSetting } from "@/services/states";
|
||||
import { useClashInfo } from "@/hooks/use-clash";
|
||||
import { BaseEmpty, BasePage } from "@/components/base";
|
||||
import { useWebsocket } from "@/hooks/use-websocket";
|
||||
|
@ -34,7 +33,7 @@ const ConnectionsPage = () => {
|
|||
const [curOrderOpt, setOrderOpt] = useState("Default");
|
||||
const [connData, setConnData] = useState<IConnections>(initConn);
|
||||
|
||||
const [setting, setSetting] = useRecoilState(atomConnectionSetting);
|
||||
const [setting, setSetting] = useConnectionSetting();
|
||||
|
||||
const isTableLayout = setting.layout === "table";
|
||||
|
||||
|
@ -137,7 +136,7 @@ const ConnectionsPage = () => {
|
|||
size="small"
|
||||
onClick={() =>
|
||||
setSetting((o) =>
|
||||
o.layout === "list"
|
||||
o?.layout !== "table"
|
||||
? { ...o, layout: "table" }
|
||||
: { ...o, layout: "list" }
|
||||
)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { useMemo, useState } from "react";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { Box, Button, IconButton, MenuItem } from "@mui/material";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -7,7 +6,7 @@ import {
|
|||
PlayCircleOutlineRounded,
|
||||
PauseCircleOutlineRounded,
|
||||
} from "@mui/icons-material";
|
||||
import { atomEnableLog, atomLogData } from "@/services/states";
|
||||
import { useEnableLog, useLogData, useSetLogData } from "@/services/states";
|
||||
import { BaseEmpty, BasePage } from "@/components/base";
|
||||
import LogItem from "@/components/log/log-item";
|
||||
import { useCustomTheme } from "@/components/layout/use-custom-theme";
|
||||
|
@ -16,8 +15,9 @@ import { BaseStyledSelect } from "@/components/base/base-styled-select";
|
|||
|
||||
const LogPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const [logData, setLogData] = useRecoilState(atomLogData);
|
||||
const [enableLog, setEnableLog] = useRecoilState(atomEnableLog);
|
||||
const logData = useLogData();
|
||||
const setLogData = useSetLogData();
|
||||
const [enableLog, setEnableLog] = useEnableLog();
|
||||
const { theme } = useCustomTheme();
|
||||
const isDark = theme.palette.mode === "dark";
|
||||
const [logState, setLogState] = useState("all");
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import useSWR, { mutate } from "swr";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useSetRecoilState } from "recoil";
|
||||
import { Box, Button, Grid, IconButton, Stack, Divider } from "@mui/material";
|
||||
import {
|
||||
DndContext,
|
||||
|
@ -35,7 +34,7 @@ import {
|
|||
reorderProfile,
|
||||
createProfile,
|
||||
} from "@/services/cmds";
|
||||
import { atomLoadingCache } from "@/services/states";
|
||||
import { useSetLoadingCache, useThemeMode } from "@/services/states";
|
||||
import { closeAllConnections } from "@/services/api";
|
||||
import { BasePage, DialogRef, Notice } from "@/components/base";
|
||||
import {
|
||||
|
@ -47,8 +46,6 @@ import { ProfileMore } from "@/components/profile/profile-more";
|
|||
import { useProfiles } from "@/hooks/use-profiles";
|
||||
import { ConfigViewer } from "@/components/setting/mods/config-viewer";
|
||||
import { throttle } from "lodash-es";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { atomThemeMode } from "@/services/states";
|
||||
import { BaseStyledTextField } from "@/components/base/base-styled-text-field";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { readTextFile } from "@tauri-apps/api/fs";
|
||||
|
@ -239,7 +236,7 @@ const ProfilePage = () => {
|
|||
});
|
||||
|
||||
// 更新所有订阅
|
||||
const setLoadingCache = useSetRecoilState(atomLoadingCache);
|
||||
const setLoadingCache = useSetLoadingCache();
|
||||
const onUpdateAll = useLockFn(async () => {
|
||||
const throttleMutate = throttle(mutateProfiles, 2000, {
|
||||
trailing: true,
|
||||
|
@ -271,7 +268,7 @@ const ProfilePage = () => {
|
|||
const text = await readText();
|
||||
if (text) setUrl(text);
|
||||
};
|
||||
const [mode] = useRecoilState(atomThemeMode);
|
||||
const mode = useThemeMode();
|
||||
const islight = mode === "light" ? true : false;
|
||||
const dividercolor = islight
|
||||
? "rgba(0, 0, 0, 0.06)"
|
||||
|
|
|
@ -7,8 +7,7 @@ import { openWebUrl } from "@/services/cmds";
|
|||
import SettingVerge from "@/components/setting/setting-verge";
|
||||
import SettingClash from "@/components/setting/setting-clash";
|
||||
import SettingSystem from "@/components/setting/setting-system";
|
||||
import { atomThemeMode } from "@/services/states";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { useThemeMode } from "@/services/states";
|
||||
|
||||
const SettingPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -25,7 +24,7 @@ const SettingPage = () => {
|
|||
return openWebUrl("https://clash-verge-rev.github.io/guide/log.html");
|
||||
});
|
||||
|
||||
const [mode] = useRecoilState(atomThemeMode);
|
||||
const mode = useThemeMode();
|
||||
const isDark = mode === "light" ? false : true;
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,73 +1,51 @@
|
|||
import { atom } from "recoil";
|
||||
import { createContextState } from "foxact/create-context-state";
|
||||
import { useLocalStorage } from "foxact/use-local-storage";
|
||||
|
||||
export const atomThemeMode = atom<"light" | "dark">({
|
||||
key: "atomThemeMode",
|
||||
default: "light",
|
||||
});
|
||||
const [ThemeModeProvider, useThemeMode, useSetThemeMode] = createContextState<
|
||||
"light" | "dark"
|
||||
>("light");
|
||||
|
||||
export const atomLogData = atom<ILogItem[]>({
|
||||
key: "atomLogData",
|
||||
default: [],
|
||||
});
|
||||
const [LogDataProvider, useLogData, useSetLogData] = createContextState<
|
||||
ILogItem[]
|
||||
>([]);
|
||||
|
||||
export const atomEnableLog = atom<boolean>({
|
||||
key: "atomEnableLog",
|
||||
effects: [
|
||||
({ setSelf, onSet }) => {
|
||||
const key = "enable-log";
|
||||
|
||||
try {
|
||||
setSelf(localStorage.getItem(key) !== "false");
|
||||
} catch {}
|
||||
|
||||
onSet((newValue, _, isReset) => {
|
||||
try {
|
||||
if (isReset) {
|
||||
localStorage.removeItem(key);
|
||||
} else {
|
||||
localStorage.setItem(key, newValue.toString());
|
||||
}
|
||||
} catch {}
|
||||
});
|
||||
},
|
||||
],
|
||||
});
|
||||
export const useEnableLog = () => useLocalStorage("enable-log", true);
|
||||
|
||||
interface IConnectionSetting {
|
||||
layout: "table" | "list";
|
||||
}
|
||||
|
||||
export const atomConnectionSetting = atom<IConnectionSetting>({
|
||||
key: "atomConnectionSetting",
|
||||
effects: [
|
||||
({ setSelf, onSet }) => {
|
||||
const key = "connections-setting";
|
||||
const defaultConnectionSetting: IConnectionSetting = { layout: "table" };
|
||||
|
||||
try {
|
||||
const value = localStorage.getItem(key);
|
||||
const data = value == null ? { layout: "table" } : JSON.parse(value);
|
||||
setSelf(data);
|
||||
} catch {
|
||||
setSelf({ layout: "table" });
|
||||
}
|
||||
|
||||
onSet((newValue) => {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(newValue));
|
||||
} catch {}
|
||||
});
|
||||
},
|
||||
],
|
||||
});
|
||||
export const useConnectionSetting = () =>
|
||||
useLocalStorage<IConnectionSetting>(
|
||||
"connections-setting",
|
||||
defaultConnectionSetting,
|
||||
{
|
||||
serializer: JSON.stringify,
|
||||
deserializer: JSON.parse,
|
||||
}
|
||||
);
|
||||
|
||||
// save the state of each profile item loading
|
||||
export const atomLoadingCache = atom<Record<string, boolean>>({
|
||||
key: "atomLoadingCache",
|
||||
default: {},
|
||||
});
|
||||
const [LoadingCacheProvider, useLoadingCache, useSetLoadingCache] =
|
||||
createContextState<Record<string, boolean>>({});
|
||||
|
||||
// save update state
|
||||
export const atomUpdateState = atom<boolean>({
|
||||
key: "atomUpdateState",
|
||||
default: false,
|
||||
});
|
||||
const [UpdateStateProvider, useUpdateState, useSetUpdateState] =
|
||||
createContextState<boolean>(false);
|
||||
|
||||
export {
|
||||
ThemeModeProvider,
|
||||
useThemeMode,
|
||||
useSetThemeMode,
|
||||
LogDataProvider,
|
||||
useLogData,
|
||||
useSetLogData,
|
||||
LoadingCacheProvider,
|
||||
useLoadingCache,
|
||||
useSetLoadingCache,
|
||||
UpdateStateProvider,
|
||||
useUpdateState,
|
||||
useSetUpdateState,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user