VoiceInput/Sources/Core/NotchDisplayManager.swift
JOJO 76741877a8 feat: 朗读功能、弹窗优化、Node.js 打包、Prompt 更新
- Assist/Agent 模式新增朗读开关 + NSSpeechSynthesizer 语音合成
- 朗读完成后弹窗延迟5秒带动画关闭(不再写死15/20秒)
- 打字模式下不自动关闭弹窗
- 二次输入时取消旧朗读/旧延迟关闭,避免竞争问题
- Agent 进度计时器第二次输入时正确归零
- DMG 打包自动清空 models.json API Key
- Node.js 运行时打包进 Agent/bin/,用户无需安装
- Agent system prompt 更新为 VoiceInput 身份 + 语音容错说明
- AGENTS.md 全面更新,补全 Agent 模式文档
2026-04-29 18:22:14 +08:00

106 lines
3.0 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Cocoa
import SwiftUI
import DynamicNotchKit
/// AI
final class NotchDisplayManager {
static let shared = NotchDisplayManager()
private var currentNotch: DynamicNotch<NotchContentView>?
private var isActive = false
private init() {}
/// / AI
/// - Parameter autoHideAfter: nil
func show(text: String, autoHideAfter: TimeInterval? = 15) {
currentNotch?.hide()
let content = NotchContentView(
text: text,
onCopy: {
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.setString(text, forType: .string)
}
)
currentNotch = DynamicNotch(style: .notch) {
content
}
isActive = true
if let duration = autoHideAfter {
currentNotch?.show(for: duration)
} else {
currentNotch?.show()
}
}
/// /
func extendAutoHide(to duration: TimeInterval) {
currentNotch?.show(for: duration)
}
func hide() {
currentNotch?.hide()
currentNotch = nil
isActive = false
}
}
// MARK: -
struct NotchContentView: View {
let text: String
var onCopy: () -> Void
private let maxHeight: CGFloat = 220
var body: some View {
VStack(alignment: .leading, spacing: 8) {
//
HStack(spacing: 0) {
HStack(spacing: 4) {
Image(systemName: "sparkles")
.font(.system(size: 10))
Text("AI 助手回复")
.font(.system(size: 11, weight: .medium))
}
.foregroundColor(.white.opacity(0.5))
Spacer()
Button(action: onCopy) {
HStack(spacing: 3) {
Image(systemName: "doc.on.doc")
.font(.system(size: 9))
Text("复制")
.font(.system(size: 10))
}
.foregroundColor(.white.opacity(0.8))
.padding(.horizontal, 8)
.padding(.vertical, 3)
.background(.white.opacity(0.12))
.clipShape(Capsule())
}
.buttonStyle(.plain)
}
//
ScrollView(.vertical, showsIndicators: false) {
Text(text)
.font(.system(size: 13))
.foregroundColor(.white.opacity(0.85))
.lineSpacing(4)
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxHeight: maxHeight)
}
.padding(.horizontal, 14)
.padding(.vertical, 10)
.frame(width: 320)
}
}