some improvements
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* Stage 1: Shows all progress bars immediately when Generate button is clicked
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { Modal } from '../ui/modal';
|
||||
import { FileIcon, TimeIcon, CheckCircleIcon, ErrorIcon } from '../../icons';
|
||||
import { fetchAPI } from '../../services/api';
|
||||
@@ -53,6 +53,9 @@ export default function ImageQueueModal({
|
||||
onLog,
|
||||
}: ImageQueueModalProps) {
|
||||
const [localQueue, setLocalQueue] = useState<ImageQueueItem[]>(queue);
|
||||
// Track smooth progress animation for each item
|
||||
const [smoothProgress, setSmoothProgress] = useState<Record<number, number>>({});
|
||||
const progressIntervalsRef = useRef<Record<number, NodeJS.Timeout>>({});
|
||||
|
||||
useEffect(() => {
|
||||
setLocalQueue(queue);
|
||||
@@ -64,6 +67,77 @@ export default function ImageQueueModal({
|
||||
}
|
||||
}, [localQueue, onUpdateQueue]);
|
||||
|
||||
// Smooth progress animation (like reference plugin)
|
||||
useEffect(() => {
|
||||
// Start smooth progress for items that are processing
|
||||
localQueue.forEach((item) => {
|
||||
if (item.status === 'processing' && item.progress < 95) {
|
||||
// Only start animation if not already running
|
||||
if (!progressIntervalsRef.current[item.index]) {
|
||||
// Start from current progress or 0
|
||||
let currentProgress = smoothProgress[item.index] || item.progress || 0;
|
||||
let phase = currentProgress < 50 ? 1 : currentProgress < 75 ? 2 : 3;
|
||||
let phaseStartTime = Date.now();
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const elapsed = Date.now() - phaseStartTime;
|
||||
|
||||
if (phase === 1 && currentProgress < 50) {
|
||||
// Phase 1: 0% to 50% in 7 seconds (7.14% per second)
|
||||
currentProgress += 0.714;
|
||||
if (currentProgress >= 50 || elapsed >= 7000) {
|
||||
currentProgress = 50;
|
||||
phase = 2;
|
||||
phaseStartTime = Date.now();
|
||||
}
|
||||
} else if (phase === 2 && currentProgress < 75) {
|
||||
// Phase 2: 50% to 75% in 5 seconds (5% per second)
|
||||
currentProgress += 0.5;
|
||||
if (currentProgress >= 75 || elapsed >= 5000) {
|
||||
currentProgress = 75;
|
||||
phase = 3;
|
||||
phaseStartTime = Date.now();
|
||||
}
|
||||
} else if (phase === 3 && currentProgress < 95) {
|
||||
// Phase 3: 75% to 95% - 5% every second
|
||||
if (elapsed >= 1000) {
|
||||
currentProgress = Math.min(95, currentProgress + 5);
|
||||
phaseStartTime = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
setSmoothProgress(prev => ({
|
||||
...prev,
|
||||
[item.index]: Math.round(currentProgress)
|
||||
}));
|
||||
}, 100);
|
||||
|
||||
progressIntervalsRef.current[item.index] = interval;
|
||||
}
|
||||
} else {
|
||||
// Stop animation if item is no longer processing
|
||||
if (progressIntervalsRef.current[item.index]) {
|
||||
clearInterval(progressIntervalsRef.current[item.index]);
|
||||
delete progressIntervalsRef.current[item.index];
|
||||
}
|
||||
// Clear smooth progress for completed/failed items
|
||||
if (item.status === 'completed' || item.status === 'failed') {
|
||||
setSmoothProgress(prev => {
|
||||
const next = { ...prev };
|
||||
delete next[item.index];
|
||||
return next;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup on unmount
|
||||
return () => {
|
||||
Object.values(progressIntervalsRef.current).forEach(interval => clearInterval(interval));
|
||||
progressIntervalsRef.current = {};
|
||||
};
|
||||
}, [localQueue, smoothProgress]);
|
||||
|
||||
// Polling for task status updates
|
||||
useEffect(() => {
|
||||
if (!isOpen || !taskId) return;
|
||||
@@ -190,6 +264,14 @@ export default function ImageQueueModal({
|
||||
const result = results?.find((r: any) => r.image_id === item.imageId);
|
||||
|
||||
if (result) {
|
||||
// Stop smooth animation for completed/failed items
|
||||
if (result.status === 'completed' || result.status === 'failed') {
|
||||
if (progressIntervalsRef.current[item.index]) {
|
||||
clearInterval(progressIntervalsRef.current[item.index]);
|
||||
delete progressIntervalsRef.current[item.index];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
status: result.status === 'completed' ? 'completed' :
|
||||
@@ -197,23 +279,30 @@ export default function ImageQueueModal({
|
||||
progress: result.status === 'completed' ? 100 :
|
||||
result.status === 'failed' ? 0 :
|
||||
// Use current_image_progress if this is the current image being processed
|
||||
// Otherwise use smooth progress animation
|
||||
(current_image_id === item.imageId && current_image_progress !== undefined) ? current_image_progress :
|
||||
index + 1 < current_image ? 100 :
|
||||
index + 1 === current_image ? 0 : 0,
|
||||
imageUrl: result.image_url || item.imageUrl,
|
||||
index + 1 === current_image ? (smoothProgress[item.index] || 0) : 0,
|
||||
imageUrl: result.image_path
|
||||
? `/api/v1/writer/images/${item.imageId}/file/`
|
||||
: (result.image_url || item.imageUrl),
|
||||
error: result.error || null
|
||||
};
|
||||
}
|
||||
|
||||
// Update based on current_image index and progress
|
||||
if (index + 1 < current_image) {
|
||||
// Already completed
|
||||
// Already completed - stop animation
|
||||
if (progressIntervalsRef.current[item.index]) {
|
||||
clearInterval(progressIntervalsRef.current[item.index]);
|
||||
delete progressIntervalsRef.current[item.index];
|
||||
}
|
||||
return { ...item, status: 'completed', progress: 100 };
|
||||
} else if (index + 1 === current_image || current_image_id === item.imageId) {
|
||||
// Currently processing - use current_image_progress if available
|
||||
// Currently processing - use current_image_progress if available, otherwise smooth progress
|
||||
const progress = (current_image_progress !== undefined && current_image_id === item.imageId)
|
||||
? current_image_progress
|
||||
: 0;
|
||||
: (smoothProgress[item.index] || 0);
|
||||
return { ...item, status: 'processing', progress };
|
||||
}
|
||||
|
||||
@@ -230,11 +319,19 @@ export default function ImageQueueModal({
|
||||
const taskResult = results?.find((r: any) => r.image_id === item.imageId);
|
||||
|
||||
if (taskResult) {
|
||||
// Stop smooth animation
|
||||
if (progressIntervalsRef.current[item.index]) {
|
||||
clearInterval(progressIntervalsRef.current[item.index]);
|
||||
delete progressIntervalsRef.current[item.index];
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
status: taskResult.status === 'completed' ? 'completed' : 'failed',
|
||||
progress: taskResult.status === 'completed' ? 100 : 0,
|
||||
imageUrl: taskResult.image_url || item.imageUrl,
|
||||
imageUrl: taskResult.image_path
|
||||
? `/api/v1/writer/images/${item.imageId}/file/`
|
||||
: (taskResult.image_url || item.imageUrl),
|
||||
error: taskResult.error || null
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user