feat: add check for updates button, close #766
This commit is contained in:
parent
16d80718cb
commit
f4c7b17a87
@ -6,7 +6,7 @@ import {
|
||||
HorizontalRuleRounded,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
const LayoutControl = () => {
|
||||
export const LayoutControl = () => {
|
||||
const minWidth = 40;
|
||||
|
||||
return (
|
||||
@ -37,5 +37,3 @@ const LayoutControl = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LayoutControl;
|
||||
|
@ -2,7 +2,7 @@ import { alpha, ListItem, ListItemButton, ListItemText } from "@mui/material";
|
||||
import { useMatch, useResolvedPath, useNavigate } from "react-router-dom";
|
||||
import type { LinkProps } from "react-router-dom";
|
||||
|
||||
const LayoutItem = (props: LinkProps) => {
|
||||
export const LayoutItem = (props: LinkProps) => {
|
||||
const { to, children } = props;
|
||||
|
||||
const resolved = useResolvedPath(to);
|
||||
@ -40,5 +40,3 @@ const LayoutItem = (props: LinkProps) => {
|
||||
</ListItem>
|
||||
);
|
||||
};
|
||||
|
||||
export default LayoutItem;
|
||||
|
@ -14,7 +14,7 @@ import { useWebsocket } from "@/hooks/use-websocket";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
|
||||
// setup the traffic
|
||||
const LayoutTraffic = () => {
|
||||
export const LayoutTraffic = () => {
|
||||
const { clashInfo } = useClashInfo();
|
||||
const { verge } = useVerge();
|
||||
|
||||
@ -134,5 +134,3 @@ const LayoutTraffic = () => {
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default LayoutTraffic;
|
||||
|
@ -1,17 +1,19 @@
|
||||
import useSWR from "swr";
|
||||
import { useState } from "react";
|
||||
import { useRef } from "react";
|
||||
import { Button } from "@mui/material";
|
||||
import { checkUpdate } from "@tauri-apps/api/updater";
|
||||
import UpdateDialog from "./update-dialog";
|
||||
import { UpdateViewer } from "../setting/mods/update-viewer";
|
||||
import { DialogRef } from "../base";
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const UpdateButton = (props: Props) => {
|
||||
export const UpdateButton = (props: Props) => {
|
||||
const { className } = props;
|
||||
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const viewerRef = useRef<DialogRef>(null);
|
||||
|
||||
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
||||
errorRetryCount: 2,
|
||||
revalidateIfStale: false,
|
||||
@ -22,21 +24,17 @@ const UpdateButton = (props: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<UpdateViewer ref={viewerRef} />
|
||||
|
||||
<Button
|
||||
color="error"
|
||||
variant="contained"
|
||||
size="small"
|
||||
className={className}
|
||||
onClick={() => setDialogOpen(true)}
|
||||
onClick={() => viewerRef.current?.open()}
|
||||
>
|
||||
New
|
||||
</Button>
|
||||
|
||||
{dialogOpen && (
|
||||
<UpdateDialog open={dialogOpen} onClose={() => setDialogOpen(false)} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateButton;
|
||||
|
@ -9,7 +9,7 @@ import { useVerge } from "@/hooks/use-verge";
|
||||
/**
|
||||
* custom theme
|
||||
*/
|
||||
export default function useCustomTheme() {
|
||||
export const useCustomTheme = () => {
|
||||
const { verge } = useVerge();
|
||||
const { theme_mode, theme_setting } = verge ?? {};
|
||||
const [mode, setMode] = useRecoilState(atomThemeMode);
|
||||
@ -121,4 +121,4 @@ export default function useCustomTheme() {
|
||||
}, [mode, theme_setting]);
|
||||
|
||||
return { theme };
|
||||
}
|
||||
};
|
||||
|
@ -1,43 +1,45 @@
|
||||
import useSWR from "swr";
|
||||
import snarkdown from "snarkdown";
|
||||
import { useMemo } from "react";
|
||||
import { forwardRef, useImperativeHandle, useState, useMemo } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { Box, styled } from "@mui/material";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
styled,
|
||||
} from "@mui/material";
|
||||
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 { Notice } from "@/components/base";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const UpdateLog = styled(Box)(() => ({
|
||||
"h1,h2,h3,ul,ol,p": { margin: "0.5em 0", color: "inherit" },
|
||||
}));
|
||||
|
||||
const UpdateDialog = (props: Props) => {
|
||||
const { open, onClose } = props;
|
||||
export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [updateState, setUpdateState] = useRecoilState(atomUpdateState);
|
||||
|
||||
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
||||
errorRetryCount: 2,
|
||||
revalidateIfStale: false,
|
||||
focusThrottleInterval: 36e5, // 1 hour
|
||||
});
|
||||
|
||||
const [updateState, setUpdateState] = useRecoilState(atomUpdateState);
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => setOpen(true),
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
const onUpdate = async () => {
|
||||
// markdown parser
|
||||
const parseContent = useMemo(() => {
|
||||
if (!updateInfo?.manifest?.body) {
|
||||
return "New Version is available";
|
||||
}
|
||||
return snarkdown(updateInfo?.manifest?.body);
|
||||
}, [updateInfo]);
|
||||
|
||||
const onUpdate = useLockFn(async () => {
|
||||
if (updateState) return;
|
||||
setUpdateState(true);
|
||||
|
||||
@ -49,39 +51,20 @@ const UpdateDialog = (props: Props) => {
|
||||
} finally {
|
||||
setUpdateState(false);
|
||||
}
|
||||
};
|
||||
|
||||
// markdown parser
|
||||
const parseContent = useMemo(() => {
|
||||
if (!updateInfo?.manifest?.body) {
|
||||
return "New Version is available";
|
||||
}
|
||||
return snarkdown(updateInfo?.manifest?.body);
|
||||
}, [updateInfo]);
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle>New Version v{updateInfo?.manifest?.version}</DialogTitle>
|
||||
|
||||
<DialogContent sx={{ minWidth: 360, maxWidth: 400, maxHeight: "50vh" }}>
|
||||
<UpdateLog dangerouslySetInnerHTML={{ __html: parseContent }} />
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button variant="outlined" onClick={onClose}>
|
||||
{t("Cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
autoFocus
|
||||
variant="contained"
|
||||
disabled={updateState}
|
||||
onClick={onUpdate}
|
||||
>
|
||||
{t("Update")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={`New Version v${updateInfo?.manifest?.version}`}
|
||||
contentSx={{ minWidth: 360, maxWidth: 400, maxHeight: "50vh" }}
|
||||
okBtn={t("Update")}
|
||||
cancelBtn={t("Cancel")}
|
||||
onClose={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
onOk={onUpdate}
|
||||
>
|
||||
<UpdateLog dangerouslySetInnerHTML={{ __html: parseContent }} />
|
||||
</BaseDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateDialog;
|
||||
});
|
@ -1,11 +1,13 @@
|
||||
import { useRef } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { IconButton, MenuItem, Select, Typography } from "@mui/material";
|
||||
import { openAppDir, openCoreDir, openLogsDir } 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";
|
||||
import { DialogRef } from "@/components/base";
|
||||
import { DialogRef, Notice } from "@/components/base";
|
||||
import { SettingList, SettingItem } from "./mods/setting-comp";
|
||||
import { ThemeModeSwitch } from "./mods/theme-mode-switch";
|
||||
import { ConfigViewer } from "./mods/config-viewer";
|
||||
@ -14,29 +16,45 @@ import { MiscViewer } from "./mods/misc-viewer";
|
||||
import { ThemeViewer } from "./mods/theme-viewer";
|
||||
import { GuardState } from "./mods/guard-state";
|
||||
import { LayoutViewer } from "./mods/layout-viewer";
|
||||
import { UpdateViewer } from "./mods/update-viewer";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
interface Props {
|
||||
onError?: (err: Error) => void;
|
||||
}
|
||||
|
||||
const OS = getSystem();
|
||||
|
||||
const SettingVerge = ({ onError }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||
|
||||
const { theme_mode, theme_blur, traffic_graph, language } = verge ?? {};
|
||||
const { theme_mode, language } = verge ?? {};
|
||||
|
||||
const configRef = useRef<DialogRef>(null);
|
||||
const hotkeyRef = useRef<DialogRef>(null);
|
||||
const miscRef = useRef<DialogRef>(null);
|
||||
const themeRef = useRef<DialogRef>(null);
|
||||
const layoutRef = useRef<DialogRef>(null);
|
||||
const updateRef = useRef<DialogRef>(null);
|
||||
|
||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
||||
const onChangeData = (patch: Partial<IVergeConfig>) => {
|
||||
mutateVerge({ ...verge, ...patch }, false);
|
||||
};
|
||||
|
||||
const onCheckUpdate = useLockFn(async () => {
|
||||
try {
|
||||
const info = await checkUpdate();
|
||||
if (!info?.shouldUpdate) {
|
||||
Notice.success("No Updates Available");
|
||||
} else {
|
||||
updateRef.current?.open();
|
||||
}
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<SettingList title={t("Verge Setting")}>
|
||||
<ThemeViewer ref={themeRef} />
|
||||
@ -44,6 +62,7 @@ const SettingVerge = ({ onError }: Props) => {
|
||||
<HotkeyViewer ref={hotkeyRef} />
|
||||
<MiscViewer ref={miscRef} />
|
||||
<LayoutViewer ref={layoutRef} />
|
||||
<UpdateViewer ref={updateRef} />
|
||||
|
||||
<SettingItem label={t("Language")}>
|
||||
<GuardState
|
||||
@ -160,6 +179,19 @@ const SettingVerge = ({ onError }: Props) => {
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
|
||||
{!(OS === "windows" && WIN_PORTABLE) && (
|
||||
<SettingItem label={t("Check for Updates")}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ my: "2px" }}
|
||||
onClick={onCheckUpdate}
|
||||
>
|
||||
<ArrowForward />
|
||||
</IconButton>
|
||||
</SettingItem>
|
||||
)}
|
||||
|
||||
<SettingItem label={t("Verge Version")}>
|
||||
<Typography sx={{ py: "7px", pr: 1 }}>v{version}</Typography>
|
||||
</SettingItem>
|
||||
|
@ -90,6 +90,7 @@
|
||||
"Open App Dir": "Open App Dir",
|
||||
"Open Core Dir": "Open Core Dir",
|
||||
"Open Logs Dir": "Open Logs Dir",
|
||||
"Check for Updates": "Check for Updates",
|
||||
"Verge Version": "Verge Version",
|
||||
"theme.light": "Light",
|
||||
"theme.dark": "Dark",
|
||||
|
@ -90,6 +90,7 @@
|
||||
"Open App Dir": "应用目录",
|
||||
"Open Core Dir": "内核目录",
|
||||
"Open Logs Dir": "日志目录",
|
||||
"Check for Updates": "检查更新",
|
||||
"Verge Version": "应用版本",
|
||||
"theme.light": "浅色",
|
||||
"theme.dark": "深色",
|
||||
|
@ -13,11 +13,11 @@ import { getAxios } from "@/services/api";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { ReactComponent as LogoSvg } from "@/assets/image/logo.svg";
|
||||
import { BaseErrorBoundary, Notice } from "@/components/base";
|
||||
import LayoutItem from "@/components/layout/layout-item";
|
||||
import LayoutControl from "@/components/layout/layout-control";
|
||||
import LayoutTraffic from "@/components/layout/layout-traffic";
|
||||
import UpdateButton from "@/components/layout/update-button";
|
||||
import useCustomTheme from "@/components/layout/use-custom-theme";
|
||||
import { LayoutItem } from "@/components/layout/layout-item";
|
||||
import { LayoutControl } from "@/components/layout/layout-control";
|
||||
import { LayoutTraffic } from "@/components/layout/layout-traffic";
|
||||
import { UpdateButton } from "@/components/layout/update-button";
|
||||
import { useCustomTheme } from "@/components/layout/use-custom-theme";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import "dayjs/locale/ru";
|
||||
import "dayjs/locale/zh-cn";
|
||||
|
Loading…
x
Reference in New Issue
Block a user