import useSWR from "swr"; import { forwardRef, useImperativeHandle, useState, useMemo } from "react"; import { useLockFn } from "ahooks"; import { Box, LinearProgress, Button } from "@mui/material"; import { useTranslation } from "react-i18next"; import { relaunch } from "@tauri-apps/plugin-process"; import { check as checkUpdate } from "@tauri-apps/plugin-updater"; import { BaseDialog, DialogRef, Notice } from "@/components/base"; import { useUpdateState, useSetUpdateState } from "@/services/states"; import { Event, UnlistenFn } from "@tauri-apps/api/event"; import { portableFlag } from "@/pages/_layout"; import { open as openUrl } from "@tauri-apps/plugin-shell"; import ReactMarkdown from "react-markdown"; import { useListen } from "@/hooks/use-listen"; let eventListener: UnlistenFn | null = null; export const UpdateViewer = forwardRef((props, ref) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); const updateState = useUpdateState(); const setUpdateState = useSetUpdateState(); const { addListener } = useListen(); const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, { errorRetryCount: 2, revalidateIfStale: false, focusThrottleInterval: 36e5, // 1 hour }); const [downloaded, setDownloaded] = useState(0); const [buffer, setBuffer] = useState(0); const [total, setTotal] = useState(0); useImperativeHandle(ref, () => ({ open: () => setOpen(true), close: () => setOpen(false), })); const markdownContent = useMemo(() => { if (!updateInfo?.body) { return "New Version is available"; } return updateInfo?.body; }, [updateInfo]); const breakChangeFlag = useMemo(() => { if (!updateInfo?.body) { return false; } return updateInfo?.body.toLowerCase().includes("break change"); }, [updateInfo]); const onUpdate = useLockFn(async () => { if (portableFlag) { Notice.error(t("Portable Updater Error")); return; } if (!updateInfo?.body) return; if (breakChangeFlag) { Notice.error(t("Break Change Update Error")); return; } if (updateState) return; setUpdateState(true); if (eventListener !== null) { eventListener(); } eventListener = await addListener( "tauri://update-download-progress", (e: Event) => { setTotal(e.payload.contentLength); setBuffer(e.payload.chunkLength); setDownloaded((a) => { return a + e.payload.chunkLength; }); }, ); try { await updateInfo.install(); await relaunch(); } catch (err: any) { Notice.error(err?.message || err.toString()); } finally { setUpdateState(false); } }); return ( {`New Version v${updateInfo?.version}`} } contentSx={{ minWidth: 360, maxWidth: 400, height: "50vh" }} okBtn={t("Update")} cancelBtn={t("Cancel")} onClose={() => setOpen(false)} onCancel={() => setOpen(false)} onOk={onUpdate} > { const { children } = props; return ( {children} ); }, }} > {markdownContent} {updateState && ( )} ); });