mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-07-28 19:14:30 +08:00
91 lines
3.4 KiB
TypeScript
91 lines
3.4 KiB
TypeScript
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { App } from "antd";
|
|
import { APP_VERSION } from "@/constant/env";
|
|
import { parseChangelog, type ReleaseInfo } from "@/lib/release";
|
|
|
|
const latestVersionUrl = "https://raw.githubusercontent.com/basketikun/infinite-canvas/main/VERSION";
|
|
const latestChangelogUrl = "https://raw.githubusercontent.com/basketikun/infinite-canvas/main/CHANGELOG.md";
|
|
|
|
function readLocalReleases(): ReleaseInfo[] {
|
|
return __APP_RELEASES__ || [];
|
|
}
|
|
|
|
function toVersionParts(version: string) {
|
|
const match = version.trim().match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
return match ? match.slice(1).map(Number) : null;
|
|
}
|
|
|
|
function isNewerVersion(latestVersion: string, currentVersion: string) {
|
|
const latest = toVersionParts(latestVersion);
|
|
const current = toVersionParts(currentVersion);
|
|
if (!latest || !current) return false;
|
|
return latest.some((value, index) => value > current[index] && latest.slice(0, index).every((part, prevIndex) => part === current[prevIndex]));
|
|
}
|
|
|
|
export function useVersionCheck() {
|
|
const currentVersion = APP_VERSION;
|
|
const { message } = App.useApp();
|
|
const localReleases = useMemo(readLocalReleases, []);
|
|
const [latestVersion, setLatestVersion] = useState(currentVersion);
|
|
const [releases, setReleases] = useState<ReleaseInfo[]>(localReleases);
|
|
const [checking, setChecking] = useState(false);
|
|
const [open, setOpen] = useState(false);
|
|
const hasNewVersion = isNewerVersion(latestVersion, currentVersion);
|
|
|
|
const checkLatestVersion = useCallback(async () => {
|
|
try {
|
|
const response = await fetch(latestVersionUrl);
|
|
if (!response.ok) return false;
|
|
const version = await response.text();
|
|
setLatestVersion(version.trim() || currentVersion);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}, [currentVersion]);
|
|
|
|
const checkLatestRelease = useCallback(
|
|
async (showMessage = false) => {
|
|
setChecking(true);
|
|
try {
|
|
const [versionResponse, changelogResponse] = await Promise.all([fetch(latestVersionUrl), fetch(latestChangelogUrl)]);
|
|
if (!versionResponse.ok) throw new Error("版本读取失败");
|
|
if (!changelogResponse.ok) throw new Error("更新日志读取失败");
|
|
const [version, changelog] = await Promise.all([versionResponse.text(), changelogResponse.text()]);
|
|
setLatestVersion(version.trim() || currentVersion);
|
|
if (changelog.trim()) setReleases(parseChangelog(changelog));
|
|
if (showMessage) message.success("已获取最新版本信息");
|
|
return true;
|
|
} catch {
|
|
setLatestVersion(currentVersion);
|
|
setReleases(localReleases);
|
|
if (showMessage) message.error("获取最新版本信息失败");
|
|
return false;
|
|
} finally {
|
|
setChecking(false);
|
|
}
|
|
},
|
|
[currentVersion, localReleases, message],
|
|
);
|
|
|
|
useEffect(() => {
|
|
void checkLatestVersion();
|
|
}, [checkLatestVersion]);
|
|
|
|
const openReleaseModal = useCallback(() => {
|
|
setOpen(true);
|
|
void checkLatestRelease();
|
|
}, [checkLatestRelease]);
|
|
|
|
return {
|
|
open,
|
|
setOpen,
|
|
openReleaseModal,
|
|
latestVersion,
|
|
releases,
|
|
checking,
|
|
hasNewVersion,
|
|
checkLatestRelease,
|
|
};
|
|
}
|