import { powerMonitor, BrowserWindow } from 'electron' import { IPC } from '@shared/ipc' import type { Tick } from '@shared/types' import { isQuietAt } from '@shared/types' import { getExercises, getSettings, updateExercise } from './store' import { fireReminder } from './notifications' const TICK_MS = 1000 const CHECK_MS = 5000 let tickHandle: NodeJS.Timeout | null = null let lastCheckAt = 0 let paused = false function checkDueExercises(): void { if (paused) return const settings = getSettings() if (!settings.globalEnabled) return // Inside the quiet window: defer all due fires to the next minute boundary. // The next tick after the window closes will pick them up. if (isQuietAt(settings.quietHours, new Date())) return const now = Date.now() const exercises = getExercises() for (const ex of exercises) { if (!ex.enabled) continue if (ex.nextFireAt <= now) { const updated = updateExercise(ex.id, { nextFireAt: now + ex.intervalMinutes * 60_000 }) if (updated) fireReminder(updated, settings.notificationMode) } } } function broadcastTicks(): void { const now = Date.now() const ticks: Tick[] = getExercises().map((e) => ({ exerciseId: e.id, msUntilFire: Math.max(0, e.nextFireAt - now), enabled: e.enabled })) for (const win of BrowserWindow.getAllWindows()) { if (!win.isDestroyed()) win.webContents.send(IPC.evtTick, ticks) } } function tick(): void { broadcastTicks() const now = Date.now() if (now - lastCheckAt >= CHECK_MS) { lastCheckAt = now checkDueExercises() } } export function startScheduler(): void { if (tickHandle) return lastCheckAt = 0 tickHandle = setInterval(tick, TICK_MS) // Run an immediate tick so renderer hydrates quickly. tick() powerMonitor.on('resume', () => { lastCheckAt = 0 tick() }) powerMonitor.on('unlock-screen', () => { lastCheckAt = 0 tick() }) } export function stopScheduler(): void { if (tickHandle) { clearInterval(tickHandle) tickHandle = null } } export function setPaused(value: boolean): void { paused = value } export function isPaused(): boolean { return paused } export function forceCheck(): void { lastCheckAt = 0 tick() }