From f4c7b17a87ae853ad67fdcea727e93266babf779 Mon Sep 17 00:00:00 2001 From: GyDi Date: Sun, 10 Sep 2023 14:30:31 +0800 Subject: [PATCH] feat: add check for updates button, close #766 --- src/components/layout/layout-control.tsx | 4 +- src/components/layout/layout-item.tsx | 4 +- src/components/layout/layout-traffic.tsx | 4 +- src/components/layout/update-button.tsx | 20 ++--- src/components/layout/use-custom-theme.ts | 4 +- .../mods/update-viewer.tsx} | 89 ++++++++----------- src/components/setting/setting-verge.tsx | 40 ++++++++- src/locales/en.json | 1 + src/locales/zh.json | 1 + src/pages/_layout.tsx | 10 +-- 10 files changed, 93 insertions(+), 84 deletions(-) rename src/components/{layout/update-dialog.tsx => setting/mods/update-viewer.tsx} (53%) diff --git a/src/components/layout/layout-control.tsx b/src/components/layout/layout-control.tsx index 379527b..6ec12b9 100644 --- a/src/components/layout/layout-control.tsx +++ b/src/components/layout/layout-control.tsx @@ -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; diff --git a/src/components/layout/layout-item.tsx b/src/components/layout/layout-item.tsx index 545b36e..5a33da2 100644 --- a/src/components/layout/layout-item.tsx +++ b/src/components/layout/layout-item.tsx @@ -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) => { ); }; - -export default LayoutItem; diff --git a/src/components/layout/layout-traffic.tsx b/src/components/layout/layout-traffic.tsx index 01e55e5..4e65a87 100644 --- a/src/components/layout/layout-traffic.tsx +++ b/src/components/layout/layout-traffic.tsx @@ -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 = () => { ); }; - -export default LayoutTraffic; diff --git a/src/components/layout/update-button.tsx b/src/components/layout/update-button.tsx index 5bccb4c..b71ea07 100644 --- a/src/components/layout/update-button.tsx +++ b/src/components/layout/update-button.tsx @@ -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(null); + const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, { errorRetryCount: 2, revalidateIfStale: false, @@ -22,21 +24,17 @@ const UpdateButton = (props: Props) => { return ( <> + + - - {dialogOpen && ( - setDialogOpen(false)} /> - )} ); }; - -export default UpdateButton; diff --git a/src/components/layout/use-custom-theme.ts b/src/components/layout/use-custom-theme.ts index d7aae55..e029494 100644 --- a/src/components/layout/use-custom-theme.ts +++ b/src/components/layout/use-custom-theme.ts @@ -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 }; -} +}; diff --git a/src/components/layout/update-dialog.tsx b/src/components/setting/mods/update-viewer.tsx similarity index 53% rename from src/components/layout/update-dialog.tsx rename to src/components/setting/mods/update-viewer.tsx index 392e086..8b4e68a 100644 --- a/src/components/layout/update-dialog.tsx +++ b/src/components/setting/mods/update-viewer.tsx @@ -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((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 ( - - New Version v{updateInfo?.manifest?.version} - - - - - - - - - - + setOpen(false)} + onCancel={() => setOpen(false)} + onOk={onUpdate} + > + + ); -}; - -export default UpdateDialog; +}); diff --git a/src/components/setting/setting-verge.tsx b/src/components/setting/setting-verge.tsx index 9805e5e..d54094d 100644 --- a/src/components/setting/setting-verge.tsx +++ b/src/components/setting/setting-verge.tsx @@ -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(null); const hotkeyRef = useRef(null); const miscRef = useRef(null); const themeRef = useRef(null); const layoutRef = useRef(null); + const updateRef = useRef(null); - const onSwitchFormat = (_e: any, value: boolean) => value; const onChangeData = (patch: Partial) => { 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 ( @@ -44,6 +62,7 @@ const SettingVerge = ({ onError }: Props) => { + { + {!(OS === "windows" && WIN_PORTABLE) && ( + + + + + + )} + v{version} diff --git a/src/locales/en.json b/src/locales/en.json index 3a14bc5..1ac4a0e 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -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", diff --git a/src/locales/zh.json b/src/locales/zh.json index 65a1340..26964be 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -90,6 +90,7 @@ "Open App Dir": "应用目录", "Open Core Dir": "内核目录", "Open Logs Dir": "日志目录", + "Check for Updates": "检查更新", "Verge Version": "应用版本", "theme.light": "浅色", "theme.dark": "深色", diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index f0b1b96..27ef9b0 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -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";