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,13 +245,15 @@ 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)
let nowTs = Date().timeIntervalSince1970
if nowTs - lastFired >= Double(triggerSec) {
defaults.set(nowTs, forKey: K.sitLastNotified)
WorkerNotificationCenter.shared.notify( WorkerNotificationCenter.shared.notify(
title: "该起来动一下了", title: "该起来动一下了",
body: "你已连续坐了 \(sitTriggerMin) 分钟,起身喝口水吧。" body: "你已连续坐了 \(sitTriggerMin) 分钟,起身喝口水吧。"
@ -260,8 +262,14 @@ final class WorkerStore: ObservableObject {
// notification ding is too easy to miss in a meeting, // notification ding is too easy to miss in a meeting,
// so the sit alert gets a louder, longer signal. // so the sit alert gets a louder, longer signal.
SoundPlayer.shared.playMorseSitAlert(count: 15) SoundPlayer.shared.playMorseSitAlert(count: 15)
WorkerDebugLog.write("sit threshold notification + morse alert fired (\(sitElapsedSec)s)") WorkerDebugLog.write("sit threshold fired @ \(sitElapsedSec)s — resetting accumulator")
}
// Reset for next cycle. Update lastFired for telemetry
// even though it's no longer the dedupe gate.
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).