chore: optimize update function (#18)
* chore: add zip target with arm64 and x64 architectures to dmg/targets * feat(updates): move update UI handling to About page and add progress UI and i18n key
This commit is contained in:
@@ -23,6 +23,10 @@ mac:
|
||||
notarize: false
|
||||
artifactName: ${name}-${version}-${arch}.${ext}
|
||||
target:
|
||||
- target: zip
|
||||
arch:
|
||||
- arm64
|
||||
- x64
|
||||
- target: dmg
|
||||
arch:
|
||||
- arm64
|
||||
|
||||
@@ -61,35 +61,6 @@ function AppContent() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleGoToDownloadPage = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.open('https://vidbee.org/download/', '_blank', 'noopener,noreferrer')
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateAvailable = (rawInfo: unknown) => {
|
||||
const info = (rawInfo ?? {}) as { version?: string }
|
||||
const versionLabel = info.version ?? ''
|
||||
|
||||
if (autoUpdateEnabled) {
|
||||
// Update will be downloaded automatically because autoDownload is enabled in main process
|
||||
toast.success(t('about.notifications.updateAvailable', { version: versionLabel }), {
|
||||
action: {
|
||||
label: t('about.actions.goToDownload'),
|
||||
onClick: handleGoToDownloadPage
|
||||
}
|
||||
})
|
||||
// No need to manually call downloadUpdate() because autoDownload is true
|
||||
} else {
|
||||
toast.success(t('about.notifications.updateAvailable', { version: versionLabel }), {
|
||||
action: {
|
||||
label: t('about.actions.goToDownload'),
|
||||
onClick: handleGoToDownloadPage
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateDownloaded = (rawInfo: unknown) => {
|
||||
const info = (rawInfo ?? {}) as { version?: string }
|
||||
resetDownloadState()
|
||||
@@ -135,14 +106,14 @@ function AppContent() {
|
||||
})
|
||||
}
|
||||
|
||||
ipcEvents.on('update:available', handleUpdateAvailable)
|
||||
// Only listen to update events that should be shown globally
|
||||
// update:available is handled in About page only
|
||||
ipcEvents.on('update:downloaded', handleUpdateDownloaded)
|
||||
ipcEvents.on('update:error', handleUpdateError)
|
||||
ipcEvents.on('update:download-progress', handleDownloadProgress)
|
||||
ipcEvents.on('update:show-notification', handleUpdateNotification)
|
||||
|
||||
return () => {
|
||||
ipcEvents.removeListener('update:available', handleUpdateAvailable)
|
||||
ipcEvents.removeListener('update:downloaded', handleUpdateDownloaded)
|
||||
ipcEvents.removeListener('update:error', handleUpdateError)
|
||||
ipcEvents.removeListener('update:download-progress', handleDownloadProgress)
|
||||
|
||||
@@ -75,7 +75,8 @@
|
||||
"available": "New version available",
|
||||
"uptodate": "You're up to date",
|
||||
"error": "Unable to fetch the latest version"
|
||||
}
|
||||
},
|
||||
"downloadingUpdate": "Downloading update"
|
||||
},
|
||||
"advancedOptions": {
|
||||
"closeWhenDone": "Close app when download finishes",
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
CardHeader,
|
||||
CardTitle
|
||||
} from '@renderer/components/ui/card'
|
||||
import { Progress } from '@renderer/components/ui/progress'
|
||||
import { Switch } from '@renderer/components/ui/switch'
|
||||
import { useAtom, useSetAtom } from 'jotai'
|
||||
import type { LucideIcon } from 'lucide-react'
|
||||
@@ -25,7 +26,7 @@ import {
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'sonner'
|
||||
import { ipcServices } from '../lib/ipc'
|
||||
import { ipcEvents, ipcServices } from '../lib/ipc'
|
||||
import { saveSettingAtom, settingsAtom } from '../store/settings'
|
||||
|
||||
interface AboutResource {
|
||||
@@ -48,6 +49,7 @@ export function About() {
|
||||
const [settings, _setSettings] = useAtom(settingsAtom)
|
||||
const [appVersion, setAppVersion] = useState<string>('—')
|
||||
const [latestVersionState, setLatestVersionState] = useState<LatestVersionState>(null)
|
||||
const [updateDownloadProgress, setUpdateDownloadProgress] = useState<number | null>(null)
|
||||
const saveSetting = useSetAtom(saveSettingAtom)
|
||||
const shareTargetUrl = 'https://vidbee.org'
|
||||
|
||||
@@ -72,6 +74,49 @@ export function About() {
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Listen for update events only in About page
|
||||
useEffect(() => {
|
||||
if (!window?.api) {
|
||||
return
|
||||
}
|
||||
|
||||
const handleUpdateAvailable = (rawInfo: unknown) => {
|
||||
const info = (rawInfo ?? {}) as { version?: string }
|
||||
const versionLabel = info.version ?? ''
|
||||
|
||||
// Update will be downloaded automatically because autoDownload is enabled in main process
|
||||
toast.success(t('about.notifications.updateAvailable', { version: versionLabel }))
|
||||
setLatestVersionState({
|
||||
status: 'available',
|
||||
version: versionLabel
|
||||
})
|
||||
// Reset download progress when new update is available
|
||||
setUpdateDownloadProgress(0)
|
||||
}
|
||||
|
||||
const handleUpdateDownloadProgress = (rawProgress: unknown) => {
|
||||
const progress = (rawProgress ?? {}) as { percent?: number }
|
||||
if (typeof progress?.percent === 'number') {
|
||||
setUpdateDownloadProgress(progress.percent)
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateDownloaded = () => {
|
||||
// Clear progress when download is complete
|
||||
setUpdateDownloadProgress(null)
|
||||
}
|
||||
|
||||
ipcEvents.on('update:available', handleUpdateAvailable)
|
||||
ipcEvents.on('update:download-progress', handleUpdateDownloadProgress)
|
||||
ipcEvents.on('update:downloaded', handleUpdateDownloaded)
|
||||
|
||||
return () => {
|
||||
ipcEvents.removeListener('update:available', handleUpdateAvailable)
|
||||
ipcEvents.removeListener('update:download-progress', handleUpdateDownloadProgress)
|
||||
ipcEvents.removeListener('update:downloaded', handleUpdateDownloaded)
|
||||
}
|
||||
}, [t])
|
||||
|
||||
const handleSettingChange = async (
|
||||
key: keyof typeof settings,
|
||||
value: (typeof settings)[keyof typeof settings]
|
||||
@@ -87,12 +132,7 @@ export function About() {
|
||||
|
||||
if (result.available) {
|
||||
// The update will be downloaded automatically because autoDownload is enabled
|
||||
toast.success(t('about.notifications.updateAvailable', { version: result.version }), {
|
||||
action: {
|
||||
label: t('about.actions.goToDownload'),
|
||||
onClick: handleGoToDownload
|
||||
}
|
||||
})
|
||||
toast.success(t('about.notifications.updateAvailable', { version: result.version }))
|
||||
setLatestVersionState({
|
||||
status: 'available',
|
||||
version: result.version ?? ''
|
||||
@@ -127,12 +167,7 @@ export function About() {
|
||||
const result = await ipcServices.update.checkForUpdates()
|
||||
|
||||
if (result.available) {
|
||||
toast.success(t('about.notifications.updateAvailable', { version: result.version }), {
|
||||
action: {
|
||||
label: t('about.actions.goToDownload'),
|
||||
onClick: handleGoToDownload
|
||||
}
|
||||
})
|
||||
toast.success(t('about.notifications.updateAvailable', { version: result.version }))
|
||||
setLatestVersionState({
|
||||
status: 'available',
|
||||
version: result.version ?? ''
|
||||
@@ -281,6 +316,19 @@ export function About() {
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{updateDownloadProgress !== null && (
|
||||
<div className="space-y-2 w-full">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t('about.downloadingUpdate')}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{updateDownloadProgress.toFixed(1)}%
|
||||
</span>
|
||||
</div>
|
||||
<Progress value={updateDownloadProgress} className="h-2" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user