Files
YG-Datasets/easy-dataset-main/components/UpdateChecker.js

236 lines
7.1 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { Box, Button, Snackbar, Alert, Typography, Link, CircularProgress, LinearProgress } from '@mui/material';
import UpdateIcon from '@mui/icons-material/Update';
import { useTranslation } from 'react-i18next';
const UpdateChecker = () => {
const { t } = useTranslation();
const [updateAvailable, setUpdateAvailable] = useState(false);
const [updateInfo, setUpdateInfo] = useState(null);
const [open, setOpen] = useState(false);
const [checking, setChecking] = useState(false);
const [downloading, setDownloading] = useState(false);
const [downloadProgress, setDownloadProgress] = useState(0);
const [updateDownloaded, setUpdateDownloaded] = useState(false);
const [updateError, setUpdateError] = useState(null);
// 检查更新
const checkForUpdates = async () => {
if (!window.electron?.updater) {
console.warn('Update feature is not available, possibly running in browser environment');
return;
}
try {
setChecking(true);
setUpdateError(null);
const result = await window.electron.updater.checkForUpdates();
console.log('Update check result:', result);
// 返回当前版本信息
if (result) {
setUpdateInfo(prev => ({
...prev,
currentVersion: result.currentVersion
}));
}
} catch (error) {
console.error('Failed to check for updates:', error);
// setUpdateError(error.message || 'Failed to check for updates');
} finally {
setChecking(false);
}
};
// 下载更新
const downloadUpdate = async () => {
if (!window.electron?.updater) return;
try {
setDownloading(true);
setUpdateError(null);
await window.electron.updater.downloadUpdate();
} catch (error) {
console.error('下载更新失败:', error);
setUpdateError(error.message || '下载更新失败');
setDownloading(false);
}
};
// 安装更新
const installUpdate = async () => {
if (!window.electron?.updater) return;
try {
await window.electron.updater.installUpdate();
} catch (error) {
console.error('Failed to install update:', error);
// setUpdateError(error.message || 'Failed to install update');
}
};
// 设置更新事件监听
useEffect(() => {
if (!window.electron?.updater) return;
// 有可用更新
const removeUpdateAvailable = window.electron.updater.onUpdateAvailable(info => {
console.log('发现新版本:', info);
setUpdateAvailable(true);
setUpdateInfo(prev => ({
...prev,
...info,
releaseUrl: `https://github.com/ConardLi/easy-dataset/releases`
}));
setOpen(true);
});
// 没有可用更新
const removeUpdateNotAvailable = window.electron.updater.onUpdateNotAvailable(() => {
console.log('没有可用更新');
setUpdateAvailable(false);
});
// 更新错误
const removeUpdateError = window.electron.updater.onUpdateError(error => {
console.error('更新错误:', error);
// setUpdateError(error);
});
// 下载进度
const removeDownloadProgress = window.electron.updater.onDownloadProgress(progress => {
console.log('下载进度:', progress);
setDownloadProgress(progress.percent || 0);
});
// 更新下载完成
const removeUpdateDownloaded = window.electron.updater.onUpdateDownloaded(info => {
console.log('更新下载完成:', info);
setDownloading(false);
setUpdateDownloaded(true);
});
// 组件挂载时检查更新
const timer = setTimeout(() => {
checkForUpdates();
}, 5000);
// 清理函数
return () => {
clearTimeout(timer);
removeUpdateAvailable();
removeUpdateNotAvailable();
removeUpdateError();
removeDownloadProgress();
removeUpdateDownloaded();
};
}, []);
// 定期检查更新(每小时一次)
useEffect(() => {
if (!window.electron?.updater) return;
const interval = setInterval(
() => {
checkForUpdates();
},
60 * 60 * 1000
);
return () => clearInterval(interval);
}, []);
const handleClose = () => {
setOpen(false);
};
// 如果没有更新或者不在 Electron 环境中,不显示任何内容
if (!updateAvailable && !open) return null;
return (
<>
{updateAvailable && (
<Button color="primary" startIcon={<UpdateIcon />} onClick={() => setOpen(true)} sx={{ ml: 1 }}>
{t('update.newVersion')}
</Button>
)}
<Snackbar
open={open}
autoHideDuration={null}
onClose={handleClose}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<Alert onClose={handleClose} severity="info" sx={{ width: '100%', maxWidth: 400 }}>
<Box sx={{ p: 1 }}>
<Typography variant="h6">{t('update.newVersionAvailable')}</Typography>
{updateInfo && (
<>
<Typography variant="body2" sx={{ mt: 1 }}>
{t('update.currentVersion')}: {updateInfo.currentVersion}
</Typography>
<Typography variant="body2">
{t('update.latestVersion')}: {updateInfo.version}
</Typography>
</>
)}
{checking && (
<Box sx={{ display: 'flex', alignItems: 'center', mt: 1 }}>
<CircularProgress size={16} sx={{ mr: 1 }} />
<Typography variant="body2">{t('update.checking')}</Typography>
</Box>
)}
{updateError && (
<Typography variant="body2" color="error.main" sx={{ mt: 1 }}>
{updateError}
</Typography>
)}
{downloading && (
<Box sx={{ mt: 2, width: '100%' }}>
<Typography variant="body2" sx={{ mb: 0.5 }}>
{t('update.downloading')}: {Math.round(downloadProgress)}%
</Typography>
<LinearProgress variant="determinate" value={downloadProgress} />
</Box>
)}
<Box sx={{ mt: 2, display: 'flex', gap: 2 }}>
{/* {!downloading && !updateDownloaded ? (
<Button
variant="contained"
color="primary"
disabled={checking || downloading}
onClick={downloadUpdate}
>
{t('update.downloadNow')}
</Button>
) : updateDownloaded ? (
<Button
variant="contained"
color="primary"
onClick={installUpdate}
>
{t('update.installNow')}
</Button>
) : null} */}
{updateInfo?.releaseUrl && (
<Link href={updateInfo.releaseUrl} target="_blank" rel="noopener noreferrer">
<Button variant="outlined">{t('update.viewRelease')}</Button>
</Link>
)}
</Box>
</Box>
</Alert>
</Snackbar>
</>
);
};
export default UpdateChecker;