返回 AiToEarn
index.tsx
1 import type { ProgressInfo } from 'electron-updater';
2 import { useCallback, useEffect, useState } from 'react';
3 import Modal from '@/components/update/Modal';
4 import Progress from '@/components/update/Progress';
5 import './update.css';
6 import { Button } from 'antd';
7
8 const Update = () => {
9 const [checking, setChecking] = useState(false);
10 const [updateAvailable, setUpdateAvailable] = useState(false);
11 const [versionInfo, setVersionInfo] = useState<VersionInfo>();
12 const [updateError, setUpdateError] = useState<ErrorType>();
13 const [progressInfo, setProgressInfo] = useState<Partial<ProgressInfo>>();
14 const [modalOpen, setModalOpen] = useState<boolean>(false);
15 const [modalBtn, setModalBtn] = useState<{
16 cancelText?: string;
17 okText?: string;
18 onCancel?: () => void;
19 onOk?: () => void;
20 }>({
21 onCancel: () => setModalOpen(false),
22 onOk: () => window.ipcRenderer.invoke('start-download'),
23 });
24
25 const checkUpdate = async () => {
26 setChecking(true);
27 /**
28 * @type {import('electron-updater').UpdateCheckResult | null | { message: string, error: Error }}
29 */
30 const result = await window.ipcRenderer.invoke('check-update');
31 setProgressInfo({ percent: 0 });
32 setChecking(false);
33 setModalOpen(true);
34 if (result?.error) {
35 setUpdateAvailable(false);
36 setUpdateError(result?.error);
37 }
38 };
39
40 const onUpdateCanAvailable = useCallback(
41 (_event: Electron.IpcRendererEvent, arg1: VersionInfo) => {
42 setVersionInfo(arg1);
43 setUpdateError(undefined);
44 // Can be update
45 if (arg1.update) {
46 setModalBtn((state) => ({
47 ...state,
48 cancelText: '取消',
49 okText: '更新',
50 onOk: () => window.ipcRenderer.invoke('start-download'),
51 }));
52 setUpdateAvailable(true);
53 } else {
54 setUpdateAvailable(false);
55 }
56 },
57 [],
58 );
59
60 const onUpdateError = useCallback(
61 (_event: Electron.IpcRendererEvent, arg1: ErrorType) => {
62 setUpdateAvailable(false);
63 setUpdateError(arg1);
64 },
65 [],
66 );
67
68 const onDownloadProgress = useCallback(
69 (_event: Electron.IpcRendererEvent, arg1: ProgressInfo) => {
70 setProgressInfo(arg1);
71 },
72 [],
73 );
74
75 const onUpdateDownloaded = useCallback(
76 (_event: Electron.IpcRendererEvent, ...args: any[]) => {
77 setProgressInfo({ percent: 100 });
78 setModalBtn((state) => ({
79 ...state,
80 cancelText: '稍后',
81 okText: '现在安装',
82 onOk: () => window.ipcRenderer.invoke('quit-and-install'),
83 }));
84 },
85 [],
86 );
87
88 useEffect(() => {
89 // Get version information and whether to update
90 window.ipcRenderer.on('update-can-available', onUpdateCanAvailable);
91 window.ipcRenderer.on('update-error', onUpdateError);
92 window.ipcRenderer.on('download-progress', onDownloadProgress);
93 window.ipcRenderer.on('update-downloaded', onUpdateDownloaded);
94
95 return () => {
96 window.ipcRenderer.off('update-can-available', onUpdateCanAvailable);
97 window.ipcRenderer.off('update-error', onUpdateError);
98 window.ipcRenderer.off('download-progress', onDownloadProgress);
99 window.ipcRenderer.off('update-downloaded', onUpdateDownloaded);
100 };
101 }, []);
102
103 return (
104 <>
105 <Modal
106 open={modalOpen}
107 cancelText={modalBtn?.cancelText}
108 okText={modalBtn?.okText}
109 onCancel={modalBtn?.onCancel}
110 onOk={modalBtn?.onOk}
111 footer={updateAvailable ? /* hide footer */ null : undefined}
112 >
113 <div className="modal-slot">
114 {updateError ? (
115 <div>
116 <p>下载最新版本时出错:</p>
117 <p>{updateError.message}</p>
118 </div>
119 ) : updateAvailable ? (
120 <div>
121 <div>当前最新的版本: v{versionInfo?.newVersion}</div>
122 <div className="new-version__target">
123 v{versionInfo?.version} -&gt; v{versionInfo?.newVersion}
124 </div>
125 <div className="update__progress">
126 <div className="progress__title">Update progress:</div>
127 <div className="progress__bar">
128 <Progress percent={progressInfo?.percent}></Progress>
129 </div>
130 </div>
131 </div>
132 ) : (
133 <div className="can-not-available">
134 {JSON.stringify(versionInfo ?? {}, null, 2)}
135 </div>
136 )}
137 </div>
138 </Modal>
139 <Button
140 disabled={checking}
141 onClick={checkUpdate}
142 type="text"
143 className="w-full text-left !p-0 !bg-transparent hover:!bg-transparent !border-none"
144 style={{ marginLeft: '-10px' }}
145 >
146 {checking ? '检查中...' : '检查更新'}
147 </Button>
148 </>
149 );
150 };
151
152 export default Update;
153
153 lines Plain Text