feat: implement version comparison for updates, enhance TitleBar component with platform support, and improve language handling in settings

This commit is contained in:
Nexmoe
2025-10-27 20:23:29 +08:00
parent baa887da2e
commit 5246ab8369
5 changed files with 79 additions and 10 deletions

View File

@@ -3,6 +3,33 @@ import { type IpcContext, IpcMethod, IpcService } from 'electron-ipc-decorator'
import { autoUpdater } from 'electron-updater'
import { settingsManager } from '../../settings'
const isNewerVersion = (latest: string, current: string): boolean => {
const toSegments = (version: string) =>
version.split(/[.-]/).map((segment) => {
const parsed = Number.parseInt(segment, 10)
return Number.isNaN(parsed) ? 0 : parsed
})
const latestSegments = toSegments(latest)
const currentSegments = toSegments(current)
const maxLength = Math.max(latestSegments.length, currentSegments.length)
for (let index = 0; index < maxLength; index += 1) {
const latestValue = latestSegments[index] ?? 0
const currentValue = currentSegments[index] ?? 0
if (latestValue > currentValue) {
return true
}
if (latestValue < currentValue) {
return false
}
}
return false
}
class UpdateService extends IpcService {
static readonly groupName = 'update'
@@ -11,11 +38,20 @@ class UpdateService extends IpcService {
_context: IpcContext
): Promise<{ available: boolean; version?: string; error?: string }> {
try {
// In production, use checkForUpdatesAndNotify for automatic notifications
const result = await autoUpdater.checkForUpdatesAndNotify()
const currentVersion = app.getVersion()
const result = await autoUpdater.checkForUpdates()
const latestVersion = result?.updateInfo?.version
if (latestVersion && isNewerVersion(latestVersion, currentVersion)) {
return {
available: true,
version: latestVersion
}
}
return {
available: result !== null,
version: result?.updateInfo?.version
available: false,
version: latestVersion ?? currentVersion
}
} catch (error) {
return {

View File

@@ -53,8 +53,8 @@ function AppContent() {
{/* Main Content */}
<main className="flex flex-col flex-1 min-h-0 overflow-hidden bg-background">
{/* Custom Title Bar - Hide on macOS */}
{platform !== 'darwin' && <TitleBar />}
{/* Custom Title Bar */}
<TitleBar platform={platform} />
<ScrollArea
className="flex-1 w-full overflow-y-auto overflow-x-hidden"

View File

@@ -7,11 +7,15 @@ import IconFluentSubtract20Regular from '~icons/fluent/subtract-20-regular'
import { ipcEvents, ipcServices } from '../../lib/ipc'
import '../../assets/title-bar.css'
export function TitleBar() {
interface TitleBarProps {
platform?: string
}
export function TitleBar({ platform }: TitleBarProps) {
const [isMaximized, setIsMaximized] = useState(false)
useEffect(() => {
// 监听窗口最大化状态变化
// Listen for window maximize state changes
const handleMaximized = () => {
setIsMaximized(true)
}
@@ -41,8 +45,17 @@ export function TitleBar() {
ipcServices.window.close()
}
const isMac = platform === 'darwin'
const containerClass = `flex drag-region bg-background select-none ${
isMac ? 'h-10 items-center px-4' : 'justify-end pt-4 px-5'
}`
if (isMac) {
return <div className={containerClass} />
}
return (
<div className="flex drag-region justify-end bg-background pt-4 px-5 select-none">
<div className={containerClass}>
{/* Window controls */}
<div className="flex items-center gap-1 no-drag">
<Button

View File

@@ -165,6 +165,13 @@ export function About() {
const aboutResources = useMemo<AboutResource[]>(
() => [
{
icon: LinkIcon,
label: t('about.resources.website'),
description: t('about.resources.websiteDescription'),
actionLabel: t('about.actions.visit'),
href: 'https://vidbee.org/'
},
{
icon: FileText,
label: t('about.resources.changelog'),

View File

@@ -1,6 +1,8 @@
import { atom } from 'jotai'
import { normalizeLanguageCode } from '../../../shared/languages'
import type { AppSettings } from '../../../shared/types'
import { defaultSettings } from '../../../shared/types'
import i18n from '../i18n'
import { ipcServices } from '../lib/ipc'
// Settings atom
@@ -10,7 +12,18 @@ export const settingsAtom = atom<AppSettings>(defaultSettings)
export const loadSettingsAtom = atom(null, async (_get, set) => {
try {
const settings = await ipcServices.settings.getAll()
set(settingsAtom, settings)
const savedLanguage = normalizeLanguageCode(settings.language)
const currentLanguage = normalizeLanguageCode(i18n.language)
if (currentLanguage !== savedLanguage) {
try {
await i18n.changeLanguage(savedLanguage)
} catch (error) {
console.error('Failed to apply saved language:', error)
}
}
set(settingsAtom, { ...settings, language: savedLanguage })
} catch (error) {
console.error('Failed to load settings:', error)
}