feat: add keyboard shortcuts (Del/S) and download statistics bar
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c96fd13aff
commit
2481230983
@ -218,6 +218,7 @@
|
|||||||
<button class="btn btn-clear" id="btnClear" onclick="clearCompleted()">Leeren</button>
|
<button class="btn btn-clear" id="btnClear" onclick="clearCompleted()">Leeren</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="stats-bar" id="statsBar"></div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main class="main">
|
<main class="main">
|
||||||
|
|||||||
@ -96,6 +96,10 @@ async function init(): Promise<void> {
|
|||||||
byId('mergeProgressText').textContent = Math.round(percent) + '%';
|
byId('mergeProgressText').textContent = Math.round(percent) + '%';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update stats bar
|
||||||
|
updateStatsBar();
|
||||||
|
setInterval(updateStatsBar, 5000);
|
||||||
|
|
||||||
if (config.client_id && config.client_secret) {
|
if (config.client_id && config.client_secret) {
|
||||||
await connect();
|
await connect();
|
||||||
} else {
|
} else {
|
||||||
@ -119,9 +123,56 @@ async function init(): Promise<void> {
|
|||||||
scheduleQueueSync(document.hidden ? 600 : 150);
|
scheduleQueueSync(document.hidden ? 600 : 150);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Keyboard shortcuts
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
// Skip if user is typing in an input field
|
||||||
|
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement) return;
|
||||||
|
|
||||||
|
if (e.key === 'Delete' && selectedQueueIds.length > 0) {
|
||||||
|
// Delete selected queue items
|
||||||
|
const idsToRemove = [...selectedQueueIds];
|
||||||
|
selectedQueueIds = [];
|
||||||
|
(async () => {
|
||||||
|
for (const id of idsToRemove) {
|
||||||
|
queue = await window.api.removeFromQueue(id);
|
||||||
|
}
|
||||||
|
renderQueue();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((e.key === 's' || e.key === 'S') && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleDownload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
scheduleQueueSync(QUEUE_SYNC_DEFAULT_MS);
|
scheduleQueueSync(QUEUE_SYNC_DEFAULT_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatBytesRenderer(bytes: number): string {
|
||||||
|
if (bytes < 1024) return `${bytes} B`;
|
||||||
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
||||||
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
||||||
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSpeedRenderer(bytesPerSec: number): string {
|
||||||
|
if (bytesPerSec < 1024) return `${bytesPerSec.toFixed(0)} B/s`;
|
||||||
|
if (bytesPerSec < 1024 * 1024) return `${(bytesPerSec / 1024).toFixed(1)} KB/s`;
|
||||||
|
return `${(bytesPerSec / (1024 * 1024)).toFixed(1)} MB/s`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateStatsBar(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const metrics = await window.api.getRuntimeMetrics();
|
||||||
|
const bar = byId('statsBar');
|
||||||
|
if (!bar) return;
|
||||||
|
const totalDL = formatBytesRenderer(metrics.downloadedBytesTotal);
|
||||||
|
const avgSpeed = metrics.avgSpeedBytesPerSec > 0 ? formatSpeedRenderer(metrics.avgSpeedBytesPerSec) : '-';
|
||||||
|
bar.textContent = `${totalDL} | ${avgSpeed} avg | ${metrics.downloadsCompleted} done | ${metrics.downloadsFailed} failed`;
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
let toastHideTimer: number | null = null;
|
let toastHideTimer: number | null = null;
|
||||||
let queueSyncTimer: number | null = null;
|
let queueSyncTimer: number | null = null;
|
||||||
let queueSyncInFlight = false;
|
let queueSyncInFlight = false;
|
||||||
|
|||||||
@ -386,6 +386,14 @@ body {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stats-bar {
|
||||||
|
padding: 6px 15px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.1);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user