From 519acf0d9ab1489c3b4debd91f10fcdb4b253d55 Mon Sep 17 00:00:00 2001 From: DhyaniKavya Date: Tue, 17 Feb 2026 11:22:59 +0530 Subject: [PATCH] fix: add idle watcher interval cleanup and resource management - Store interval ID in _idleWatcherIntervalId property - Store reset handler in _resetIdleTimer for cleanup - Prevent duplicate intervals with clearInterval check - Add cleanupIdleWatcher() method to remove interval and event listeners - No behavior changes to idle detection or FPS throttling --- js/activity.js | 54 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/js/activity.js b/js/activity.js index a5101c7f1b..c2913aa1ee 100644 --- a/js/activity.js +++ b/js/activity.js @@ -1919,8 +1919,9 @@ class Activity { // Queue and take first step. if (!this.turtles.running()) { this.logo.runLogoCommands(); - document.getElementById("stop").style.color = - this.toolbar.stopIconColorWhenPlaying; + document.getElementById( + "stop" + ).style.color = this.toolbar.stopIconColorWhenPlaying; } this.logo.step(); } else { @@ -2245,8 +2246,9 @@ class Activity { i < this.palettes.dict[this.palettes.activePalette].protoList.length; i++ ) { - const name = - this.palettes.dict[this.palettes.activePalette].protoList[i]["name"]; + const name = this.palettes.dict[this.palettes.activePalette].protoList[i][ + "name" + ]; if (name in obj["FLOWPLUGINS"]) { // eslint-disable-next-line no-console console.log("deleting " + name); @@ -2758,6 +2760,11 @@ class Activity { let lastActivity = Date.now(); let isIdle = false; + // Prevent duplicate intervals + if (this._idleWatcherIntervalId) { + clearInterval(this._idleWatcherIntervalId); + } + // Wake up function - restores full framerate const resetIdleTimer = () => { lastActivity = Date.now(); @@ -2769,6 +2776,9 @@ class Activity { } }; + // Store reset handler for cleanup + this._resetIdleTimer = resetIdleTimer; + // Track user activity window.addEventListener("mousemove", resetIdleTimer); window.addEventListener("mousedown", resetIdleTimer); @@ -2777,7 +2787,7 @@ class Activity { window.addEventListener("wheel", resetIdleTimer); // Periodic check for idle state - setInterval(() => { + this._idleWatcherIntervalId = setInterval(() => { // Check if music/code is playing const isMusicPlaying = this.logo?._alreadyRunning || false; @@ -2799,6 +2809,26 @@ class Activity { } }; + /** + * Cleans up the Idle Watcher resources. + * Clears the interval and removes event listeners to prevent memory leaks. + * This method can be called when the activity is being destroyed or reset. + */ + this.cleanupIdleWatcher = function () { + if (this._idleWatcherIntervalId) { + clearInterval(this._idleWatcherIntervalId); + this._idleWatcherIntervalId = null; + } + + if (this._resetIdleTimer) { + window.removeEventListener("mousemove", this._resetIdleTimer); + window.removeEventListener("mousedown", this._resetIdleTimer); + window.removeEventListener("keydown", this._resetIdleTimer); + window.removeEventListener("touchstart", this._resetIdleTimer); + window.removeEventListener("wheel", this._resetIdleTimer); + } + }; + /* * Creates and renders error message containers with appropriate artwork. * Some error messages have special artwork. @@ -5204,8 +5234,9 @@ class Activity { } } staffBlocksMap[staffIndex].baseBlocks[0][0][firstnammedo][4][0] = blockId; - staffBlocksMap[staffIndex].baseBlocks[repeatId.end][0][endnammedo][4][1] = - null; + staffBlocksMap[staffIndex].baseBlocks[repeatId.end][0][ + endnammedo + ][4][1] = null; blockId += 2; } else { @@ -5273,8 +5304,9 @@ class Activity { prevnameddo ][4][1] = blockId; } else { - staffBlocksMap[staffIndex].repeatBlock[prevrepeatnameddo][4][3] = - blockId; + staffBlocksMap[staffIndex].repeatBlock[ + prevrepeatnameddo + ][4][3] = blockId; } if (afternamedo !== -1) { staffBlocksMap[staffIndex].baseBlocks[repeatId.end][0][ @@ -6149,8 +6181,8 @@ class Activity { let customName = "custom"; if (myBlock.connections[1] !== null) { // eslint-disable-next-line max-len - customName = - this.blocks.blockList[myBlock.connections[1]].value; + customName = this.blocks.blockList[myBlock.connections[1]] + .value; } // eslint-disable-next-line no-console console.log(customName);