feat(update): add download action and guide users to download page when (#12)

* feat(update): add download action and guide users to download page when

* fix(updater): always initialize auto-updater in non-prod builds for testing
This commit is contained in:
Nexmoe
2025-11-02 19:35:49 +08:00
committed by GitHub
parent 0bcddddc37
commit 1a8e26a847
4 changed files with 89 additions and 39 deletions

View File

@@ -107,11 +107,6 @@ function setupDownloadEvents(): void {
}
function initAutoUpdater(): void {
if (process.env.NODE_ENV !== 'production') {
log.info('Skipping auto-updater initialization in development mode')
return
}
try {
log.info('Initializing auto-updater...')
@@ -123,6 +118,12 @@ function initAutoUpdater(): void {
autoUpdater.on('update-available', (info) => {
log.info('Update available:', info.version)
mainWindow?.webContents.send('update:available', info)
// If auto-update is enabled, the update will be downloaded automatically
// because autoDownload is set to true
if (settingsManager.get('autoUpdate')) {
log.info('Auto-update is enabled, update will be downloaded automatically')
}
})
autoUpdater.on('update-not-available', (info) => {
@@ -153,12 +154,18 @@ function initAutoUpdater(): void {
}
})
if (settingsManager.get('autoUpdate')) {
log.info('Auto-update is enabled, checking for updates...')
void autoUpdater.checkForUpdatesAndNotify()
}
log.info('Auto-updater initialized successfully')
// Check for updates immediately if auto-update is enabled
const autoUpdateEnabled = settingsManager.get('autoUpdate')
if (autoUpdateEnabled) {
log.info('Auto-update is enabled, checking for updates immediately...')
// Use checkForUpdates instead of checkForUpdatesAndNotify
// because we have our own notification system and want to ensure immediate download
void autoUpdater.checkForUpdates()
} else {
log.info('Auto-update is disabled, skipping automatic update check')
}
} catch (error) {
log.error('Failed to initialize auto-updater:', error)
}

View File

@@ -61,43 +61,30 @@ function AppContent() {
}
}
const startUpdateDownload = async () => {
if (updateDownloadInProgressRef.current) {
return
}
updateDownloadInProgressRef.current = true
toast.info(t('about.notifications.downloadStarted'))
try {
const result = await ipcServices.update.downloadUpdate()
if (!result.success) {
throw new Error(result.error ?? 'Unknown error')
}
} catch (error) {
updateDownloadInProgressRef.current = false
const message =
error instanceof Error && error.message
? error.message
: t('about.notifications.unknownErrorFallback')
toast.error(t('about.notifications.updateError', { error: message }))
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 ?? ''
toast.success(t('about.notifications.updateAvailable', { version: versionLabel }))
if (autoUpdateEnabled) {
void startUpdateDownload()
} else {
toast(t('about.notifications.downloadUpdate', { version: versionLabel }), {
// Update will be downloaded automatically because autoDownload is enabled in main process
toast.success(t('about.notifications.updateAvailable', { version: versionLabel }), {
action: {
label: t('about.notifications.manualDownloadAction'),
onClick: () => {
void startUpdateDownload()
}
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
}
})
}

View File

@@ -2,8 +2,10 @@
"about": {
"actions": {
"checkUpdates": "Check updates",
"download": "Download",
"email": "Email",
"feedback": "Feedback",
"goToDownload": "Go to download page",
"openRepo": "Open GitHub repository",
"view": "View",
"visit": "Visit"
@@ -32,6 +34,7 @@
"restartToUpdate": "Restart now to install update?",
"restartNowAction": "Restart now",
"updateAvailable": "Update available: {{version}}",
"updateAvailableMessage": "A new version {{version}} is available. Please download it from the official website.",
"updateDownloaded": "Update downloaded, restart to install",
"updateDownloadedVersion": "Update {{version}} downloaded, restart to install",
"updateError": "Failed to check for updates: {{error}}",

View File

@@ -11,6 +11,7 @@ import { Switch } from '@renderer/components/ui/switch'
import { useAtom, useSetAtom } from 'jotai'
import type { LucideIcon } from 'lucide-react'
import {
Download,
Facebook,
FileText,
Github,
@@ -77,6 +78,47 @@ export function About() {
) => {
await saveSetting({ key, value })
toast.success(t('notifications.settingsSaved'))
// If auto-update is enabled, check for updates immediately
if (key === 'autoUpdate' && value === true) {
try {
toast.info(t('about.notifications.checkingUpdates'))
const result = await ipcServices.update.checkForUpdates()
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
}
})
setLatestVersionState({
status: 'available',
version: result.version ?? ''
})
} else if (result.error) {
toast.error(t('about.notifications.updateError', { error: result.error }))
setLatestVersionState({
status: 'error',
error: result.error
})
} else {
toast.success(t('about.notifications.noUpdatesAvailable'))
setLatestVersionState({
status: 'uptodate',
version: result.version ?? appVersion
})
}
} catch (error) {
console.error('Failed to check for updates:', error)
toast.error(t('about.notifications.updateError', { error: 'Unknown error' }))
}
}
}
const handleGoToDownload = () => {
openShareUrl('https://vidbee.org/download/')
}
const handleCheckForUpdates = async () => {
@@ -85,7 +127,12 @@ export function About() {
const result = await ipcServices.update.checkForUpdates()
if (result.available) {
toast.success(t('about.notifications.updateAvailable', { version: result.version }))
toast.success(t('about.notifications.updateAvailable', { version: result.version }), {
action: {
label: t('about.actions.goToDownload'),
onClick: handleGoToDownload
}
})
setLatestVersionState({
status: 'available',
version: result.version ?? ''
@@ -247,6 +294,12 @@ export function About() {
<Github className="h-4 w-4" />
</a>
</Button>
{latestVersionState?.status === 'available' ? (
<Button onClick={handleGoToDownload} variant="default" className="gap-2">
<Download className="h-4 w-4" />
{t('about.actions.goToDownload')}
</Button>
) : null}
<Button onClick={handleCheckForUpdates} className="gap-2">
<RefreshCw className="h-4 w-4" />
{t('about.actions.checkUpdates')}