// Loading Progress Component with Qt-style progress bar export class LoadingProgress { constructor(container) { this.container = container; this.progressBar = null; this.progressFill = null; this.animationFrame = null; this.progress = 0; this.targetProgress = 0; this.isAnimating = false; } show(message = 'Loading...', showProgress = true) { if (!this.container) return; const loadingHTML = `
${message}
${showProgress ? `
0%
` : ''}
`; this.container.innerHTML = loadingHTML; if (showProgress) { this.progressBar = this.container.querySelector('.progress-bar'); this.progressFill = document.getElementById('progressFill'); this.progressText = document.getElementById('progressText'); this.startProgressAnimation(); } } startProgressAnimation() { this.progress = 0; this.targetProgress = 0; this.isAnimating = true; // More stable progress simulation with smoother steps const steps = [ { progress: 8, delay: 150 }, { progress: 20, delay: 250 }, { progress: 35, delay: 400 }, { progress: 50, delay: 350 }, { progress: 65, delay: 500 }, { progress: 78, delay: 450 }, { progress: 88, delay: 600 }, { progress: 95, delay: 700 }, ]; let stepIndex = 0; let isCancelled = false; this.cancelProgress = () => { isCancelled = true; }; const updateProgress = () => { if (isCancelled || !this.isAnimating) return; if (stepIndex < steps.length) { const step = steps[stepIndex]; this.targetProgress = step.progress; stepIndex++; setTimeout(updateProgress, step.delay); } else { // Keep at 95% until actual loading completes this.targetProgress = 95; } }; updateProgress(); this.animateProgress(); } animateProgress() { if (!this.isAnimating || !this.progressFill) return; // Smooth interpolation const diff = this.targetProgress - this.progress; if (Math.abs(diff) > 0.1) { this.progress += diff * 0.15; // Smooth easing } else { this.progress = this.targetProgress; } if (this.progressFill) { this.progressFill.style.width = `${this.progress}%`; } if (this.progressText) { this.progressText.textContent = `${Math.round(this.progress)}%`; } // Add class when progress starts if (this.progressBar) { if (this.progress > 0) { this.progressBar.classList.add('has-progress'); } else { this.progressBar.classList.remove('has-progress'); } } if (this.isAnimating) { this.animationFrame = requestAnimationFrame(() => this.animateProgress()); } } setProgress(value) { this.targetProgress = Math.min(100, Math.max(0, value)); if (!this.isAnimating && this.progressFill) { this.startProgressAnimation(); } } complete() { this.targetProgress = 100; // Animate to 100% and then hide const checkComplete = () => { if (this.progress >= 99.9) { setTimeout(() => { this.hide(); }, 200); } else { setTimeout(checkComplete, 50); } }; checkComplete(); } hide() { this.isAnimating = false; if (this.cancelProgress) { this.cancelProgress(); } if (this.animationFrame) { cancelAnimationFrame(this.animationFrame); } // Clear progress elements this.progressBar = null; this.progressFill = null; this.progressText = null; if (this.container) { this.container.innerHTML = ''; } } }