feat: add auto-update functionality
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { onMount, createEventDispatcher } from 'svelte'
|
||||
import { GetSettings, UpdateSettings, GetMeeting, UpdateMeeting } from '../../wailsjs/go/app/App'
|
||||
import { WindowSetSize, ScreenGetAll } from '../../wailsjs/runtime/runtime'
|
||||
import { GetSettings, UpdateSettings, GetMeeting, UpdateMeeting, GetVersion, CheckForUpdates, DownloadAndInstallUpdate, RestartApp } from '../../wailsjs/go/app/App'
|
||||
import { WindowSetSize, ScreenGetAll, EventsOn, EventsOff } from '../../wailsjs/runtime/runtime'
|
||||
import { t, locale, setLocale } from '../lib/i18n'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -16,6 +16,15 @@
|
||||
let windowFullHeight = true
|
||||
let audioContext = null
|
||||
|
||||
// Update state
|
||||
let currentVersion = 'dev'
|
||||
let updateInfo = null
|
||||
let checkingUpdate = false
|
||||
let downloadingUpdate = false
|
||||
let downloadProgress = 0
|
||||
let updateError = null
|
||||
let updateComplete = false
|
||||
|
||||
function getAudioContext() {
|
||||
if (!audioContext) {
|
||||
audioContext = new (window.AudioContext || window.webkitAudioContext)()
|
||||
@@ -67,8 +76,63 @@
|
||||
|
||||
onMount(async () => {
|
||||
await loadData()
|
||||
|
||||
// Load version and check for updates
|
||||
try {
|
||||
currentVersion = await GetVersion()
|
||||
checkForUpdates()
|
||||
} catch (e) {
|
||||
console.error('Failed to get version:', e)
|
||||
}
|
||||
|
||||
// Listen for update progress events
|
||||
EventsOn('update:progress', (progress) => {
|
||||
downloadProgress = progress
|
||||
})
|
||||
EventsOn('update:complete', () => {
|
||||
downloadingUpdate = false
|
||||
updateComplete = true
|
||||
})
|
||||
|
||||
return () => {
|
||||
EventsOff('update:progress')
|
||||
EventsOff('update:complete')
|
||||
}
|
||||
})
|
||||
|
||||
async function checkForUpdates() {
|
||||
checkingUpdate = true
|
||||
updateError = null
|
||||
updateInfo = null
|
||||
|
||||
try {
|
||||
updateInfo = await CheckForUpdates()
|
||||
} catch (e) {
|
||||
console.error('Failed to check for updates:', e)
|
||||
updateError = e.message || 'Unknown error'
|
||||
} finally {
|
||||
checkingUpdate = false
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadAndInstall() {
|
||||
downloadingUpdate = true
|
||||
downloadProgress = 0
|
||||
updateError = null
|
||||
|
||||
try {
|
||||
await DownloadAndInstallUpdate()
|
||||
} catch (e) {
|
||||
console.error('Failed to download update:', e)
|
||||
updateError = e.message || 'Download failed'
|
||||
downloadingUpdate = false
|
||||
}
|
||||
}
|
||||
|
||||
async function restartApp() {
|
||||
await RestartApp()
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
loading = true
|
||||
try {
|
||||
@@ -204,6 +268,66 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="updates-section">
|
||||
<h2>{$t('updates.title')}</h2>
|
||||
|
||||
<div class="version-info">
|
||||
<span class="version-label">{$t('updates.currentVersion')}:</span>
|
||||
<span class="version-value">{currentVersion}</span>
|
||||
</div>
|
||||
|
||||
{#if checkingUpdate}
|
||||
<div class="update-status checking">
|
||||
<span class="spinner"></span>
|
||||
{$t('updates.checkingForUpdates')}
|
||||
</div>
|
||||
{:else if updateError}
|
||||
<div class="update-status error">
|
||||
{$t('updates.error')}: {updateError}
|
||||
</div>
|
||||
<button class="update-btn" on:click={checkForUpdates}>
|
||||
{$t('updates.checkNow')}
|
||||
</button>
|
||||
{:else if updateComplete}
|
||||
<div class="update-status success">
|
||||
{$t('updates.restartRequired')}
|
||||
</div>
|
||||
<div class="update-buttons">
|
||||
<button class="update-btn primary" on:click={restartApp}>
|
||||
{$t('updates.restart')}
|
||||
</button>
|
||||
<button class="update-btn" on:click={() => updateComplete = false}>
|
||||
{$t('updates.later')}
|
||||
</button>
|
||||
</div>
|
||||
{:else if downloadingUpdate}
|
||||
<div class="update-status downloading">
|
||||
{$t('updates.downloading')} {Math.round(downloadProgress * 100)}%
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" style="width: {downloadProgress * 100}%"></div>
|
||||
</div>
|
||||
{:else if updateInfo?.available}
|
||||
<div class="update-status available">
|
||||
{$t('updates.updateAvailable')}: <strong>{updateInfo.latestVersion}</strong>
|
||||
</div>
|
||||
<button class="update-btn primary" on:click={downloadAndInstall}>
|
||||
{$t('updates.downloadAndInstall')}
|
||||
</button>
|
||||
{:else if updateInfo}
|
||||
<div class="update-status uptodate">
|
||||
✓ {$t('updates.upToDate')}
|
||||
</div>
|
||||
<button class="update-btn" on:click={checkForUpdates}>
|
||||
{$t('updates.checkNow')}
|
||||
</button>
|
||||
{:else}
|
||||
<button class="update-btn" on:click={checkForUpdates}>
|
||||
{$t('updates.checkNow')}
|
||||
</button>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<button class="save-btn" on:click={saveSettings} disabled={saving}>
|
||||
{saving ? $t('common.loading') : $t('settings.save')}
|
||||
</button>
|
||||
@@ -369,4 +493,126 @@
|
||||
.test-btn:active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
/* Updates section */
|
||||
.updates-section {
|
||||
border: 1px solid #3d4f61;
|
||||
}
|
||||
|
||||
.version-info {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.version-label {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.version-value {
|
||||
color: #4a90d9;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.update-status {
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.update-status.checking {
|
||||
background: #1b2636;
|
||||
color: #9ca3af;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.update-status.error {
|
||||
background: #7f1d1d;
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
.update-status.available {
|
||||
background: #164e63;
|
||||
color: #67e8f9;
|
||||
}
|
||||
|
||||
.update-status.uptodate {
|
||||
background: #14532d;
|
||||
color: #86efac;
|
||||
}
|
||||
|
||||
.update-status.downloading {
|
||||
background: #1e3a5f;
|
||||
color: #93c5fd;
|
||||
}
|
||||
|
||||
.update-status.success {
|
||||
background: #14532d;
|
||||
color: #86efac;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid #4a90d9;
|
||||
border-top-color: transparent;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background: #1b2636;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: #4a90d9;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.update-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.update-btn {
|
||||
padding: 10px 16px;
|
||||
border: 2px solid #3d4f61;
|
||||
border-radius: 8px;
|
||||
background: #1b2636;
|
||||
color: #9ca3af;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.update-btn:hover {
|
||||
border-color: #4a90d9;
|
||||
background: #2a3a4e;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.update-btn.primary {
|
||||
background: #4a90d9;
|
||||
border-color: #4a90d9;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.update-btn.primary:hover {
|
||||
background: #3b7dc9;
|
||||
border-color: #3b7dc9;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user