diff --git a/src/app/features/settings/general/General.tsx b/src/app/features/settings/general/General.tsx index 86735c6ee..9cafa1a8c 100644 --- a/src/app/features/settings/general/General.tsx +++ b/src/app/features/settings/general/General.tsx @@ -110,7 +110,8 @@ import { } from '../../../utils/translation/langUtils'; import { chromeTranslationEngine } from '../../../utils/translation/chromeEngine'; import { SequenceCardStyle } from '../styles.css'; -import { useTauriUpdater } from '../../../hooks/useTauriUpdater'; +import { UpdateProgress, useTauriUpdater } from '../../../hooks/useTauriUpdater'; +import { describeUpdateError, manualDownloadUrl } from '../../../utils/updateErrors'; import { isTauri as isTauriEnv, invokeTauri, tauriInvoke } from '../../../hooks/useTauri'; import { isSafeGlobalToggleKey } from '../../../hooks/useCallHotkeys'; import { customWindowChromeAtom } from '../../../state/customWindowChrome'; @@ -2682,6 +2683,22 @@ function Messages() { ); } +const formatMb = (bytes: number): string => `${(bytes / 1_048_576).toFixed(1)} MB`; + +function updateProgressText(progress: UpdateProgress | undefined): string { + if (!progress) return 'Checking for the update…'; + if (progress.phase === 'installing') return 'Installing — Lotus Chat will restart in a moment…'; + if (progress.phase === 'retrying') { + return `The update server didn’t respond. Trying again in ${progress.waitSecs} s (attempt ${progress.attempt + 1} of ${progress.maxAttempts})…`; + } + const attempt = + progress.attempt > 1 ? ` (attempt ${progress.attempt} of ${progress.maxAttempts})` : ''; + const { downloaded, total } = progress; + if (!total) return `Downloading update… ${formatMb(downloaded)}${attempt}`; + const pct = Math.min(100, Math.floor((downloaded / total) * 100)); + return `Downloading update… ${pct}% (${formatMb(downloaded)} of ${formatMb(total)})${attempt}`; +} + function AppUpdates() { const { isTauri, status, check, install } = useTauriUpdater(); if (!isTauri) return null; @@ -2694,18 +2711,41 @@ function AppUpdates() { : status.state === 'available' ? `Update available: v${status.version}` : status.state === 'installing' - ? 'Installing update, the app will restart shortly...' + ? updateProgressText(status.progress) : status.state === 'error' - ? `Update check failed: ${status.message}` + ? describeUpdateError(status.phase, status.message) : 'Check for a new version of Lotus Chat.'; + const retry = () => { + if (status.state === 'error' && status.phase !== 'check') install(); + else check(); + }; + const after = status.state === 'available' ? ( - ) : status.state === 'checking' || status.state === 'installing' ? ( + ) : status.state === 'error' ? ( + + + {status.phase !== 'check' && ( + + )} + ) : (