From 1a8e26a8470fddbf4ab7260f6517b49e025ef4ae Mon Sep 17 00:00:00 2001
From: Nexmoe <16796652+nexmoe@users.noreply.github.com>
Date: Sun, 2 Nov 2025 19:35:49 +0800
Subject: [PATCH] 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
---
src/main/index.ts | 27 ++++++++++------
src/renderer/src/App.tsx | 43 +++++++++----------------
src/renderer/src/locales/en.json | 3 ++
src/renderer/src/pages/About.tsx | 55 +++++++++++++++++++++++++++++++-
4 files changed, 89 insertions(+), 39 deletions(-)
diff --git a/src/main/index.ts b/src/main/index.ts
index 3010655..81b9104 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -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)
}
diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx
index 93d66cb..c0aba93 100644
--- a/src/renderer/src/App.tsx
+++ b/src/renderer/src/App.tsx
@@ -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
}
})
}
diff --git a/src/renderer/src/locales/en.json b/src/renderer/src/locales/en.json
index 53987a1..b811731 100644
--- a/src/renderer/src/locales/en.json
+++ b/src/renderer/src/locales/en.json
@@ -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}}",
diff --git a/src/renderer/src/pages/About.tsx b/src/renderer/src/pages/About.tsx
index ae93303..3ec15eb 100644
--- a/src/renderer/src/pages/About.tsx
+++ b/src/renderer/src/pages/About.tsx
@@ -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() {
+ {latestVersionState?.status === 'available' ? (
+
+ ) : null}