import Cocoa import SwiftUI import DynamicNotchKit /// 管理 AI 回复的刘海弹窗展示 final class NotchDisplayManager { static let shared = NotchDisplayManager() private var currentNotch: DynamicNotch? private var isActive = false private init() {} /// 在刘海/浮动区域展示 AI 回复 func show(text: String) { 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 // 显示 15 秒;用户鼠标悬停时自动暂停倒计时 currentNotch?.show(for: 15) } 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) } }