录制/回放健壮性修复 + 麦克风提示 + 投屏录制偏好分页 + 交互 Bug 修复 (#10–#15, #18, #19) - #16
Merged
Conversation
- RecordingService: 麦克风权限检查由抛错阻断改为返回 Bool,音频降级为 可选轨道;缺麦克风或拒权限时继续纯截图录制,新增 isAudioEnabled 标记 - RecordingLibrary: RecordingSession.audioURL 改为可选;扫描判据放宽为 "无音频且无截图"才跳过;无音频时按最大截图秒数估算时长 - RecordingReplayView: 引入 ReplayClock 抽象(AudioReplayClock / VirtualReplayClock),回放逻辑统一走时钟,无音频时用虚拟时钟驱动时间轴 - 补充纯截图会话应被收录的测试 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 录制前预检磁盘空间(默认 <1GB 不启动),新增 insufficientDiskSpace 错误 - 录制中每约 10 秒检查一次剩余空间,低于安全线(200MB)主动停录 - 连续写截图失败达阈值(3 次)主动停录,不再静默丢帧 - 被动停录(.failed)经状态订阅弹 Toast,并对消息去重避免重复提示; 手动启动失败的提示也统一到该来源 - 补充中英文本地化 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cleanupAfterFailedStart 删除本次已创建但无有效内容的会话目录: 仅当目录为空或只含失败残片(未写入的 audio.m4a / .DS_Store)时删除, 含其他内容则保留,避免误删有效数据。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 新增 SnapshotEncoder:自带后台串行队列 + CIContext,承接缩放/JPEG 编码/写盘,主线程不再阻塞 - 提交前在主线程对 CVPixelBuffer 逐平面深拷贝,规避上游解码器复用缓冲 导致的读到错帧/崩溃 - 背压:编码积压超过阈值(12 帧)丢最新帧并告警,避免内存无限增长 - 写盘结果异步回主线程记账,连续失败达阈值仍能主动停录 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- RecordingLibrary 新增 deleteSession(移入废纸篓,可恢复;限录制根目录下) 与 totalSize(按文件分配大小统计会话占用) - 历史窗口每行新增删除按钮(红色 trash 图标),点击弹确认 sheet,确认后 移入废纸篓并刷新列表;失败弹 Toast - 历史窗口底部展示"共 N 条 · 占用 X"摘要,窗口加宽以容纳三枚操作按钮 - 补充中英文本地化 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
imageCache 由无上限的 [URL: NSImage] 字典改为 NSCache: - countLimit 60 条、totalCostLimit 256MB,长录制回放不再内存无限增长 - 新增 NSImage.estimatedByteCost 按位图像素估算 cost - 读写点与清空(removeAllObjects)同步改造;内存吃紧时系统自动回收 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 9, 2026
Closed
- 权限面板新增"系统权限"组,含麦克风权限行(状态检查/打开系统设置/撤销)
- PermissionType 扩为 .camera/.microphone,并携带按钮 tag、隐私设置 URL、
撤销提示,统一按类型分发
- 修复原 handler 的"摄像头写死"问题:openSystemPreferences/revokePermission
之前无视 sender,现按按钮 tag 反查类型打开对应隐私面板
- checkCameraPermission 通用化为 checkPermission(_:),麦克风查 .audio
- 文案中性表述("录制时用于采集麦克风音频"),与 #17 旁白轨方向兼容
- 补充中英文本地化
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#10 后拒麦克风/麦克风不可用会静默降级为纯截图录制,用户无感知。 现在开始录制成功后按 isAudioEnabled 分支: - 有音频:照旧 success「录制已开始」 - 无音频:改弹 warning「录制已开始(麦克风不可用,仅录制画面)」 复用现有 ToastView.warning,单条提示避免与 success 叠加。文案用中性 表述,覆盖"拒权限"与"授权但 recorder 启动失败"两种情形。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
上一版用单个 isAudioEnabled 布尔,无法区分"为什么没有声音",提示只能 含糊。现引入 RecordingAudioStatus 枚举,startRecording 时按序判定: - noDevice:DiscoverySession 未发现麦克风硬件 - permissionDenied:有设备但权限被拒/受限 - unavailable:有设备有权限但录音器启动失败(被占用/硬件异常) - enabled:正常录制 isAudioEnabled 改为 audioStatus == .enabled 的计算属性。toggleRecording 按四种状态弹对应 toast(有音频 success,其余 warning 分别措辞)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.builtInMicrophone / .externalUnknown 自 macOS 14 起废弃,改名为 .microphone / .external。因部署目标为 13.0 不能直接用新类型,故用 #available 运行时分支:14+ 用 .microphone/.external,13 用旧类型。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
confirmAndDeleteRecording 中 beginSheetModal 的 completion 闭包为非隔离 上下文,直接调用 @mainactor 的 ToastView.error 触发警告。该闭包实际在 主线程回调,用 MainActor.assumeIsolated 包裹,零延迟且消除警告。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
新增分页开放 4 项录制设置,替换 RecordingService 中的写死常量: - 保存位置:文件夹选择器,默认 ~/Movies。录制写入与历史扫描统一 取自 UserPreferences.recordingsRootDirectory,改动即时生效 (RecordingLibrary 根目录改为动态读取,注入值仅测试用)。 - 截图间隔:1/2/5/10s 档位。受整秒时间轴模型约束(文件名以整秒为键、 回放按秒查找),上限 1fps,故为「间隔」而非「帧率」。 - 截图画质:低/中/高档,合成截图长边上限与 JPEG 质量两个内部参数。 - 麦克风录制开关:关闭则纯画面录制,configureAudioTrack 直接短路, 不查硬件/权限;新增 RecordingAudioStatus.disabled,启动 Toast 视为 预期成功而非警告。 音频采样率/码率、磁盘安全阈值等内部参数不开放。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
修复无音频录制回放时,播放到末尾按钮卡在「播放中(暂停图标)」的问题。 根因:VirtualReplayClock 无自停机制,isPlaying 恒为 true,而 playbackTimerFired 仅靠 !isPlaying 复位按钮,故纯截图回放播完后定时器 空转、按钮不复位。音频路径因 AVAudioPlayer.isPlaying 会转 false 而不明显, 但两者播完后都只复位为「播放」图标,没有「重播」态。 改动: - 播放按钮升级为三态 PlaybackButtonState(playing / paused / ended), ended 用 arrow.counterclockwise 重播图标。 - playbackTimerFired 重写:手动暂停走 playPauseTapped 会同步失效定时器、 不进此回调,故定时器一旦观测到停止或到达 duration,必为自然播完 → 置 ended。音频靠 isPlaying 转 false、虚拟时钟靠 currentTime>=duration 判定, 两条路统一。播完顺带对齐进度条/时间到末尾。 - 结束后再点按钮,复用既有 seek(to:0) 逻辑从头播放,闭环正常。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
麦克风开关下方说明用的是 createCheckboxRow 内置 helpText,其容器无底部 padding,紧贴分组边缘。改为独立的 recordingNote 说明行(自带 rowVerticalPadding*1.5 底边距),与截图组一致。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
现象:投屏进行中点红叉或按 Cmd+Q 退出,确认框在主窗口已消失后才出现, 点「取消」又反复弹出,循环无法退出。 根因:两条退出入口对"投屏退出确认"处理不一致。Cmd+Q 走 applicationShouldTerminate,会在窗口可见时弹 sheet;而红叉/Cmd+W 走 windowShouldClose,仅检查未保存 Markdown、不查投屏会话,直接放行关窗。 窗口关闭后 applicationShouldTerminateAfterLastWindowClosed 返回 true 触发 终止,再进 applicationShouldTerminate 才发现投屏活跃,把 sheet 贴到已关闭 的窗口上——窗口没了弹窗还在;取消后"最后窗口已关闭"状态反复触发导致循环。 改动: - windowShouldClose 在 Markdown 确认后、真正关窗前增加投屏会话检查: 投屏中则在窗口仍可见时弹确认。确认→置 isTerminationCloseApproved 并 NSApp.terminate(窗口仍开着,审批状态不会被 windowWillClose 重置); 取消→windowShouldClose 已返回 false,窗口保持打开,投屏不中断。 - presentCaptureQuitConfirmation 改为接受 completion 回调,供 windowShouldClose 与 applicationShouldTerminate 两条路径复用;新增 isVisible 兜底,窗口不可见时退回 runModal。 - 快捷键监视器的无 sheet 分支改走 pendingCaptureQuitCompletion 统一结算。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
停录后不自动弹回放窗口(投屏工具场景下会打断画面/暴露给观众),改为在 "录制已保存"提示条末尾放一个「回放」按钮,点击直接打开回放;不点则延时 消失,悬停暂停消失计时以留出点击时间。 改动: - ToastView 新增尾部文字动作按钮能力(actionTitle + handler,点击执行并 消失),复用原 error 的悬停暂停机制;新增带动作的 success 便捷方法。 原有调用不受影响。 - RecordingLibrary 将单目录→RecordingSession 的构建逻辑从 scanSessions 抽为公开的 makeSession(from:),供停录后即时构建会话复用(不重扫目录)。 - AppDelegate 停录提示改走 presentRecordingSavedToast(directory:):能构建 会话则带「回放」动作,否则退回普通提示。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
围绕录制与回放的一轮完善:先修复 6 项健壮性问题(#10–#15),再补上用户可见的提示与权限入口(#18)、系统兼容性,新增「投屏录制」偏好分页把写死参数开放给用户,并修复回放/退出相关的交互 bug(#19)。每项独立成 commit。
健壮性修复(#10–#15)
RecordingSession.audioURL可选化,回放引入ReplayClock抽象(AudioReplayClock/VirtualReplayClock),无音频时用虚拟时钟驱动时间轴。SnapshotEncoder(后台串行队列 + CIContext),提交前主线程逐平面深拷贝CVPixelBuffer规避上游缓冲复用,带背压丢帧。deleteSession(移入废纸篓)+totalSize;历史窗口每行加删除按钮(确认 sheet)、底部展示"共 N 条 · 占用 X"。imageCache由无上限字典改为NSCache(60 条 / 256MB)。用户提示与权限入口(#18)
RecordingService以RecordingAudioStatus表达,AppDelegate按成因给出对应文案。系统兼容性
AVCaptureDevice.DeviceType(14+ 与更早分支),消除弃用告警。新增「投屏录制」偏好分页
新开一个分页,开放 4 项录制设置,替换
RecordingService中的写死常量:~/Movies。录制写入与历史扫描统一取自UserPreferences.recordingsRootDirectory,改动即时生效(RecordingLibrary根目录改为动态读取,注入值仅测试用)。configureAudioTrack直接短路、不查硬件/权限;新增RecordingAudioStatus.disabled,启动 Toast 视为预期成功而非警告。音频采样率/码率、磁盘安全阈值等内部参数不开放。
交互 Bug 修复
VirtualReplayClock无自停机制、isPlaying恒真,而按钮复位只依赖!isPlaying。改为三态按钮(播放中/已暂停/已播完·重播图标),并在定时器里用"手动暂停不进此回调"这一事实统一判定自然播完(音频靠isPlaying、虚拟时钟靠currentTime>=duration)。windowShouldClose不查投屏会话直接放行关窗,窗口关闭后终止流程才把 sheet 贴到已关闭窗口上。改为在windowShouldClose关窗前(窗口仍可见时)先弹确认:确认→NSApp.terminate,取消→窗口保持打开、投屏不中断;确认逻辑重构为 completion 回调供两条路径复用。停止录制提示优化
停录后不自动弹回放窗口(投屏场景会打断画面/暴露给观众),改为在"录制已保存"提示条末尾放「回放」按钮,点击直接打开回放;不点则延时消失,悬停暂停消失计时。
ToastView为此新增尾部文字动作按钮能力,RecordingLibrary抽出makeSession(from:)供停录即时构建会话复用。测试
xcodebuild build通过xcodebuild test通过:RecordingLibraryTests全绿,含"纯截图会话应被收录并按截图估算时长"用例后续
🤖 Generated with Claude Code