Super Productivity 休息提醒(Break Reminders)完全指南:触发逻辑、源码原理与配置实战
【免费下载链接】super-productivitySuper Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, GitLab, GitHub and Open Project.项目地址: https://gitcode.com/GitHub_Trending/su/super-productivity
Super Productivity 的休息提醒(Break Reminder)功能会在你连续工作超过设定时长、中间没有任何休息时,主动提示你起身离开电脑。它与真实的时间跟踪(Time Tracking)绑定——只有任务正在被跟踪的时间才会计入阈值,因此反映的是真实的"净工作时间",而非简单的挂钟计时。阅读本文后,你将掌握休息提醒的完整触发条件、"无休息工作时间"的累计与重置机制、全部配置项与默认值,以及锁屏/全屏拦截器等桌面端强化手段的底层实现原理。
休息提醒用于解释"何时时间被记录"可参见如何记录时间,Focus Mode 内置的番茄钟休息参见计时器与专注模式,全部设置项位于设置与偏好。
什么条件下会触发休息提醒?
休息提醒是所有条件同时满足时才显示的"与"逻辑,缺一不可。在源码中,这一判断由TakeABreakService._triggerBanner$完成(见 take-a-break.service.ts):
- 功能已开启—— 设置中
isTakeABreakEnabled为真;否则整个提醒流程直接短路。 - 超过最小工作时间—— 连续"无休息工作时间"(见下文)大于配置的
takeABreakMinWorkingTime。文档默认是 60 分钟,源码中该值来自duration类型的配置项;如果你习惯长时间深度工作,可以放宽到 2 小时。 - 未被 snooze—— 最近没有点过"稍后提醒"(snooze);一旦 snooze,提醒在
takeABreakSnoozeTime(默认 15 分钟)内保持隐藏。 - 没有空闲弹窗—— 空闲(idle)对话框没有打开。对应源码中的
(!isIdle || !cfg.idle.isEnableIdleTimeTracking)判断,避免两个打断弹窗同时叠加出现。
条件满足后,应用显示一个横幅(banner),并且可选地触发桌面通知、声音或更强的强制措施(见下文)。横幅会周期性刷新(源码中PING_UPDATE_BANNER_INTERVAL = 60 * 1000,即每分钟一次)来反映你已经连续工作了多久;桌面通知也做了节流(DESKTOP_NOTIFICATION_THROTTLE = 60 * 1000,每分钟至多一条),避免通知轰炸造成"通知疲劳"。
值得注意的实现细节:_triggerBanner$用throttleTime(PING_UPDATE_BANNER_INTERVAL)限流,而锁屏/全屏拦截器故意不加节流,靠distinctUntilChanged()保证只在状态翻转时触发——防止在休息结束时出现过期横幅。
"无休息工作时间"是如何计数的?
这是休息提醒最核心、也最容易误解的机制。TakeABreakService内部维护了一个timeWorkingWithoutABreak$流,用scan累加器持续累计"无休息工作时间"(take-a-break.service.ts)。
什么会计入计时?
- 只有任务正在被跟踪的 tick才会累加:源码中
_tick$对每个跟踪 tick 先filter(() => !!this._taskService.currentTaskId()),即当前没有活动任务时的 tick 被直接过滤掉。 - 某些流程中手动加入的"工作"时间也会计入(通过
otherNoBreakTIme$手动注入)。 - 空闲(idle)时间段被跟踪到任务上的时间不会计入(对应 issue #9352 的修复,测试用例见 take-a-break.service.spec.ts)。
也就是说:应用开着但没有任何任务在计时,属于被动时间,不累计。提醒完全由"真实被跟踪的工作量"驱动,而不是一个简单的墙钟计时器。
计时器何时归零(reset)?
计时器在以下情况下被重置为 0,然后从零重新开始累计:
- 把时间标记为休息(break)—— 例如在空闲对话框把空闲时间归类为"休息",或通过其他方式记录一次休息。系统据此认为你已经休息过了,重新开始计数。
- 点击"Already Did"(已经休息过了)—— 告诉应用你其实已经休息过。计时器重置,并且应用会在你的休息时间指标里记入一小段休息时间(约 5 分钟),鼓励你真的起身休息而不是仅仅点掉提醒。
- 长时间没有活动任务—— 如果关闭了空闲跟踪,在没有任何任务被跟踪一段时间(约 10 分钟,对应源码常量
BREAK_TRIGGER_DURATION = 10 * 60 * 1000)后计时器自动重置,默认你可能已经离开了电脑。 - 空闲时间被计为休息—— 如果开启了空闲检测,从空闲状态返回并把该段时间归为"休息"时,计时器立即归零,避免你刚休息完又被立刻提醒。
在源码层面,所有归零路径最终都汇入_triggerReset$(take-a-break.service.ts),它既清零计数器,也负责"拆除"提醒(关闭横幅、解除锁屏/全屏拦截状态)。该服务刻意把归零与提醒拆除绑在一起——历史上空闲对话框和 Focus Mode 休息绕过该路径,曾导致横幅残留、锁屏/全屏拦截状态永久锁死(见 issue #9305,相关回归测试在 take-a-break.service.spec.ts)。
一个重要的边界细节:零值与负值 tick
源码注释特别强调:只有_triggerReset$才被允许把计数器归零。来自跟踪流的 tick 若出现0或负值(例如 Android 端焦点会话到期时会传入cap = 0的唤醒 tick,或系统时钟回拨导致 tick 为负),都会被filter((duration) => duration > 0)直接丢弃,绝不会经由 tick 分支把计数器清零——否则横幅会声称"你已经工作了数小时"而计数器实际是 0。相关测试见 take-a-break.service.spec.ts。
休息提醒的间隔如何配置?
有两个核心时间间隔可以在设置 UI(duration 输入框)中配置,对应的配置模型TakeABreakConfig定义在 global-config.model.ts,表单配置在 take-a-break-form.const.ts:
| 配置键 | 含义 | 默认行为 |
|---|---|---|
takeABreakMinWorkingTime | 首次提醒出现前必须连续工作(有任务被跟踪)的最短时长 | 通常为 1 小时;可加大以支持长专注块,也可减小以获得更频繁的提醒 |
takeABreakSnoozeTime | snooze 后提醒保持隐藏的时长 | 通常为 15 分钟;到期后若仍未休息,提醒会再次出现 |
takeABreakMessage | 提醒文案,支持${duration}占位符 | 源码中_createMessage()用msToString(duration)替换${duration},即"已无休息工作多久"(take-a-break.service.ts) |
motivationalImgs | 可选激励图片(Web URL 列表) | 横幅与全屏拦截器会随机挑选一张展示,见Math.floor(Math.random() * ...)随机选择逻辑 |
英文界面的完整帮助文本(见 en.json)这样描述功能:"允许你在连续工作指定时长、中间没有休息时配置一个周期性提醒。你可以修改显示的消息,${duration}会被替换为无休息时长。" 其余设置项还包括isLockScreen(到点锁屏)、isTimedFullScreenBlocker(全屏窗口展示消息)、timedFullScreenBlockerDuration(全屏窗口显示时长)与isFocusWindow(提醒激活时聚焦应用窗口),后三项均标注"desktop only"。
为什么休息被显式支持?
应用默认消息点明了设计初衷:你已经连续工作了相当长的时间而没有休息,起身走动一下(比如散个步)有助于长期生产力。休息提醒的存在理由包括:
- 认知疲劳是非线性的—— 人们往往意识不到自己效率开始下降,一个提醒能起到作用。
- 自愿休息很容易被跳过—— 专注时"再做完这一件小事"可能无限延长;提醒创造了清晰的边界。
- 身体健康—— 久坐和长时间盯屏幕需要规律性打断;应用无法强制你,但可以提醒。
- 未来与当下的权衡—— 休息的收益有一部分在未来(健康、持续表现);提醒让这种取舍变得可见。
该设计是非惩罚性的:你可以 snooze,也可以用"Already Did"直接确认。需要更强边界感的用户,可以在桌面端(Electron)使用升级选项:锁屏和全屏拦截器(可配置时长)。你可以自由选择提醒强度——从温和的横幅到强制暂停。
桌面端强制手段的底层实现
- 锁屏(Lock Screen):Electron 端收到
window.ea.lockScreen()调用后,会按平台执行系统锁屏命令(lockscreen.ts):macOS 使用CGSession -suspend(Big Sur 后的回退方案是模拟Ctrl+Cmd+Q快捷键),Windows 使用rundll32.exe user32.dll, LockWorkStation,Linux 则依次尝试gnome-screensaver-command、dm-tool或qdbus。 - 全屏拦截器(Fullscreen Blocker):由 full-screen-blocker.ts 实现,会创建一个
fullscreen: true, alwaysOnTop: true, skipTaskbar: true的无边框全屏窗口,加载break-reminder-overlay.html页面,通过 URL hash 传入消息、随机激励图片和timedFullScreenBlockerDuration时长;在时长结束前窗口不可关闭(close事件被preventDefault拦截),时长到后才允许关闭。窗口创建还显式设置了contextIsolation、关闭nodeIntegration,确保覆盖层保持安全默认值。
从源码看,锁屏与全屏拦截在触发后还有30 秒延迟(LOCK_SCREEN_DELAY与FULLSCREEN_BLOCKER_DELAY均为30 * 1000),给用户一个短暂的缓冲窗口。
休息提醒如何支持长会话与可持续性?
休息提醒通过以下方式支持可持续的长工作会话:
- 跨整日累积工作时间—— 计时器跨多个工作块累积,不会在中午或会话边界自动清零,除非满足上述重置条件之一。
- 可配置阈值—— 可以把最小工作时间设得更长(如 2 小时),避免深度工作块过早被打断。
- 尊重自主性—— snooze 与"Already Did"让你自己决定何时休息,同时把提醒留在意识中。
- 休息时间指标—— 当你确认休息(如点击"Already Did")时,应用会记录休息时间,让你看到自己确实离开了工位;"Already Did"附赠的 5 分钟休息信用是一种激励,鼓励你真正起身做短暂休息,而不是仅仅点掉提醒。
因此,休息提醒既是安全网(防止连续数小时无暂停),也是一个可以按个人节奏调校的可配置工具。
权衡:不被打断的专注 vs 强制休息
应用在"保护专注"与"鼓励休息"之间保持平衡:
为保护专注:
- 空闲对话框打开时不显示提醒(避免双重打断)。
- 桌面通知被节流,避免刷屏。
- snooze允许你在关键时刻推迟。
- 可配置的最小工作时间允许为深度工作设置更长间隔。
为强制休息(可选,仅桌面端):
- 锁屏—— 应用可以锁住屏幕直到你确认。
- 全屏拦截器—— 持续一段设定时长的全屏覆盖层。
- 窗口聚焦—— 把应用带到前台,确保你看到提醒。
- 声音—— 可以穿透注意力的提示音(配置键
breakReminderSound,来自应用音效设置)。
你可以在设置中选择平衡点:从柔和横幅到硬性停止。
休息提醒与 Focus Mode 的关系
休息提醒和Focus Mode(如番茄钟)是两套独立系统,可以同时运行:
休息提醒:
- 基于整日累积的工作时间(来自任务跟踪)。
- 按可配置间隔(如 1 小时)触发。
- 强调身体健康与可持续生产力。
- 始终可以 snooze 或关闭,是可打断的。
Focus Mode 休息:
- 是番茄钟循环的一部分(如 25 分钟工作、5 分钟休息、每 4 个循环一次长休息)。
- 有自动的会话/休息切换。
- 如果启用相关选项,可以在休息期间暂停任务跟踪。
- 休息可以按设置自动或手动开始。
默认情况下,Focus Mode 的休息不会重置休息提醒的计时器。也就是说,如果你做了一次番茄钟休息,休息提醒的"无休息工作时间"计数器会继续从那次休息之前的位置累加——除非你也把该时段标记为"休息"意义上的休息(例如通过空闲对话框或"Already Did")。如果你希望番茄钟休息也算作提醒意义上的"真休息",可以在番茄钟休息后使用"Already Did",或者在离开时把空闲时间记为休息。
两套系统共同支持结构化工作(Focus Mode)以及在没有 Focus Mode、或超出单个番茄钟块时的安全网。
与空闲检测的集成
如果空闲检测已启用,并且你返回时把空闲时间归为休息,休息提醒的计时器就会重置。这避免了刚离开(且该时段已被计为休息)后立刻又被提醒休息。对应源码中的_triggerIdleDialogReset$:它监听idleDialogResultaction,当isResetBreakTimer为真时触发归零(take-a-break.service.ts)。空闲检测与重新分配对话框的工作方式参见空闲时间。
值得一提的细节:空闲对话框中的重置复选框默认勾选(当一次休息被跟踪时自动默认勾选),因此用户主动取消勾选即表示明确选择不重置计时器。空闲对话框的结果本身不会喂给计数器(issue #9352),归零完全由重置开关驱动。相关的边角行为——例如"未跟踪的空闲时段重置优先于用户在对话框中显式取消重置"——在测试中有详细刻画(take-a-break.service.spec.ts)。
小结
- 休息提醒在功能开启、被跟踪的工作时间超过最小值、未 snooze、且空闲对话框未打开时触发。
- 只有任务被跟踪的时间(以及某些手动工作时间)会计入;当你休息或确认休息(或关闭空闲跟踪后长时间无任务)时计时器重置。
- 可配置最小工作时间与snooze 时长;可自定义消息(支持
${duration}占位符)并添加激励图片。 - 该功能的存在是为了支持可持续生产力与健康;可选的锁屏与全屏拦截器(仅桌面端)提供更强的强制手段。
- 休息提醒独立于 Focus Mode;两者可以同时运行,你也可以调整它们的交互程度(例如在 Focus Mode 休息后使用"Already Did")。
相关文档
- 如何记录时间 —— 任务时间跟踪如何工作(休息提醒计入这段时间)
- 计时器与专注模式 —— Focus Mode 休息 vs 休息提醒
- 空闲时间 —— 把空闲时间归为休息如何重置休息提醒计时器
- 设置与偏好 —— 启用/禁用、最小时间、snooze、消息、锁屏、全屏拦截器
【免费下载链接】super-productivitySuper Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, GitLab, GitHub and Open Project.项目地址: https://gitcode.com/GitHub_Trending/su/super-productivity
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考