-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathuseUpdateChecker.tsx
More file actions
100 lines (96 loc) · 3.49 KB
/
useUpdateChecker.tsx
File metadata and controls
100 lines (96 loc) · 3.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { useCallback } from 'react';
import { App, Progress, Button } from 'antd';
import { useTranslation } from 'react-i18next';
import { isTauri } from '@/lib/invoke';
/**
* Shared hook for checking app updates.
* Used by TitleBar, App.tsx, and AboutPage to avoid duplicated logic.
*/
export function useUpdateChecker() {
const { t } = useTranslation();
const { modal, message } = App.useApp();
const checkForUpdate = useCallback(async (options?: { silent?: boolean }) => {
if (!isTauri()) return false;
const silent = options?.silent ?? false;
try {
const { check } = await import('@tauri-apps/plugin-updater');
const update = await check();
if (!update) {
if (!silent) message.success(t('settings.noUpdate'));
return false;
}
modal.confirm({
title: t('settings.updateAvailable'),
content: (
<div>
<p>{t('settings.newVersion')}: {update.version}</p>
{update.body && (
<div style={{ maxHeight: 300, overflow: 'auto', marginTop: 8, whiteSpace: 'pre-wrap', fontSize: 13, opacity: 0.85 }}>
{update.body}
</div>
)}
</div>
),
okText: t('settings.updateNow'),
cancelText: t('settings.updateLater'),
onOk: async () => {
let cancelled = false;
const handleCancel = async () => {
cancelled = true;
try { await update.close(); } catch { /* ignore */ }
};
const renderContent = (percent: number, status: 'active' | 'success') => (
<div>
<Progress percent={percent} status={status} />
{status !== 'success' && (
<div style={{ textAlign: 'right', marginTop: 12 }}>
<Button onClick={handleCancel}>{t('settings.cancelUpdate')}</Button>
</div>
)}
</div>
);
const progressModal = modal.info({
title: t('settings.updating'),
content: renderContent(0, 'active'),
closable: false,
footer: null,
maskClosable: false,
keyboard: false,
});
try {
let totalSize = 0;
let downloaded = 0;
await update.downloadAndInstall((event) => {
if (event.event === 'Started' && event.data.contentLength) {
totalSize = event.data.contentLength;
} else if (event.event === 'Progress') {
downloaded += event.data.chunkLength;
if (totalSize > 0) {
progressModal.update({
content: renderContent(Math.round((downloaded / totalSize) * 100), 'active'),
});
}
} else if (event.event === 'Finished') {
progressModal.update({ content: renderContent(100, 'success') });
}
});
const { relaunch } = await import('@tauri-apps/plugin-process');
await relaunch();
} catch (e) {
progressModal.destroy();
if (!cancelled) {
message.error(t('settings.updateFailed'));
console.error('Update install failed:', e);
}
}
},
});
return true;
} catch (e) {
if (!silent) message.error(t('settings.checkUpdateFailed'));
console.error('Update check failed:', e);
return false;
}
}, [t, modal, message]);
return { checkForUpdate };
}