news 2026/10/3 7:38:28

Dorso 坐姿监测 AppState 状态机解析:热插拔、断连与锁屏后的自动恢复

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dorso 坐姿监测 AppState 状态机解析:热插拔、断连与锁屏后的自动恢复

Dorso 坐姿监测 AppState 状态机解析:热插拔、断连与锁屏后的自动恢复

【免费下载链接】dorsoA macOS app that blurs your screen when you slouch.项目地址: https://gitcode.com/gh_mirrors/po/dorso

Dorso 是一款 macOS 坐姿监测工具,当你弯腰驼背时会自动模糊屏幕提醒你坐直。它的核心是一个简洁的AppState状态机:面对相机热插拔、外接显示器断开、锁屏休眠等系统事件,如何"暂停—快照—自动恢复"而不让用户手动干预?本文带你完整拆解这套设计。

一、状态机全景:4 个状态 + 6 种暂停原因

整个应用的顶层状态定义在 Sources/Core/AppState.swift 中,非常克制:

状态含义
disabled用户关闭了监测
calibrating正在校准基准坐姿
monitoring正常监测中,检测到驼背即模糊屏幕
paused(reason)因某个原因暂停

暂停不是一个笼统的"停",而是携带原因的paused(PauseReason),共 6 种:noProfile(未完成校准)、onTheGo(仅笔记本屏、外出模式)、cameraDisconnected(相机断连)、screenLocked(锁屏)、airPodsRemoved(AirPods 摘下)、onBattery(电池供电)。

这种"原因枚举"是关键设计:每一种暂停都对应一条明确的恢复路径,菜单栏也能精准显示当前为什么暂停。

二、事件从哪来:四个系统观察者

状态机不直接监听系统,而是由System/目录下的观察者类统一收集事件,再转成Action派发:

  • 相机插拔:CameraObserver.swift 监听AVCaptureDeviceWasConnected/Disconnected通知,只处理视频设备。
  • 显示器热插拔:DisplayMonitor.swift 注册 CoreGraphics 重排回调,并做了0.5 秒防抖,避免插拔瞬间的抖动事件触发多次状态迁移。
  • 锁屏/休眠:ScreenLockObserver.swift 同时监听锁屏通知和屏幕休眠/唤醒通知,覆盖"合盖但不要求密码"的场景。
  • 电源切换:PowerSourceObserver.swift 通过 IOKit 监听 AC/电池切换,并去重电池容量抖动。

观察到的事件在 Sources/AppDelegate/AppDelegate+DeviceEvents.swift 中被"翻译"——先查当前显示器配置对应的坐姿配置文件(Profile),再向TrackingFeature派发cameraDisconnected、displayConfigurationChanged等 Action。

三、相机断连:先找备用相机,再决定暂停还是接管

核心决策逻辑在 PostureEngine.stateWhenCameraDisconnects,规则像一棵清晰的决策树:

  1. 断掉的不是当前选中的相机 → 只同步 UI,状态不变;
  2. 没有备用相机 → 进入paused(cameraDisconnected);
  3. 备用相机正好匹配当前显示器配置档案→ 直接切换到备用相机并立即恢复监测,全程无感;
  4. 备用相机存在但没有匹配档案 → 切换过去,但停在paused(noProfile),等待用户校准。

反向也对称:相机插入时(stateWhenCameraConnects),若新相机匹配档案则自动选中并开始监测;若不匹配且正处于断连暂停,则转入paused(noProfile)提示用户校准。

四、显示器热插拔:"外出模式"的暂停与回归

外接显示器拔掉后,应用要判断"我是不是在移动场景"。stateWhenDisplayConfigurationChanges 的处理顺序:

  1. 状态为disabled或电池暂停时直接忽略(电池暂停是"粘性"的,只有插电/改设置/用户操作才能解除);
  2. 开启了"外出暂停"(Pause on the go)且当前只剩笔记本内置屏→paused(onTheGo);
  3. 任何相机都消失了 →paused(cameraDisconnected);
  4. 有匹配档案的相机 → 必要时自动切换到该相机并恢复monitoring;
  5. 否则 →paused(noProfile)。

插回外接显示器后,同样的逻辑会重新评估:只要当前配置存在匹配的相机档案,状态机就会自动切回监测,不需要任何人工操作。

五、锁屏与解锁:快照-恢复,而不是盲目重启

这是整个状态机最优雅的部分。stateWhenScreenLocks 在锁屏时做两件事:

  • 把当前状态快照进stateBeforeLock(注意它可能本来就是paused(.airPodsRemoved)这类状态,也一并快照);
  • 进入paused(.screenLocked),同时shouldDetectorRun让检测器停转,省资源。

解锁时(stateWhenScreenUnlocks):

  • 有快照且非电池暂停 →精确恢复到锁屏前的状态(monitoring则重启监测,calibrating则回到校准流程);
  • 若无快照(异常情况)→ 保持在锁屏暂停态,等待下一次事件;
  • 特例:如果合盖期间电源被拔掉且开启了"电池暂停",解锁后落到paused(onBattery)而非盲目重启。

细节值得点赞:handleScreenUnlocked 在派发解锁 Action之前先补发一次powerSourceChanged,因为合盖期间电源可能已变化,保证恢复决策基于真实状态。

六、自动模式与可测试性:纯函数 + 副作用意图

开启自动模式后,resolveAutomaticSource 会在每次相机/AirPods 就绪度变化时重新裁决活动源:首选源就绪就用它,否则用备胎,谁都不就绪就带原因暂停。注意开头的"粘性守卫"——paused(onBattery)不会被任何硬件事件悄悄解除。

架构上有个值得学习的模式:

  • PostureEngine.swift 是纯函数状态机,每个场景一个stateWhenXxx方法,输入当前状态,输出新状态 + 需要的副作用标记;
  • TrackingFeature.swift 作为 TCA Reducer 只做路由,把副作用描述为EffectIntent(如startMonitoring、switchCamera),由运行期闭包执行;
  • 因此所有迁移路径都可以离线断言,Tests/PostureEngineTransitionTests.swift 中就能看到"锁屏快照 monitoring → 解锁精确恢复"这类用例。

小结

Dorso 的AppState状态机用 4 个状态 + 6 种暂停原因覆盖了绝大多数系统事件。三条值得借鉴的经验:暂停永远携带原因(恢复路径明确)、先快照再恢复(锁屏场景精确回滚)、决策纯函数化 + 副作用意图化(迁移逻辑可单测、可回放)。无论你做桌面工具还是嵌入式应用,这套"事件 → 纯决策 → 意图副作用"的三层结构都能直接套用。

更多设计背景可参考 PROFILES.md 中的相机档案说明,以及 Sources/Settings/SettingsProfiles.swift 的实现。

【免费下载链接】dorsoA macOS app that blurs your screen when you slouch.项目地址: https://gitcode.com/gh_mirrors/po/dorso

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 7:38:27

下载个资料也要填邮箱?临时邮箱哪些场景该用,哪几种情况千万别用

国庆假期在家整理资料,想下一份某个开源项目的 PDF 手册,点下载,弹出来一个框:「请输入邮箱,我们会把下载链接发给你」。 这种框我一年要遇到几十次。白皮书、行业报告、软件试用、某个论坛看帖、领一张优惠券。每填一…

作者头像 李华
网站建设 2026/10/3 7:38:10

视频动态目标三维重构在边海防平战一体指挥沙盘中的应用技术解析方案

技术权属说明:边海防实景沙盘动态更新、视频驱动三维态势接入、平战态势一体化融合、动态目标三维拟合、沙盘实战推演赋能技术体系由华东师范大学浙江普陀时空大数据研究院团队原创研发,镜像视界(浙江)科技有限公司为唯一产业化落…

作者头像 李华
网站建设 2026/10/3 7:38:07

单视频三维实时重构在岛礁、港口、锚地立体管控中的应用技术解析方案

技术权属说明:岛礁复杂地形三维重建、港口泊位立体感知、锚地船舶动态三维管控、港区通航空间推演、潮汐动态态势自适应更新、海事场景无依托单视频三维感知技术体系由华东师范大学浙江普陀时空大数据研究院团队原创研发,镜像视界(浙江&#…

作者头像 李华
网站建设 2026/10/3 7:36:43

抠图后为什么还有白底从 Alpha 通道到 PNG 和 JPEG 导出

抠图结果在编辑器里看着已经透明,保存下来却像一张白底图。这个现象不能只靠换一个文件后缀解决:有时是查看器的白色底板,有时是导出时合成了底色,也有时,所谓“透明棋盘格”早已变成图片里的普通像素。 我开发的图片…

作者头像 李华