diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 29294f8c..0ba75cb2 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + diff --git a/src/components/settings/UpdatesSettings.tsx b/src/components/settings/UpdatesSettings.tsx index b55c088d..898dcb86 100644 --- a/src/components/settings/UpdatesSettings.tsx +++ b/src/components/settings/UpdatesSettings.tsx @@ -4,6 +4,7 @@ import { SettingsSection, SettingItem, ToggleSwitch } from './settings-section'; import Button from '../Button'; import { colors, spacing, radius, typography } from '../../theme/tokens'; import { useUpdatesStore } from '../../stores/updates-store'; +import type { InstallProgress } from '../../lib/install-update'; function formatTime(ts: number): string { if (!ts) return 'never'; @@ -11,11 +12,37 @@ function formatTime(ts: number): string { return date.toLocaleString(); } +function formatBytes(n: number): string { + if (n < 1024) return `${n} B`; + if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`; + return `${(n / (1024 * 1024)).toFixed(1)} MB`; +} + +function formatProgressLabel(p: InstallProgress): string { + const pct = p.progress != null ? `${Math.round(p.progress * 100)}%` : null; + const written = p.bytesWritten ? formatBytes(p.bytesWritten) : null; + const total = p.totalBytes ? formatBytes(p.totalBytes) : null; + const sizes = written && total ? `${written} of ${total}` : written ?? ''; + return [pct, sizes].filter(Boolean).join(' · ') || 'Downloading…'; +} + +function installButtonLabel( + installing: boolean, + progress: InstallProgress | null, + apkAsset: unknown, +): string { + if (!installing) return apkAsset ? 'Install' : 'Open release'; + if (progress?.phase === 'installing') return 'Installing…'; + if (progress?.progress != null) return `Downloading ${Math.round(progress.progress * 100)}%`; + return 'Downloading…'; +} + export function UpdatesSettings() { const hydrated = useUpdatesStore((s) => s.hydrated); const hydrate = useUpdatesStore((s) => s.hydrate); const checking = useUpdatesStore((s) => s.checking); const installing = useUpdatesStore((s) => s.installing); + const installProgress = useUpdatesStore((s) => s.installProgress); const error = useUpdatesStore((s) => s.error); const lastCheckedAt = useUpdatesStore((s) => s.lastCheckedAt); const cachedLatest = useUpdatesStore((s) => s.cachedLatest); @@ -81,7 +108,7 @@ export function UpdatesSettings() { onPress={onInstall} disabled={installing} > - {installing ? 'Downloading…' : apkAsset ? 'Install' : 'Open release'} + {installButtonLabel(installing, installProgress, apkAsset)} ) : (