|
1 | 1 | import { check, Update } from '@tauri-apps/plugin-updater'; |
2 | 2 | import { relaunch } from '@tauri-apps/plugin-process'; |
3 | | -import { useState } from 'react'; |
| 3 | +import { useEffect, useState } from 'react'; |
4 | 4 | import { Button } from '@/components/ui/button'; |
5 | 5 | import { useTranslations } from 'next-intl'; |
6 | 6 | import useSettingStore from '@/stores/setting'; |
7 | 7 | import Image from 'next/image'; |
8 | 8 | import { toast } from '@/hooks/use-toast'; |
9 | 9 | import { Badge } from '@/components/ui/badge'; |
10 | | -import { Loader2 } from 'lucide-react'; |
| 10 | +import { ArrowBigRightDash, Loader2 } from 'lucide-react'; |
11 | 11 |
|
12 | 12 | export default function Updater() { |
13 | 13 | const t = useTranslations('settings.about'); |
| 14 | + const [checking, setChecking] = useState(false); |
14 | 15 | const [loading, setLoading] = useState(false); |
15 | | - const [updateStatus, setUpdateStatus] = useState(t('checkUpdate')); |
16 | | - const [downloaded, setDownloaded] = useState(0); |
17 | | - const [contentLength, setContentLength] = useState(0); |
18 | 16 | const { version } = useSettingStore(); |
| 17 | + const [update, setUpdate] = useState<Update | null>(null); |
| 18 | + |
| 19 | + async function checkUpdate() { |
| 20 | + setChecking(true); |
| 21 | + try { |
| 22 | + setUpdate(await check()); |
| 23 | + } catch (error) { |
| 24 | + toast({ |
| 25 | + title: t('checkError'), |
| 26 | + description: error as string, |
| 27 | + variant: 'destructive' |
| 28 | + }); |
| 29 | + } finally { |
| 30 | + setChecking(false); |
| 31 | + } |
| 32 | + } |
19 | 33 |
|
20 | 34 | async function checkVersion() { |
21 | | - if (updateStatus === t('checkUpdate')) { |
22 | | - setLoading(true); |
23 | | - let update: Update | null = null; |
| 35 | + setLoading(true); |
| 36 | + if (update) { |
24 | 37 | try { |
25 | | - update = await check(); |
| 38 | + await update.downloadAndInstall(); |
26 | 39 | } catch (error) { |
27 | 40 | toast({ |
28 | 41 | title: t('checkError'), |
29 | 42 | description: error as string, |
30 | 43 | variant: 'destructive' |
31 | 44 | }); |
32 | | - } finally { |
33 | | - setLoading(false); |
34 | 45 | } |
35 | | - if (update) { |
36 | | - try { |
37 | | - setUpdateStatus(t('updateAvailable', { version: update.version })); |
38 | | - await update.downloadAndInstall((event) => { |
39 | | - switch (event.event) { |
40 | | - case 'Started': |
41 | | - setContentLength(event.data.contentLength || 0); |
42 | | - break; |
43 | | - case 'Progress': |
44 | | - setDownloaded(event.data.chunkLength || 0); |
45 | | - setUpdateStatus(t('updateDownloading', { downloaded, contentLength })); |
46 | | - break; |
47 | | - case 'Finished': |
48 | | - setUpdateStatus(t('updateInstalled')); |
49 | | - break; |
50 | | - } |
51 | | - }); |
52 | | - } catch (error) { |
53 | | - toast({ |
54 | | - title: t('checkError'), |
55 | | - description: error as string, |
56 | | - variant: 'destructive' |
57 | | - }); |
58 | | - } finally { |
59 | | - setLoading(false); |
60 | | - } |
61 | | - } |
62 | | - } else if (updateStatus === t('updateInstalled')) { |
63 | 46 | await relaunch(); |
| 47 | + } else { |
| 48 | + toast({ |
| 49 | + title: t('checkError'), |
| 50 | + description: t('noUpdate'), |
| 51 | + variant: 'default' |
| 52 | + }); |
| 53 | + setLoading(false); |
64 | 54 | } |
65 | 55 | } |
66 | 56 |
|
| 57 | + useEffect(() => { |
| 58 | + checkUpdate(); |
| 59 | + }, []); |
| 60 | + |
67 | 61 | return ( |
68 | 62 | <div className="flex justify-between w-full items-center"> |
69 | | - <div className='flex items-center gap-4'> |
| 63 | + <div className="flex items-center gap-4"> |
70 | 64 | <div> |
71 | | - <Image src="/app-icon.png" alt="logo" className='size-24' width={0} height={0} /> |
| 65 | + <Image src="/app-icon.png" alt="logo" className="size-24 dark:invert" width={0} height={0} /> |
72 | 66 | </div> |
73 | | - <div className='h-24 flex flex-col justify-between'> |
74 | | - <span className='text-2xl font-bold flex items-center gap-2'>NoteGen</span> |
| 67 | + <div className="h-24 flex flex-col justify-between"> |
| 68 | + <span className="text-2xl font-bold flex items-center gap-2">NoteGen</span> |
75 | 69 | <span> |
76 | 70 | {t('desc')} |
77 | 71 | </span> |
78 | | - <div> |
| 72 | + <div className="flex items-center gap-2"> |
79 | 73 | <Badge variant="outline">v{version}</Badge> |
| 74 | + { |
| 75 | + update ? ( |
| 76 | + <> |
| 77 | + <ArrowBigRightDash className="size-4" /> |
| 78 | + <Badge className="bg-green-500 text-white" variant="outline">v{update.version}</Badge> |
| 79 | + </> |
| 80 | + ) : null |
| 81 | + } |
80 | 82 | </div> |
81 | 83 | </div> |
82 | 84 | </div> |
83 | | - <Button disabled={loading} onClick={checkVersion}> |
| 85 | + <Button disabled={!update || loading || checking} onClick={checkVersion}> |
84 | 86 | {loading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null} |
85 | | - {updateStatus} |
| 87 | + {checking ? t('checkUpdate') : update ? t('updateAvailable') : t('noUpdate')} |
86 | 88 | </Button> |
87 | 89 | </div> |
88 | 90 | ) |
|
0 commit comments