From 486767fca99df10a7667058ebaf15180c18b6f8c Mon Sep 17 00:00:00 2001 From: Nexmoe <16796652+nexmoe@users.noreply.github.com> Date: Sat, 8 Nov 2025 18:29:26 +0800 Subject: [PATCH] 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 --- electron-builder.yml | 4 ++ src/renderer/src/App.tsx | 33 +------------- src/renderer/src/locales/en.json | 3 +- src/renderer/src/pages/About.tsx | 74 ++++++++++++++++++++++++++------ 4 files changed, 69 insertions(+), 45 deletions(-) diff --git a/electron-builder.yml b/electron-builder.yml index 59be930..2f9fcb3 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -23,6 +23,10 @@ mac: notarize: false artifactName: ${name}-${version}-${arch}.${ext} target: + - target: zip + arch: + - arm64 + - x64 - target: dmg arch: - arm64 diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 8bd1c5d..17fd322 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -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) diff --git a/src/renderer/src/locales/en.json b/src/renderer/src/locales/en.json index e45800e..cf69974 100644 --- a/src/renderer/src/locales/en.json +++ b/src/renderer/src/locales/en.json @@ -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", diff --git a/src/renderer/src/pages/About.tsx b/src/renderer/src/pages/About.tsx index fbc8eec..7fad698 100644 --- a/src/renderer/src/pages/About.tsx +++ b/src/renderer/src/pages/About.tsx @@ -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('—') const [latestVersionState, setLatestVersionState] = useState(null) + const [updateDownloadProgress, setUpdateDownloadProgress] = useState(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() { ) : null} + {updateDownloadProgress !== null && ( +
+
+ + {t('about.downloadingUpdate')} + + + {updateDownloadProgress.toFixed(1)}% + +
+ +
+ )}