fix(sit): reset accumulator after threshold fire

Prior path used a lastFired-timestamp dedupe but never reset the
sitAccumActiveSec counter, so after the first 45min alert the
panel kept showing "已坐 90 分钟" / "135 分钟" — counter monotonic
across cycles. The UX intent is each ack starts a fresh cycle.

Now: on fire, alert + reset counter to 0. Next triggerSec of
sitting kicks a fresh alert. Reset is the simpler dedupe — there's
no physical way to re-fire without accumulating triggerSec from 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
徐翔宇 2026-05-20 09:29:28 +08:00
parent 19c5be91fa
commit c1747dc1ce

View File

@ -245,23 +245,31 @@ final class WorkerStore: ObservableObject {
sitElapsedSec = sitAccumActiveSec sitElapsedSec = sitAccumActiveSec
// Threshold notification, deduped by triggerSec. // Threshold notification fire once, then reset the
// accumulator so the next triggerSec of sitting kicks a
// FRESH cycle. The prior dedupe-by-lastFired path kept the
// counter monotonically growing, so the panel showed "
// 90 " / " 135 " instead of restarting each
// cycle. Reset is the simpler dedupe: physically can't
// re-fire until the user accumulates another triggerSec.
let triggerSec = sitTriggerMin * 60 let triggerSec = sitTriggerMin * 60
if triggerSec > 0 && sitElapsedSec >= triggerSec { if triggerSec > 0 && sitElapsedSec >= triggerSec {
let lastFired = defaults.double(forKey: K.sitLastNotified) WorkerNotificationCenter.shared.notify(
let nowTs = Date().timeIntervalSince1970 title: "该起来动一下了",
if nowTs - lastFired >= Double(triggerSec) { body: "你已连续坐了 \(sitTriggerMin) 分钟,起身喝口水吧。"
defaults.set(nowTs, forKey: K.sitLastNotified) )
WorkerNotificationCenter.shared.notify( // 1Hz × 15 ticks of system Morse tone the UN
title: "该起来动一下了", // notification ding is too easy to miss in a meeting,
body: "你已连续坐了 \(sitTriggerMin) 分钟,起身喝口水吧。" // so the sit alert gets a louder, longer signal.
) SoundPlayer.shared.playMorseSitAlert(count: 15)
// 1Hz × 15 ticks of system Morse tone the UN WorkerDebugLog.write("sit threshold fired @ \(sitElapsedSec)s — resetting accumulator")
// notification ding is too easy to miss in a meeting,
// so the sit alert gets a louder, longer signal. // Reset for next cycle. Update lastFired for telemetry
SoundPlayer.shared.playMorseSitAlert(count: 15) // even though it's no longer the dedupe gate.
WorkerDebugLog.write("sit threshold notification + morse alert fired (\(sitElapsedSec)s)") sitAccumActiveSec = 0
} sitElapsedSec = 0
defaults.set(0, forKey: K.sitAccumActive)
defaults.set(Date().timeIntervalSince1970, forKey: K.sitLastNotified)
} }
// Persist accumulator once every N ticks (cheap & resilient). // Persist accumulator once every N ticks (cheap & resilient).