feat : Add electron auto update function
This commit is contained in:
parent
564c48861d
commit
9432cd793f
|
@ -37,6 +37,6 @@
|
||||||
publish:{
|
publish:{
|
||||||
provider: 'generic',
|
provider: 'generic',
|
||||||
channel: 'latest',
|
channel: 'latest',
|
||||||
url: 'https://github.com/RSS1101/electron-vite-react/releases/download/v9.9.9/',
|
url: 'https://github.com/electron-vite/electron-vite-react/releases/download/v0.9.9/',
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,108 +1,90 @@
|
||||||
import { autoUpdater } from "electron-updater"
|
import { autoUpdater } from "electron-updater"
|
||||||
import { app, ipcMain } from "electron";
|
import { app, ipcMain } from "electron";
|
||||||
export const update = (win: Electron.CrossProcessExports.BrowserWindow) => {
|
export const update = (win: Electron.CrossProcessExports.BrowserWindow) => {
|
||||||
// 设置日志打印
|
|
||||||
|
|
||||||
// 是否自动下载更新,设置为 false 时将通过 API 触发更新下载
|
// When set to false, the update download will be triggered through the API
|
||||||
autoUpdater.autoDownload = false;
|
autoUpdater.autoDownload = false;
|
||||||
|
|
||||||
autoUpdater.disableWebInstaller = false
|
autoUpdater.disableWebInstaller = false
|
||||||
|
|
||||||
// 是否允许版本降级,也就是服务器版本低于本地版本时,依旧以服务器版本为主
|
|
||||||
autoUpdater.allowDowngrade = false;
|
autoUpdater.allowDowngrade = false;
|
||||||
|
|
||||||
// 设置服务器版本最新版本查询接口配置
|
// Save the version status of whether the update needs to be installed,
|
||||||
autoUpdater.setFeedURL({
|
// Because the user needs to update immediately and later after the update is downloaded
|
||||||
provider: 'generic',
|
|
||||||
channel: 'latest',
|
|
||||||
url: 'https://github.com/RSS1101/electron-vite-react/releases/download/v9.9.9/',
|
|
||||||
});
|
|
||||||
|
|
||||||
// 保存是否需要安装更新的版本状态,因为需要提供用户在下载完成更新之后立即更新和稍后更新的操作
|
|
||||||
let NEED_INSTALL = false;
|
let NEED_INSTALL = false;
|
||||||
|
|
||||||
Object.defineProperty(app, 'isPackaged', {
|
// Check whether update is used
|
||||||
get() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 调用 API 检查是否用更新
|
|
||||||
ipcMain.on('check-update',()=>{
|
ipcMain.on('check-update',()=>{
|
||||||
autoUpdater.checkForUpdatesAndNotify()
|
autoUpdater.checkForUpdatesAndNotify()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
win.webContents.send('check-update-type',{ checkUpdate: true})
|
win.webContents.send('check-update-type',{ checkUpdate: true})
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
// 网络错误 network error
|
// network error
|
||||||
win.webContents.send('check-update-type', { checkUpdate: false})
|
win.webContents.send('check-update-type', { checkUpdate: false})
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
// 检测开始
|
// start check
|
||||||
autoUpdater.on('checking-for-update', function () {
|
autoUpdater.on('checking-for-update', function () {
|
||||||
console.log('checking-for-update')
|
console.log('checking-for-update')
|
||||||
})
|
})
|
||||||
// 更新可用
|
// update available
|
||||||
autoUpdater.on('update-available', (arg) => {
|
autoUpdater.on('update-available', (arg) => {
|
||||||
console.log('update-available')
|
console.log('update-available')
|
||||||
win.webContents.send('is-update-available', { isUpdate: true, oldVersion: app.getVersion(), newVersion: arg?.version })
|
win.webContents.send('is-update-available', { isUpdate: true, oldVersion: app.getVersion(), newVersion: arg?.version })
|
||||||
})
|
})
|
||||||
// 更新不可用
|
// update not available
|
||||||
autoUpdater.on('update-not-available', (arg) => {
|
autoUpdater.on('update-not-available', (arg) => {
|
||||||
console.log('update-not-available')
|
console.log('update-not-available')
|
||||||
win.webContents.send('is-update-available', { isUpdate: false, oldVersion: app.getVersion(), newVersion: arg?.version })
|
win.webContents.send('is-update-available', { isUpdate: false, oldVersion: app.getVersion(), newVersion: arg?.version })
|
||||||
})
|
})
|
||||||
// API 触发更新下载
|
|
||||||
const startDownload = (callback: any, successCallback: any) => {
|
const startDownload = (callback: any, successCallback: any) => {
|
||||||
// 监听下载进度并推送到更新窗口
|
// Monitor the download progress and push it to the update window
|
||||||
autoUpdater.on('download-progress', (data) => {
|
autoUpdater.on('download-progress', (data) => {
|
||||||
console.log("progress", data)
|
console.log("progress", data)
|
||||||
win.webContents.send('download-progress-data', data)
|
win.webContents.send('download-progress-data', data)
|
||||||
callback && callback instanceof Function && callback(null, data);
|
callback && callback instanceof Function && callback(null, data);
|
||||||
});
|
});
|
||||||
// 监听下载错误并推送到更新窗口
|
// Listen for download errors and push to the update window
|
||||||
autoUpdater.on('error', (err) => {
|
autoUpdater.on('error', (err) => {
|
||||||
console.log("error")
|
|
||||||
callback && callback instanceof Function && callback(err);
|
callback && callback instanceof Function && callback(err);
|
||||||
});
|
});
|
||||||
// 监听下载完成并推送到更新窗口
|
// Listen to the download completion and push it to the update window
|
||||||
autoUpdater.on('update-downloaded', () => {
|
autoUpdater.on('update-downloaded', () => {
|
||||||
console.log("update-downloaded")
|
|
||||||
NEED_INSTALL = true;
|
NEED_INSTALL = true;
|
||||||
successCallback && successCallback instanceof Function && successCallback();
|
successCallback && successCallback instanceof Function && successCallback();
|
||||||
});
|
});
|
||||||
// 下载更新
|
|
||||||
autoUpdater.downloadUpdate();
|
autoUpdater.downloadUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听应用层发送来的进程消息,开始下载更新
|
// Listen to the process message sent by the application layer and start downloading updates
|
||||||
ipcMain.on('start-download', (event) => {
|
ipcMain.on('start-download', (event) => {
|
||||||
console.log("start")
|
console.log("start")
|
||||||
startDownload(
|
startDownload(
|
||||||
(err: any, progressInfo: { percent: any; }) => {
|
(err: any, progressInfo: { percent: any; }) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
//回推下载错误消息
|
// callback download error message
|
||||||
console.log("update-error")
|
|
||||||
event.sender.send('update-error', { updateError:true});
|
event.sender.send('update-error', { updateError:true});
|
||||||
} else {
|
} else {
|
||||||
//回推下载进度消息
|
// callback update progress message
|
||||||
console.log("pdate-progress-percent")
|
|
||||||
event.sender.send('update-progress', { progressInfo: progressInfo.percent });
|
event.sender.send('update-progress', { progressInfo: progressInfo.percent });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
//回推下载完成消息
|
// callback update downed message
|
||||||
console.log("update-downed")
|
|
||||||
event.sender.send('update-downed');
|
event.sender.send('update-downed');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// install now
|
||||||
ipcMain.on('quit-and-install', () => {
|
ipcMain.on('quit-and-install', () => {
|
||||||
autoUpdater.quitAndInstall(false, true);
|
autoUpdater.quitAndInstall(false, true);
|
||||||
})
|
})
|
||||||
|
|
||||||
// 用户点击稍后安装后程序退出时执行立即安装更新
|
// install later
|
||||||
app.on('will-quit', () => {
|
app.on('will-quit', () => {
|
||||||
console.log("NEED_INSTALL=true")
|
console.log("NEED_INSTALL=true")
|
||||||
if (NEED_INSTALL) {
|
if (NEED_INSTALL) {
|
||||||
|
|
|
@ -32,10 +32,6 @@
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
button{
|
|
||||||
margin: 0 20px;
|
|
||||||
background-color: #646cffaa;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.read-the-docs {
|
.read-the-docs {
|
||||||
|
|
61
src/App.tsx
61
src/App.tsx
|
@ -1,75 +1,36 @@
|
||||||
import nodeLogo from "./assets/node.svg"
|
import nodeLogo from './assets/node.svg'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import './App.scss'
|
import './App.scss'
|
||||||
import Update from "./pages/update"
|
import Update from '@/components/update'
|
||||||
import { ipcRenderer } from "electron"
|
|
||||||
|
|
||||||
console.log('[App.tsx]', `Hello world from Electron ${process.versions.electron}!`)
|
console.log('[App.tsx]', `Hello world from Electron ${process.versions.electron}!`)
|
||||||
|
|
||||||
interface checkUpdateType {
|
|
||||||
checkUpdate: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [count, setCount] = useState(0)
|
const [count, setCount] = useState(0)
|
||||||
const ref =useRef<any>(null)
|
|
||||||
const [checkBtnText, setCheckBtnText] = useState('check update')
|
|
||||||
const [checkLoading, setCheckLoading] = useState(false)
|
|
||||||
const [checkType, setCheckType] = useState(false)
|
|
||||||
const [openModalType, setopenModalType] = useState(false)
|
|
||||||
/**
|
|
||||||
* @description 检查是否有新的更新 Listen for new updates
|
|
||||||
*/
|
|
||||||
const checkUpdate = () => {
|
|
||||||
setCheckLoading(true)
|
|
||||||
setCheckBtnText('checking Update ...')
|
|
||||||
ipcRenderer.send('check-update')
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @description 获取到检查结果 Get the check results
|
|
||||||
*/
|
|
||||||
ipcRenderer.on('check-update-type', (_event, ...args: checkUpdateType[]) => {
|
|
||||||
setCheckLoading(false)
|
|
||||||
setCheckBtnText('check update')
|
|
||||||
setCheckType(args[0].checkUpdate)
|
|
||||||
setopenModalType(true)
|
|
||||||
})
|
|
||||||
/**
|
|
||||||
* @description 在通信监听的过程中获取不到ref.
|
|
||||||
*/
|
|
||||||
useEffect(()=>{
|
|
||||||
if (openModalType){
|
|
||||||
ref.current!.openModal()
|
|
||||||
setopenModalType(false)
|
|
||||||
}
|
|
||||||
}, [openModalType])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className='App'>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://github.com/electron-vite/electron-vite-react" target="_blank">
|
<a href='https://github.com/electron-vite/electron-vite-react' target='_blank'>
|
||||||
<img src="./electron-vite.svg" className="logo" alt="Electron + Vite logo" />
|
<img src='./electron-vite.svg' className='logo' alt='Electron + Vite logo' />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<h1>Electron + Vite + React</h1>
|
<h1>Electron + Vite + React</h1>
|
||||||
<div className="card">
|
<div className='card'>
|
||||||
<button onClick={() => setCount((count) => count + 1)}>
|
<button onClick={() => setCount((count) => count + 1)}>
|
||||||
count is {count}
|
count is {count}
|
||||||
</button>
|
</button>
|
||||||
<button disabled={checkLoading} onClick={checkUpdate}>
|
|
||||||
{checkBtnText}
|
|
||||||
</button>
|
|
||||||
<p>
|
<p>
|
||||||
Edit <code>src/App.tsx</code> and save to test HMR
|
Edit <code>src/App.tsx</code> and save to test HMR
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="read-the-docs">
|
<p className='read-the-docs'>
|
||||||
Click on the Electron + Vite logo to learn more
|
Click on the Electron + Vite logo to learn more
|
||||||
</p>
|
</p>
|
||||||
<div className="flex-center">
|
<div className='flex-center'>
|
||||||
Place static files into the<code>/public</code> folder <img style={{ width: "5em" }} src={nodeLogo} alt="Node logo" />
|
Place static files into the<code>/public</code> folder <img style={{ width: '5em' }} src={nodeLogo} alt='Node logo' />
|
||||||
</div>
|
</div>
|
||||||
<Update ref={ref} checkType={checkType}/>
|
<Update />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
import { ReactNode } from 'react';
|
|
||||||
interface childrens {
|
|
||||||
titleText?: string;
|
|
||||||
isHeaderShow?: boolean;
|
|
||||||
isFooterShow?: boolean;
|
|
||||||
canCelText?: string;
|
|
||||||
submitText?: string;
|
|
||||||
onSubmit?: () => void;
|
|
||||||
onCanCel?: () => void;
|
|
||||||
}
|
|
||||||
export interface ModalChildType extends childrens {
|
|
||||||
body: ReactNode | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ModalPropsType extends childrens {
|
|
||||||
isOpenModal: boolean;
|
|
||||||
children: ReactNode | null;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { RsProgressType } from './type';
|
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
const RsProgress = (props: RsProgressType) => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="rs-progress">
|
|
||||||
<div className="rs-progress-pr" style={{ width: props.rateWidth ?? 250 }}>
|
|
||||||
<div
|
|
||||||
className="rs-progress-rate"
|
|
||||||
style={{
|
|
||||||
width: (props.percent ?? 0) * ((props.rateWidth ?? 250) / 100),
|
|
||||||
backgroundColor: props.rateColor ?? 'blue',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span className='rs-progress-num'>{props.percent > 100 ? 100 :(props.percent.toString().substring(0,2) ?? 0) }%</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RsProgress;
|
|
|
@ -1,5 +0,0 @@
|
||||||
export interface RsProgressType {
|
|
||||||
rateColor?: string;
|
|
||||||
rateWidth?: number;
|
|
||||||
percent: number;
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
.rs-modal-bg{
|
.up-modal-bg{
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -7,30 +7,30 @@
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
background: rgba(0, 0, 0, 0.3);
|
background: rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
.rs-modal {
|
.up-modal {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20vh;
|
top: 20vh;
|
||||||
left: 30vw;
|
left: 30vw;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
.rs-modal-panel {
|
.up-modal-panel {
|
||||||
border: 1px solid #000000;
|
border: 1px solid #000000;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
.rs-modal-header {
|
.up-modal-header {
|
||||||
$titleheight: 38px;
|
$titleheight: 38px;
|
||||||
width: 530px;
|
width: 530px;
|
||||||
height: $titleheight;
|
height: $titleheight;
|
||||||
line-height: $titleheight;
|
line-height: $titleheight;
|
||||||
background-color: rgb(99, 153, 255);
|
background-color: rgb(99, 153, 255);
|
||||||
display: flex;
|
display: flex;
|
||||||
.rs-modal-header-text {
|
.up-modal-header-text {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 480px;
|
width: 480px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.rs-modal-body{
|
.up-modal-body{
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
.rs-modal-footer {
|
.up-modal-footer {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
justify-content: end;
|
|
@ -4,12 +4,12 @@ import './index.scss';
|
||||||
const ModalTemplate = (child: ModalChildType) => {
|
const ModalTemplate = (child: ModalChildType) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="rs-modal-bg" onClick={child.onCanCel} />
|
<div className="up-modal-bg" onClick={child.onCanCel} />
|
||||||
<div className="rs-modal">
|
<div className="up-modal">
|
||||||
<div className="rs-modal-panel">
|
<div className="up-modal-panel">
|
||||||
{child.isHeaderShow ? (
|
{child.isHeaderShow ? (
|
||||||
<div className="rs-modal-header">
|
<div className="up-modal-header">
|
||||||
<div className="rs-modal-header-text">{child.titleText}</div>
|
<div className="up-modal-header-text">{child.titleText}</div>
|
||||||
<svg
|
<svg
|
||||||
onClick={child.onCanCel}
|
onClick={child.onCanCel}
|
||||||
className="icon"
|
className="icon"
|
||||||
|
@ -28,11 +28,11 @@ const ModalTemplate = (child: ModalChildType) => {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div className="rs-modal-body">{child.body}</div>
|
<div className="up-modal-body">{child.body}</div>
|
||||||
{child.isFooterShow ? (
|
{child.isFooterShow ? (
|
||||||
<div className="rs-modal-footer">
|
<div className="up-modal-footer">
|
||||||
<button onClick={child.onSubmit}>{child.submitText ?? '确认'}</button>
|
{(child.isSubmitShow ?? true) ?<button onClick={child.onSubmit}>{child.submitText ?? '确认'}</button> : null}
|
||||||
<button onClick={child.onCanCel}>{child.canCelText ?? '取消'}</button>
|
{(child.isCanCelShow ?? true) ? <button onClick={child.onCanCel}>{child.canCelText ?? '取消'}</button> : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,13 +41,15 @@ const ModalTemplate = (child: ModalChildType) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RsModal = (props: ModalPropsType) => {
|
const Modal = (props: ModalPropsType) => {
|
||||||
return createPortal(
|
return createPortal(
|
||||||
props.isOpenModal?
|
props.isOpenModal?
|
||||||
ModalTemplate({
|
ModalTemplate({
|
||||||
titleText: props.titleText,
|
titleText: props.titleText,
|
||||||
isHeaderShow: props.isHeaderShow ?? true,
|
isHeaderShow: props.isHeaderShow ?? true,
|
||||||
isFooterShow: props.isFooterShow ?? true,
|
isFooterShow: props.isFooterShow ?? true,
|
||||||
|
isCanCelShow: props.isCanCelShow ?? true,
|
||||||
|
isSubmitShow: props.isSubmitShow ?? true,
|
||||||
body: props.children,
|
body: props.children,
|
||||||
submitText: props.submitText,
|
submitText: props.submitText,
|
||||||
canCelText: props.canCelText,
|
canCelText: props.canCelText,
|
||||||
|
@ -57,4 +59,4 @@ const RsModal = (props: ModalPropsType) => {
|
||||||
document.body,
|
document.body,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default RsModal;
|
export default Modal;
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { ReactNode } from 'react'
|
||||||
|
interface childrens {
|
||||||
|
titleText?: string
|
||||||
|
isHeaderShow?: boolean
|
||||||
|
isFooterShow?: boolean
|
||||||
|
isCanCelShow?: boolean
|
||||||
|
isSubmitShow?: boolean
|
||||||
|
canCelText?: string
|
||||||
|
submitText?: string
|
||||||
|
onSubmit?: () => void
|
||||||
|
onCanCel?: () => void
|
||||||
|
}
|
||||||
|
export interface ModalChildType extends childrens {
|
||||||
|
body: ReactNode | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModalPropsType extends childrens {
|
||||||
|
isOpenModal: boolean
|
||||||
|
children: ReactNode | null
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
.rs-progress{
|
.up-progress{
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
.rs-progress-pr{
|
.up-progress-pr{
|
||||||
border: 1px solid #000000;
|
border: 1px solid #000000;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
}
|
}
|
||||||
.rs-progress-rate{
|
.up-progress-rate{
|
||||||
height: 6px;
|
height: 6px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
.rs-progress-num{
|
.up-progress-num{
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { RsProgressType } from './type'
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
const Progress = (props: RsProgressType) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="up-progress">
|
||||||
|
<div className="up-progress-pr" style={{ width: props.rateWidth ?? 250 }}>
|
||||||
|
<div
|
||||||
|
className="up-progress-rate"
|
||||||
|
style={{
|
||||||
|
width: (props.percent ?? 0) * ((props.rateWidth ?? 250) / 100),
|
||||||
|
backgroundColor: props.rateColor ?? 'blue',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className='up-progress-num'>{props.percent > 100 ? 100 :(props.percent.toString().substring(0,4) ?? 0) }%</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Progress;
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface RsProgressType {
|
||||||
|
rateColor?: string
|
||||||
|
rateWidth?: number
|
||||||
|
percent: number
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
.modal-body{
|
.up-modal-body{
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
|
@ -1,27 +1,18 @@
|
||||||
import RsModal from "@/components/RsModal"
|
import Modal from '@/components/update/Modal'
|
||||||
import RsProgress from "@/components/RsProgress"
|
import Progress from '@/components/update/Progress'
|
||||||
import { ipcRenderer } from "electron"
|
import { ipcRenderer } from 'electron'
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react"
|
import { useEffect, useState } from 'react'
|
||||||
import "./index.scss"
|
import './index.scss'
|
||||||
|
import { checkUpdateType, isUpdateAvailable, ModalBtnText, VersionInfo } from './type'
|
||||||
|
|
||||||
interface VersionInfo {
|
|
||||||
oldVersion: string,
|
|
||||||
newVersion: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface isUpdateAvailable extends VersionInfo {
|
|
||||||
isUpdate: boolean,
|
|
||||||
|
|
||||||
}
|
|
||||||
interface ModalBtnText {
|
|
||||||
canCelText: string,
|
|
||||||
submitText: string
|
|
||||||
}
|
|
||||||
|
|
||||||
let onModalSubmit = () => { }
|
let onModalSubmit = () => { }
|
||||||
let onModalCanCel = () => { }
|
let onModalCanCel = () => { }
|
||||||
|
|
||||||
const Update = forwardRef((props: { checkType: boolean }, ref) => {
|
const Update = () => {
|
||||||
|
const [checkBtnText, setCheckBtnText] = useState('check update')
|
||||||
|
const [checkType, setCheckType] = useState(false)
|
||||||
|
const [checkLoading, setCheckLoading] = useState(false)
|
||||||
const [isOpenModal, setIsOpenModal] = useState<boolean>(false)
|
const [isOpenModal, setIsOpenModal] = useState<boolean>(false)
|
||||||
const [percentNum, setPercentNum] = useState<number>(0)
|
const [percentNum, setPercentNum] = useState<number>(0)
|
||||||
const [isNeedUpdate, setIsNeedUpdate] = useState<boolean>(false)
|
const [isNeedUpdate, setIsNeedUpdate] = useState<boolean>(false)
|
||||||
|
@ -35,23 +26,33 @@ const Update = forwardRef((props: { checkType: boolean }, ref) => {
|
||||||
submitText: ''
|
submitText: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
|
||||||
openModal: () => setIsOpenModal(true)
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onModalCanCel = () => setIsOpenModal(false)
|
onModalCanCel = () => setIsOpenModal(false)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
/**
|
// Check for updates
|
||||||
* @description 获取版本信息和是否需要更新 Get version information and whether to update
|
const checkUpdate = () => {
|
||||||
*/
|
setCheckLoading(true)
|
||||||
|
setCheckBtnText('checking Update ...')
|
||||||
|
ipcRenderer.send('check-update')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen to get the check result
|
||||||
|
ipcRenderer.on('check-update-type', (_event, ...args: checkUpdateType[]) => {
|
||||||
|
setCheckLoading(false)
|
||||||
|
setCheckBtnText('check update')
|
||||||
|
setCheckType(args[0].checkUpdate)
|
||||||
|
setIsOpenModal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get version information and whether to update
|
||||||
ipcRenderer.on('is-update-available', (_event, ...args: isUpdateAvailable[]) => {
|
ipcRenderer.on('is-update-available', (_event, ...args: isUpdateAvailable[]) => {
|
||||||
setVersionInfo({
|
setVersionInfo({
|
||||||
oldVersion: args[0].oldVersion,
|
oldVersion: args[0].oldVersion,
|
||||||
newVersion: args[0].newVersion,
|
newVersion: args[0].newVersion,
|
||||||
})
|
})
|
||||||
setIsNeedUpdate(args[0].isUpdate)
|
setIsNeedUpdate(args[0].isUpdate)
|
||||||
|
// Update required
|
||||||
if (args[0].isUpdate) {
|
if (args[0].isUpdate) {
|
||||||
setModalBtnText({
|
setModalBtnText({
|
||||||
canCelText: 'cancel',
|
canCelText: 'cancel',
|
||||||
|
@ -61,21 +62,19 @@ const Update = forwardRef((props: { checkType: boolean }, ref) => {
|
||||||
onModalCanCel = () => setIsOpenModal(false)
|
onModalCanCel = () => setIsOpenModal(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
/**
|
|
||||||
* @description 如果更新失败了抛出更新失败信息 Throw the update failure message if the update fails
|
// Throw the update failure message when the update fails
|
||||||
*/
|
|
||||||
ipcRenderer.on('update-error', (_event, ...args: { updateError: boolean }[]) => {
|
ipcRenderer.on('update-error', (_event, ...args: { updateError: boolean }[]) => {
|
||||||
setUpdateError(args[0].updateError)
|
setUpdateError(args[0].updateError)
|
||||||
|
setCheckType(false)
|
||||||
})
|
})
|
||||||
/**
|
|
||||||
* @description 监听更新进度 update progress
|
// Get update progress
|
||||||
*/
|
|
||||||
ipcRenderer.on('update-progress', (_event, ...args: { progressInfo: number }[]) => {
|
ipcRenderer.on('update-progress', (_event, ...args: { progressInfo: number }[]) => {
|
||||||
setPercentNum(args[0].progressInfo)
|
setPercentNum(args[0].progressInfo)
|
||||||
})
|
})
|
||||||
/**
|
|
||||||
* @description 监听是否更新完成 is update been completed
|
// is update been completed
|
||||||
*/
|
|
||||||
ipcRenderer.on('update-downed', (_event, ...args) => {
|
ipcRenderer.on('update-downed', (_event, ...args) => {
|
||||||
setPercentNum(100)
|
setPercentNum(100)
|
||||||
setModalBtnText({
|
setModalBtnText({
|
||||||
|
@ -90,34 +89,35 @@ const Update = forwardRef((props: { checkType: boolean }, ref) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div>
|
||||||
<RsModal isOpenModal={isOpenModal} onCanCel={onModalCanCel} onSubmit={onModalSubmit}
|
<Modal isOpenModal={isOpenModal} onCanCel={onModalCanCel} onSubmit={onModalSubmit}
|
||||||
canCelText={modalBtnText.canCelText} submitText={modalBtnText.submitText}
|
canCelText={modalBtnText.canCelText} submitText={modalBtnText.submitText}
|
||||||
isFooterShow={props.checkType && isNeedUpdate}>
|
isFooterShow={checkType && isNeedUpdate}>
|
||||||
<div className="modal-body">
|
<div className='up-modal-body'>
|
||||||
{updateError ?
|
{updateError ?
|
||||||
<div className="update-error">Error downloading the latest version, please contact the developer</div> :
|
<div className='update-error'>Error downloading the latest version, please contact the developer</div> :
|
||||||
props.checkType ? (
|
checkType ? (
|
||||||
isNeedUpdate ? (
|
isNeedUpdate ? (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<span> oldVersion : v.{versionInfo.oldVersion} </span>
|
<span> oldVersion : v.{versionInfo.oldVersion} </span>
|
||||||
<span> newVersion : v.{versionInfo.newVersion} </span>
|
<span> newVersion : v.{versionInfo.newVersion} </span>
|
||||||
</div>
|
</div>
|
||||||
<div className="update-progress">
|
<div className='update-progress'>
|
||||||
<span className="progress-title"> update progress : </span>
|
<span className='progress-title'> update progress : </span>
|
||||||
<RsProgress percent={percentNum} ></RsProgress>
|
<Progress percent={percentNum} ></Progress>
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
: <span>This is last version : v.{versionInfo.oldVersion} !</span>
|
: <span>This is last version : v.{versionInfo.oldVersion} !</span>
|
||||||
) : <span>Check update is Error,Please check your network!</span>
|
) : <span>Check update is Error,Please check your network!</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</RsModal>
|
</Modal>
|
||||||
|
<button disabled={checkLoading} onClick={checkUpdate}>
|
||||||
</>
|
{checkBtnText}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
|
||||||
export default Update
|
export default Update
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
export interface checkUpdateType {
|
||||||
|
checkUpdate: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VersionInfo {
|
||||||
|
oldVersion: string
|
||||||
|
newVersion: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface isUpdateAvailable extends VersionInfo {
|
||||||
|
isUpdate: boolean
|
||||||
|
|
||||||
|
}
|
||||||
|
export interface ModalBtnText {
|
||||||
|
canCelText: string
|
||||||
|
submitText: string
|
||||||
|
}
|
Loading…
Reference in New Issue