mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-18 16:30:32 +08:00
fix(updater): compute real download progress and stabilize progress bar states
This commit is contained in:
parent
bfa7e1a2e6
commit
32a5044026
@ -1,32 +1,26 @@
|
|||||||
import { Box, Button, LinearProgress } from "@mui/material";
|
import { Box, Button, LinearProgress } from "@mui/material";
|
||||||
import { Event, UnlistenFn } from "@tauri-apps/api/event";
|
|
||||||
import { relaunch } from "@tauri-apps/plugin-process";
|
import { relaunch } from "@tauri-apps/plugin-process";
|
||||||
import { open as openUrl } from "@tauri-apps/plugin-shell";
|
import { open as openUrl } from "@tauri-apps/plugin-shell";
|
||||||
|
import type { DownloadEvent } from "@tauri-apps/plugin-updater";
|
||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import type { Ref } from "react";
|
import type { Ref } from "react";
|
||||||
import { useEffect, useImperativeHandle, useMemo, useState } from "react";
|
import { useImperativeHandle, useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
import { BaseDialog, DialogRef } from "@/components/base";
|
import { BaseDialog, DialogRef } from "@/components/base";
|
||||||
import { useListen } from "@/hooks/use-listen";
|
|
||||||
import { portableFlag } from "@/pages/_layout";
|
import { portableFlag } from "@/pages/_layout";
|
||||||
import { showNotice } from "@/services/noticeService";
|
import { showNotice } from "@/services/noticeService";
|
||||||
import { useSetUpdateState, useUpdateState } from "@/services/states";
|
import { useSetUpdateState, useUpdateState } from "@/services/states";
|
||||||
import { checkUpdateSafe as checkUpdate } from "@/services/update";
|
import { checkUpdateSafe as checkUpdate } from "@/services/update";
|
||||||
import { debugLog } from "@/utils/debug";
|
|
||||||
|
|
||||||
export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [currentProgressListener, setCurrentProgressListener] =
|
|
||||||
useState<UnlistenFn | null>(null);
|
|
||||||
|
|
||||||
const updateState = useUpdateState();
|
const updateState = useUpdateState();
|
||||||
const setUpdateState = useSetUpdateState();
|
const setUpdateState = useSetUpdateState();
|
||||||
const { addListener } = useListen();
|
|
||||||
|
|
||||||
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
||||||
errorRetryCount: 2,
|
errorRetryCount: 2,
|
||||||
@ -35,8 +29,14 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [downloaded, setDownloaded] = useState(0);
|
const [downloaded, setDownloaded] = useState(0);
|
||||||
const [buffer, setBuffer] = useState(0);
|
|
||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
|
const downloadedRef = useRef(0);
|
||||||
|
const totalRef = useRef(0);
|
||||||
|
|
||||||
|
const progress = useMemo(() => {
|
||||||
|
if (total <= 0) return 0;
|
||||||
|
return Math.min((downloaded / total) * 100, 100);
|
||||||
|
}, [downloaded, total]);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
open: () => setOpen(true),
|
open: () => setOpen(true),
|
||||||
@ -69,46 +69,49 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
|||||||
}
|
}
|
||||||
if (updateState) return;
|
if (updateState) return;
|
||||||
setUpdateState(true);
|
setUpdateState(true);
|
||||||
|
setDownloaded(0);
|
||||||
|
setTotal(0);
|
||||||
|
downloadedRef.current = 0;
|
||||||
|
totalRef.current = 0;
|
||||||
|
|
||||||
if (currentProgressListener) {
|
const onDownloadEvent = (event: DownloadEvent) => {
|
||||||
currentProgressListener();
|
if (event.event === "Started") {
|
||||||
|
const contentLength = event.data.contentLength ?? 0;
|
||||||
|
totalRef.current = contentLength;
|
||||||
|
setTotal(contentLength);
|
||||||
|
setDownloaded(0);
|
||||||
|
downloadedRef.current = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const progressListener = await addListener(
|
if (event.event === "Progress") {
|
||||||
"tauri://update-download-progress",
|
setDownloaded((prev) => {
|
||||||
(e: Event<any>) => {
|
const next = prev + event.data.chunkLength;
|
||||||
setTotal(e.payload.contentLength);
|
downloadedRef.current = next;
|
||||||
setBuffer(e.payload.chunkLength);
|
return next;
|
||||||
setDownloaded((a) => {
|
|
||||||
return a + e.payload.chunkLength;
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
);
|
|
||||||
setCurrentProgressListener(() => progressListener);
|
if (event.event === "Finished" && totalRef.current === 0) {
|
||||||
|
totalRef.current = downloadedRef.current;
|
||||||
|
setTotal(downloadedRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateInfo.downloadAndInstall();
|
await updateInfo.downloadAndInstall(onDownloadEvent);
|
||||||
await relaunch();
|
await relaunch();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
showNotice.error(err);
|
showNotice.error(err);
|
||||||
} finally {
|
} finally {
|
||||||
setUpdateState(false);
|
setUpdateState(false);
|
||||||
if (progressListener) {
|
setDownloaded(0);
|
||||||
progressListener();
|
setTotal(0);
|
||||||
}
|
downloadedRef.current = 0;
|
||||||
setCurrentProgressListener(null);
|
totalRef.current = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
if (currentProgressListener) {
|
|
||||||
debugLog("UpdateViewer unmounting, cleaning up progress listener.");
|
|
||||||
currentProgressListener();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [currentProgressListener]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
open={open}
|
open={open}
|
||||||
@ -157,9 +160,8 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
|||||||
</Box>
|
</Box>
|
||||||
{updateState && (
|
{updateState && (
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="buffer"
|
variant={total > 0 ? "determinate" : "indeterminate"}
|
||||||
value={(downloaded / total) * 100}
|
value={progress}
|
||||||
valueBuffer={buffer}
|
|
||||||
sx={{ marginTop: "5px" }}
|
sx={{ marginTop: "5px" }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user