159 lines
4.2 KiB
JavaScript
159 lines
4.2 KiB
JavaScript
// 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 = `
|
|
<div class="loading-container">
|
|
<div class="loading-spinner">
|
|
<div class="spinner-ring"></div>
|
|
<div class="spinner-ring"></div>
|
|
<div class="spinner-ring"></div>
|
|
<div class="spinner-ring"></div>
|
|
</div>
|
|
<div class="loading-text">${message}</div>
|
|
${showProgress ? `
|
|
<div class="progress-container">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" id="progressFill"></div>
|
|
<div class="progress-shine"></div>
|
|
</div>
|
|
<div class="progress-text" id="progressText">0%</div>
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
`;
|
|
|
|
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 = '';
|
|
}
|
|
}
|
|
}
|
|
|