feat: clarify update progress states
Use a full-width green download track, preserve completed progress in red when cancellation or failure occurs, move status copy below the track, and smooth percentage transitions.
This commit is contained in:
+14
-11
@@ -7492,7 +7492,7 @@ function showUpdateBanner(info) {
|
||||
installButton.disabled = false;
|
||||
installButton.textContent = 'Jetzt installieren';
|
||||
}
|
||||
_setUpdateProgress(0, 'Bereit zum Download');
|
||||
_setUpdateProgress(0, 'Bereit zum Download', 'ready');
|
||||
_setUpdateDialogBusy(false);
|
||||
_syncHeaderUpdateState();
|
||||
_setUpdateDialogVisible(true);
|
||||
@@ -7505,38 +7505,39 @@ function handleUpdateProgress(data) {
|
||||
if (progress.stage === 'starting') {
|
||||
_updateInstallBusy = true;
|
||||
_setUpdateDialogBusy(true, true);
|
||||
_setUpdateProgress(0, 'Download 0%');
|
||||
_setUpdateProgress(0, 'Download 0%', 'downloading');
|
||||
if (message) message.hidden = true;
|
||||
if (button) button.textContent = 'Download 0%';
|
||||
} else if (progress.stage === 'downloading') {
|
||||
const percent = Math.max(0, Math.min(100, Math.round(Number(progress.percent) || 0)));
|
||||
_updateInstallBusy = true;
|
||||
_setUpdateDialogBusy(true, true);
|
||||
_setUpdateProgress(percent, `Download ${percent}%`);
|
||||
_setUpdateProgress(percent, `Download ${percent}%`, 'downloading');
|
||||
if (message) message.hidden = true;
|
||||
if (button) button.textContent = `Download ${percent}%`;
|
||||
} else if (progress.stage === 'verifying') {
|
||||
_updateInstallBusy = true;
|
||||
_setUpdateDialogBusy(true, false);
|
||||
_setUpdateProgress(100, 'Prüfen…');
|
||||
_setUpdateProgress(100, 'Prüfen…', 'verifying');
|
||||
if (message) message.hidden = true;
|
||||
if (button) button.textContent = 'Prüfen…';
|
||||
} else if (progress.stage === 'prepared') {
|
||||
_updateInstallBusy = true;
|
||||
_setUpdateDialogBusy(true, false);
|
||||
_setUpdateProgress(100, 'Neustart…');
|
||||
_setUpdateProgress(100, 'Neustart…', 'prepared');
|
||||
if (message) message.hidden = true;
|
||||
if (button) button.textContent = 'Neustart…';
|
||||
} else if (progress.stage === 'launching' || progress.stage === 'done') {
|
||||
_updateInstallBusy = true;
|
||||
_setUpdateDialogBusy(true, false);
|
||||
_setUpdateProgress(100, 'Neustart…');
|
||||
_setUpdateProgress(100, 'Neustart…', 'prepared');
|
||||
if (message) message.hidden = true;
|
||||
if (button) button.textContent = 'Neustart…';
|
||||
} else if (progress.stage === 'aborted') {
|
||||
_updateInstallBusy = false;
|
||||
_setUpdateDialogBusy(false);
|
||||
_setUpdateProgress(0, 'Download abgebrochen');
|
||||
const currentProgress = Number(document.getElementById('updateProgressBar')?.getAttribute('aria-valuenow')) || 0;
|
||||
_setUpdateProgress(currentProgress, 'Download abgebrochen', 'aborted');
|
||||
if (message) {
|
||||
message.hidden = false;
|
||||
message.textContent = 'Download abgebrochen';
|
||||
@@ -7549,7 +7550,8 @@ function handleUpdateProgress(data) {
|
||||
} else if (progress.stage === 'error') {
|
||||
_updateInstallBusy = false;
|
||||
_setUpdateDialogBusy(false);
|
||||
_setUpdateProgress(0, 'Update fehlgeschlagen');
|
||||
const currentProgress = Number(document.getElementById('updateProgressBar')?.getAttribute('aria-valuenow')) || 0;
|
||||
_setUpdateProgress(currentProgress, 'Update fehlgeschlagen', 'error');
|
||||
if (message) {
|
||||
message.hidden = false;
|
||||
message.textContent = `Update fehlgeschlagen: ${String(progress.error || 'Unbekannter Fehler').slice(0, 400)}`;
|
||||
@@ -7669,7 +7671,7 @@ async function handleUpdateDismiss() {
|
||||
if (!_updateDownloadCancelable || _updateCancelBusy) return false;
|
||||
_updateCancelBusy = true;
|
||||
_setUpdateDialogBusy(true, true);
|
||||
_setUpdateProgress(Number(document.getElementById('updateProgressBar')?.getAttribute('aria-valuenow')) || 0, 'Abbrechen…');
|
||||
_setUpdateProgress(Number(document.getElementById('updateProgressBar')?.getAttribute('aria-valuenow')) || 0, 'Abbrechen…', 'aborted');
|
||||
try {
|
||||
const canceled = await window.api.abortUpdate();
|
||||
if (!canceled) handleUpdateProgress({ stage: 'error', error: 'Update konnte nicht abgebrochen werden' });
|
||||
@@ -7699,7 +7701,7 @@ function _setUpdateDialogBusy(busy, cancelable = false) {
|
||||
if (busy && dialog && (!dialog.contains(document.activeElement) || document.activeElement.matches?.(':disabled'))) dialog.focus();
|
||||
}
|
||||
|
||||
function _setUpdateProgress(percent, text) {
|
||||
function _setUpdateProgress(percent, text, state = 'ready') {
|
||||
const value = Math.max(0, Math.min(100, Math.round(Number(percent) || 0)));
|
||||
const progressText = document.getElementById('updateProgressText');
|
||||
const progressBar = document.getElementById('updateProgressBar');
|
||||
@@ -7707,6 +7709,7 @@ function _setUpdateProgress(percent, text) {
|
||||
if (progressBar) {
|
||||
progressBar.setAttribute('aria-valuenow', String(value));
|
||||
progressBar.setAttribute('aria-valuetext', String(text || `${value}%`));
|
||||
progressBar.dataset.state = state;
|
||||
if ('value' in progressBar) progressBar.value = value;
|
||||
progressBar.style.width = `${value}%`;
|
||||
}
|
||||
@@ -7720,7 +7723,7 @@ async function installKnownUpdate() {
|
||||
}
|
||||
_updateInstallBusy = true;
|
||||
_setUpdateDialogBusy(true, true);
|
||||
_setUpdateProgress(0, 'Download 0%');
|
||||
_setUpdateProgress(0, 'Download 0%', 'downloading');
|
||||
const message = document.getElementById('updateMessage');
|
||||
const button = document.getElementById('installUpdateBtn');
|
||||
if (message) message.hidden = true;
|
||||
|
||||
+10
-5
@@ -2424,9 +2424,8 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
|
||||
.update-progress {
|
||||
grid-column: 1 / -1;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 7px;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
@@ -2473,12 +2472,18 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
|
||||
height: 100%;
|
||||
display: block;
|
||||
border-radius: inherit;
|
||||
background: var(--accent);
|
||||
transition: width .2s ease;
|
||||
background: var(--success);
|
||||
transition: width .48s cubic-bezier(.22, 1, .36, 1), background-color .16s ease;
|
||||
}
|
||||
|
||||
.update-progress-track span[data-state="aborted"],
|
||||
.update-progress-track span[data-state="error"] {
|
||||
background: var(--danger);
|
||||
}
|
||||
|
||||
#updateProgressText {
|
||||
min-width: 34px;
|
||||
justify-self: end;
|
||||
color: var(--text-dim);
|
||||
font-size: 11px;
|
||||
text-align: right;
|
||||
|
||||
+9
-3
@@ -2475,15 +2475,21 @@ setTimeout(async () => {
|
||||
messageHidden: document.getElementById('updateMessage').hidden,
|
||||
messageText: document.getElementById('updateMessage').textContent,
|
||||
progressLabel: progress.getAttribute('aria-label'),
|
||||
progressText: progress.getAttribute('aria-valuetext')
|
||||
progressText: progress.getAttribute('aria-valuetext'),
|
||||
progressState: progress.dataset.state,
|
||||
progressColor: getComputedStyle(progress).backgroundColor,
|
||||
progressTrackWidth: progress.parentElement.getBoundingClientRect().width,
|
||||
progressTextTop: document.getElementById('updateProgressText').getBoundingClientRect().top,
|
||||
progressTrackBottom: progress.parentElement.getBoundingClientRect().bottom
|
||||
};
|
||||
})()\`);
|
||||
check('Busy update keeps its progress dialog open with a dangerous download cancellation action', busyUpdateState.display === 'flex' && busyUpdateState.hidden === 'false' && busyUpdateState.closeDisabled === true && busyUpdateState.dismissDisabled === false && busyUpdateState.dismissText === 'Download abbrechen' && busyUpdateState.dismissDanger === true && busyUpdateState.headerHidden === false);
|
||||
check('Update progress exposes an accessible live value', busyUpdateState.progressLabel === 'Update-Fortschritt' && busyUpdateState.progressText === 'Download 50%');
|
||||
check('Update download progress is green, wide, and places its status below the line', busyUpdateState.progressState === 'downloading' && busyUpdateState.progressColor === 'rgb(117, 211, 155)' && busyUpdateState.progressTrackWidth >= 390 && busyUpdateState.progressTextTop >= busyUpdateState.progressTrackBottom);
|
||||
check('Busy update shows progress only below the bar', busyUpdateState.messageHidden === true && busyUpdateState.messageText === 'Update v9.9.9 verfügbar');
|
||||
|
||||
const updateErrorRecovery = await wc.executeJavaScript('handleUpdateProgress({ stage: "error", error: "Netzwerkfehler" }); document.getElementById("dismissUpdateBtn").click(); document.getElementById("updateBanner").style.display + "|" + document.getElementById("updateCloseBtn").disabled + "|" + document.getElementById("dismissUpdateBtn").disabled + "|" + document.getElementById("headerUpdateBtn").hidden');
|
||||
check('Update errors restore all close actions', updateErrorRecovery === 'none|false|false|false');
|
||||
const updateErrorRecovery = await wc.executeJavaScript('handleUpdateProgress({ stage: "aborted", error: "Update abgebrochen" }); (() => { const bar = document.getElementById("updateProgressBar"); const state = [bar.style.width, bar.dataset.state, getComputedStyle(bar).backgroundColor].join("|"); document.getElementById("dismissUpdateBtn").click(); return state + "|" + document.getElementById("updateBanner").style.display + "|" + document.getElementById("updateCloseBtn").disabled + "|" + document.getElementById("dismissUpdateBtn").disabled + "|" + document.getElementById("headerUpdateBtn").hidden; })()');
|
||||
check('Canceled updates preserve progress in red and restore all close actions', updateErrorRecovery === '50%|aborted|rgb(255, 133, 140)|none|false|false|false');
|
||||
|
||||
const initialInstallUpdateHandler = initialIpcHandlers.get('app:install-update');
|
||||
const initialUpdateQueueHandler = initialIpcHandlers.get('save-pending-queue');
|
||||
|
||||
Reference in New Issue
Block a user