Skip to content

Commit 9f9c066

Browse files
committed
Enhance queue management by adding timer recalculation and improving pause/resume functionality
1 parent 619f5f9 commit 9f9c066

File tree

3 files changed

+143
-37
lines changed

3 files changed

+143
-37
lines changed

floating-panel-ui-engine.js

Lines changed: 135 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
// Methods included:
1010
// - addToQueue(buttonConfig): Adds a prompt to the queue.
1111
// - removeFromQueue(index): Removes a prompt from the queue by its index.
12-
// - startQueue(): Begins the sequential sending process.
13-
// - pauseQueue(): Pauses the sending process.
14-
// - resetQueue(): Stops and clears the entire queue.
12+
// - startQueue(): Begins or resumes the sequential sending process.
13+
// - pauseQueue(): Pauses the sending process, remembering the elapsed time.
14+
// - resetQueue(): Stops and clears the entire queue and resets timer state.
15+
// - recalculateRunningTimer(): Adjusts the current timer and progress bar when the delay is changed.
1516
// - processNextQueueItem(): The core function that sends one item and sets a timer for the next.
1617
// - getSiteSpecificSendFunction(): A helper to determine which site-specific send function to use.
1718
//
@@ -28,7 +29,6 @@
2829
window.MaxExtensionFloatingPanel.addToQueue = function (buttonConfig) {
2930
if (this.promptQueue.length >= this.QUEUE_MAX_SIZE) {
3031
logConCgp('[queue-engine] Queue is full. Cannot add more prompts.');
31-
// Optional: Add visual feedback for the user
3232
if (this.queueDisplayArea) {
3333
this.queueDisplayArea.style.borderColor = 'red';
3434
setTimeout(() => {
@@ -58,40 +58,77 @@ window.MaxExtensionFloatingPanel.removeFromQueue = function (index) {
5858
};
5959

6060
/**
61-
* Starts the queue processing.
61+
* Starts or resumes the queue processing.
6262
*/
6363
window.MaxExtensionFloatingPanel.startQueue = function () {
64-
if (this.isQueueRunning || this.promptQueue.length === 0) {
64+
// Prevent starting if already running, or if there's nothing to do.
65+
if (this.isQueueRunning || (this.promptQueue.length === 0 && this.remainingTimeOnPause <= 0)) {
6566
return;
6667
}
6768
this.isQueueRunning = true;
68-
logConCgp('[queue-engine] Queue started.');
69+
this.updateQueueControlsState();
6970

70-
// Show progress bar container when queue starts
7171
if (this.queueProgressContainer) {
7272
this.queueProgressContainer.style.display = 'block';
7373
}
7474

75-
this.updateQueueControlsState();
76-
this.processNextQueueItem();
75+
// If we have remaining time, we are resuming a paused timer.
76+
if (this.remainingTimeOnPause > 0) {
77+
logConCgp(`[queue-engine] Resuming queue with ${this.remainingTimeOnPause}ms remaining.`);
78+
79+
const elapsedTimeBeforePause = this.currentTimerDelay - this.remainingTimeOnPause;
80+
const progressPercentage = (elapsedTimeBeforePause / this.currentTimerDelay) * 100;
81+
82+
// Restore the conceptual start time for accurate future calculations.
83+
this.timerStartTime = Date.now() - elapsedTimeBeforePause;
84+
85+
// Resume progress bar animation from its paused state.
86+
if (this.queueProgressBar) {
87+
this.queueProgressBar.style.transition = 'none';
88+
this.queueProgressBar.style.width = `${progressPercentage}%`;
89+
void this.queueProgressBar.offsetWidth; // Force reflow
90+
this.queueProgressBar.style.transition = `width ${this.remainingTimeOnPause / 1000}s linear`;
91+
this.queueProgressBar.style.width = '100%';
92+
}
93+
94+
this.queueTimerId = setTimeout(() => {
95+
this.remainingTimeOnPause = 0; // Clear the remainder state
96+
this.processNextQueueItem();
97+
}, this.remainingTimeOnPause);
98+
99+
} else {
100+
// This is a fresh start, so process the first item immediately.
101+
logConCgp('[queue-engine] Queue started.');
102+
this.processNextQueueItem();
103+
}
77104
};
78105

79106
/**
80-
* Pauses the queue processing.
107+
* Pauses the queue processing and saves the remaining time.
81108
*/
82109
window.MaxExtensionFloatingPanel.pauseQueue = function () {
83110
this.isQueueRunning = false;
111+
84112
if (this.queueTimerId) {
85113
clearTimeout(this.queueTimerId);
86114
this.queueTimerId = null;
115+
116+
const elapsedTime = Date.now() - this.timerStartTime;
117+
// Ensure remaining time doesn't go negative if the timer fires slightly late.
118+
this.remainingTimeOnPause = (elapsedTime < this.currentTimerDelay)
119+
? this.currentTimerDelay - elapsedTime
120+
: 0;
121+
122+
logConCgp(`[queue-engine] Queue paused. Remaining time: ${this.remainingTimeOnPause}ms`);
123+
} else {
124+
logConCgp('[queue-engine] Queue paused.');
87125
}
88-
logConCgp('[queue-engine] Queue paused.');
89126

90-
// Freeze the progress bar
127+
// Freeze the progress bar at its current position.
91128
if (this.queueProgressBar) {
92129
const computedWidth = window.getComputedStyle(this.queueProgressBar).width;
93-
this.queueProgressBar.style.transition = 'none';
94-
this.queueProgressBar.style.width = computedWidth;
130+
this.queueProgressBar.style.transition = 'none'; // Stop animation
131+
this.queueProgressBar.style.width = computedWidth; // Freeze at current width
95132
}
96133

97134
this.updateQueueControlsState();
@@ -103,19 +140,80 @@ window.MaxExtensionFloatingPanel.pauseQueue = function () {
103140
window.MaxExtensionFloatingPanel.resetQueue = function () {
104141
this.pauseQueue(); // Stop any running timers and set isQueueRunning to false
105142
this.promptQueue = [];
143+
// Reset all timer-related state.
144+
this.remainingTimeOnPause = 0;
145+
this.timerStartTime = 0;
146+
this.currentTimerDelay = 0;
106147
logConCgp('[queue-engine] Queue reset.');
107148

108-
// Hide and reset progress bar
149+
// Hide and reset progress bar to 0%.
109150
if (this.queueProgressBar) {
110151
this.queueProgressBar.style.transition = 'none';
111-
this.queueProgressBar.style.width = '100%';
152+
this.queueProgressBar.style.width = '0%';
112153
}
113154
if (this.queueProgressContainer) {
114155
this.queueProgressContainer.style.display = 'none';
115156
}
116157

117158
this.renderQueueDisplay();
118-
this.updateQueueControlsState(); // This will disable buttons as needed
159+
this.updateQueueControlsState();
160+
};
161+
162+
/**
163+
* Recalculates the running timer when the delay value is changed.
164+
* This function adjusts the progress bar and timer to reflect the new total delay.
165+
*/
166+
window.MaxExtensionFloatingPanel.recalculateRunningTimer = function () {
167+
// Only act if a timer is currently running.
168+
if (!this.isQueueRunning || !this.queueTimerId) {
169+
return;
170+
}
171+
172+
logConCgp('[queue-engine] Recalculating timer due to delay change.');
173+
174+
clearTimeout(this.queueTimerId);
175+
176+
// Calculate how much time has passed on the current timer.
177+
const elapsedTime = Date.now() - this.timerStartTime;
178+
179+
// Get the new total delay from the configuration.
180+
const unit = globalMaxExtensionConfig.queueDelayUnit || 'min';
181+
let newTotalDelayMs;
182+
if (unit === 'sec') {
183+
newTotalDelayMs = (globalMaxExtensionConfig.queueDelaySeconds || 300) * 1000;
184+
} else { // 'min'
185+
newTotalDelayMs = (globalMaxExtensionConfig.queueDelayMinutes || 5) * 60 * 1000;
186+
}
187+
188+
// If time is up with the new delay, process next item.
189+
if (elapsedTime >= newTotalDelayMs) {
190+
logConCgp('[queue-engine] New delay is less than elapsed time. Processing next item.');
191+
this.remainingTimeOnPause = 0;
192+
this.processNextQueueItem();
193+
} else {
194+
// Otherwise, set a new timer for the adjusted remaining time.
195+
const newRemainingTime = newTotalDelayMs - elapsedTime;
196+
logConCgp(`[queue-engine] New remaining time is ${newRemainingTime}ms.`);
197+
198+
// Update the total delay for this timer, critical for subsequent actions.
199+
this.currentTimerDelay = newTotalDelayMs;
200+
201+
this.queueTimerId = setTimeout(() => this.processNextQueueItem(), newRemainingTime);
202+
203+
// Instantly update the progress bar to reflect the new reality.
204+
if (this.queueProgressBar) {
205+
const newProgressPercentage = (elapsedTime / newTotalDelayMs) * 100;
206+
207+
// Set the new progress instantly.
208+
this.queueProgressBar.style.transition = 'none';
209+
this.queueProgressBar.style.width = `${newProgressPercentage}%`;
210+
void this.queueProgressBar.offsetWidth; // Force reflow to apply the new width.
211+
212+
// Animate to 100% over the new remaining time.
213+
this.queueProgressBar.style.transition = `width ${newRemainingTime / 1000}s linear`;
214+
this.queueProgressBar.style.width = '100%';
215+
}
216+
}
119217
};
120218

121219
/**
@@ -128,31 +226,28 @@ window.MaxExtensionFloatingPanel.processNextQueueItem = function () {
128226

129227
if (this.promptQueue.length === 0) {
130228
logConCgp('[queue-engine] Queue is empty. Stopping.');
131-
this.pauseQueue(); // Effectively stops and resets the UI
229+
this.pauseQueue();
132230
return;
133231
}
134232

135-
const item = this.promptQueue.shift(); // Get the first item and remove it
136-
this.renderQueueDisplay(); // Update UI to show the item is gone
233+
const item = this.promptQueue.shift();
234+
this.renderQueueDisplay();
137235
logConCgp(`[queue-engine] Sending item:`, item.text);
138236

139237
const sendFunction = this.getSiteSpecificSendFunction();
140238
if (sendFunction) {
141-
// A mock event object is sufficient for the send functions
142239
const mockEvent = { preventDefault: () => { } };
143-
// Always force auto-send for queued items by passing `true`, overriding the button's individual setting.
144240
sendFunction(mockEvent, item.text, true);
145241
} else {
146242
logConCgp('[queue-engine] No send function found for this site. Stopping queue.');
147243
this.resetQueue();
148244
return;
149245
}
150246

151-
// If there are more items, set a timeout for the next one
247+
// If there are more items, set a timeout for the next one.
152248
if (this.promptQueue.length > 0) {
153249
const unit = globalMaxExtensionConfig.queueDelayUnit || 'min';
154250
let delayMs;
155-
156251
if (unit === 'sec') {
157252
const delaySec = globalMaxExtensionConfig.queueDelaySeconds || 300;
158253
delayMs = delaySec * 1000;
@@ -163,34 +258,39 @@ window.MaxExtensionFloatingPanel.processNextQueueItem = function () {
163258
logConCgp(`[queue-engine] Waiting for ${delayMin} minutes before next item.`);
164259
}
165260

166-
// Start the progress bar animation
261+
// Start the progress bar animation from 0% to 100%.
167262
if (this.queueProgressBar) {
168-
// Reset to full width instantly, then start the transition
169263
this.queueProgressBar.style.transition = 'none';
170-
this.queueProgressBar.style.width = '100%';
264+
this.queueProgressBar.style.width = '0%';
171265

172-
// Force reflow to apply the reset before starting transition
173266
setTimeout(() => {
174267
this.queueProgressBar.style.transition = `width ${delayMs / 1000}s linear`;
175-
this.queueProgressBar.style.width = '0%';
268+
this.queueProgressBar.style.width = '100%';
176269
}, 20);
177270
}
178271

272+
this.timerStartTime = Date.now();
273+
this.currentTimerDelay = delayMs;
274+
this.remainingTimeOnPause = 0; // Ensure reset for a new timer.
179275
this.queueTimerId = setTimeout(() => this.processNextQueueItem(), delayMs);
180276
} else {
181277
logConCgp('[queue-engine] All items have been sent.');
182-
this.pauseQueue(); // Queue finished, so pause/stop
278+
// Visually complete the progress bar.
279+
if (this.queueProgressBar) {
280+
this.queueProgressBar.style.transition = 'none';
281+
this.queueProgressBar.style.width = '100%';
282+
}
283+
this.pauseQueue(); // Queue finished, so pause/stop.
183284

184-
// Hide progress bar after a short delay to let animation finish
285+
// Hide progress bar after a short delay.
185286
setTimeout(() => {
186287
if (this.queueProgressContainer && !this.isQueueRunning) {
187288
this.queueProgressContainer.style.display = 'none';
188289
if (this.queueProgressBar) {
189-
this.queueProgressBar.style.transition = 'none';
190-
this.queueProgressBar.style.width = '100%';
290+
this.queueProgressBar.style.width = '0%'; // Reset for next time.
191291
}
192292
}
193-
}, 1000); // Wait 1 second after finish to hide
293+
}, 1000);
194294
}
195295
};
196296

floating-panel-ui-queue.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ window.MaxExtensionFloatingPanel.initializeQueueSection = function () {
7272
window.globalMaxExtensionConfig.queueDelayUnit = (window.globalMaxExtensionConfig.queueDelayUnit === 'min') ? 'sec' : 'min';
7373
updateDelayUI();
7474
this.saveCurrentProfileConfig(); // Save to profile
75+
this.recalculateRunningTimer(); // Recalculate timer if it's running
7576
});
7677

7778
this.delayInputElement.addEventListener('change', (event) => {
@@ -93,6 +94,7 @@ window.MaxExtensionFloatingPanel.initializeQueueSection = function () {
9394
window.globalMaxExtensionConfig.queueDelayMinutes = delay;
9495
}
9596
this.saveCurrentProfileConfig(); // Save to profile
97+
this.recalculateRunningTimer(); // Recalculate timer if it's running
9698
});
9799

98100
// --- TOS Confirmation (Global) and Queue Toggle (Profile-specific) ---
@@ -194,6 +196,7 @@ window.MaxExtensionFloatingPanel.updateQueueControlsState = function () {
194196
if (!this.playQueueButton || !this.resetQueueButton) return;
195197

196198
const hasItems = this.promptQueue.length > 0;
199+
const isPaused = this.remainingTimeOnPause > 0;
197200

198201
// Play/Pause Button
199202
if (this.isQueueRunning) {
@@ -203,11 +206,11 @@ window.MaxExtensionFloatingPanel.updateQueueControlsState = function () {
203206
} else {
204207
this.playQueueButton.innerHTML = '▶️'; // Play icon
205208
this.playQueueButton.title = 'Start sending the queued prompts.';
206-
this.playQueueButton.disabled = !hasItems; // Disabled if no items
209+
this.playQueueButton.disabled = !hasItems && !isPaused; // Disabled if no items and not paused
207210
}
208211

209212
// Reset Button
210-
this.resetQueueButton.disabled = !hasItems && !this.isQueueRunning;
213+
this.resetQueueButton.disabled = !hasItems && !this.isQueueRunning && !isPaused;
211214

212215
// Hide progress bar if queue is empty and not running
213216
if (this.queueProgressContainer && !this.isQueueRunning && !hasItems) {

floating-panel.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ window.MaxExtensionFloatingPanel = {
5454
promptQueue: [],
5555
isQueueRunning: false,
5656
queueTimerId: null,
57+
timerStartTime: 0,
58+
currentTimerDelay: 0,
59+
remainingTimeOnPause: 0,
5760
queueSectionElement: null,
5861
queueDisplayArea: null,
5962
queueProgressContainer: null,

0 commit comments

Comments
 (0)