@@ -649,7 +650,7 @@ function renderLaneStrip(m) {
/* =========================================================================
PRESETS (localStorage)
========================================================================= */
-const LS = { presets: "metronome.presets", setlists: "metronome.setlists", logs: "metronome.logs", seeded: "metronome.seeded", continue: "metronome.continue" };
+const LS = { presets: "metronome.presets", setlists: "metronome.setlists", logs: "metronome.logs", seeded: "metronome.seeded", continue: "metronome.continue", timers: "metronome.timers" };
function lsGet(k, fb) { try { const v = localStorage.getItem(k); return v ? JSON.parse(v) : fb; } catch (e) { return fb; } }
function lsSet(k, v) { try { localStorage.setItem(k, JSON.stringify(v)); return true; } catch (e) { console.warn("localStorage unavailable", e); return false; } }
@@ -676,6 +677,7 @@ let activeItem = -1; // selected / loaded item in the active set list
let nowPlaying = null; // { at, name } for duration logging
let historyName = null; // item whose past-session history is shown
let continueMode = lsGet(LS.continue, false); // auto-advance to next item when countdown ends
+let timersOn = lsGet(LS.timers, true); // master switch for the elapsed/countdown timers
function currentSetup() { return { bpm: state.bpm, lanes: snapshotLanes(), trainer: { ...trainer }, ramp: { ...ramp }, countMs: timers.totalMs }; }
function applySetup(s) {
@@ -694,6 +696,7 @@ function syncPracticeUI() {
function refreshFeatureBoxes() {
$("trainerBox").classList.toggle("on", trainer.on);
$("rampBox").classList.toggle("on", ramp.on);
+ $("timerBox").classList.toggle("on", timersOn);
}
function fmtDur(sec) { sec = Math.round(sec); const m = Math.floor(sec / 60); return m + ":" + String(sec % 60).padStart(2, "0"); }
function getSL() { return setlists[activeSL]; }
@@ -996,7 +999,7 @@ function tickTimers() {
const now = Date.now();
const dt = timers.last ? Math.min(now - timers.last, 1000) : 0; // clamp so backgrounded gaps don't jump
timers.last = now;
- if (state.running) {
+ if (timersOn && state.running) {
timers.elapsedMs += dt;
if (timers.totalMs > 0) {
const before = timers.remainingMs;
@@ -1011,6 +1014,8 @@ function tickTimers() {
renderTimers();
}
function renderTimers() {
+ $("dtimers").hidden = !timersOn;
+ if (!timersOn) return;
$("elapsedVal").textContent = fmtClock(timers.elapsedMs);
const off = timers.totalMs <= 0;
$("countWrap").hidden = off; // hide countdown when off
@@ -1090,6 +1095,7 @@ $("countTime").addEventListener("input", (e) => { timers.totalMs = parseTime(e.t
$("elapsedReset").addEventListener("click", () => { timers.elapsedMs = 0; renderTimers(); });
$("countReset").addEventListener("click", () => { timers.remainingMs = timers.totalMs; renderTimers(); });
$("continueMode").addEventListener("change", (e) => { continueMode = e.target.checked; lsSet(LS.continue, continueMode); });
+$("timersOn").addEventListener("change", (e) => { timersOn = e.target.checked; lsSet(LS.timers, timersOn); refreshFeatureBoxes(); renderTimers(); });
$("trayMenuBtn").addEventListener("click", (e) => { e.stopPropagation(); $("trayMenu").hidden = !$("trayMenu").hidden; });
document.addEventListener("click", (e) => { const m = $("trayMenu"); if (m && !m.hidden && !m.contains(e.target) && e.target.id !== "trayMenuBtn") m.hidden = true; });
$("newSetlistBtn").addEventListener("click", newSetlist);
@@ -1155,6 +1161,7 @@ renderLog();
updateCtx();
refreshFeatureBoxes();
$("continueMode").checked = continueMode;
+$("timersOn").checked = timersOn;
$("appVersion").textContent = "v" + APP_VERSION;
requestAnimationFrame(drawLoop);